trigger.contrib — Extra, optional tools that solve common problems, extend, or modify core functionality.


Simple command running for Trigger meant to be used with a long-running reactor loop (such using the Twisted XMLRPC server).

This differs from Commando in that:

  • It does not start/stop the reactor, instead it uses sentinel values and a task monitor to detect when it’s done.
  • The .run() method returns a twisted.internet.defer.Deferred object.
  • Results/errors are stored in a list instead of a dict.
  • Each result object is meant to be easily serialized (e.g. to JSON).
class trigger.contrib.commando.CommandoApplication(*args, **kwargs)

Commando subclass to be used in an application where the reactor is always running (e.g. twistd or an application server).

Stores results as a list of dictionaries ideal for serializing to JSON.

device_object(device_name, **kwargs)

Create a basic device dictionary with optional data.

from_base(results, device, commands=None)

Call store_results directly

from_juniper(results, device, commands=None)

(Maybe) convert Juniper XML results into a strings

map_results(commands=None, results=None)

Return a list of command objects.

[{‘command’: ‘foo’, ‘result’: ‘bar’}, ...]

monitor_result(result, reactor)

Loop periodically or until the factory stops to monitor the results and return them.

store_error(device, error)

Called when an errback is fired.

Should do somethign meaningful with the errors, but for now just stores it as it would a result.

store_results(device, results)

Called by the parse (from) methods to store command output.

Device:A NetDevice object
Parameters:results – The results to store. Anything you want really.


This package provides facilities for running commands on devices using the CLI. Plugins for the Commando API built around Trigger.


This package provides facilities for running commands on devices using the CLI.

class trigger.contrib.docommand.DoCommandBase(devices=None, commands=None, creds=None, incremental=None, max_conns=10, verbose=False, timeout=30, production_only=True, allow_fallback=True, with_errors=True, force_cli=False, with_acls=False, command_interval=0, stop_reactor=True)

Base class for docommand action classes.

from_base(results, device, commands=None)

Call store_results without calling map_results

class trigger.contrib.docommand.CommandRunner(files=None, commands=None, debug=False, timeout=30, **kwargs)

Run commands on network devices.


n = CommandRunner(devices=['dev1', dev2'], files=['file1', 'file2'])

This will execute all commands inside of each file (‘file1’,’file2’) onto all listed devices (‘dev1, ‘dev2’).

  • devices – List of device names. Each hostname must have a match in NetDevices.
  • files – List of files named after the FQDN of each device.
store_results(device, results)

Define how we’re storing results.

class trigger.contrib.docommand.ConfigLoader(files=None, commands=None, debug=False, **kwargs)

Load configuration changes on network devices.


n = ConfigLoader(devices=['dev1', dev2'], files=['file1', 'file2'])

This will load all listed config files (‘file1’,’file2’) onto all listed devices (‘dev1, ‘dev2’).


List of files named after the FQDN of each device.

  • Files must exist in a local TFTP directory for non-Juniper devices.
  • Files must be accessible by device via TFTP for non-Juniper devices.
from_juniper(data, device, commands=None)

Parse results from a Juniper device.

store_results(device, results)

Store the results from a commands.

If you’d rather just change the default method for storing results, overload this. All default parse/generate methods call this.

to_juniper(device=None, commands=None, extra=None)

Configure a Juniper device using JunoScript.

trigger.contrib.docommand.xml_print(xml, iterations=10)

Display XML in a tree format.

  • xml – XML object to parse
  • iterations – Number of iterations to perform
trigger.contrib.docommand.do_work(work=None, action_class=None)

list results = do_work(list work)


list commands = get_commands_from_opts(dict opts)

User specified on cmdline either a path to a file containing a list of commands/config or an actual list. Return the list!


list devicenames = get_devices_from_opts(dict opts)

User specified on cmdline either a path to a file containing a list of devices or an actual list. Return the list!


list devicenames = get_devices_from_path(str path)

If path specified for devices/configs, then the list of filenames in dir will correspond to the list of devices.

The contents of each file contain the config/commands to be loaded/run on the specific device.

Future enhancements

  • verify that the filenames are fqdns
  • verify that the devnames exist in netdevices.xml

list jobs = get_jobs(dict opts)

Based on which arguments are provided, figure out what is loaded/run on which devices and create a list of objects matching the 2:

job = {'d': [],'c': [],'f': []}

Is read as “load ALL configs listed in ‘c’ on ALL devs listed in ‘d’”. Each such grouping is a separate job.

Future enhancements:

  • If multiple jobs exist for the same device we should regroup and optimize biggest optimization, though, will come after minor Commando enhancements would allow feeding entire list into a single run()

list text = get_list_from_file(str path)

Specified file (path) will contain a list of newline-separated items. This function is used for loading both configs/cmds as well as devices.


void = main(CommandoClass action_class)


binary success = print_results(list results)


void = do_work(list work)

Cycle through the list of jobs and then display the work to be done.

trigger.contrib.docommand.stage_tftp(acls, nonce)

Need to edit this for cmds, not just acls, but the basic idea is borrowed from bin/load_acl.


Validate opts and return whether they are ok.

returns True if all is good, otherwise (False, errormsg)


XMLRPC Server for Trigger with SSH manhole service.

Trigger Twisted XMLRPC server with an SSH manhole. Supports SSL.

This provides a daemonized Twisted reactor loop, Trigger and client applications do not have to co-habitate. Using the XMLRPC server model, all Trigger compatibility tasks can be executed using simple XMLRPC clients that call the appropriate method with arguments on the local XMLRPC server instance.

New methods can be added by way of plugins.

See examples/xmlrpc_server in the Trigger source distribution for a simple usage example.

class trigger.contrib.xmlrpc.server.TriggerXMLRPCServer(*args, **kwargs)

Twisted XMLRPC server front-end for Commando


Add a handler and bind it to an XMLRPC procedure.

Handler must a be a function or an instance of an object with handler methods.


Add multiple handlers


Return a list of the registered procedures


Lookup a method dynamically.

  1. First, see if it’s provided by a sub-handler.
  2. Or try a self-defined method (prefixed with xmlrpc_)
  3. Lastly, try dynamically mapped methods.
  4. Or fail loudly.
xmlrpc_add(x, y)

Adds x and y

xmlrpc_add_handler(mod_name, task_name, force=False)

Add a handler object from a remote call.

xmlrpc_execute_commands(args, kwargs)

Execute commands on devices


Raise a Fault indicating that the procedure should not be used.


To daemonize as a twistd plugin! Except this doesn’t work and these