Esempio n. 1
0
 def test_find_processes(self):
     """Test the :func:`proc.core.find_processes()` function."""
     # Test argument validation. Obscure Python implementation detail:
     # Because find_processes() returns a generator we need to actually ask
     # for the first value to be produced in order to invoke the argument
     # validation.
     self.assertRaises(TypeError, next, find_processes(obj_type=object))
     # Test some basic assumptions about the result of find_processes().
     processes = dict((p.pid, p) for p in find_processes())
     assert 1 in processes, "init process not found in output of find_processes()!"
     assert processes[1].comm == 'init', "init isn't called init?!"
     assert os.getpid(
     ) in processes, "Current process not found in output of find_processes()!"
Esempio n. 2
0
def find_graphical_context():
    """
    Create a command execution context for the current graphical session.

    :returns: A :class:`~executor.contexts.LocalContext` object.

    This function scans the process tree for processes that are running in a
    graphical session and collects information about graphical sessions from
    each of these processes. The collected information is then ranked by
    "popularity" (number of occurrences) and the most popular information is
    used to create a command execution context that targets the graphical
    session.
    """
    options = {}
    # Collect information about graphical sessions from running processes.
    matches = collections.defaultdict(int)
    for process in find_processes():
        environment = dict((k, v) for k, v in process.environ.items()
                           if k in REQUIRED_VARIABLES and v)
        if environment:
            hashable_environment = tuple(sorted(environment.items()))
            matches[(process.user_ids.real, hashable_environment)] += 1
    ordered = sorted((counter, key) for key, counter in matches.items())
    if ordered:
        # Pick the most popular graphical session.
        counter, key = ordered[-1]
        uid, environment = key
        # Apply the user ID to the context?
        if os.getuid() != uid:
            options['uid'] = uid
        # Apply the environment to the context.
        options['environment'] = dict(environment)
    return LocalContext(**options)
Esempio n. 3
0
def find_gpg_agent_info():
    """
    Reconstruct ``$GPG_AGENT_INFO`` based on a running ``gpg-agent`` process.

    :returns: A string or :data:`None`.

    This function uses :func:`~proc.core.find_processes()` to search for
    ``gpg-agent`` processes and runs lsof_ to find out which UNIX socket is
    being used by the agent. Based on this information it reconstructs
    the expected value of ``$GPG_AGENT_INFO``.
    """
    logger.debug("Searching for running GPG agent ..")
    our_uid = os.getuid()
    for process in find_processes():
        if process.exe_name == 'gpg-agent':
            logger.debug("Found GPG agent with PID %i, checking user id .. ",
                         process.pid)
            if process.user_ids.real == our_uid:
                logger.debug(
                    "GPG agent user id matches ours! Using `lsof' to determine socket .."
                )
                # A quick lsof tutorial :-)
                #  -F enables output that is easy to parse,
                #  -p lists the open files of a specific PID,
                #  -a combines -p and -U using AND instead of OR,
                #  -U lists only UNIX domain socket files.
                output = execute('lsof',
                                 '-F',
                                 '-p',
                                 str(process.pid),
                                 '-a',
                                 '-U',
                                 capture=True,
                                 check=False)
                for line in output.splitlines():
                    if line and line[0] == 'n':
                        filename = line[1:]
                        if filename:
                            logger.debug(
                                "UNIX domain socket reported by lsof: %s",
                                filename)
                            if os.access(filename, os.W_OK):
                                # We will now reconstruct $GPG_AGENT_INFO based on the
                                # information that we've gathered. We should end up with
                                # an expression like `/tmp/gpg-KE5ZZL/S.gpg-agent:2407:1'.
                                agent_info = ':'.join(
                                    [filename, str(process.pid), '1'])
                                logger.debug(
                                    "Reconstructed $GPG_AGENT_INFO: %s",
                                    agent_info)
                                return agent_info
                            else:
                                logger.debug(
                                    "No write access to socket, ignoring process %i.",
                                    process.pid)
            else:
                logger.debug(
                    "GPG agent user id (%i) doesn't match ours (%i), ignoring process %i.",
                    process.user_ids.real, our_uid, process.pid)
Esempio n. 4
0
 def test_exe_path_fallback(self):
     """Test the fall back method of :attr:`proc.core.Process.exe_path`."""
     candidates = [p for p in find_processes() if p.exe_path and not p.exe]
     logger.debug("Candidates for Process.exe_path fall back test:\n%s",
                  pformat(candidates))
     if not candidates:
         return self.skipTest(
             "No processes available on which Process.exe_path fall back can be tested!"
         )
     assert executable(candidates[0].exe_path), \
         "Fall back method of Process.exe_path reported invalid executable pathname!"
