Automation & Programmability
Showing results for 
Search instead for 
Do you mean 

Python for Non-Programmers (Part 2)

by ‎11-14-2013 07:28 AM - edited ‎03-27-2014 04:39 AM

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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Comments
by alpha
on ‎12-07-2013 10:23 PM
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.
by
on ‎12-08-2013 07:28 AM

@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!

 

by
on ‎12-08-2013 09:36 AM

@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!

 

by
on ‎12-08-2013 09:38 AM
by mabernathy
on ‎03-05-2014 06:50 AM

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'

 

by
on ‎03-07-2014 11:58 AM

@Matt,

 

Please let me know what version of py-junos-eznc you are using.  I believe we made a fix for VC in version 0.0.4.  If not there, I do know that it works with the latest code in github.  That code will be submitted itno PyPI at the end of March.

 

Apologies for the problems you are facing.  Hopefully either re-installing 0.4.0 or the github latest will resolve your issue.

 

We are working on streamlining the installation process as well to avoid these types of issues.  Really appreciate everyone's support and feedback at this early stage of the project!

by mabernathy
on ‎03-12-2014 10:34 AM

No Worries thanks for your time putting all this out here and responding to comments. I am running 0.0.4. i'll see if i can get it the newest updates from github and try again. 

by mabernathy
on ‎03-12-2014 01:57 PM

Turns out it has something to do with the version of junos. The box I have that fails is running 12.1r2.9 I have another virtual chassis running 12.1r5.5 and I was able to run dev.open() on that one with no issues.

by dbarker1979
on ‎08-12-2014 09:23 AM

Can i use the IP of the device to connect rather than the hostname ? 

by
on ‎08-12-2014 09:34 AM

Yes, you can, providing the hostname you provide is DNS reachable; i.e. you could "ping" or "ssh" to it.

by
on ‎07-08-2015 02:35 PM

The link you provided above for using multiple set_cmd is broken (link is https://github.com/jeremyschulman/py-junos-eznc/tree/master/examples/config)

 

any chance you can fix that up?

by thegeneralmills
on ‎07-17-2015 03:27 PM

First of all, thank you very much for making these tutorials. I find them very helpful and I am currently trying to automate a huge chunk of my day to day tasks leveraging PyEZ and Ansible. 

 

Anyway, I guess what was frustrating about this particual tutorial is that you call using the *.cli() the cheater method to get device configuration information but you never explained how to get the information using another function, you just show ways to use the set fucntion.

 

Thanks again!

Announcements
Juniper TechCafe Ask the Author
About the Author
  • Ben has been working with service providers around the world for the last 15 years developing business cases for a variety of product concepts and new ventures. Ben holds an MBA from MIT and a BS & MS in Mechanical Engineering from Johns Hopkins University.
  • Part of Juniper PS EMEA since 2005 Primarily interested in making technology do the boring repetitive work so I can do fun new work.
  • Donyel Jones-Williams is the Director of Service Provider Product Marketing Management overseeing all of Juniper's Service Provider Products for Juniper Networks. In this role, he leads all of the internal and external marketing activities for Juniper with respect to routing, automation, SDN and NFV. Prior to joining Juniper Networks in January 2014, Donyel was a Senior Product Line Manager for Cisco Systems with in the High End Optical Routing Group managing product lifecycle for multiple products lines helping telecom providers operate efficiently and effectively including; ONS 155xx Product Family, ONS 15216, ONS 15454 MSTP, Carrier Packet Transport Product Family, ME 2600x, & ASR 9000v. He also negotiated favorable agreements with 3rd-party vendors furnishing components and parts and conducted both outbound and inbound marketing (webinars, case study-development, developed and delivered both business & technical at Cisco Live 2005-2012). Donyel graduated from California Polytechnic State University-San Luis Obispo with a Bachelor of Science in Computer Science. While attending Cal Poly SLO he was a collegiate student athlete playing football as a wide receiver and a key member of the National Society of Black Engineers. Donyel is now an active volunteer for V Foundation.
  • Dwayne loves everything related to automation and enjoys talking about it: Automation benefits outweigh any associated disruption.
  • Ebben Aries is a Principal Engineer for Junos Manageability in the Juniper Development and Innovation Division.
  • Marcel Wiget is a member of the Routing TME team. His career within Juniper started back in 2009 as a Senior Systems Engineer driving one of the first MX based Broadband Edge deployment to success. Prior to Juniper, Marcel held various positions in pre-sales, professional services and development at Chantry Networks, Spring Tide, Nortel Networks and Wellfleet.
  • Michael Pergament, JNCIE-SP #510, JNCIE-ENT #23, JNCIP-SEC
  • Pallavi Mahajan is Vice President Engineering, Junos Engineering, and leads the Junos Programmability & Automation teams
  • Product Manager, JUNOS Automation