Esempio n. 1
0
 def test_get_process_info_state_preserves_case(self):
     """
     C{get_process_info} retains the case of the process state, since
     for example both x and X can be different states.
     """
     self._add_process_info(12, state="a (some state)")
     process_info = ProcessInformation(self.proc_dir)
     info = process_info.get_process_info(12)
     self.assertEqual(b"a", info["state"])
Esempio n. 2
0
 def test_get_process_info_state(self):
     """
     C{get_process_info} reads the process state from the status file
     and uses the first character to represent the process state.
     """
     self._add_process_info(12, state="A (some state)")
     process_info = ProcessInformation(self.proc_dir)
     info = process_info.get_process_info(12)
     self.assertEqual(b"A", info["state"])
Esempio n. 3
0
 def __init__(self, proc_dir="/proc", boot_time=None, jiffies=None,
              uptime=None, popen=subprocess.Popen):
     super(ActiveProcessInfo, self).__init__()
     self._proc_dir = proc_dir
     self._persist_processes = {}
     self._previous_processes = {}
     self._jiffies_per_sec = jiffies or detect_jiffies()
     self._popen = popen
     self._first_run = True
     self._process_info = ProcessInformation(proc_dir=proc_dir,
                                             jiffies=jiffies,
                                             boot_time=boot_time,
                                             uptime=uptime)
Esempio n. 4
0
 def test_get_process_info_state_tracing_stop_lucid(self):
     """
     In Lucid, capital T was used for both stopped and tracing stop.
     From Natty and onwards lowercase t is used for tracing stop, so
     we special-case that state and always return lowercase t for
     tracing stop.
     """
     self._add_process_info(12, state="T (tracing stop)")
     self._add_process_info(13, state="t (tracing stop)")
     process_info = ProcessInformation(self.proc_dir)
     info1 = process_info.get_process_info(12)
     info2 = process_info.get_process_info(12)
     self.assertEqual(b"t", info1["state"])
     self.assertEqual(b"t", info2["state"])
Esempio n. 5
0
 def run(self):
     num_processes = 0
     num_zombies = 0
     info = ProcessInformation(proc_dir=self._proc_dir)
     for process_info in info.get_all_process_info():
         num_processes += 1
         if process_info["state"] == "Z":
             num_zombies += 1
     if num_zombies:
         if num_zombies == 1:
             msg = "There is 1 zombie process."
         else:
             msg = "There are %d zombie processes." % (num_zombies, )
         self._sysinfo.add_note(msg)
     self._sysinfo.add_header("Processes", str(num_processes))
     return succeed(None)
    def test_missing_process_race(self, get_uptime_mock, list_dir_mock,
                                  jiffies_mock):
        """
        We use os.listdir("/proc") to get the list of active processes, if a
        process ends before we attempt to read the process' information, then
        this should not trigger an error.
        """
        class FakeFile(object):
            def __init__(self, response=""):
                self._response = response
                self.closed = False

            def readline(self):
                return self._response

            def __iter__(self):
                if self._response is None:
                    raise IOError("Fake file error")
                else:
                    yield self._response

            def close(self):
                self.closed = True

        list_dir_mock.return_value = ["12345"]
        get_uptime_mock.return_value = 1.0
        fakefile1 = FakeFile("test-binary")
        fakefile2 = FakeFile(None)
        with mock.patch(
                "landscape.lib.process.open",
                mock.mock_open(),
                create=True,
        ) as open_mock:
            # This means "return fakefile1, then fakefile2"
            open_mock.side_effect = [fakefile1, fakefile2]
            process_info = ProcessInformation("/proc")
            processes = list(process_info.get_all_process_info())
            calls = [
                mock.call("/proc/12345/cmdline", "r"),
                mock.call("/proc/12345/status", "r")
            ]
            open_mock.assert_has_calls(calls)
        self.assertEqual(processes, [])
        list_dir_mock.assert_called_with("/proc")
        self.assertTrue(fakefile1.closed)
        self.assertTrue(fakefile2.closed)
 def setUp(self):
     LandscapeTest.setUp(self)
     self.sample_dir = self.makeDir()
     self.builder = ProcessDataBuilder(self.sample_dir)
     self.process_info = ProcessInformation(proc_dir=self.sample_dir,
                                            jiffies=1,
                                            boot_time=10)
     self.signaller = ProcessKiller(process_info=self.process_info)
     service = self.broker_service
     service.message_store.set_accepted_types(["operation-result"])
    def _test_signal_real_process(self, signame):
        """
        When a 'signal-process' message is received the plugin should
        signal the appropriate process and generate an operation-result
        message with details of the outcome.  Data is gathered from
        internal plugin methods to get the start time of the test
        process being signalled.
        """
        process_info_factory = ProcessInformation()
        signaller = ProcessKiller()
        signaller.register(self.manager)
        popen = get_active_process()
        process_info = process_info_factory.get_process_info(popen.pid)
        self.assertNotEquals(process_info, None)
        start_time = process_info["start-time"]

        self.manager.dispatch_message({
            "type": "signal-process",
            "operation-id": 1,
            "pid": popen.pid,
            "name": "python",
            "start-time": start_time,
            "signal": signame
        })
        # We're waiting on the child process here so that we (the
        # parent process) consume it's return code; this prevents it
        # from becoming a zombie and makes the test do a better job of
        # reflecting the real world.
        return_code = popen.wait()
        # The return code is negative if the process was terminated by
        # a signal.
        self.assertTrue(return_code < 0)
        process_info = process_info_factory.get_process_info(popen.pid)
        self.assertEqual(process_info, None)

        service = self.broker_service
        self.assertMessages(service.message_store.get_pending_messages(),
                            [{
                                "type": "operation-result",
                                "status": SUCCEEDED,
                                "operation-id": 1
                            }])
