示例#1
0
    def test_setup_console(self, set_console_active_screen_buffer_mock,
                           set_console_cursor_info_mock,
                           create_console_screen_buffer_mock,
                           get_console_cursor_info_mock,
                           get_console_screen_buffer_info_mock,
                           get_std_handle_mock):

        with patch('fibratus.term.byref', side_effect=[1, 2, 3]):
            ansi_term = AnsiTerm()
            assert not ansi_term.term_ready
            ansi_term.setup_console()

            get_std_handle_mock.assert_called_with(STD_OUTPUT_HANDLE)
            get_console_screen_buffer_info_mock.assert_called_with(1, 1)
            get_console_cursor_info_mock.assert_called_with(1, 2)

            create_console_screen_buffer_mock.assert_called_with(
                GENERIC_READ | GENERIC_WRITE,
                FILE_SHARE_READ | FILE_SHARE_WRITE, None,
                CONSOLE_TEXTMODE_BUFFER, None)

            set_console_cursor_info_mock.assert_called_with(2, 3)
            set_console_active_screen_buffer_mock.assert_called_with(2)

            assert ansi_term.term_ready
示例#2
0
    def test_setup_console_invalid_std_console(self, get_std_handle_mock):

        ansi_term = AnsiTerm()
        with pytest.raises(TermInitializationError):
            ansi_term.setup_console()
            get_std_handle_mock.assert_called_with(STD_OUTPUT_HANDLE)

        assert not ansi_term.term_ready
示例#3
0
    def test_setup_console_invalid_frame_buffer(self, create_console_screen_buffer_mock,
                                                get_console_cursor_info_mock,
                                                get_console_screen_buffer_info_mock,
                                                get_std_handle_mock):

            ansi_term = AnsiTerm()
            with pytest.raises(TermInitializationError):
                ansi_term.setup_console()
                create_console_screen_buffer_mock.assert_called_with(GENERIC_READ | GENERIC_WRITE,
                                                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                                     None,
                                                                     CONSOLE_TEXTMODE_BUFFER,
                                                                     None)
示例#4
0
 def __init__(self):
     self._filament = None
     self._filters = []
     self._tabular = None
     self._cols = []
     self._limit = 10
     self._interval = 1
     self._sort_by = None
     self._sort_desc = True
     self.ansi_term = AnsiTerm()
     self.scheduler = BackgroundScheduler()
     self.term_initialized = False
     self._on_stop = None
示例#5
0
    def __init__(self):
        """Builds a new instance of the filament.

        Attributes:
        ----------

        filament_module: module
            module which contains the filament logic
        """
        self._filament_module = None
        self._name = None
        self._filters = []
        self._cols = []
        self._tabular = None
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self._logger = None
        self._ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()
示例#6
0
 def __init__(self):
     self._filament = None
     self._filters = []
     self._tabular = None
     self._cols = []
     self._limit = 10
     self._interval = 1
     self._sort_by = None
     self._sort_desc = True
     self.ansi_term = AnsiTerm()
     self.scheduler = BackgroundScheduler()
     self.term_initialized = False
     self._on_stop = None
示例#7
0
    def test_setup_console(self, set_console_active_screen_buffer_mock,
                           set_console_cursor_info_mock,
                           create_console_screen_buffer_mock,
                           get_console_cursor_info_mock,
                           get_console_screen_buffer_info_mock,
                           get_std_handle_mock):

        with patch('fibratus.term.byref', side_effect=[1, 2, 3]):
            ansi_term = AnsiTerm()
            ansi_term.setup_console()

            get_std_handle_mock.assert_called_with(STD_OUTPUT_HANDLE)
            get_console_screen_buffer_info_mock.assert_called_with(1, 1)
            get_console_cursor_info_mock.assert_called_with(1, 2)

            create_console_screen_buffer_mock.assert_called_with(GENERIC_READ | GENERIC_WRITE,
                                                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                                                                 None,
                                                                 CONSOLE_TEXTMODE_BUFFER,
                                                                 None)

            set_console_cursor_info_mock.assert_called_with(2, 3)
            set_console_active_screen_buffer_mock.assert_called_with(2)
