The plan is to develop an API for BroControl plugins that provide external functionality executed when broctl runs its commands.
- Plugins should be implementable as both Python modules or shell scripts.
- Plugins can hook into any of broctl’s commands, either before a command runs, or after it has finished.
- If run before the actual command, the plugin can signal an error and prevent its execution.
- If run afterwards, the plugin gets a hint whether the actual command was successful or not.
- A plugin can execute actions on any of the cluster nodes.
- A plugin needs to have access to configuration values, and to be able to define its own configuration options for broctl.cfg.
- A plugin can provide new commands.
Let’s create a plugin directory, say <prefix>/lib/broctl/plugins by default. broctl assumes every file in there is one plugin, and reads it in and activates it at startup.
Let’s for now assume each plugin is a Python module (see below for shell scripts). Here’s a proposed API with methods for the plugin to override:
class MyPlugin(BroControlPlugin): def name(self): """Returns a name for the plugin.""" def version(self): """Returns a version for the plugin.""" def options(self): """Returns a set of custom configuration options provided by the plugin. Format of the return value TBD. """ pass def commands(self): """Returns a set of custom commands provided by the plugin. Format of the return value TBD. """ pass def init(self): """Called just before BroControl starts executing any commands. This method should do any initialization the plugin may require. Note that at this point BroControl will have everything fully set up internally, which may not be the case the ``__init__`` is run. Returns a boolean, indicating whether the plugin should be used. If ``False``, the plugin will be removed and no other methods called. """ def done(self): """Called before BroControl terminates. This method can do any cleanup the plugin may require. """ def cmd_start_pre(self, nodes): """Called just before the ``start`` command is run. It receives the list of nodes being started, and returns a list of nodes that should proceed with being started. The standard case would be returning simply the unmodified ``nodes`` parameter. To completely block the start, return an empty list. If a node (or all of them) are removed, the plugin must report that to the user via ``message`` or ``error`` methods. def cmd_start_post(self, nodes): """Called just after the ``start`` command has run. It receives the list of tuples ``(node, rc) of nodes that were attempted to start, with ``rc`` indicating whether doing so was successful.""" ... [ def cmd_*_{pre,post}(self, ...) for other commands in a similar fashion ] ... def cmd_custom(self, cmd, args): """Called whenever a command returned by ``commands`` is executed. ``cmd`` is the command, and ``args`` is a *string* with all arguments. If the arguments are actually node names, ``getNodes`` can be used to get the Node objects. """
The BroControlPlugin class provides functionality the plugin may use:
class BroControlPlugin: def getOption(self, name): """Returns the value of a configuration option.""" def getNodes(self, names): """Returns node objects for the given node names.""" def log(self, log): """Logs a message in BroControl's log file.""" def debug(self, debug): """Logs a debug message in BroControl' debug log if enabled.""" def message(self, msg): """Reports a message to the user.""" def error(self, msg): """Reports an error to the user.""" def execute(self, node, cmd): """Executes a command on the given node. Returns a tuple ``(rc, output)`` in which ``rc`` is the command's exit code and ``output`` the combined stdout/stderr output. def executeParallel(self, cmds): """Executes a set of commands in parallel on multiple nodes. ``cmds`` is a list of tuples ``(node, cmd)``. The method returns a list of tuples ``(node, rc, output)``, in which ``rc`` is the exit code and ``output`` the combined stdout/stderr output for the corresponding ``node``.
To enable shell scripts, I think we can just provide a Python plugin that forwards every command to a script. The script would do a big switch to implement its functionality.
However, the shell script would quite likely only be able to do a subset of what a Python plugin can do, in particular most of the stuff requiring a back channel into BroControl doesn’t really seem worth implementing.
Seems it’s ok if shell scripts can be used for simple stuff, and more complex things need to be done in Python.
© 2014 The Bro Project.