systemd, EnvironmentFile, re-using variables – how?
I am migrating from upstart to systemd. I am having a bit of trouble making the transition with the EnvironmentFile directive. I cannot get this EnvironmentFile to work:
########################################################
# Catalina Settings
CLUSTER_BASE=/d01/tomcat/prod/xyz
CATALINA_BASE=$CLUSTER_BASE/1
CATALINA_TMPDIR=$CATALINA_BASE/temp
CATALINA_HOME=/usr/share/tomcat7
CATALINA_PID=/run/tomcat/tc-prod-xyz-1.pid
########################################################
# Java Settings
JAVA_HOME=/usr/lib/jvm/default-java/jre
JAVA_OPTS=-Djava.awt.headless=true
JAVA_OPTS=$JAVA_OPTS -server
JAVA_OPTS=$JAVA_OPTS -Xms2048m
JAVA_OPTS=$JAVA_OPTS -Xmx2048m
JAVA_OPTS=$JAVA_OPTS -XX:MaxPermSize=2048m
JAVA_OPTS=$JAVA_OPTS -XX:+UseParallelGC
JAVA_OPTS=$JAVA_OPTS -XX:+AggressiveHeap
JAVA_OPTS=$JAVA_OPTS -javaagent:$CLUSTER_BASE/newrelic/newrelic.jar
It would appear that this type of statement where I re-use a variable:
JAVA_OPTS=$JAVA_OPTS -XX:+UseParallelGC
is not supported in systemd like it was in upstart. Does systemd support something like this or do I need to make one long hard to read statement?
Do I need to make one long hard to read statement?
No
A line ending with a backslash will be concatenated with the following one, allowing multiline variable definitions.
You could use bash to expand your variables.
Environment file:
BLA=bla
BLABLA=${BLA}${BLA}
Use bash -c
to execute the command:
ExecStart=/usr/bin/bash -c 'echo ${BLA} .. ${BLABLA}'
Output:
bash[4771]: bla .. blabla
Unfortunately that file you have is actually a shell script. In the past, most init systems/scripts have interpreted files which provide environment variables by using the shell, so you could get away with doing shell things in them. Systemd however does not do this. The environment file is truly an environment file, not a script. This is documented in the systemd.exec
man page:
Variable expansion is not performed inside the strings, however, specifier expansion is possible. The $ character has no special meaning.
Therefore you have 2 options.
-
Expand out all your variables manually. Meaning use
CATALINA_BASE=/d01/tomcat/prod/xyz/1
. -
Evaluate the file with the shell:
ExecStart=/bin/bash -ac '. /path/to/env_file; exec /path/to/program'
In the specific case of Tomcat (as in this question), I found that it is easier to put most of these settings in bin/setenv.sh
, which is executed by Tomcat at startup, and evaluates the variables in the shell script as expected.
So in /etc/systemd/system/tomcat.service
I only specify the Environment
variables for CATALINA_BASE
and CATALINA_HOME
, and then I put the rest of the stuff in ${CATALINA_BASE}/bin/setenv.sh
.
Another option: Have a secondary unit that runs before this one and creates an EnvironmentFile
it can use: https://stackoverflow.com/a/42841480/32453
The secondary unit can use bash for instance. Seems to be the systemd
way for importing env. 😐