Esempio n. 5
0
def find_gpg_agent_info():
    """
    Reconstruct ``$GPG_AGENT_INFO`` based on a running ``gpg-agent`` process.

    :returns: A string or :data:`None`.

    This function uses :func:`~proc.core.find_processes()` to search for
    ``gpg-agent`` processes and runs lsof_ to find out which UNIX socket is
    being used by the agent. Based on this information it reconstructs
    the expected value of ``$GPG_AGENT_INFO``.
    """
    logger.debug("Searching for running GPG agent ..")
    our_uid = os.getuid()
    for process in find_processes():
        if process.exe_name == 'gpg-agent':
            logger.debug("Found GPG agent with PID %i, checking user id .. ",
                         process.pid)
            their_uid = process.user_ids.real if process.user_ids else 'unknown'
            if our_uid == their_uid:
                socket_file = None
                logger.debug(
                    "GPG agent user id matches ours! Looking for UNIX socket .."
                )
                fixed_socket = find_fixed_agent_socket()
                if validate_unix_socket(fixed_socket):
                    logger.debug("Found GnuPG >= 2.1 compatible socket: %s",
                                 fixed_socket)
                    socket_file = fixed_socket
                else:
                    logger.debug("Using `lsof' to find open UNIX sockets ..")
                    for filename in find_open_unix_sockets(process.pid):
                        logger.debug("UNIX domain socket reported by lsof: %s",
                                     filename)
                        if validate_unix_socket(filename):
                            socket_file = filename
                            break
                # We will now reconstruct $GPG_AGENT_INFO based on the
                # information that we've gathered. We should end up with
                # an expression like `/tmp/gpg-KE5ZZL/S.gpg-agent:2407:1'.
                if socket_file:
                    agent_info = ':'.join([socket_file, str(process.pid), '1'])
                    logger.debug("Reconstructed $GPG_AGENT_INFO: %s",
                                 agent_info)
                    return agent_info
            else:
                logger.debug(
                    "GPG agent user id (%s) doesn't match ours (%i), ignoring process %i.",
                    their_uid, our_uid, process.pid)
Esempio n. 6
0
def running_processes() -> Iterator[Tuple[int, str, int, int]]:
    """
    Returns an interator of all processes running on the
    system. Iterator contains tuples of [@profile_key, @exe, @pid, @tid]
    """
    for p in find_processes():
        exe = p.exe
        pid = p.pgrp
        tid = p.pid
        if not exe:
            continue
        try:
            profile_key = calculate_profile_key(exe)
        except Exception:
            continue
        yield (profile_key, exe, pid, tid)
Esempio n. 7
0
 def test_exe_name_fallback(self):
     """Test the fall back method of :attr:`proc.core.Process.exe_name`."""
     if os.getuid() == 0:
         # Given root privileges all /proc/[pid]/exe symbolic links can be
         # successfully resolved so we can't test the fall back method.
         return self.skipTest(
             "Fall back method of Process.exe_name is useless with root privileges!"
         )
     candidates = [
         p for p in find_processes() if p.exe_name and not p.exe_path
     ]
     logger.debug("Candidates for Process.exe_name fall back test:\n %s",
                  pformat(candidates))
     if not candidates:
         return self.skipTest(
             "No processes available on which Process.exe_name fall back can be tested!"
         )
     assert any(which(p.exe_name) for p in candidates), \
         "Fall back method of Process.exe_name reported executable base name not available on $PATH?!"
Esempio n. 8
0
    def _stop_force(self):
        """
            The _stop_force method iterates over the /proc and search for toaster path
            in the process cmdline then send SIGKILL for every matched process.
        """

        pids = []
        for p in find_processes():
            if len(p.cmdline) > 1 and \
                os.path.basename(p.cmdline[0]) == 'python' and \
                p.cmdline[1].startswith(self.directory):
                    pids.append(p.pid)

        for pid in pids:
            try:
                os.kill(pid, signal.SIGKILL)
            except:
                pass

        return ''
