Source code for eww.implant

# -*- coding: utf-8 -*-
"""
    eww.implant
    ~~~~~~~~~~~

    Provides functions for inserting and removing Eww.

"""

import sys
import logging
import threading
import __builtin__

from .dispatch import DispatchThread
from .ioproxy import IOProxy
from .quitterproxy import QuitterProxy
from .shared import (DISPATCH_THREAD_NAME, EMBEDDED, IMPLANT_LOCK, REMOVAL,
                     STATS_THREAD_NAME)
from .stats import StatsThread

LOGGER = logging.getLogger(__name__)

[docs]class WildlyInsecureFlagNotSet(Exception): """Raised when someone tries to make Eww listen on an external interface without setting the ``wildly_insecure`` flag in their :py:mod:`~eww.implant.embed` call. """
[docs]def embed(host='localhost', port=10000, timeout=1, max_datapoints=500, wildly_insecure=False): """The main entry point for eww. It creates the threads we need. Args: host (str): The interface to listen for connections on. port (int): The port to listen for connections on. timeout (float): Frequency, in seconds, to check for a stop or remove request. max_datapoints (int): The maximum number of graph datapoints to record. If this limit is hit, datapoints will be discarded based on age, oldest-first. wildly_insecure (bool): This must be set to True in order to set the ``host`` argument to anything besides ``localhost`` or ``127.0.0.1``. Returns: None Raises: WildlyInsecureFlagNotSet: Will be raised if you attempt to change the ``host`` parameter to something besides ``localhost`` or ``127.0.0.1`` without setting ``wildly_insecure`` to True. """ if not wildly_insecure: try: # pragma: no cover -- We hit this branch, but coverage disagrees allowed = ['localhost', '127.0.0.1', '::1'] assert host in allowed except AssertionError: msg = 'You cannot listen on an external interface without setting ' msg += 'wildly_insecure to True.' raise WildlyInsecureFlagNotSet(msg) with IMPLANT_LOCK: if EMBEDDED.isSet(): LOGGER.debug('attempted to embed eww more than once') return EMBEDDED.set() LOGGER.debug('eww beginning embed') sys.stdin = IOProxy(sys.stdin) sys.stdout = IOProxy(sys.stdout) sys.stderr = IOProxy(sys.stderr) __builtin__.quit = QuitterProxy(__builtin__.quit) __builtin__.exit = QuitterProxy(__builtin__.exit) dispatch_thread = DispatchThread(str(host), int(port), timeout=timeout) dispatch_thread.name = DISPATCH_THREAD_NAME dispatch_thread.daemon = True dispatch_thread.start() stats_thread = StatsThread(max_datapoints=max_datapoints, timeout=timeout) stats_thread.name = STATS_THREAD_NAME stats_thread.daemon = True stats_thread.start() LOGGER.debug('eww completed embed') return
[docs]def remove(): """Stops and removes all of eww. Returns: None """ with IMPLANT_LOCK: if EMBEDDED.isSet() == False: LOGGER.debug('remove called without an embed') return if REMOVAL.isSet(): LOGGER.debug('attempted to remove more than once simultaneously') return REMOVAL.set() LOGGER.debug('attempting to remove eww') all_threads = threading.enumerate() eww_threads = [] for thread in all_threads: if 'eww' in thread.name: eww_threads.append(thread) for thread in eww_threads: thread.stop() thread.join(5) for thread in eww_threads: if thread.isAlive(): # Our threads haven't stopped. LOGGER.debug('failed to remove eww, some threads may be alive') __builtin__.quit = __builtin__.quit.original_quit __builtin__.exit = __builtin__.exit.original_quit sys.stdin = sys.stdin.original_file sys.stdout = sys.stdout.original_file sys.stderr = sys.stderr.original_file with IMPLANT_LOCK: EMBEDDED.clear() REMOVAL.clear() LOGGER.debug('eww removal complete') return