2

I have Python script with works as a systemd daemon in CentOS 7. The daemon gets executed by the version of python I created in a virtualenv. I am trying to tweak the script to be able to set the virtualenv path in an environment variable so I can easily switch to a different virtualenv by changing paths via the one variable and restarting the service. I have created my systemd scripts to be able to initialize multiple instances of the daemon and this works great. When I try to use an environment variable to point to my python parser things break. Here is what I have so far.

/etc/systemd/system/[email protected]:

[Unit]
Description=pipeline remove tickets worker instances as a service, instance %i
Requires=pipeline-remove.service
Before=pipeline-remove.service
BindsTo=pipeline-remove.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
ExecStart=/path/to/venv/bin/python /pipeline/python/daemons/remove_tickets.py
Restart=always
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=pipeline-remove.service

/etc/systemd/system/pipeline-remove.service (to start all instances):

[Unit]
Description=manages pipeline remove tickets worker instances as a service, instance

[Service]
Type=oneshot
ExecStart=/usr/bin/sh /usr/bin/pipeline-remove-start.sh
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

pipeline-remove-start.sh:

#!/bin/bash
systemctl start pipeline-remove@{1..2}

This works great for me, but things break when I try to set the python dir the following way:

/etc/profile.d/pipeline_envvars.sh:

PIPELINE_VIRTUALENV=/path/to/venv

/etc/systemd/system/[email protected]:

[Unit]
Description=pipeline remove tickets worker instances as a service, instance %i
Requires=pipeline-remove.service
Before=pipeline-remove.service
BindsTo=pipeline-remove.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
EnvironmentFile=/etc/profile.d/pipeline_envvars.sh
ExecStart=/${PIPELINE_VIRTUALENV}/bin/python /pipeline/python/daemons/remove_tickets.py
Restart=always
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=pipeline-remove.service

I then try to start it:

sudo systemctl daemon-reload
sudo systemctl restart pipeline-remove@{1..1}
sudo systemctl status pipeline-remove@{1..1}

The status shows the following exit code 203 which means executable not found:

[email protected] - pipeline remove tickets worker instances as a service, instance 1
   Loaded: loaded (/etc/systemd/system/[email protected]; disabled; vendor preset: disabled)
   Active: activating (auto-restart) (Result: exit-code) since Fri 2018-01-26 15:04:50 UTC; 6s ago
  Process: 11716 ExecStart=/${PIPELINE_VIRTUALENV}/bin/python /pipeline/python/daemons/remove_tickets.py (code=exited, status=203/EXEC)
 Main PID: 11716 (code=exited, status=203/EXEC)

Jan 26 15:04:50 dev systemd[1]: [email protected]: main process exited, code=exited, status=203/EXEC
Jan 26 15:04:50 dev systemd[1]: Unit [email protected] entered failed state.
Jan 26 15:04:50 dev systemd[1]: [email protected] failed.

Found the exec code here. Also found this in syslog, /var/log/messages:

Jan 26 15:07:13 dev systemd: Starting pipeline remove tickets worker instances as a service, instance 1...
Jan 26 15:07:13 dev systemd: Failed at step EXEC spawning /${PIPELINE_VIRTUALENV}/bin/python: No such file or directory
Jan 26 15:07:13 dev systemd: [email protected]: main process exited, code=exited, status=203/EXEC
Jan 26 15:07:13 dev systemd: Unit [email protected] entered failed state.
Jan 26 15:07:13 dev systemd: [email protected] failed.
Jan 26 15:07:23 dev systemd: [email protected] holdoff time over, scheduling restart.
Jan 26 15:07:23 dev systemd: Started pipeline remove tickets worker instances as a service, instance 1.

When I try to drop the leading / in ExecStart I get a relative path error even though my env var does contain an absolute path:

Failed to start [email protected]: Unit is not loaded properly: 
Invalid argument.
See system logs and 'systemctl status [email protected]' for 
details.

And status shows the following:

vagrant@dev:~$ sudo systemctl status pipeline-remove@{1..1}
● [email protected] - pipeline remove tickets worker instances as a service, instance 1
   Loaded: error (Reason: Invalid argument)
   Active: inactive (dead)

Jan 26 15:11:39 dev systemd[1]: [email protected] failed.
Jan 26 15:11:42 dev systemd[1]: Stopped pipeline remove tickets worker instances as a service, instance 1.
Jan 26 15:11:42 dev systemd[1]: [/etc/systemd/system/[email protected]:12] Executable path is not absolute, ignoring: ${PIPELINE_VIRTUALENV}/bin/python /pipel...e_tickets.py
Jan 26 15:11:42 dev systemd[1]: [email protected] lacks both ExecStart= and ExecStop= setting. Refusing.

I used this guide to help me get started but now I'm stuck. How can I get my python daemon to come up while setting the python executable path from an environment variable?

1 Answer 1

5

After some more reading, I stumbled on the answer here. The problem is the first argument of ExecStart must be a literal:

ExecStart= Commands with their arguments that are executed when this service is started. For each of the specified commands, the first argument must be an absolute and literal path to an executable.

Reading on further on ExecStart it says:

Variables whose value is not known at expansion time are treated as empty strings. Note that the first argument (i.e. the program to execute) may not be a variable.

I also ended up stumbling across this answer which looks like the same problem. In the end this is what worked: wrapping the entire thing with shell to run:

[Unit]
Description=pipeline remove tickets worker instances as a service, instance %i
Requires=pipeline-remove.service
Before=pipeline-remove.service
BindsTo=pipeline-remove.service

[Service]
PermissionsStartOnly=true
Type=idle
User=root
EnvironmentFile=/etc/profile.d/pipeline_envvars.sh
ExecStart=/bin/sh -c '${PIPELINE_VIRTUALENV}/bin/python /pipeline/python/daemons/remove_tickets.py'
Restart=always
TimeoutStartSec=10
RestartSec=10

[Install]
WantedBy=pipeline-remove.service

So ExecStart=/bin/sh -c '<your command>' saves the day, I can now specify the python interpreter path for my environment variable. Will leave the answer up, hopefully, saves others some time.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.