示例#8
0
    def test_restore_console(self, set_console_active_screen_buffer_mock,
                             set_console_cursor_info_mock,
                             create_console_screen_buffer_mock,
                             get_console_cursor_info_mock,
                             get_console_screen_buffer_info_mock,
                             get_std_handle_mock):

        ansi_term = AnsiTerm()
        ansi_term.setup_console()
        with patch('fibratus.term.byref', return_value=2):
            ansi_term.restore_console()
            set_console_active_screen_buffer_mock.assert_called_with(1)
            set_console_cursor_info_mock.assert_called_with(1, 2)
示例#9
0
    def __init__(self):
        """Builds a new instance of the filament.

        Attributes:
        ----------

        filament_module: module
            module which contains the filament logic
        """
        self._filament_module = None
        self._name = None
        self._filters = []
        self._cols = []
        self._tabular = None
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self._logger = None
        self._ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()
示例#10
0
    def test_write_output(self, write_console_output_mock,
                          set_console_active_screen_buffer_mock,
                          set_console_cursor_info_mock,
                          create_console_screen_buffer_mock,
                          get_console_cursor_info_mock,
                          get_console_screen_buffer_info_mock,
                          get_std_handle_mock):
        ansi_term = AnsiTerm()

        buffer_info = CONSOLE_SCREEN_BUFFER_INFO()
        buffer_info.size.x = 200
        buffer_info.size.y = 300

        with patch.object(CONSOLE_SCREEN_BUFFER_INFO, '__new__', return_value=buffer_info):
            ansi_term.setup_console()
            ansi_term.write_output('Top inbound packets\n')
            write_console_output_mock.assert_called_once()
