Implement "find_parent_pid" natively
Use Python native libraries instead of shell calls. Closes-Bug: #1900268 Change-Id: Iaad9e2b3374b5c81f83c780d306685773af719ed
This commit is contained in:
parent
0431531b0c
commit
b4211c8c54
@ -33,6 +33,7 @@ from oslo_rootwrap import client
|
|||||||
from oslo_utils import encodeutils
|
from oslo_utils import encodeutils
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import fileutils
|
from oslo_utils import fileutils
|
||||||
|
import psutil
|
||||||
|
|
||||||
from neutron._i18n import _
|
from neutron._i18n import _
|
||||||
from neutron.agent.linux import xenapi_root_helper
|
from neutron.agent.linux import xenapi_root_helper
|
||||||
@ -186,18 +187,10 @@ def find_parent_pid(pid):
|
|||||||
If the pid doesn't exist in the system, this function will return
|
If the pid doesn't exist in the system, this function will return
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
try:
|
process = psutil.Process(pid=int(pid))
|
||||||
ppid = execute(['ps', '-o', 'ppid=', pid],
|
if process:
|
||||||
log_fail_as_error=False)
|
return str(process.parent().pid)
|
||||||
except exceptions.ProcessExecutionError as e:
|
return None
|
||||||
# Unexpected errors are the responsibility of the caller
|
|
||||||
with excutils.save_and_reraise_exception() as ctxt:
|
|
||||||
# Exception has already been logged by execute
|
|
||||||
no_such_pid = e.returncode == 1
|
|
||||||
if no_such_pid:
|
|
||||||
ctxt.reraise = False
|
|
||||||
return
|
|
||||||
return ppid.strip()
|
|
||||||
|
|
||||||
|
|
||||||
def get_process_count_by_name(name):
|
def get_process_count_by_name(name):
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
import os
|
||||||
|
import signal
|
||||||
|
|
||||||
from neutron.agent.common import async_process
|
from neutron.agent.common import async_process
|
||||||
from neutron.agent.linux import utils
|
from neutron.agent.linux import utils
|
||||||
@ -91,3 +93,28 @@ class TestGetRootHelperChildPid(functional_base.BaseSudoTestCase):
|
|||||||
with open('/proc/%s/cmdline' % child_pid, 'r') as f_proc_cmdline:
|
with open('/proc/%s/cmdline' % child_pid, 'r') as f_proc_cmdline:
|
||||||
cmdline = f_proc_cmdline.readline().split('\0')[0]
|
cmdline = f_proc_cmdline.readline().split('\0')[0]
|
||||||
self.assertIn('bash', cmdline)
|
self.assertIn('bash', cmdline)
|
||||||
|
|
||||||
|
|
||||||
|
class TestFindParentPid(functional_base.BaseSudoTestCase):
|
||||||
|
|
||||||
|
def _stop_process(self, process):
|
||||||
|
process.stop(kill_signal=signal.SIGKILL)
|
||||||
|
|
||||||
|
def _test_process(self, run_as_root):
|
||||||
|
test_pid = str(os.getppid())
|
||||||
|
cmd = ['bash', '-c', '(sleep 10)']
|
||||||
|
proc = async_process.AsyncProcess(cmd, run_as_root=run_as_root)
|
||||||
|
proc.start()
|
||||||
|
self.addCleanup(self._stop_process, proc)
|
||||||
|
common_utils.wait_until_true(lambda: proc._process.pid,
|
||||||
|
sleep=0.5, timeout=10)
|
||||||
|
|
||||||
|
bash_pid = utils.find_parent_pid(proc._process.pid)
|
||||||
|
testcase_pid = utils.find_parent_pid(bash_pid)
|
||||||
|
self.assertEqual(test_pid, testcase_pid)
|
||||||
|
|
||||||
|
def test_root_process(self):
|
||||||
|
self._test_process(run_as_root=True)
|
||||||
|
|
||||||
|
def test_non_root_process(self):
|
||||||
|
self._test_process(run_as_root=False)
|
||||||
|
@ -188,32 +188,6 @@ class AgentUtilsExecuteEncodeTest(base.BaseTestCase):
|
|||||||
self.assertEqual((str_data, ''), result)
|
self.assertEqual((str_data, ''), result)
|
||||||
|
|
||||||
|
|
||||||
class TestFindParentPid(base.BaseTestCase):
|
|
||||||
def setUp(self):
|
|
||||||
super(TestFindParentPid, self).setUp()
|
|
||||||
self.m_execute = mock.patch.object(utils, 'execute').start()
|
|
||||||
|
|
||||||
def test_returns_none_for_no_valid_pid(self):
|
|
||||||
self.m_execute.side_effect = exceptions.ProcessExecutionError(
|
|
||||||
'', returncode=1)
|
|
||||||
self.assertIsNone(utils.find_parent_pid(-1))
|
|
||||||
|
|
||||||
def test_returns_parent_id_for_good_ouput(self):
|
|
||||||
self.m_execute.return_value = '123 \n'
|
|
||||||
self.assertEqual(utils.find_parent_pid(-1), '123')
|
|
||||||
|
|
||||||
def test_raises_exception_returncode_0(self):
|
|
||||||
with testtools.ExpectedException(exceptions.ProcessExecutionError):
|
|
||||||
self.m_execute.side_effect = \
|
|
||||||
exceptions.ProcessExecutionError('', returncode=0)
|
|
||||||
utils.find_parent_pid(-1)
|
|
||||||
|
|
||||||
def test_raises_unknown_exception(self):
|
|
||||||
with testtools.ExpectedException(RuntimeError):
|
|
||||||
self.m_execute.side_effect = RuntimeError()
|
|
||||||
utils.find_parent_pid(-1)
|
|
||||||
|
|
||||||
|
|
||||||
class TestFindForkTopParent(base.BaseTestCase):
|
class TestFindForkTopParent(base.BaseTestCase):
|
||||||
def _test_find_fork_top_parent(self, expected=_marker,
|
def _test_find_fork_top_parent(self, expected=_marker,
|
||||||
find_parent_pid_retvals=None,
|
find_parent_pid_retvals=None,
|
||||||
|
Loading…
Reference in New Issue
Block a user