setting environment variables from command line inside unit files

5

5

I am trying to set a date inside the unit file for logging

my unit file look like this:

[Unit]
Description=Jetty service
After=multiuser.target

[Service]
Environment=MAIN_CLASS="com.candorgrc.nphase.MainJetty"
Type=simple
User=jetty
Group=jetty
WorkingDirectory=/home/jetty/dist
PermissionsStartOnly=true
ExecStartPre=/bin/systemctl set-environment date=$(/bin/date +%%Y-%%m-%%d-%%H-%%M)
ExecStart=/usr/bin/java -Xms512m -Xmx1024m -Djava.util.logging.config.file=/home/jetty/logging.properties -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/u01/jetty/hdumps/hdump_${date} -verbose:gc -Dcom.sun.management.jmxremote.port=12321 -Dcom.sun.management.jmxremote.authen
PIDFile=/var/run/jetty.pid
ExecReload=/bin/kill -HUP $MAINPID
#Restart=on-failure
ExecStop=/bin/kill -9 $MAINPID

Setting the date does not seam to be working. The error I get is the following:

Nov 26 16:47:50 vps203756 systemctl[14275]: Failed to set environment: Invalid environment assignments
Nov 26 16:47:50 vps203756 systemd[1]: jetty.service: Control process exited, code=exited status=1
Nov 26 16:47:50 vps203756 systemd[1]: jetty.service: Failed with result 'exit-code'.
Nov 26 16:47:50 vps203756 systemd[1]: Failed to start Jetty service.

Any idea how to configure it for it to work?

zozo6015

Posted 2018-11-26T21:54:50.020

Reputation: 51

Answers

6

Commands in ExecStart= in systemd service units do not really run on a shell, so shell expansions (such as the command substitution $(...) you use there) are not really available.

You can use them by calling a shell script explicitly, with /bin/sh -c '...', in your ExecStartPre=. For example:

ExecStartPre=/bin/sh -c 'systemctl set-environment date=$$(/bin/date +%%Y-%%m-%%d-%%H-%%M)'

Note that you need to escape the $ itself, by using $$, otherwise systemd will try to interpret as a systemd variable expansion. (Actually, as the next character is (, a single $ might work there, but doubling it is the more correct setup.)

Please note that using systemctl set-environment like you're doing is really not recommended, since you're creating a global environment variable ${date} that will be available everywhere.

Instead, consider running your ExecStart= command through a shell, in which case you can define a shell variable ${date} and just use it in the single place you need it:

ExecStart=/bin/sh -c 'date=$$(/bin/date +%%Y-%%m-%%d-%%H-%%M); exec java -Xms512m -Xmx1024m ... -XX:HeapDumpPath=/u01/jetty/hdumps/hdump_$${date} -verbose:gc ...

Note again, escaping the $ with $${date}, so systemd doesn't think it's a systemd variable to expand. Also, using exec to ensure the shell is replaced with the java process, making sure systemd will know what the main PID of the service is.

Escaping on systemd ExecStart= can become complex and burdensome quite quickly... So consider instead storing the shell script in a file (in which case you don't need to worry about escaping $ and % and about how the quotes might work slightly differently) and just run that script from the ExecStart=, that's a lot simpler (even though it requires an extra file...)

filbranden

Posted 2018-11-26T21:54:50.020

Reputation: 1 058