1

On a RHEL 6.7 server running Python 2.6.6 I am trying to start and stop the Apache webserver as an unprivileged user in a Python script.

The command I am using is "sudo service httpd " where parameter is "start", "stop" or "status".

p = subprocess.Popen("sudo service httpd start", stdout=subprocess.PIPE, stderr=subprocess.PIPE)

This line alone does not work. Adding a

p.communicate()

lets the commands work as desired. Can somebody tell me why?

UPDATE: The sudoers file contains a line that allows my user to run these commands passwordless.

Trevor
  • 1,111
  • 2
  • 18
  • 30
Ronzo
  • 97
  • 1
  • 9

2 Answers2

3

Neither code works (with and without .communicate()).

You should use instead (assuming passwordless sudo for these commands):

import subprocess
subprocess.check_call("sudo service httpd start".split())

The reasons:

  1. subprocess functions do not run the shell by default and therefore the string is interpreted as a name of the command: you should use a list to pass multiple command-line arguments on POSIX
  2. Popen() starts the command and returns immediately without waiting for it to finish i.e., it may happen before httpd is started. Assuming Popen() call is fixed, .communicate() waits for the child process to terminate and therefore it returns after httpd is started (whether it was successful or not).
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • The code definitely works with `.communicate()` and does not without. `shell=True` or `shell=False`makes no difference in my case. The weird thing for me is why Apache won't stop or start when I do not call `.communicate()`. – Ronzo Dec 12 '15 at 00:46
  • @Ronzo: there is no way the code in your question works on a POSIX system such as RHEL. It works if you call `.split()` as in my answer (or if you pass `shell=True` that you should not do here). – jfs Dec 12 '15 at 00:50
  • As I stated above, the code definitely works when I call `.communicate()` and does not when it is not called. It makes no difference if I call `subprocess.Popen(['sudo', 'service', 'httpd', 'start'], Shell=False, ...)` or `subprocess.Popen('sudo service httpd start', Shell=True, ...)` – Ronzo Dec 12 '15 at 09:50
  • @Ronzo: do you understand that the code in your question *differs* from the both variants in your last comment? The code **in your question** does not work. period. Unrelated: Python is a case-sensitive language. Anyway, copy-paste **as is** the code from my answer. If you need to discard the output then also [use `DEVNULL`, not `PIPE`](http://stackoverflow.com/q/11269575/4279) – jfs Dec 12 '15 at 11:33
  • I posted the code passage from my memory because I was not sitting in front of the machine. The code I am using is: `p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)` where `cmd`is the start command with which I am starting various applications on a server. If `cmd="sudo service httpd start"` it only works after i call `p.communicate()`. I am aware of case sensitivity and have realized that `check_call` is a completely different function. I am just wondering why the command to start Apache does not work without calling `.communicate()`. – Ronzo Dec 12 '15 at 12:41
  • `check_call()` is just `Popen()` + `.wait()` call. Now that you understand the first reason in my answer, read the second one. – jfs Dec 12 '15 at 13:04
  • Ok, but when using just `Popen` shouldn't Apache start anyway despite from the fact that `Popen` is not waiting for the process to terminate? The command `sudo service httpd start`has already been issued when `Popen` was called, right? Does calling `Popen` alone prevent it from terminating in its usual manner? – Ronzo Dec 12 '15 at 13:16
  • @Ronzo: add `time.sleep(1)` (for the test), to see that `Popen()` is not the issue. The issue *might* be what happens *after* your main script exits e.g., whether SIGHUP is sent. There is no reason not use `check_call()` here that waits for `sudo` to return and works regardless of what happens after your parent script exits. – jfs Dec 12 '15 at 13:48
  • Thank you very, very much. You pointed me to my scripts' problem. My script exited before the command could complete and I did not realize that this happened. – Ronzo Dec 12 '15 at 16:41
0

There are different reasons for that to happen: 1. the user is in sudoers and configured to not insert password.

  1. sudo remembers your password for some time (depending on your system configuration), see: https://unix.stackexchange.com/questions/37299/how-does-sudo-remember-you-already-entered-roots-password

does it work in a brand new terminal session?

Community
  • 1
  • 1
jarias
  • 166
  • 7
  • sudoers is configured to allow this command passwordless: `myuser ALL = NOPASSWD:/sbin/service httpd *` Behaviour is exactly like I wrote above. Without the communicate line the command does not work, with that line it works as desired. – Ronzo Dec 11 '15 at 11:45