Add process name to AsyncProcess
Since [1], Neutron sets the name of some processes (Neutron agents). The "ps" output is modified consequently according to the defined string: "<process name> (<process command>)" "AsyncProcess" class should use the process name to parse the "ps" output correctly. Closes-Bug: #1902678 [1]https://review.opendev.org/#/c/735125/ Change-Id: If33c49c0f3e1e6696f5d2aa4008b287dc3f76c61
This commit is contained in:
parent
dc10558c0b
commit
ad0605f9c3
|
@ -59,7 +59,8 @@ class AsyncProcess(object):
|
|||
"""
|
||||
|
||||
def __init__(self, cmd, run_as_root=False, respawn_interval=None,
|
||||
namespace=None, log_output=False, die_on_error=False):
|
||||
namespace=None, log_output=False, die_on_error=False,
|
||||
process_name=None):
|
||||
"""Constructor.
|
||||
|
||||
:param cmd: The list of command arguments to invoke.
|
||||
|
@ -71,6 +72,8 @@ class AsyncProcess(object):
|
|||
namespace.
|
||||
:param log_output: Optional, also log received output.
|
||||
:param die_on_error: Optional, kills the process on stderr output.
|
||||
:param process_name: Optional, process name set manually by Neutron to
|
||||
nominate a specific process (e.g.: OVS agent, DHCP agent, etc.).
|
||||
"""
|
||||
self.cmd_without_namespace = cmd
|
||||
self._cmd = ip_lib.add_namespace_to_cmd(cmd, namespace)
|
||||
|
@ -86,6 +89,7 @@ class AsyncProcess(object):
|
|||
self._watchers = []
|
||||
self.log_output = log_output
|
||||
self.die_on_error = die_on_error
|
||||
self.process_name = process_name
|
||||
|
||||
@property
|
||||
def cmd(self):
|
||||
|
@ -100,7 +104,8 @@ class AsyncProcess(object):
|
|||
# spawns rootwrap and rootwrap spawns the process. self.pid will make
|
||||
# sure to get the correct pid.
|
||||
return utils.pid_invoked_with_cmdline(
|
||||
self.pid, self.cmd_without_namespace)
|
||||
self.pid, self.cmd_without_namespace,
|
||||
process_name=self.process_name)
|
||||
|
||||
def start(self, block=False):
|
||||
"""Launch a process and monitor it asynchronously.
|
||||
|
|
|
@ -339,7 +339,14 @@ def get_cmdline_from_pid(pid):
|
|||
return cmdline
|
||||
|
||||
|
||||
def cmd_matches_expected(cmd, expected_cmd):
|
||||
def cmd_matches_expected(cmd, expected_cmd, process_name):
|
||||
if process_name and cmd and cmd[0] == process_name:
|
||||
# If Neutron has defined the title (setproctitle) of the running
|
||||
# process, the "ps" output will be "<process_name> (cmd)"
|
||||
cmd = cmd[1:]
|
||||
cmd[0] = cmd[0].strip('(')
|
||||
cmd[-1] = cmd[-1].strip(')')
|
||||
|
||||
abs_cmd = remove_abs_path(cmd)
|
||||
abs_expected_cmd = remove_abs_path(expected_cmd)
|
||||
if abs_cmd != abs_expected_cmd:
|
||||
|
@ -350,12 +357,12 @@ def cmd_matches_expected(cmd, expected_cmd):
|
|||
return abs_cmd == abs_expected_cmd
|
||||
|
||||
|
||||
def pid_invoked_with_cmdline(pid, expected_cmd):
|
||||
def pid_invoked_with_cmdline(pid, expected_cmd, process_name=None):
|
||||
"""Validate process with given pid is running with provided parameters
|
||||
|
||||
"""
|
||||
cmd = get_cmdline_from_pid(pid)
|
||||
return cmd_matches_expected(cmd, expected_cmd)
|
||||
return cmd_matches_expected(cmd, expected_cmd, process_name)
|
||||
|
||||
|
||||
def ensure_directory_exists_without_file(path):
|
||||
|
|
|
@ -69,7 +69,8 @@ class ProcessFixture(fixtures.Fixture):
|
|||
for filename in self.config_filenames:
|
||||
cmd += ['--config-file', filename]
|
||||
self.process = async_process.AsyncProcess(
|
||||
cmd, run_as_root=run_as_root, namespace=self.namespace
|
||||
cmd, run_as_root=run_as_root, namespace=self.namespace,
|
||||
process_name=self.process_name
|
||||
)
|
||||
self.process.start(block=True)
|
||||
LOG.debug("Process started: %s", self.process_name)
|
||||
|
|
|
@ -402,14 +402,29 @@ class TestPathUtilities(base.BaseTestCase):
|
|||
|
||||
def test_cmd_matches_expected_matches_abs_path(self):
|
||||
cmd = ['/bar/../foo']
|
||||
self.assertTrue(utils.cmd_matches_expected(cmd, cmd))
|
||||
self.assertTrue(utils.cmd_matches_expected(cmd, cmd, None))
|
||||
|
||||
def test_cmd_matches_expected_matches_script(self):
|
||||
self.assertTrue(utils.cmd_matches_expected(['python', 'script'],
|
||||
['script']))
|
||||
['script'], None))
|
||||
|
||||
def test_cmd_matches_expected_doesnt_match(self):
|
||||
self.assertFalse(utils.cmd_matches_expected('foo', 'bar'))
|
||||
self.assertFalse(utils.cmd_matches_expected('foo', 'bar', None))
|
||||
|
||||
def test_cmd_matches_expected_matches_script_with_procname(self):
|
||||
self.assertTrue(utils.cmd_matches_expected(
|
||||
['proc_name', '(python', 'script)'], ['script'], 'proc_name'))
|
||||
|
||||
def test_cmd_matches_expected_matches_abs_path_script_with_procname(self):
|
||||
self.assertTrue(utils.cmd_matches_expected(
|
||||
['proc_name', '(python', '/bar/../foo)'], ['/bar/../foo'],
|
||||
'proc_name'))
|
||||
self.assertTrue(utils.cmd_matches_expected(
|
||||
['proc_name', '(python', '/bar/../foo', 'input_param)'],
|
||||
['/bar/../foo', 'input_param'], 'proc_name'))
|
||||
self.assertTrue(utils.cmd_matches_expected(
|
||||
['proc_name', '(/bar/../foo', 'input_param)'],
|
||||
['/bar/../foo', 'input_param'], 'proc_name'))
|
||||
|
||||
|
||||
class FakeUser(object):
|
||||
|
|
Loading…
Reference in New Issue