示例#11
0
class Filament(object):
    """Filament initialization and execution engine.

    Filaments are lightweight Python modules which run
    on top of Fibratus. They are often used to enrich/extend the
    functionality of Fibratus by performing any type of logic
    (aggregations, groupings, filters, counters, etc) on the
    kernel event stream.

    """
    def __init__(self):
        """Builds a new instance of the filament.

        Attributes:
        ----------

        filament_module: module
            module which contains the filament logic
        """
        self._filament_module = None
        self._name = None
        self._filters = []
        self._cols = []
        self._tabular = None
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self._logger = None
        self._ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()

    def load_filament(self, name):
        """Loads the filament module.

        Finds and loads the python module which
        holds the filament logic. It also looks up for
        some essential filament methods and raises an error
        if they can't be found.

        Parameters
        ----------
        name: str
            name of the filament to load

        """
        self._name = name
        Filament._assert_root_dir()
        filament_path = self._find_filament_path(name)
        if filament_path:
            loader = SourceFileLoader(name, filament_path)
            self._filament_module = loader.load_module()
            sys.path.append(FILAMENTS_DIR)
            doc = inspect.getdoc(self._filament_module)
            if not doc:
                raise FilamentError('Please provide a short '
                                    'description for the filament')

            on_next_kevent = self._find_filament_func('on_next_kevent')
            if on_next_kevent:
                if self._num_args(on_next_kevent) != 1:
                    raise FilamentError('Missing one argument on_next_kevent '
                                        'method on filament')
                self._initialize_funcs()
            else:
                raise FilamentError('Missing required on_next_kevent '
                                    'method on filament')
        else:
            raise FilamentError('%s filament not found' % name)

    def _initialize_funcs(self):
        """Setup the filament modules functions.

        Functions
        ---------

        set_filter: func
            accepts the comma separated list of kernel events
            for whose the filter should be applied
        set_interval: func
            establishes the fixed repeating interval in seconds
        columns: func
            configure the column set for the table
        add_row: func
            adds a new row to the table
        sort_by: func
            sorts the table by specific column
        """
        def set_filter(*args):
            self._filters = args

        self._filament_module.set_filter = set_filter

        def set_interval(interval):
            if not type(interval) is int:
                raise FilamentError('Interval must be an integer value')
            self._interval = interval

        self._filament_module.set_interval = set_interval

        def columns(cols):
            if not isinstance(cols, list):
                raise FilamentError('Columns must be a list, '
                                    '%s found' % type(cols))
            self._cols = cols
            self._tabular = Tabular(self._cols)
            self._tabular.padding_width = 10
            self._tabular.junction_char = '|'

        def add_row(row):
            if not isinstance(row, list):
                raise FilamentError(
                    'Expected list type for the row, found %s' % type(row))
            self._tabular.add_row(row)

        def sort_by(col, sort_desc=True):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if col not in self._cols:
                raise FilamentError('%s column does not exist' % col)
            self._sort_by = col
            self._sort_desc = sort_desc

        def limit(l):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if not type(l) is int:
                raise FilamentError('Limit must be an integer value')
            self._limit = l

        def title(text):
            self._tabular.title = text

        self._filament_module.columns = columns
        self._filament_module.title = title
        self._filament_module.sort_by = sort_by
        self._filament_module.limit = limit
        self._filament_module.add_row = add_row
        self._filament_module.render_tabular = self.render_tabular

        on_init = self._find_filament_func('on_init')
        if on_init and self._zero_args(on_init):
            self._filament_module.on_init()
        if self._find_filament_func('on_interval'):
            self.scheduler.add_executor(ThreadPoolExecutor(max_workers=4))
            self.scheduler.start()

            def on_interval():
                try:
                    self._filament_module.on_interval()
                except Exception:
                    self._logger.error(
                        'Unexpected error on interval elapsed %s' %
                        traceback.format_exc())

            self.scheduler.add_job(on_interval,
                                   'interval',
                                   seconds=self._interval,
                                   max_instances=4,
                                   misfire_grace_time=60)
        if len(self._cols) > 0:
            try:
                self._ansi_term.setup_console()
            except TermInitializationError:
                panic('fibratus run: ERROR - console initialization failed')

    def do_output_accessors(self, outputs):
        """Creates the filament's output accessors.

        Parameters
        ----------

        outputs: dict
            outputs initialized from the configuration
            descriptor
        """
        for name, output in outputs.items():
            setattr(self._filament_module, name, OutputAccessor(output))

    def on_next_kevent(self, kevent):
        try:
            self._filament_module.on_next_kevent(ddict(kevent))
        except Exception as e:
            self._logger.error('Unexpected filament error %s' % e)

    def render_tabular(self):
        """Renders the table on the console.
        """
        if len(self._cols) > 0:
            tabular = self._tabular.get_string(start=1, end=self._limit)
            if self._sort_by:
                tabular = self._tabular.get_string(start=1,
                                                   end=self._limit,
                                                   sortby=self._sort_by,
                                                   reversesort=self._sort_desc)
            self._tabular.clear_rows()
            self._ansi_term.write_output(tabular)

    def close(self):
        on_stop = self._find_filament_func('on_stop')
        if on_stop and self._zero_args(on_stop):
            self._filament_module.on_stop()
        if self.scheduler.running:
            self.scheduler.shutdown()
        self._ansi_term.restore_console()

    @classmethod
    def exists(cls, filament):
        Filament._assert_root_dir()
        return os.path.exists(os.path.join(FILAMENTS_DIR, '%s.py' % filament))

    @classmethod
    def list_filaments(cls):
        Filament._assert_root_dir()
        filaments = {}
        paths = [
            os.path.join(FILAMENTS_DIR, path)
            for path in os.listdir(FILAMENTS_DIR) if path.endswith('.py')
        ]
        for path in paths:
            filament_name = os.path.basename(path)[:-3]
            loader = SourceFileLoader(filament_name, path)
            filament = loader.load_module()
            filaments[filament_name] = inspect.getdoc(filament)
        return filaments

    @classmethod
    def _assert_root_dir(cls):
        if not os.path.exists(FILAMENTS_DIR):
            panic('fibratus run: ERROR - %s path does not exist.' %
                  FILAMENTS_DIR)

    @property
    def filters(self):
        return self._filters

    @property
    def logger(self):
        return self._logger

    @logger.setter
    def logger(self, logger):
        self._logger = logger

    @property
    def filament_module(self):
        return self._filament_module

    @property
    def name(self):
        return self._name

    def _find_filament_func(self, func_name):
        """Finds the function in the filament module.

        Parameters
        ----------

        func_name: str
            the name of the function
        """
        functions = inspect.getmembers(self._filament_module,
                                       predicate=inspect.isfunction)
        return next(
            iter([func for name, func in functions if name == func_name]),
            None)

    def _find_filament_path(self, filament_name):
        """Resolves the filament full path from the name

        Parameters
        ----------

        filament_name: str
            the name of the filament whose path if about to be resolved
        """
        return next(
            iter([
                os.path.join(FILAMENTS_DIR, filament)
                for filament in os.listdir(FILAMENTS_DIR)
                if filament.endswith('.py') and filament_name == filament[:-3]
            ]), None)

    def _num_args(self, func):
        return len(inspect.getargspec(func).args)

    def _zero_args(self, func):
        return self._num_args(func) == 0
