[tor-commits] [stem/master] Support for pulling multiple pids with get_pid_by_name()
atagar at torproject.org
atagar at torproject.org
Sun May 12 02:51:20 UTC 2013
commit 7c0b3ca25596123b5cfbc9251bdfbe630d23ffed
Author: Damian Johnson <atagar at torproject.org>
Date: Sat May 11 17:09:52 2013 -0700
Support for pulling multiple pids with get_pid_by_name()
A leading cause of test failures in our jenkins environment is
test_get_pid_by_name_lsof. This is because the test assumes that there is only
a single tor process, but that's often not the case on the dixie host.
This not only fixes the test, but expands get_pid_by_name() to include a
'multiple' flag to pull all pids for a given process name. This includes unit
test coverage.
---
docs/change_log.rst | 1 +
stem/util/system.py | 80 ++++++++++++++++++++++++++++++--------------
test/integ/util/system.py | 8 +++-
test/unit/util/system.py | 18 ++++++++++
4 files changed, 79 insertions(+), 28 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst
index 5ddfcda..6189038 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -43,6 +43,7 @@ The following are only available within stem's `git repository
* :class:`~stem.response.events.AddrMapEvent` support for the new CACHED argument (:trac:`8596`, :spec:`25b0d43`)
* :func:`~stem.control.Controller.attach_stream` could encounter an undocumented 555 response (:trac:`8701`, :spec:`7286576`)
* :class:`~stem.descriptor.server_descriptor.RelayDescriptor` digest validation was broken with python 3 (:trac:`8755`)
+ * :func:`~stem.util.system.get_pid_by_name` can now pull for all processes with a given name
* **Website**
diff --git a/stem/util/system.py b/stem/util/system.py
index 645fbbe..6b767c7 100644
--- a/stem/util/system.py
+++ b/stem/util/system.py
@@ -219,7 +219,7 @@ def is_running(command):
return None
-def get_pid_by_name(process_name):
+def get_pid_by_name(process_name, multiple = False):
"""
Attempts to determine the process id for a running process, using...
@@ -231,11 +231,15 @@ def get_pid_by_name(process_name):
ps axc | egrep " <name>$" (bsd)
4. lsof -tc <name>
- Results with multiple instances of the process are discarded.
-
:param str process_name: process name for which to fetch the pid
+ :param bool multiple: provides a list of all pids if **True**, otherwise
+ results with multiple processes are discarded
- :returns: **int** with the process id, **None** if it can't be determined
+ :returns:
+ Response depends upon the 'multiple' argument as follows...
+
+ * if **False** then this provides an **int** with the process id or **None** if it can't be determined
+ * if **True** then this provides a **list** of all **int** process ids, and an empty list if it can't be determined
"""
# attempts to resolve using pgrep, failing if:
@@ -249,11 +253,16 @@ def get_pid_by_name(process_name):
if is_available("pgrep"):
results = call(GET_PID_BY_NAME_PGREP % process_name)
- if results and len(results) == 1:
- pid = results[0].strip()
+ if results:
+ try:
+ pids = map(int, results)
- if pid.isdigit():
- return int(pid)
+ if multiple:
+ return pids
+ elif len(pids) == 1:
+ return pids[0]
+ except ValueError:
+ pass
# attempts to resolve using pidof, failing if:
# - we're running on bsd (command unavailable)
@@ -265,11 +274,16 @@ def get_pid_by_name(process_name):
if is_available("pidof"):
results = call(GET_PID_BY_NAME_PIDOF % process_name)
- if results and len(results) == 1 and len(results[0].split()) == 1:
- pid = results[0].strip()
+ if results and len(results) == 1:
+ try:
+ pids = map(int, results[0].split())
- if pid.isdigit():
- return int(pid)
+ if multiple:
+ return pids
+ elif len(pids) == 1:
+ return pids[0]
+ except ValueError:
+ pass
# attempts to resolve using ps, failing if:
# - system's ps variant doesn't handle these flags (none known at the moment)
@@ -292,11 +306,16 @@ def get_pid_by_name(process_name):
# linux variant of ps
results = call(GET_PID_BY_NAME_PS_LINUX % process_name)
- if results and len(results) == 2:
- pid = results[1].strip()
+ if results:
+ try:
+ pids = map(int, results[1:])
- if pid.isdigit():
- return int(pid)
+ if multiple:
+ return pids
+ elif len(pids) == 1:
+ return pids[0]
+ except ValueError:
+ pass
if is_bsd():
# bsd variant of ps
@@ -304,13 +323,17 @@ def get_pid_by_name(process_name):
if results:
# filters results to those with our process name
- results = [r for r in results if r.endswith(" %s" % process_name)]
+ results = [r.split()[0] for r in results if r.endswith(" %s" % process_name)]
- if len(results) == 1 and len(results[0].split()) > 0:
- pid = results[0].split()[0]
+ try:
+ pids = map(int, results)
- if pid.isdigit():
- return int(pid)
+ if multiple:
+ return pids
+ elif len(pids) == 1:
+ return pids[0]
+ except ValueError:
+ pass
# resolves using lsof which works on both Linux and BSD, only failing if:
# - lsof is unavailable (not included by default on OpenBSD)
@@ -329,14 +352,19 @@ def get_pid_by_name(process_name):
if is_available("lsof"):
results = call(GET_PID_BY_NAME_LSOF % process_name)
- if results and len(results) == 1:
- pid = results[0].strip()
+ if results:
+ try:
+ pids = map(int, results)
- if pid.isdigit():
- return int(pid)
+ if multiple:
+ return pids
+ elif len(pids) == 1:
+ return pids[0]
+ except ValueError:
+ pass
log.debug("failed to resolve a pid for '%s'" % process_name)
- return None
+ return [] if multiple else None
def get_pid_by_port(port):
diff --git a/test/integ/util/system.py b/test/integ/util/system.py
index 2c2bc5d..63486a4 100644
--- a/test/integ/util/system.py
+++ b/test/integ/util/system.py
@@ -201,8 +201,12 @@ class TestSystem(unittest.TestCase):
lsof_prefix = stem.util.system.GET_PID_BY_NAME_LSOF % ""
mocking.mock(stem.util.system.call, filter_system_call([lsof_prefix]))
- tor_pid = test.runner.get_runner().get_pid()
- self.assertEquals(tor_pid, stem.util.system.get_pid_by_name("tor"))
+ our_tor_pid = test.runner.get_runner().get_pid()
+
+ all_tor_pids = stem.util.system.get_pid_by_name("tor", multiple = True)
+
+ if len(all_tor_pids) == 1:
+ self.assertEquals(our_tor_pid, all_tor_pids[0])
def test_get_pid_by_port(self):
"""
diff --git a/test/unit/util/system.py b/test/unit/util/system.py
index 4a3473c..fc961cd 100644
--- a/test/unit/util/system.py
+++ b/test/unit/util/system.py
@@ -37,6 +37,12 @@ GET_PID_BY_NAME_PS_BSD = [
" 11 ?? Ss 5:47.36 DirectoryService",
" 12 ?? Ss 3:01.44 notifyd"]
+GET_PID_BY_NAME_PS_BSD_MULTIPLE = [
+ " PID TT STAT TIME COMMAND",
+ " 1 ?? Ss 9:00.22 launchd",
+ " 10 ?? Ss 0:09.97 kextd",
+ " 41 ?? Ss 9:00.22 launchd"]
+
GET_PID_BY_PORT_NETSTAT_RESULTS = [
"Active Internet connections (only servers)",
"Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name",
@@ -141,6 +147,8 @@ class TestSystem(unittest.TestCase):
expected_response = 1111 if test_input == "success" else None
self.assertEquals(expected_response, system.get_pid_by_name(test_input))
+ self.assertEquals([123, 456, 789], system.get_pid_by_name("multiple_results", multiple = True))
+
def test_get_pid_by_name_pidof(self):
"""
Tests the get_pid_by_name function with pidof responses.
@@ -155,6 +163,8 @@ class TestSystem(unittest.TestCase):
expected_response = 1111 if test_input == "success" else None
self.assertEquals(expected_response, system.get_pid_by_name(test_input))
+ self.assertEquals([123, 456, 789], system.get_pid_by_name("multiple_results", multiple = True))
+
def test_get_pid_by_name_ps_linux(self):
"""
Tests the get_pid_by_name function with the linux variant of ps.
@@ -170,6 +180,8 @@ class TestSystem(unittest.TestCase):
expected_response = 1111 if test_input == "success" else None
self.assertEquals(expected_response, system.get_pid_by_name(test_input))
+ self.assertEquals([123, 456, 789], system.get_pid_by_name("multiple_results", multiple = True))
+
def test_get_pid_by_name_ps_bsd(self):
"""
Tests the get_pid_by_name function with the bsd variant of ps.
@@ -181,6 +193,10 @@ class TestSystem(unittest.TestCase):
self.assertEquals(11, system.get_pid_by_name("DirectoryService"))
self.assertEquals(None, system.get_pid_by_name("blarg"))
+ mocking.mock(system.call, mock_call(system.GET_PID_BY_NAME_PS_BSD, GET_PID_BY_NAME_PS_BSD_MULTIPLE))
+
+ self.assertEquals([1, 41], system.get_pid_by_name("launchd", multiple = True))
+
def test_get_pid_by_name_lsof(self):
"""
Tests the get_pid_by_name function with lsof responses.
@@ -195,6 +211,8 @@ class TestSystem(unittest.TestCase):
expected_response = 1111 if test_input == "success" else None
self.assertEquals(expected_response, system.get_pid_by_name(test_input))
+ self.assertEquals([123, 456, 789], system.get_pid_by_name("multiple_results", multiple = True))
+
def test_get_pid_by_port_netstat(self):
"""
Tests the get_pid_by_port function with a netstat response.
More information about the tor-commits
mailing list