trigger.cmds — Command execution library¶
Abstracts the asynchronous execution of commands on multiple network devices. It allows for integrated parsing and event-handling of return data for rapid integration to existing or newly-created tools.
The Commando class is designed to be extended but can still be
used as-is to execute commands and return the results as-is.
- class trigger.cmds.Commando(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)¶
Execute commands asynchronously on multiple network devices.
This class is designed to be extended but can still be used as-is to execute commands and return the results as-is.
At the bare minimum you must specify a list of
devicesto interact with. You may optionally specify a list ofcommandsto execute on those devices, but doing so will execute the same commands on every device regardless of platform.If
commandsare not specified, they will be expected to be emitted by thegeneratemethod for a given platform. Otherwise no commands will be executed.If you wish to customize the commands executed by device, you must define a
to_{vendor_name}method containing your custom logic.If you wish to customize what is done with command results returned from a device, you must define a
from_{vendor_name}method containing your custom logic.- Parameters:
devices – A list of device hostnames or
NetDeviceobjectscommands – (Optional) A list of commands to execute on the
devices.creds – (Optional) A 3-tuple of (username, password, realm). If only (username, password) are provided, realm will be populated from
DEFAULT_REALM. If unset it will fetch from.tacacsrc.incremental – (Optional) A callback that will be called with an empty sequence upon connection and then called every time a result comes back from the device, with the list of all results.
max_conns – (Optional) The maximum number of simultaneous connections to keep open.
verbose – (Optional) Whether or not to display informational messages to the console.
timeout – (Optional) Time in seconds to wait for each command executed to return a result. Set to
Noneto disable timeout (not recommended).production_only – (Optional) If set, includes all devices instead of excluding any devices where
adminStatusis not set toPRODUCTION.allow_fallback – If set (default), allow fallback to base parse/generate methods when they are not customized in a subclass, otherwise an exception is raised when a method is called that has not been explicitly defined.
with_errors – (Optional) Return exceptions as results instead of raising them. The default is to always return them.
force_cli – (Optional) Juniper only. If set, sends commands using CLI instead of Junoscript.
with_acls – Whether to load ACL associations (requires Redis). Defaults to whatever is specified in settings.WITH_ACLS
command_interval – (Optional) Amount of time in seconds to wait between sending commands.
stop_reactor – Whether to stop the reactor loop when all results have returned. (Default:
True)
- append_parsed_results(device, results)¶
A simple method for appending results called by template parser method.
If you want to customize the default method for storing parsed results, overload this in your subclass.
- Parameters:
device – A
NetDeviceobjectresults – The results to store. Anything you want really.
- errback(failure, device)¶
The default errback. Overload for custom behavior but make sure it always decrements the connections.
- Parameters:
failure – Usually a Twisted
Failureinstance.device – A
NetDeviceobject
- generate(device, commands=None, extra=None)¶
Generate commands to be run on a device. If you don’t provide
commandsto the class constructor, this will return an empty list.Define a ‘to_{vendor_name}’ method to customize the behavior for each platform.
- Parameters:
device (
NetDevice) – NetDevice objectcommands (list) – (Optional) A list of commands to execute on the device. If not specified in they will be inherited from commands passed to the class constructor.
extra – (Optional) A dictionary of extra data to send to the generate method for the device.
- map_parsed_results(command=None, fsm=None)¶
Return a dict of
{command: fsm, ...}.
- map_results(commands=None, results=None)¶
Return a dict of
{command: result, ...}.
- parse(results, device, commands=None)¶
Parse output from a device. Calls to
self._lookup_methodto find specificfrommethod.Define a ‘from_{vendor_name}’ method to customize the behavior for each platform.
- Parameters:
results (list) – The results of the commands executed on the device
device (
NetDevice) – Device objectcommands (list) – (Optional) A list of commands to execute on the device. If not specified in they will be inherited from commands passed to the class constructor.
- parse_template(results, device, commands=None)¶
Generator function that processes unstructured CLI data and yields either a TextFSM based object or generic raw output.
- Parameters:
results (str) – The unstructured “raw” CLI data from device.
device (
NetDevice) – NetDevice object
- property reactor_running¶
Return whether reactor event loop is running or not.
- run()¶
Nothing happens until you execute this to perform the actual work.
- select_next_device(jobs=None)¶
Select another device for the active queue.
Currently only returns the next device in the job queue. This is abstracted out so that this behavior may be customized, such as for future support for incremental callbacks.
If a device is determined to be invalid, you must return
None.- Parameters:
jobs – (Optional) The jobs queue. If not set, uses
self.jobs.- Returns:
A
NetDeviceobject orNone.
- store_error(device, error)¶
A simple method for storing an error called by all default parse/generate methods.
If you want to customize the default method for storing results, overload this in your subclass.
- Parameters:
device – A
NetDeviceobjecterror – The error to store. Anything you want really, but usually a Twisted
Failureinstance.
- store_results(device, results)¶
A simple method for storing results called by all default parse/generate methods.
If you want to customize the default method for storing results, overload this in your subclass.
- Parameters:
device – A
NetDeviceobjectresults – The results to store. Anything you want really.
- to_juniper(device, commands=None, extra=None)¶
Creates a series of
<command>foo</command>elements to pass along to execute_junoscript().
- class trigger.cmds.NetACLInfo(**args)¶
Class to fetch and parse interface information. Exposes a config attribute which is a dictionary of devices passed to the constructor and their interface information.
Each device is a dictionary of interfaces. Each interface field will default to an empty list if not populated after parsing. Below is a skeleton of the basic config, with expected fields:
config { 'device1': { 'interface1': { 'acl_in': [], 'acl_out': [], 'addr': [], 'description': [], 'subnets': [], } } }
Interface field descriptions:
- addr:
List of
IPy.IPobjects of interface addresses- acl_in:
List of inbound ACL names
- acl_out:
List of outbound ACL names
- description:
List of interface description(s)
- subnets:
List of
IPy.IPobjects of interface networks/CIDRs
Example:
>>> n = NetACLInfo(devices=['jm10-cc101-lab.lab.aol.net']) >>> n.run() Fetching jm10-cc101-lab.lab.aol.net >>> n.config.keys() [<NetDevice: jm10-cc101-lab.lab.aol.net>] >>> dev = n.config.keys()[0] >>> n.config[dev].keys() ['lo0.0', 'ge-0/0/0.0', 'ge-0/2/0.0', 'ge-0/1/0.0', 'fxp0.0'] >>> n.config[dev]['lo0.0'].keys() ['acl_in', 'subnets', 'addr', 'acl_out', 'description'] >>> lo0 = n.config[dev]['lo0.0'] >>> lo0['acl_in']; lo0['addr'] ['abc123'] [IP('66.185.128.160')]
This accepts all arguments from the
Commandoparent class, as well as this one extra:- Parameters:
skip_disabled – Whether to include interface names without any information. (Default:
True)
- IPhost(addr)¶
Given ‘172.20.1.4/24’, return TIP(‘172.20.1.4/32’).
- IPsubnet(addr)¶
Given ‘172.20.1.4/24’, return TIP(‘172.20.1.0/24’).
- from_arista(data, device, commands=None)¶
Parse IOS config based on EBNF grammar.
- from_brocade(data, device, commands=None)¶
Parse IOS config based on EBNF grammar.
- from_cisco(data, device, commands=None)¶
Parse IOS config based on EBNF grammar.
- from_force10(data, device, commands=None)¶
Parse IOS config based on EBNF grammar.
- from_foundry(data, device, commands=None)¶
Parse IOS config based on EBNF grammar.
- from_juniper(data, device, commands=None)¶
Do all the magic to parse Junos interfaces.
- to_arista(dev, commands=None, extra=None)¶
Generate commands for Arista, similar to IOS.
Arista has no “show conf” so we have to do “show run”
The regex used in the CLI for Arista is more “precise” so we have to change the pattern a little bit compared to the on in generate_ios_cmd
- to_brocade(dev, commands=None, extra=None)¶
Generate the “show me all interface information” command we pass to IOS devices.
- to_cisco(dev, commands=None, extra=None)¶
Generate the “show me all interface information” command we pass to IOS devices.
- to_force10(dev, commands=None, extra=None)¶
Similar to IOS, but: + You only get the “grep” (“include” equivalent) when using “show
run”.
The regex must be quoted.
- to_foundry(dev, commands=None, extra=None)¶
Generate the “show me all interface information” command we pass to IOS devices.
- to_juniper(dev, commands=None, extra=None)¶
Generates an etree.Element object suitable for use with JunoScript.
- class trigger.cmds.ReactorlessCommando(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)¶
A reactor-less Commando subclass.
This allows multiple instances to coexist, with the side-effect that you have to manage the reactor start/stop manually.
An example of how this could be used:
from twisted.internet import defer, reactor devices = ['dev1', 'dev2'] # Our Commando instances. This is an example to show we have two instances # co-existing under the same reactor. c1 = ShowClock(devices) c2 = ShowUsers(devices) instances = [c1, c2] # Call the run method for each instance to get a list of Deferred task objects. deferreds = [] for i in instances: deferreds.append(i.run()) # Here we use a DeferredList to track a list of Deferred tasks that only # returns once they've all completed. d = defer.DeferredList(deferreds) # Once every task has returned a result, stop the reactor d.addBoth(lambda _: reactor.stop()) # And... finally, start the reactor to kick things off. reactor.run() # Inspect your results print(d.result)
- monitor_result(result, reactor)¶
Loop periodically or until the factory stops to check if we’re
all_doneand then return the results.
- run()¶
We’ve overloaded the run method to return a Deferred task object.