pythonpathsubprocessjupyter

python: subprocess.Popen, openvpn command not found


OS X 10.13.6 Python 3.6

I am trying to run the following command from a jupyter notebook:

vpn_cmd = '''
sudo openvpn 
--config ~/Downloads/configs/ipvanish-US-Chicago-chi-a49.ovpn 
--ca ~/Downloads/configs/ca.ipvanish.com.crt'''

proc = Popen(vpn_cmd.split(), stdout=PIPE, stderr=STDOUT)
stdout, stderr = proc.communicate()
print(stdout.decode())

But get the error:

sudo: openvpn: command not found

What I've tried:

So far, nothing has fixed this. I can run openvpn from my terminal just fine. It seems like a simple path issue but I can't figure out what I need to add to my python path. Is there something particular with the jupyter notebook kernel?


Solution

  • Jupyter probably isn't picking up your personal .bashrc settings, depending also on how you are running it. Just hardcode the path or augment the PATH in your Python script instead.

    With shell=False you don't get the tildes expanded; so you should change those to os.environ["HOME"], or make sure you know in which directory you run this, and use relative paths.

    You should not be using Popen() if run can do what you require.

    home = os.environ["HOME"]
    configs = home + '/Downloads/configs/'
    r = subprocess.run(
        ['sudo', '/usr/local/sbin/openvpn', 
         '--config', configs + 'ipvanish-US-Chicago-chi-a49.ovpn', 
         '--ca', configs + 'ca.ipvanish.com.crt'],
        stdout=PIPE, stderr=PIPE, text=True)
    print(r.stdout)
    

    Tangentially, you should not use "...".split() to split a command line. In this case, it would not matter, but for robustness, probably still prefer shlex.split(), which knows how to handle backslashes and quoted strings in shell commands properly.

    This answer originally used universal_newlines=True but this was changed to the more understandable text=True in Python 3.7. The old syntax will still work, but I updated this answer to reflect current best practice.