示例#12
0
    def test_setup_console_invalid_std_console(self, get_std_handle_mock):

            ansi_term = AnsiTerm()
            with pytest.raises(TermInitializationError):
                ansi_term.setup_console()
                get_std_handle_mock.assert_called_with(STD_OUTPUT_HANDLE)
示例#13
0
class Filament(object):
    """Filament initialization and execution engine.

    Filaments are lightweight Python modules which run
    on top of Fibratus. They are often used to enrich/extend the
    functionality of Fibratus by performing any type of logic
    (aggregations, groupings, filters, counters, etc) on the
    kernel event stream.

    """
    def __init__(self):
        """Builds a new instance of the filament.

        Attributes:
        ----------

        filament_module: module
            module which contains the filament logic
        """
        self._filament_module = None
        self._name = None
        self._filters = []
        self._cols = []
        self._tabular = None
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self._logger = None
        self._ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()

    def load_filament(self, name):
        """Loads the filament module.

        Finds and loads the python module which
        holds the filament logic. It also looks up for
        some essential filament methods and raises an error
        if they can't be found.

        Parameters
        ----------
        name: str
            name of the filament to load

        """
        self._name = name
        Filament._assert_root_dir()
        filament_path = self._find_filament_path(name)
        if filament_path:
            loader = SourceFileLoader(name, filament_path)
            self._filament_module = loader.load_module()
            sys.path.append(FILAMENTS_DIR)
            doc = inspect.getdoc(self._filament_module)
            if not doc:
                raise FilamentError('Please provide a short '
                                    'description for the filament')

            on_next_kevent = self._find_filament_func('on_next_kevent')
            if on_next_kevent:
                if self._num_args(on_next_kevent) != 1:
                    raise FilamentError('Missing one argument on_next_kevent '
                                        'method on filament')
                self._initialize_funcs()
            else:
                raise FilamentError('Missing required on_next_kevent '
                                    'method on filament')
        else:
            raise FilamentError('%s filament not found' % name)

    def _initialize_funcs(self):
        """Setup the filament modules functions.

        Functions
        ---------

        set_filter: func
            accepts the comma separated list of kernel events
            for whose the filter should be applied
        set_interval: func
            establishes the fixed repeating interval in seconds
        columns: func
            configure the column set for the table
        add_row: func
            adds a new row to the table
        sort_by: func
            sorts the table by specific column
        """

        def set_filter(*args):
            self._filters = args
        self._filament_module.set_filter = set_filter

        def set_interval(interval):
            if not type(interval) is int:
                raise FilamentError('Interval must be an integer value')
            self._interval = interval
        self._filament_module.set_interval = set_interval

        def columns(cols):
            if not isinstance(cols, list):
                raise FilamentError('Columns must be a list, '
                                    '%s found' % type(cols))
            self._cols = cols
            self._tabular = Tabular(self._cols)
            self._tabular.padding_width = 10
            self._tabular.junction_char = '|'

        def add_row(row):
            if not isinstance(row, list):
                raise FilamentError('Expected list type for the row, found %s'
                                    % type(row))
            self._tabular.add_row(row)

        def sort_by(col, sort_desc=True):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if col not in self._cols:
                raise FilamentError('%s column does not exist' % col)
            self._sort_by = col
            self._sort_desc = sort_desc

        def limit(l):
            if len(self._cols) == 0:
                raise FilamentError('Expected at least 1 column but 0 found')
            if not type(l) is int:
                raise FilamentError('Limit must be an integer value')
            self._limit = l

        def title(text):
            self._tabular.title = text

        self._filament_module.columns = columns
        self._filament_module.title = title
        self._filament_module.sort_by = sort_by
        self._filament_module.limit = limit
        self._filament_module.add_row = add_row
        self._filament_module.render_tabular = self.render_tabular

        on_init = self._find_filament_func('on_init')
        if on_init and self._zero_args(on_init):
            self._filament_module.on_init()
        if self._find_filament_func('on_interval'):
            self.scheduler.add_executor(ThreadPoolExecutor(max_workers=4))
            self.scheduler.start()

            def on_interval():
                try:
                    self._filament_module.on_interval()
                except Exception:
                    self._logger.error('Unexpected error on interval elapsed %s'
                                       % traceback.format_exc())
            self.scheduler.add_job(on_interval,
                                   IntervalTrigger(),
                                   seconds=self._interval,
                                   max_instances=4,
                                   misfire_grace_time=60)
        if len(self._cols) > 0:
            try:
                self._ansi_term.setup_console()
            except TermInitializationError:
                panic('fibratus run: ERROR - console initialization failed')

    def do_output_accessors(self, outputs):
        """Creates the filament's output accessors.

        Parameters
        ----------

        outputs: dict
            outputs initialized from the configuration
            descriptor
        """
        for name, output in outputs.items():
            setattr(self._filament_module, name, OutputAccessor(output))

    def on_next_kevent(self, kevent):
        try:
            self._filament_module.on_next_kevent(ddict(kevent))
        except Exception as e:
            self._logger.error('Unexpected filament error %s' % e)

    def render_tabular(self):
        """Renders the table on the console.
        """
        if len(self._cols) > 0:
            tabular = self._tabular.get_string(start=1, end=self._limit)
            if self._sort_by:
                tabular = self._tabular.get_string(start=1, end=self._limit,
                                                   sortby=self._sort_by,
                                                   reversesort=self._sort_desc)
            self._tabular.clear_rows()
            self._ansi_term.write_output(tabular)

    def close(self):
        on_stop = self._find_filament_func('on_stop')
        if on_stop and self._zero_args(on_stop):
            self._filament_module.on_stop()
        if self.scheduler.running:
            self.scheduler.shutdown()
        self._ansi_term.restore_console()

    @classmethod
    def exists(cls, filament):
        Filament._assert_root_dir()
        return os.path.exists(os.path.join(FILAMENTS_DIR, '%s.py' % filament))

    @classmethod
    def list_filaments(cls):
        Filament._assert_root_dir()
        filaments = {}
        paths = [os.path.join(FILAMENTS_DIR, path) for path in os.listdir(FILAMENTS_DIR)
                 if path.endswith('.py')]
        for path in paths:
            filament_name = os.path.basename(path)[:-3]
            loader = SourceFileLoader(filament_name, path)
            filament = loader.load_module()
            filaments[filament_name] = inspect.getdoc(filament)
        return filaments

    @classmethod
    def _assert_root_dir(cls):
        if not os.path.exists(FILAMENTS_DIR):
            panic('fibratus run: ERROR - %s path does not exist.' % FILAMENTS_DIR)

    @property
    def filters(self):
        return self._filters

    @property
    def logger(self):
        return self._logger

    @logger.setter
    def logger(self, logger):
        self._logger = logger

    @property
    def filament_module(self):
        return self._filament_module

    @property
    def name(self):
        return self._name

    def _find_filament_func(self, func_name):
        """Finds the function in the filament module.

        Parameters
        ----------

        func_name: str
            the name of the function
        """
        functions = inspect.getmembers(self._filament_module, predicate=inspect.isfunction)
        return next(iter([func for name, func in functions if name == func_name]), None)

    def _find_filament_path(self, filament_name):
        """Resolves the filament full path from the name

        Parameters
        ----------

        filament_name: str
            the name of the filament whose path if about to be resolved
        """
        return next(iter([os.path.join(FILAMENTS_DIR, filament) for filament in os.listdir(FILAMENTS_DIR)
                    if filament.endswith('.py') and filament_name == filament[:-3]]), None)

    def _num_args(self, func):
        return len(inspect.getargspec(func).args)

    def _zero_args(self, func):
        return self._num_args(func) == 0
