To illustrate how Trigger works, here are some basic examples of leveraging the API.
For these examples to work you must have already :ref:`installed <install-docs>` and :ref:`configured <config-docs>` Trigger, so if you haven't already please do that first!
Get a count of all your devices:
>>> from trigger.netdevices import NetDevices >>> nd = NetDevices() >>> len(nd) 5539
(Whoa! That's a lot!) Let's look up a device.
>>> dev = nd.find('edge1-abc') >>> dev.vendor, dev.deviceType (<Vendor: Juniper>, 'ROUTER') >>> dev.has_ssh() True
Since this device has SSH, let's connect to it:
>>> dev = nd.find('edge1-abc') >>> dev.connect() Connecting to edge1-abc.net.aol.com. Use ^X to exit. Fetching credentials from /home/jathan/.tacacsrc --- JUNOS 10.2S6.3 built 2011-01-22 20:06:27 UTC jathan@edge1-abc>
Let's start with a simple Cisco ACL:
>>> from trigger.acl import parse >>> aclobj = parse("""access-list 123 permit tcp any host 10.20.30.40 eq 80""") >>> aclobj.terms [<Term: None>]
And convert it to Juniper format:
>>> aclobj.name_terms() # Juniper policy terms must have names >>> aclobj.terms [<Term: T1>] >>> print '\n'.join(aclobj.output(format='junos')) filter 123 { term T1 { from { destination-address { 10.20.30.40/32; } protocol tcp; destination-port 80; } then { accept; } } }
Trigger will encrypt and store your credentials in a file called .tacacsrc
in your home directory. We already had them cached in the previous examples, so
I removed it and then:
>>> from trigger.tacacsrc import Tacacsrc >>> tcrc = Tacacsrc() /home/jathan/.tacacsrc not found, generating a new one! Updating credentials for device/realm 'tacacsrc' Username: jathan Password: Password (again): >>> tcrc.creds['aol'] Credentials(username='jathan', password='boguspassword', realm='tacacsrc')
Passwords can be cached by realm. By default this realm is 'aol'
, but you
can change that in the settings. Your credentials are encrypted and decrypted
using a shared key. A more secure experimental GPG-encrypted method is in the
works.
Trigger includes a simple tool for end-users to connect to devices called
gong
. (It should be just go
but we're in the future, so...):
$ gong foo1-cisco Connecting to foo1-cisco.net.aol.com. Use ^X to exit. Fetching credentials from /home/jathan/.tacacsrc foo1-cisco# foo1-cisco#show clock 20:52:05.777 UTC Sat Jun 23 2012 foo1-cisco#
Partial hostnames are supported, too:
$ gong foo1 2 possible matches found for 'foo1': [ 1] foo1-abc.net.aol.com [ 2] foo1-xyz.net.aol.com [ 0] Exit Enter a device number: 2 Connecting to foo1-xyz.net.aol.com. Use ^X to exit. Fetching credentials from /home/jathan/.tacacsrc foo1-xyz#
This is a little more advanced... so we saved it for last.
Trigger uses Twisted, which is a callback-based event loop. Wherever possible Twisted's implementation details are abstracted away, but the power is there for those who choose to wield it. Here's a super simplified example of how this might be accomplished:
from trigger.netdevices import NetDevices from twisted.internet import reactor nd = NetDevices() dev = nd.find('foo1-abc') def print_result(data): """Display results from a command""" print 'Result:', data def stop_reactor(data): """Stop the event loop""" print 'Stopping reactor' if reactor.running: reactor.stop() # Create an event chain that will execute a given list of commands on this # device async = dev.execute(['show clock']) # When we get results from the commands executed, call this async.addCallback(print_result) # Once we're out of commands, or we an encounter an error, call this async.addBoth(stop_reactor) # Start the event loop reactor.run()
Which outputs:
Result: ['21:27:46.435 UTC Sat Jun 23 2012\n'] Stopping reactor
Observe, however, that this only communicated with a single device.
~trigger.cmds.Commando tries to hide Twisted's implementation details so you don't have to deal with callbacks, while also implementing a worker pool so that you may easily communicate with multiple devices in parallel.
This is a base class that is intended to be extended to perform the operations
you desire. Here is a basic example of how we might perform the same example
above using Commando
instead, but also communicating with a second device
in parallel:
from trigger.cmds import Commando class ShowClock(Commando): """Execute 'show clock' on a list of Cisco devices.""" vendors = ['cisco'] commands = ['show clock'] if __name__ == '__main__': device_list = ['foo1-abc.net.aol.com', 'foo2-xyz.net.aol.com'] showclock = ShowClock(devices=device_list) showclock.run() # Commando exposes this to start the event loop print '\nResults:' print showclock.results
Which outputs:
Sending ['show clock'] to foo2-xyz.net.aol.com Sending ['show clock'] to foo1-abc.net.aol.com Received ['21:56:44.701 UTC Sat Jun 23 2012\n'] from foo2-xyz.net.aol.com Received ['21:56:44.704 UTC Sat Jun 23 2012\n'] from foo1-abc.net.aol.com Results: { 'foo1-abc.net.aol.com': { 'show clock': '21:56:44.704 UTC Sat Jun 23 2012\n' }, 'foo2-xyz.net.aol.com': { 'show clock': '21:56:44.701 UTC Sat Jun 23 2012\n' } }