Esempio n. 9
0
#!/usr/bin/env python3

from datetime import datetime
from landscape.lib.process import ProcessInformation

info = ProcessInformation()
for process_info in info.get_all_process_info():
    if process_info['state'] == b'Z':
        print(process_info['pid'], process_info['name'],
              datetime.fromtimestamp(process_info['start-time']))
Esempio n. 10
0
 def __init__(self, process_info=None):
     if process_info is None:
         process_info = ProcessInformation()
     self.process_info = process_info
Esempio n. 11
0
class ActiveProcessInfo(DataWatcher):

    message_type = "active-process-info"
    scope = "process"

    def __init__(self,
                 proc_dir="/proc",
                 boot_time=None,
                 jiffies=None,
                 uptime=None,
                 popen=subprocess.Popen):
        super(ActiveProcessInfo, self).__init__()
        self._proc_dir = proc_dir
        self._persist_processes = {}
        self._previous_processes = {}
        self._jiffies_per_sec = jiffies or detect_jiffies()
        self._popen = popen
        self._first_run = True
        self._process_info = ProcessInformation(proc_dir=proc_dir,
                                                jiffies=jiffies,
                                                boot_time=boot_time,
                                                uptime=uptime)

    def register(self, manager):
        super(ActiveProcessInfo, self).register(manager)
        self.call_on_accepted(self.message_type, self.exchange, True)

    def _reset(self):
        """Reset active process data."""
        self._first_run = True
        self._persist_processes = {}
        self._previous_processes = {}

    def get_message(self):
        message = {}
        if self._first_run:
            message["kill-all-processes"] = True
        message.update(self._detect_process_changes())

        if message:
            message["type"] = "active-process-info"
            return message
        return None

    def persist_data(self):
        self._first_run = False
        self._persist_processes = self._previous_processes
        self._previous_processes = {}
        # This forces the registry to write the persistent store to disk
        # This means that the persistent data reflects the state of the
        # messages sent.
        self.registry.flush()

    def _get_processes(self):
        processes = {}
        for process_info in self._process_info.get_all_process_info():
            if process_info["state"] != b"X":
                processes[process_info["pid"]] = process_info
        return processes

    def _detect_process_changes(self):
        changes = {}
        processes = self._get_processes()
        creates, updates, deletes = diff(self._persist_processes, processes)
        if creates:
            changes["add-processes"] = list(itervalues(creates))
        if updates:
            changes["update-processes"] = list(itervalues(updates))
        if deletes:
            changes["kill-processes"] = list(deletes)

        # Update cached values for use on the next run.
        self._previous_processes = processes
        return changes