示例#14
0
class Filament():
    """Filament initialization and execution engine.

    Filaments are lightweight Python modules which run
    on top of Fibratus. They are often used to enrich/extend the
    functionality of Fibratus by performing any type of logic
    (aggregations, groupings, filters, counters, etc) on the
    kernel event stream.

    """

    def __init__(self):
        self._filament = None
        self._filters = []
        self._tabular = None
        self._cols = []
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self.ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()
        self.term_initialized = False
        self._on_stop = None

    def load_filament(self, name):
        Filament._assert_root_dir()
        [filament_path] = [os.path.join(FILAMENTS_DIR, filament) for filament in os.listdir(FILAMENTS_DIR)
                           if filament.endswith('.py') and name == filament[:-3]] or [None]
        if filament_path:
            loader = SourceFileLoader(name, filament_path)
            self._filament = loader.load_module()
            # check for required methods
            # on the filament module
            doc = inspect.getdoc(self._filament)
            if not doc:
                raise FilamentError("Please provide a short description for the filament")

            [on_next_kevent] = self._find_func('on_next_kevent')
            if on_next_kevent:
                args_spec = inspect.getargspec(on_next_kevent)
                if len(args_spec.args) != 1:
                    raise FilamentError('Missing one argument on_next_kevent method on filament')
            else:
                raise FilamentError('Missing required on_next_kevent method on filament')
        else:
            raise FilamentError('%s filament not found' % name)

    def initialize_filament(self):
        if self._filament:
            def set_filter(*args):
                self._filters = args
            self._filament.set_filter = set_filter

            def set_interval(interval):
                if not type(interval) is int:
                    raise FilamentError('Interval must be an integer value')
                self._interval = interval
            self._filament.set_interval = set_interval

            def columns(cols):
                if not isinstance(cols, list):
                    raise FilamentError('Columns must be a list, %s found' % type(cols))
                self._cols = cols
                self._tabular = PrettyTable(self._cols)
                self._tabular.padding_width = 10
                self._tabular.junction_char = '|'

            def sort_by(col, sort_desc=True):
                if len(self._cols) == 0:
                    raise FilamentError('Expected at least 1 column but 0 found')
                if not col in self._cols:
                    raise FilamentError('%s column does not exist' % col)
                self._sort_by = col
                self._sort_desc = sort_desc

            def limit(limit):
                if len(self._cols) == 0:
                    raise FilamentError('Expected at least 1 column but 0 found')
                if not type(limit) is int:
                    raise FilamentError('Limit must be an integer value')
                self._limit = limit

            def title(text):
                self._tabular.title = text

            def add_row(row):
                if not isinstance(row, list):
                    raise FilamentError('Expected list type for the row')
                self._tabular.add_row(row)

            self._filament.columns = columns
            self._filament.title = title
            self._filament.sort_by = sort_by
            self._filament.limit = limit
            self._filament.add_row = add_row
            self._filament.render_tabular = self.render_tabular

            # call filaments methods if defined
            [on_init] = self._find_func('on_init')
            if on_init:
                if len(inspect.getargspec(on_init).args) == 0:
                    self._filament.on_init()

            [on_stop] = self._find_func('on_stop')
            if on_stop:
                if len(inspect.getargspec(on_stop).args) == 0:
                    self._on_stop = on_stop

            [on_interval] = self._find_func('on_interval')
            if on_interval:
                self.scheduler.add_executor(ThreadPoolExecutor(max_workers=8))
                self.scheduler.start()
                self.scheduler.add_job(self._filament.on_interval,
                                       'interval',
                                       seconds=1, max_instances=8,
                                       misfire_grace_time=60)

    def render_tabular(self):
        if len(self._cols) > 0:
            tabular = self._tabular.get_string(start=1, end=self._limit)
            if self._sort_by:
                tabular = self._tabular.get_string(start=1, end=self._limit,
                                                   sortby=self._sort_by,
                                                   reversesort=self._sort_desc)
            if not self.term_initialized:
                self.term_initialized = True
                self.ansi_term.init_console()
            self._tabular.clear_rows()
            self.ansi_term.cls()
            self.ansi_term.write(tabular)

    def process(self, kevent):
        self._filament.on_next_kevent(kevent)

    def close(self):
        if self._on_stop:
            self._on_stop()
        if self.scheduler.running:
            self.scheduler.shutdown()
        self.ansi_term.restore_console()

    @classmethod
    def exists(cls, filament):
        Filament._assert_root_dir()
        return os.path.exists(os.path.join(FILAMENTS_DIR, '%s.py' % filament))

    @classmethod
    def list_filaments(cls):
        Filament._assert_root_dir()
        filaments = {}
        paths = [os.path.join(FILAMENTS_DIR, path) for path in os.listdir(FILAMENTS_DIR)
                 if path.endswith('.py')]
        for path in paths:
            filament_name = os.path.basename(path)[:-3]
            loader = SourceFileLoader(filament_name, path)
            filament = loader.load_module()
            filaments[filament_name] = inspect.getdoc(filament)
        return filaments

    @property
    def filters(self):
        return self._filters

    @classmethod
    def _assert_root_dir(cls):
        if not os.path.exists(FILAMENTS_DIR):
            IO.write_console('fibratus run: ERROR - %s path does not exist.' % FILAMENTS_DIR)
            sys.exit(0)

    def _find_func(self, func_name):
        functions = inspect.getmembers(self._filament, predicate=inspect.isfunction)
        return [func for name, func in functions if name == func_name] or [None]