Esempio n. 9
0
def get_process_tree(obj_type=ProcessNode):
    """
    Construct a process tree from the result of :func:`~proc.core.find_processes()`.

    :param obj_type: The type of process objects to construct (expected to be
                     :class:`ProcessNode` or a subclass of
                     :class:`ProcessNode`).
    :returns: A :class:`ProcessNode` object that forms the root node of the
              constructed tree (this node represents init_).

    .. _init: http://en.wikipedia.org/wiki/init
    """
    if not issubclass(obj_type, ProcessNode):
        raise TypeError("Custom process types should inherit from proc.tree.ProcessNode!")
    mapping = dict((p.pid, p) for p in find_processes(obj_type=obj_type))
    for obj in mapping.values():
        if obj.ppid != 0 and obj.ppid in mapping:
            obj.parent = mapping[obj.ppid]
            obj.parent.children.append(obj)
    return mapping[1]
Esempio n. 10
0
    def test_race_conditions(self, timeout=60):
        """
        Test the handling of race conditions in :mod:`proc.core`.

        Scanning ``/proc`` is inherently vulnerable to race conditions, for
        example:

        1. A listing of available processes in ``/proc`` confirms a process
           exists, but by the time ``/proc/[pid]/stat`` is read the process has
           ended and ``/proc/[pid]`` no longer exists.

        2. A :class:`proc.core.Process` object is constructed from the
           information available in ``/proc/[pid]/stat``, but by the time
           ``/proc/[pid]/cmdline`` is read the process has ended and
           ``/proc/[pid]`` no longer exists.

        This test intentionally creates race conditions in the reading of
        ``/proc/[pid]/stat``, ``/proc/[pid]/cmdline`` and
        ``/proc/[pid]/environ`` files, to verify that the :mod:`proc.core`
        module never breaks on a race condition.

        It works by using the :mod:`multiprocessing` module to quickly spawn
        and reclaim subprocesses while at the same time scanning through
        ``/proc`` continuously. The test times out after 60 seconds but in all
        of the runs I've tried so far it never needs more than 10 seconds to
        encounter a handful of race conditions.
        """
        # Copy the race condition counters so we can verify all counters have
        # increased before we consider this test to have passed.
        logger.info(
            "Testing handling of race conditions, please be patient :-) ..")
        timer = Timer()
        at_start = dict(num_race_conditions)
        shutdown_event = multiprocessing.Event()
        manager = multiprocessing.Process(target=race_condition_manager,
                                          args=(shutdown_event, ))
        manager.start()
        try:
            while True:
                # Scan the process tree with the knowledge that subprocesses could
                # be disappearing any second now :-).
                for process in find_processes():
                    if process.ppid == manager.pid:
                        # Force a time window between when /proc/[pid]/stat was
                        # read and when /proc/[pid]/cmdline will be read.
                        time.sleep(0.1)
                        # Read /proc/[pid]/cmdline, /proc/[pid]/environ and
                        # /proc/[pid]/exe even though they may no longer exist.
                        assert isinstance(process.cmdline, list)
                        assert isinstance(process.environ, dict)
                        assert isinstance(process.exe, basestring)
                        assert isinstance(process.status_fields, dict)
                # Check whether race conditions have been handled.
                if all(num_race_conditions[k] > at_start[k] for k in at_start):
                    # The test has passed: We were able to simulate at least
                    # one race condition of every type within the timeout.
                    logger.info(
                        "Successfully finished race condition test in %s.",
                        timer)
                    return
                assert timer.elapsed_time < timeout, "Timeout elapsed before race conditions could be simulated!"
                # Don't burn CPU cycles too much.
                time.sleep(0.1)
        finally:
            shutdown_event.set()
            manager.join()
Esempio n. 11
0
import os
from proc.core import find_processes
import smtplib
from email.mime.text import MIMEText
from email.parser import Parser
import subprocess
from datetime import datetime, timedelta

if __name__ == '__main__':
    page_size = os.sysconf('SC_PAGE_SIZE')
    physical_pages = os.sysconf('SC_PHYS_PAGES')
    total_mem = page_size * physical_pages
    print('Page size = {}, pages = {}, total_mem = {} ({:.1f} MB)'.format(
        page_size, physical_pages, total_mem, total_mem / (1024**2)))

    nginx_processes = [x for x in find_processes() if x.comm == 'nginx']

    cumulative_percent = 0

    for x in nginx_processes:
        print('nginx process pid = {}, parent_pid = {} , rss = {} '.format(
            x.pid, x.ppid, x.rss))

        process_percent = (x.rss / total_mem) * 100
        cumulative_percent = cumulative_percent + process_percent

    print('Cumulative nginx memory use = ', cumulative_percent)

    if cumulative_percent > 75:
        # Take action at the 75% mark - we want to schedule an nginx restart
        action_taken = 'Scheduling at for restart'
Esempio n. 12
0
def main():
    for p in find_processes():
        pid = p.pid
        mem = p.rss