How to run a command inside a virtualenv using systemd

32,955

This doesn't work because source is a shell command, so systemd's ExecStart= or ExecStartPre= won't understand them directly... (BTW, the same is true for cd and the &&.)

You could achieve that by running a shell explicitly and running all your commands together there:

ExecStart=/bin/sh -c 'cd /home/debian/ap/ && source venv-ap/bin/activate && crossbar start'

But a better approach is, instead of sourcing the "activate" script, to use the python executable in the bin/ of your virtualenv directly.

If you look at virtualenv's usage document, you'll notice it says:

ENV/bin is created, where executables live - noticeably a new python. Thus running a script with #! /path/to/ENV/bin/python would run that script under this virtualenv’s python.

In other words, assuming crossbar is the Python script you want to run that requires the venv-ap virtualenv, simply begin crossbar with:

#!/home/debian/ap/venv-ap/bin/python

And it will automatically use the virtualenv whenever invoked.

Also possible, invoking the Python interpreter from the virtualenv directly, with:

ExecStart=/home/debian/ap/venv-ap/bin/python /path/to/crossbar start

(Also, regarding running in a specific directory, setting WorkingDirectory=/home/debian/ap is better than using a cd command. You don't need a shell that way, and systemd can do better error handling for you.)

Share:
32,955

Related videos on Youtube

sscirrus
Author by

sscirrus

Updated on September 18, 2022

Comments

  • sscirrus
    sscirrus over 1 year

    I believe this should be simple but I can't get it to work properly.

    These are the commands I can run on command line:

    cd /home/debian/ap
    
    # Start a virtualenv
    source venv-ap/bin/activate
    
    # This needs to happen inside the virtualenv and takes ~20 seconds
    crossbar start
    
    # Outside the virtualenv, perhaps in a different command line window
    python3 /home/debian/myscript.py
    

    These commands have to be done in this order. Due to the virtualenv, the non-executable for crossbar, and the separate python script afterwards, I haven't been able to figure out the best way to get this to work. My current work-in-progress:

    [Unit]
    Description=Start CB
    After=network.target
    
    [Service]
    Type=simple
    User=debian
    ExecStartPre=source /home/debian/ap/venv-ap/bin/activate
    ExecStart=cd /home/debian/ap/ && crossbar start
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
    
    • Admin
      Admin almost 6 years
      Could you solve it yet? If so, how?
  • nerdoc
    nerdoc about 3 years
    But, the .venv/bin/activate script does more than setting the interpreter. E.g. installing packages does not work. `/path/to(venv/python -m pip install django" does not what it should.
  • filbranden
    filbranden about 3 years
    @nerdoc I haven't tested it myself... The venv docs call out usage without activating explicitly: "You don’t specifically need to activate an environment; activation just prepends the virtual environment’s binary directory to your path, so that “python” invokes the virtual environment’s Python interpreter and you can run installed scripts without having to use their full path. However, all scripts installed in a virtual environment should be runnable without activating it, and run with the virtual environment’s Python automatically."