示例#15
0
import sys
from importlib.machinery import SourceFileLoader

from apscheduler.executors.pool import ThreadPoolExecutor
from apscheduler.schedulers.background import BackgroundScheduler
from logbook import FileHandler
from logbook import Logger
from multiprocess import Process

from fibratus.asciiart.tabular import Tabular
from fibratus.common import DotD as ddict
from fibratus.common import IO
from fibratus.errors import FilamentError, TermInitializationError
from fibratus.term import AnsiTerm

_ansi_term = AnsiTerm()

FILAMENTS_DIR = os.getenv(
    'FILAMENTS_PATH',
    os.path.join(os.path.expanduser('~'), '.fibratus', 'filaments'))


class AdapterMetaVariable(object):
    """An accessor for the adapter meta variable.

    It represents an adapter accessor which is injected into
    every filament module.
    """
    def __init__(self, adapter):
        self._adapter = adapter
示例#16
0
class Filament():
    """Filament initialization and execution engine.

    Filaments are lightweight Python modules which run
    on top of Fibratus. They are often used to enrich/extend the
    functionality of Fibratus by performing any type of logic
    (aggregations, groupings, filters, counters, etc) on the
    kernel event stream.

    """
    def __init__(self):
        self._filament = None
        self._filters = []
        self._tabular = None
        self._cols = []
        self._limit = 10
        self._interval = 1
        self._sort_by = None
        self._sort_desc = True
        self.ansi_term = AnsiTerm()
        self.scheduler = BackgroundScheduler()
        self.term_initialized = False
        self._on_stop = None

    def load_filament(self, name):
        Filament._assert_root_dir()
        [filament_path] = [
            os.path.join(FILAMENTS_DIR, filament)
            for filament in os.listdir(FILAMENTS_DIR)
            if filament.endswith('.py') and name == filament[:-3]
        ] or [None]
        if filament_path:
            loader = SourceFileLoader(name, filament_path)
            self._filament = loader.load_module()
            # check for required methods
            # on the filament module
            doc = inspect.getdoc(self._filament)
            if not doc:
                raise FilamentError(
                    "Please provide a short description for the filament")

            [on_next_kevent] = self._find_func('on_next_kevent')
            if on_next_kevent:
                args_spec = inspect.getargspec(on_next_kevent)
                if len(args_spec.args) != 1:
                    raise FilamentError(
                        'Missing one argument on_next_kevent method on filament'
                    )
            else:
                raise FilamentError(
                    'Missing required on_next_kevent method on filament')
        else:
            raise FilamentError('%s filament not found' % name)

    def initialize_filament(self):
        if self._filament:

            def set_filter(*args):
                self._filters = args

            self._filament.set_filter = set_filter

            def set_interval(interval):
                if not type(interval) is int:
                    raise FilamentError('Interval must be an integer value')
                self._interval = interval

            self._filament.set_interval = set_interval

            def columns(cols):
                if not isinstance(cols, list):
                    raise FilamentError('Columns must be a list, %s found' %
                                        type(cols))
                self._cols = cols
                self._tabular = PrettyTable(self._cols)
                self._tabular.padding_width = 10
                self._tabular.junction_char = '|'

            def sort_by(col, sort_desc=True):
                if len(self._cols) == 0:
                    raise FilamentError(
                        'Expected at least 1 column but 0 found')
                if not col in self._cols:
                    raise FilamentError('%s column does not exist' % col)
                self._sort_by = col
                self._sort_desc = sort_desc

            def limit(limit):
                if len(self._cols) == 0:
                    raise FilamentError(
                        'Expected at least 1 column but 0 found')
                if not type(limit) is int:
                    raise FilamentError('Limit must be an integer value')
                self._limit = limit

            def title(text):
                self._tabular.title = text

            def add_row(row):
                if not isinstance(row, list):
                    raise FilamentError('Expected list type for the row')
                self._tabular.add_row(row)

            self._filament.columns = columns
            self._filament.title = title
            self._filament.sort_by = sort_by
            self._filament.limit = limit
            self._filament.add_row = add_row
            self._filament.render_tabular = self.render_tabular

            # call filaments methods if defined
            [on_init] = self._find_func('on_init')
            if on_init:
                if len(inspect.getargspec(on_init).args) == 0:
                    self._filament.on_init()

            [on_stop] = self._find_func('on_stop')
            if on_stop:
                if len(inspect.getargspec(on_stop).args) == 0:
                    self._on_stop = on_stop

            [on_interval] = self._find_func('on_interval')
            if on_interval:
                self.scheduler.add_executor(ThreadPoolExecutor(max_workers=8))
                self.scheduler.start()
                self.scheduler.add_job(self._filament.on_interval,
                                       'interval',
                                       seconds=1,
                                       max_instances=8,
                                       misfire_grace_time=60)

    def render_tabular(self):
        if len(self._cols) > 0:
            tabular = self._tabular.get_string(start=1, end=self._limit)
            if self._sort_by:
                tabular = self._tabular.get_string(start=1,
                                                   end=self._limit,
                                                   sortby=self._sort_by,
                                                   reversesort=self._sort_desc)
            if not self.term_initialized:
                self.term_initialized = True
                self.ansi_term.init_console()
            self._tabular.clear_rows()
            self.ansi_term.cls()
            self.ansi_term.write(tabular)

    def process(self, kevent):
        self._filament.on_next_kevent(kevent)

    def close(self):
        if self._on_stop:
            self._on_stop()
        if self.scheduler.running:
            self.scheduler.shutdown()
        self.ansi_term.restore_console()

    @classmethod
    def exists(cls, filament):
        Filament._assert_root_dir()
        return os.path.exists(os.path.join(FILAMENTS_DIR, '%s.py' % filament))

    @classmethod
    def list_filaments(cls):
        Filament._assert_root_dir()
        filaments = {}
        paths = [
            os.path.join(FILAMENTS_DIR, path)
            for path in os.listdir(FILAMENTS_DIR) if path.endswith('.py')
        ]
        for path in paths:
            filament_name = os.path.basename(path)[:-3]
            loader = SourceFileLoader(filament_name, path)
            filament = loader.load_module()
            filaments[filament_name] = inspect.getdoc(filament)
        return filaments

    @property
    def filters(self):
        return self._filters

    @classmethod
    def _assert_root_dir(cls):
        if not os.path.exists(FILAMENTS_DIR):
            IO.write_console('fibratus run: ERROR - %s path does not exist.' %
                             FILAMENTS_DIR)
            sys.exit(0)

    def _find_func(self, func_name):
        functions = inspect.getmembers(self._filament,
                                       predicate=inspect.isfunction)
        return [func
                for name, func in functions if name == func_name] or [None]