Source code for stoq.plugins.deep_dispatcher
#!/usr/bin/env python3
# Copyright 2014-2018 PUNCH Cyber Analytics Group
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
.. _deepdispatcher:
Overview
========
Deep Dispatcher plugins are similar to :ref:`dispatcher plugins <dispatcher>`, but there
are some significant differences in their utility. One of the primary differences between
them is deep dispatchers can be run 0 to N times per payload, where dispatcher plugins
are only run once per payload. Additionally, deep dispatchers are run after dispatcher
plugins and after the worker plugins has scanned the payload, but before continuing on
to any additional payloads. Because deep dispatchers are handled after the worker plugins
scan the payload, deep dispatchers are passed the original payload in addition to the
scan results from the workers. This allows for additional and deeper dispatching based
on not only the payload, but also any results from the workers. This concept can become
somewhat complex, so it is recommended the reader review the
:ref:`workflow section <workflow>` to better understand the full workflow.
Deep Dispatcher plugins can be defined multiple ways. In these examples, we will use
the ``test_deep_dispatcher`` deep dispatcher plugin.
From ``stoq.cfg``::
[core]
deep_dispatchers = test_deep_dispatcher
max_dispatch_passes = 3
.. note:: Multiple plugins can be defined separated by a comma. Additionally, ``max_dispatch_passes``
can be defined in ``stoq.cfg`` to ensure Deep Dispatchers do not end up in an endless loop.
From the command line::
$ stoq run -E test_deep_dispatcher [...]
.. note:: Multiple plugins can be defined by simply adding the plugin name
Or, when instantiating the ``Stoq()`` class:
>>> import stoq
>>> deep_dispatchers = ['test_deep_dispatcher']
>>> s = Stoq(deep_dispatchers=deep_dispatchers, [...])
Writing a plugin
================
A `deep dispatcher` plugin must be a subclass of the ``DeepDispatcherPlugin`` class.
As with any plugin, a :ref:`configuration file <pluginconfig>` must also exist
and be properly configured.
Example
-------
::
from typing import Dict, Optional
from configparser import ConfigParser
from stoq.data_classes import Payload, DeepDispatcherResponse, RequestMeta
from stoq.plugins import DeepDispatcherPlugin
class ExampleDeepDispatcher(DeepDispatcherPlugin):
def __init__(self, config: ConfigParser, plugin_opts: Optional[Dict]) -> None:
super().__init__(config, plugin_opts)
self.msg = config.get('options', 'msg', fallback='Useful content here')
def get_deep_dispatches(
self, payload: Payload, request_meta: RequestMeta
) -> Optional[DeepDispatcherResponse]:
dr = DeepDispatcherResponse()
dr.errors.append('This is an example error and is completely optional')
dr.meta['deep_key'] = 'Useful deep metadata info'
dr.meta['msg'] = self.msg
return dr
API
===
"""
from abc import abstractmethod
from typing import Optional
from stoq.data_classes import Payload, DeepDispatcherResponse, RequestMeta
from stoq.plugins import BasePlugin
[docs]class DeepDispatcherPlugin(BasePlugin):
[docs] @abstractmethod
def get_deep_dispatches(
self, payload: Payload, request_meta: RequestMeta
) -> Optional[DeepDispatcherResponse]:
pass