Search code examples
pythonpipsystemd

Install pip libraries for root user


I have a systemd service that regularly reads the first line of a root-owned file, transforms it and then uses png_util:

import png_util

with open('root-owned-file', 'r') as f:
  f.read()

...rest of logic...

Now, when the systemd daemon starts, it doesn't have access to the png_util library I installed with pip (pip install png_util) because that only installs it for the installing user. This also happens, when I start the script with sudo:

ModuleNotFoundError: No module named 'png_util'

If I read a file owned by me and execute the script normally as my user, everything works fine.

The systemd service:

[Unit]
Description=PNG

[Service]
ExecStart=/tmp/pngreader

[Install]
WantedBy=multi-user.target

Is the trick simply using pip install --user root and then setting the PYTHONPATH for the root user somehow?


Solution

  • I think you can get what you need with a virtual environment.

    You need to create a virtual environment specifically for that script. You will install all the packages you will need for it with the right versions in that environment. As long as you run your script with that virtual environment active everything will be available.- See the venv documenttion here

    To create a virtual environment you run python3 -m venv <your_venv_path> with path being where you want to store it, e.g. ~/.venvs/my_project/

    To install packages you first have to make it active and then run pip

    source <your_venv_path>/bin/activate
    pip install png_util
    

    To here you would have your virtual environment ready and your package installed. If you run your script with your virtual environment active the package will be available.

    Now, because your script is a daemon this is how you make sure it runs within your virtual environment. Basically the virtual environment creates a copy of Python in and you just add to your script the instruction to use that "copy" of python. You do it by just adding #!<your_venv_path>/bin/python as the first line of your script.

    That way when your script runs it does run within that virtual environment where all the packages are installed.

    PS: Potentially everything could work by simply running pip as sudo because it will install the package system wide making it available for all users. But that option is highly discouraged for the security risks it creates, see this post with security risks of running sudo pip

    Hope this helps!!