Automation & Programmability
Automation & Programmability
Python for Non-Programmers (Part 2)
08.12.14

LEARNING TO FALL DOWN

 

When I was in college I took martial arts (jiu-jitsu) with some friends - turns out throwing your buddies around is a great way to blow off stress.  On our first day the instructor gave a demo on what we were to learn, and we were all really amped up to learn these "ninja" like skills.  What did we do the first day?  We learned how to fall down.

 

Turns out we were going to do that a lot.  In fact, the first two sessions all we seemed to do was learn to fall down in different ways.  Ultimately we learned that if you're going to engage in a potentially dangerous high contact sport, you need to know the right way to fall down so you don't accidental hurt yourself.  This proved to be a good life lesson.

 

I talk with a lot of people that say they want to automate configuration changes.  But at the same time, they are concerned about "scripts gone wild!" and stomping out the network.  My approach?  Start with "read-only" automation.  Gain a level of confidence on the simple things before tackling the harder things.

 

STEPPING OUTSIDE THE BOX

 

We all grew up using the Junos CLI, and it is aweseome.  But now you're going to start using the Python interpreter to do some basic automation.  Maybe you find yourself wishing you could still run Junos CLI commands to get information that you need, and you don't want to write any code.  Simple.

 

First, start the Python interpreter:

 

[jeremy@laptop]$ python2.7
Python 2.7.5 (default, Aug 29 2013, 12:31:29) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 


Note that I'm using Python 2.7.  The Junos "EZ" library requires Python 2.7.  If you haven't already installed jnpr.eznc, you can find the instructions on Part 1 of this series, here.

 

To use the jnpr.eznc library you need to import it, create a Netconf object for the device, then open a connection.  The process is very straight forward, and you can either provide a password directly or use ssh-keys. 

 

Import the library:

 

>>> from jnpr.junos import Device

 

Now create a connection to a Junos device:

 

>>> dev = Device(host='jnpr-dc-fw',user='jeremy',password='jeremy1')
>>> dev.open()
Device(jnpr-dc-fw)

 

At this point you have an active connection to the Junos device, and there are a number of "facts" that the library automatically loads.  For example, you can see the version:

 

>>> dev.facts['version']
'12.1X44-D20.3'

 

Now suppose you wanted to see the output of the Junos CLI command "show interfaces terse ge-0/0/0".  You can easily print that at the Python shell like so:

 

>>> print dev.cli("show interfaces terse ge-0/0/0")

Interface               Admin Link Proto    Local                 Remote
ge-0/0/0                up    up  
ge-0/0/0.0              up    up   inet     192.168.56.10/24

>>> 

 

If you want to see the Junos configuration you can do the same:

 

>>> print dev.cli("show configuration interfaces ge-0/0/0")

unit 0 {
    family inet {
        address 192.168.56.10/24;
    }
}

>>> 

 

You can even use the "| display set" to get the output in set commands:

 

>>> print dev.cli("show configuration interfaces ge-0/0/0 | display set")

set interfaces ge-0/0/0 unit 0 family inet address 192.168.56.10/24

>>> 

 

THIS IS "CHEATING" BUT USEFUL!

 

Using cli() is what I would call a "cheater".  When you write automation scripts, you would absolutely *NOT* use this to get output and then "screen scrape" the information out.  That would be no better that the archaic practices that most folks are trapped into using ... if they don't have Junos. 

 

Junos offers a complete and comprehensive API that avoids screen scraping and the associated common pitfalls.  You can read more about the Junos API here.

 

(update: 2014-Mar-27):  It's come to my attention that some folks see the cli() command and think this is what they should be doing this when writing tools or playing around on the Python shell.  Please do not make this your standard practice, but rather read the complete series of these blogs and see how to use Tables/View, Config utils, etc. 

 

MAKING CONFIG CHANGES, THE EASY WAY

 

Most config automation tasks are repetitive simple things you need to do at large scale.  Consider the example of changing the "login message" banner on 100 devices.  The process for making the change manually is trivial, but doing it over a 100 devices is just plain annoying. 

 

