def _wait_for_child_process(self, timeout=CHILD_PROCESS_TIMEOUT, sleep=CHILD_PROCESS_SLEEP): def child_is_running(): child_pid = utils.get_root_helper_child_pid(self.pid, self.cmd, run_as_root=True) if utils.pid_invoked_with_cmdline(child_pid, self.cmd): return True try: common_utils.wait_until_true(child_is_running, timeout) except common_utils.WaitTimeout: # If there is an error, the stderr and stdout pipes usually have # information returned by the command executed. If not, timeout # the pipe communication quickly. stdout = stderr = '' try: stdout, stderr = self.communicate(timeout=0.5) except subprocess.TimeoutExpired: pass msg = ("Process %(cmd)s hasn't been spawned in %(seconds)d " "seconds. Return code: %(ret_code)s, stdout: %(stdout)s, " "sdterr: %(stderr)s" % { 'cmd': self.cmd, 'seconds': timeout, 'ret_code': self.returncode, 'stdout': stdout, 'stderr': stderr }) raise RuntimeError(msg) self.child_pid = utils.get_root_helper_child_pid(self.pid, self.cmd, run_as_root=True)
def _test_get_root_helper_child_pid(self, expected=_marker, run_as_root=False, pids=None, cmds=None): def _find_child_pids(x): if not pids: return [] pids.pop(0) return pids mock_pid = object() pid_invoked_with_cmdline = {} if cmds: pid_invoked_with_cmdline['side_effect'] = cmds else: pid_invoked_with_cmdline['return_value'] = False with mock.patch.object(utils, 'find_child_pids', side_effect=_find_child_pids), \ mock.patch.object(utils, 'pid_invoked_with_cmdline', **pid_invoked_with_cmdline): actual = utils.get_root_helper_child_pid(mock_pid, mock.ANY, run_as_root) if expected is _marker: expected = str(mock_pid) self.assertEqual(expected, actual)
def pid(self): if self._process: if not self._pid: self._pid = utils.get_root_helper_child_pid( self._process.pid, self.cmd_without_namespace, run_as_root=self.run_as_root) return self._pid
def pid(self): if self._process: if not self._pid: self._pid = utils.get_root_helper_child_pid( self._process.pid, self.cmd_without_namespace, run_as_root=self.run_as_root) return self._pid
def test_async_process_respawns(self): proc = async_process.AsyncProcess(["tail", "-f", self.test_file_path], respawn_interval=0) proc.start() # Ensure that the same output is read twice self._check_stdout(proc) pid = utils.get_root_helper_child_pid(proc._process.pid, proc.root_helper) proc._kill_process(pid) self._check_stdout(proc) proc.stop()
def _wait_for_child_process(self, timeout=CHILD_PROCESS_TIMEOUT, sleep=CHILD_PROCESS_SLEEP): def child_is_running(): child_pid = utils.get_root_helper_child_pid(self.pid, run_as_root=True) if utils.pid_invoked_with_cmdline(child_pid, self.cmd): return True utils.wait_until_true( child_is_running, timeout, exception=RuntimeError("Process %s hasn't been spawned " "in %d seconds" % (self.cmd, timeout)), ) self.child_pid = utils.get_root_helper_child_pid(self.pid, run_as_root=True)
def test_async_process_respawns(self): proc = async_process.AsyncProcess(['tail', '-f', self.test_file_path], respawn_interval=0) proc.start() # Ensure that the same output is read twice self._check_stdout(proc) pid = utils.get_root_helper_child_pid(proc._process.pid, proc.run_as_root) proc._kill_process(pid) self._check_stdout(proc) proc.stop()
def test_killed_monitor_respawns(self): self.monitor.respawn_interval = 0 old_pid = self.monitor._process.pid output1 = self.collect_initial_output() pid = utils.get_root_helper_child_pid(old_pid, self.root_helper) self.monitor._kill_process(pid) self.monitor._reset_queues() while (self.monitor._process.pid == old_pid): eventlet.sleep(0.01) output2 = self.collect_initial_output() # Initial output should appear twice self.assertEqual(output1, output2)
def test_killed_monitor_respawns(self): self.monitor.respawn_interval = 0 old_pid = self.monitor._process.pid output1 = self.collect_initial_output() pid = utils.get_root_helper_child_pid(old_pid, run_as_root=True) self.monitor._kill_process(pid) self.monitor._reset_queues() while (self.monitor._process.pid == old_pid): eventlet.sleep(0.01) output2 = self.collect_initial_output() # Initial output should appear twice self.assertEqual(output1, output2)
def _test_get_root_helper_child_pid(self, expected=_marker, run_as_root=False, pids=None): def _find_child_pids(x): if not pids: return [] pids.pop(0) return pids mock_pid = object() with mock.patch.object(utils, "find_child_pids", side_effect=_find_child_pids): actual = utils.get_root_helper_child_pid(mock_pid, run_as_root) if expected is _marker: expected = str(mock_pid) self.assertEqual(expected, actual)
def _test_get_root_helper_child_pid(self, expected=_marker, run_as_root=False, pids=None): def _find_child_pids(x): if not pids: return [] pids.pop(0) return pids mock_pid = object() with mock.patch.object(utils, 'find_child_pids', side_effect=_find_child_pids): actual = utils.get_root_helper_child_pid(mock_pid, run_as_root) if expected is _marker: expected = str(mock_pid) self.assertEqual(expected, actual)
def _wait_for_child_process(self, timeout=CHILD_PROCESS_TIMEOUT, sleep=CHILD_PROCESS_SLEEP): def child_is_running(): child_pid = utils.get_root_helper_child_pid( self.pid, run_as_root=self.run_as_root) if pid_invoked_with_cmdline(child_pid, self.cmd): return True wait_until_true( child_is_running, timeout, exception=RuntimeError("Process %s hasn't been spawned " "in %d seconds" % (self.cmd, timeout))) self.child_pid = utils.get_root_helper_child_pid( self.pid, run_as_root=self.run_as_root)
def test_get_root_helper_child_pid_returns_first_child(self): """Test that the first child, not lowest child pid is returned. Test creates following process tree: sudo + | +--rootwrap + | +--bash+ | +--sleep 100 and tests that pid of `bash' command is returned. """ def wait_for_sleep_is_spawned(parent_pid): proc_tree = utils.execute( ['pstree', parent_pid], check_exit_code=False) processes = [command.strip() for command in proc_tree.split('---') if command] if processes: return 'sleep' == processes[-1] cmd = ['bash', '-c', '(sleep 100)'] proc = async_process.AsyncProcess(cmd, run_as_root=True) proc.start() # root helpers spawn their child processes asynchronously, and we # don't want to use proc.start(block=True) as that uses # get_root_helper_child_pid (The method under test) internally. sudo_pid = proc._process.pid common_utils.wait_until_true( functools.partial( wait_for_sleep_is_spawned, sudo_pid), sleep=0.1) child_pid = utils.get_root_helper_child_pid( sudo_pid, cmd, run_as_root=True) self.assertIsNotNone( child_pid, "get_root_helper_child_pid is expected to return the pid of the " "bash process") self._addcleanup_sleep_process(child_pid) with open('/proc/%s/cmdline' % child_pid, 'r') as f_proc_cmdline: cmdline = f_proc_cmdline.readline().split('\0')[0] self.assertIn('bash', cmdline)
def test_get_root_helper_child_pid_returns_first_child(self): """Test that the first child, not lowest child pid is returned. Test creates following process tree: sudo + | +--rootwrap + | +--bash+ | +--sleep 100 and tests that pid of `bash' command is returned. """ def wait_for_sleep_is_spawned(parent_pid): proc_tree = utils.execute(['pstree', parent_pid], check_exit_code=False) processes = [ command.strip() for command in proc_tree.split('---') if command ] if processes: return 'sleep' == processes[-1] cmd = ['bash', '-c', '(sleep 100)'] proc = async_process.AsyncProcess(cmd, run_as_root=True) proc.start() # root helpers spawn their child processes asynchronously, and we # don't want to use proc.start(block=True) as that uses # get_root_helper_child_pid (The method under test) internally. sudo_pid = proc._process.pid common_utils.wait_until_true(functools.partial( wait_for_sleep_is_spawned, sudo_pid), sleep=0.1) child_pid = utils.get_root_helper_child_pid(sudo_pid, cmd, run_as_root=True) self.assertIsNotNone( child_pid, "get_root_helper_child_pid is expected to return the pid of the " "bash process") self._addcleanup_sleep_process(child_pid) with open('/proc/%s/cmdline' % child_pid, 'r') as f_proc_cmdline: cmdline = f_proc_cmdline.readline().split('\0')[0] self.assertIn('bash', cmdline)
def _kill(self, respawning=False): """Kill the process and the associated watcher greenthreads. :param respawning: Optional, whether respawn will be subsequently attempted. """ # Halt the greenthreads self._kill_event.send() pid = utils.get_root_helper_child_pid(self._process.pid, run_as_root=self.run_as_root) if pid: self._kill_process(pid) if not respawning: # Clear the kill event to ensure the process can be # explicitly started again. self._kill_event = None
def _kill(self, respawning=False): """Kill the process and the associated watcher greenthreads. :param respawning: Optional, whether respawn will be subsequently attempted. """ # Halt the greenthreads self._kill_event.send() pid = utils.get_root_helper_child_pid( self._process.pid, self.root_helper) if pid: self._kill_process(pid) if not respawning: # Clear the kill event to ensure the process can be # explicitly started again. self._kill_event = None
def _test_get_root_helper_child_pid(self, expected=_marker, run_as_root=False, pids=None, cmds=None): def _find_child_pids(x): if not pids: return [] pids.pop(0) return pids mock_pid = object() pid_invoked_with_cmdline = {} if cmds: pid_invoked_with_cmdline["side_effect"] = cmds else: pid_invoked_with_cmdline["return_value"] = False with mock.patch.object(utils, "find_child_pids", side_effect=_find_child_pids), mock.patch.object( utils, "pid_invoked_with_cmdline", **pid_invoked_with_cmdline ): actual = utils.get_root_helper_child_pid(mock_pid, mock.ANY, run_as_root) if expected is _marker: expected = str(mock_pid) self.assertEqual(expected, actual)
def pid(self): if self._process: return utils.get_root_helper_child_pid( self._process.pid, run_as_root=self.run_as_root)
def pid(self): if self._process: return utils.get_root_helper_child_pid( self._process.pid, run_as_root=self.run_as_root)
def child_is_running(): child_pid = utils.get_root_helper_child_pid(self.pid, run_as_root=True) if utils.pid_invoked_with_cmdline(child_pid, self.cmd): return True
def child_is_running(): child_pid = utils.get_root_helper_child_pid( self.pid, self.cmd, run_as_root=True) if utils.pid_invoked_with_cmdline(child_pid, self.cmd): return True