setting environment variables from command line inside unit files

6,227

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...)

Share:
6,227

Related videos on Youtube

zozo6015
Author by

zozo6015

Updated on September 18, 2022

Comments

  • zozo6015
    zozo6015 over 1 year

    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?