The jnpr.eznc library comes with a utilities library, and one of these is called "config".  The config utilities enables you to make changes, see the differences ("show|compare"), commit check, rollback, etc.  Basically most of the things you will need to do when making changes. 

 

You can import that utility into the Python shell:

 

>>> from jnpr.junos.utils.config import Config

 

If you want to see the available help on the Config utilities, you can use the Python builtin help() command:

 

>>> help(Config)

 

I'll leave you to read through the output of this as an exercise.


Once you've imported the utility, you need to associate a copy with your device.  There are a few different ways to do this, but I'll show you the simplest way here (and cover other approaches on another blog). 

 

Here I am creating a new variable called cu that I can use to interact with the device:

 

>>> cu = Config(dev)

 

If I examine the cu variable in the Python shell, it will show me what it is, and the name of the device that it is bound to:

 

>>> cu
jnpr.junos.utils.Config(jnpr-dc-fw)

 

Now I create a variable that contains the actual set command.  I am just doing a simple example by assigning the variable directly, but you could get creative by reading the contents from a file, or some other source.

 

>>> set_cmd = 'set system login message "Hello, user!"'

 

Next use the cu variable to load the contents of this command onto the device:

 

>>> cu.load(set_cmd, format='set')

 

If there was an error in your set command, you would see a Python exception (error).  We'll cover those in another blog.  But for now, if you see one, take a look at your set command variable.  Chances are you didn't enclose the message in double-quotes ... I made that mistake too.

 

You might be asking: "Can I do many set commands at once?"  Absolutely.  If you'd like to see more examples, take a look at the jnpr.eznc examples directory, here.

 

Loading the change this way does not do the commit, only updates the candidate configuration.  If you want to see the difference between the running config and the candidate config, you can use pdiff():

 

>>> cu.pdiff()

[edit system login]
+   message "Hello, user!";

>>> 

 

And if you want to commit the change, use commit():

 

>>> cu.commit()
True
>>> 

 

 

FALLING "UP"

 

Learning to use the cli() cheater and the Config utilities is a good way to get started using Python as a power-tool.  Take a deeper look at the Config utilities and you will find you can do some very sophisticated things, like Template based configs, without much effort.  There are some other goodies in the jnpr.eznc.utils directory, like managing the filesystem, using SCP, dealing with software-upgrade, and even running commands at the "shell" (*gasp*). 

 

 

FURTHER READING

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

12.07.13
alpha
Hi, I get the following error when i use the following code, from jnpr.junos import Device dev = Device(host='192.168.79.16',user='shabbir',password='abcd1234') dev.open() facts['fqdn'] = facts['hostname'] Keyerror: 'hostname' kindly help.
12.08.13

@alpha,

 

Do you have a host-name configured on the device?  This would be under [edit system].  

 

You can also check for the existance of a key using either "has_key" or "get", which would return None if not set.  For example:

 

hostname = dev.facts.get('hostname',"Amnesiac")

 

Hope this helps!

 

12.08.13

@alpha,

 

I did a test on a Junos device without a host-name configured and I see the same issue you reported.  Thank you for brining this to my attention.  I will open an issue on github to track this and make a fix.  The fix is relatively simple.  If you'd like to take a shot at it, please feel free to do so and issue a "pull-request".

 

Thank you!

 

12.08.13
03.05.14
mabernathy

Thanks for all your work on this. 

 

Is it possible to connect to a virtual chassis. when i try to i get the following message.

 

>>> dev.open()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/jnpr/junos/device.py", line 239, in open
    self.facts_refresh()
  File "/usr/lib/python2.7/site-packages/jnpr/junos/device.py", line 403, in facts_refresh
    gather(self, self._facts)
  File "/usr/lib/python2.7/site-packages/jnpr/junos/facts/personality.py", line 7, in personality
    examine = model if model != 'Virtual Chassis' else facts['RE0']['model']
KeyError: 'RE0'

 

Top Kudoed Authors
User Kudos Count
1
1