Junos PyEZ module

Junos PyEZ is a Python "micro-framework" to remotely manage or automate Junos OS devices. The user is NOT required to be a software programmer, have sophisticated knowledge of Junos OS, or have a complex understanding of the Junos OS XML API.

This library was built for two types of users:

Non-Programmers - Python as a Power Shell

This means that non-programmers, for example, the Network Engineer, can use the native Python shell on their management server (laptop, tablet, phone, and so on) as their point-of-control for remotely managing Junos OS devices. The Python shell is an interactive environment that provides the necessary means to perform common automation tasks, such as conditional testing, for-loops, macros, and templates. These building blocks are similar enough to other "shell" environments, like Bash, to enable the non-programmer to use the Python shell as a power tool, instead of a programming language. From the Python shell, a user can manage Junos OS devices using native hash tables, arrays, and so on, instead of using device-specific Junos OS XML or resorting to "screen scraping" the actual Junos OS CLI.

Programmers - Open and Extensible

There is a growing interest and need to automate the network infrastructure into larger IT systems. To do so, traditional software programmers, DevOps, hackers, and so on, need an abstraction library of code to further those activities. Junos PyEZ is designed for extensibility so that the programmer can quickly and easily add new widgets to the library in support of their specific project requirements. There is no need to "wait on the vendor" to provide new functionality. Junos PyEZ is not specifically tied to any version of Junos OS or any Junos OS product family.


The following are examples how to use  jupr.junos library.

1. Read device info:

from jnpr.junos import Device >>> dev = Device(host='jnpr-dc-fw',user='jeremy',password='jeremy1') >>> dev.open() Device(jnpr-dc-fw) >>> dev.facts['version'] '12.1X44-D20.3' >>> 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 >>> >>> print dev.cli("show configuration interfaces ge-0/0/0") unit 0 { family inet { address 192.168.56.10/24; } } >>>

2. Making Config Changes:

>>> from jnpr.junos.utils.config import Config >>> help(Config) Here I am creating a new variable called cu that I can use to interact with the device: >>> cu = Config(dev) >>> set_cmd = 'set system login message "Test Switch - 10.0.x.4"' >>> set_cmd 'set system login message "Squarespace Voip Switch - 10.0.x.4"' >>> cu.load(set_cmd, format='set') >>> >>> cu.pdiff() [edit system login] + message "Test Switch - 10.0.x.4"; ###### ###OR ##### >>> dev.bind(cfg=Config) >>> dev.cfg.diff() >>> dev.cfg.load("set system ntp server 10.1.1.1", format='set') >>> dev.cfg.diff() '\n[edit system ntp]\n server 10.x.y.z { ... }\n+ server 10.1.1.1;\n' >>> dev.cfg.rollback() >>>

3. User Manager

>>> from jnpr.junos.cfg.user import User >>> users = User(dev) >>> users Resource Manager: User >>> users.list ['jeremy', 'kim'] >>> me = users['jeremy'] >>> me NAME: User: jeremy HAS: {'$password': '$1$n/RPB3fZ$RGPy8hymoTa8G5oGiJMdr.', '$sshkeys': [('ssh-rsa', 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAm2JAE<SNIPPED>== jeremy@laptop.juniper.net')], '_active': True, '_exists': True, 'fullname': 'Jeremy Schulman', 'uid': 2001, 'userclass': 'super-user'} SHOULD:{}

4. Config Utility

>>> from jnpr.junos.utils.config import Config >>> cu = Config(dev) >>> cu jnpr.junos.utils.Config(jnpr-dc-fw) # To load changes from a file you would do something like this: >>> cu.load(path="config-example.conf") #You can see the diff of this change by using the "print diff" routine: >>> cu.pdiff() [edit system] - host-name jnpr-dc-fw; + host-name jeremy; - domain-name wfs.com; + domain-name jeremy.com; To determine the format of the contents. ['conf','text','txt'] is curly-text-style ['set'] is set-style ['xml'] is XML the format can specific set by using kvarg['format'] TEMPLATE BASED CONFIGURATION Junos "text" jinja2 template: system { host-name {{ host_name }}; domain-name {{ domain_name }}; }

5. Load jinja2 template with via python script

# setup the template variables # path (str) - path to file of config on the local server. # template_path (str) – Similar to the path parameter, but this indicates that the file contents are Jinja2 format and will require template-rendering. >>> myvars = {} >>> myvars['host_name'] = 'myhost-name' >>> myvars['domain_name'] = 'myhost-domainname' # load the template with the vars >>> cu.load(template_path='mytemplate.conf', template_vars=myvars) # now display the diff >>> cu.pdiff() [edit system] - host-name jnpr-dc-fw; + host-name myhost-name; - domain-name wfs.com; + domain-name myhost-domainname; /////Example of configuring interface using template: ##Create a template File: [ jtemplates]# cat interface_template.conf interfaces { {{ if_name }} { unit 0 { family ethernet-switching { port-mode trunk; vlan { members {{ vlan_name }}; } } } } }

6. We can also load modules on demand (or if we do this a lot, we’d want to push the loading into connect.py):

>>> from jnpr.junos.op.ethport import EthPortTable >>> eths = EthPortTable(dev) >>> eths.get() EthPortTable:srx1: 12 items >>> list(eths) [EthPortView:fe-0/0/0, EthPortView:fe-0/0/1, EthPortView:fe-0/0/2, EthPortView:fe-0/0/3, EthPortView:fe-0/0/4, EthPortView:fe-0/0/5, EthPortView:fe-0/0/6, EthPortView:fe-0/0/7, EthPortView:ae0, EthPortView:ae1, EthPortView:ae2, EthPortView:ae3] >>> ### OR >>> for key in eths: print key.name ... fe-0/0/0 fe-0/0/1 fe-0/0/2 fe-0/0/3 fe-0/0/4 fe-0/0/5 fe-0/0/6 fe-0/0/7 ae0 ae1 ae2 ae3 >>> ## Or maybe: >>> pp ( eths.keys() ) ['fe-0/0/0', 'fe-0/0/1', 'fe-0/0/2', 'fe-0/0/3', 'fe-0/0/4', 'fe-0/0/5', 'fe-0/0/6', 'fe-0/0/7', 'ae0', 'ae1', 'ae2', 'ae3'] >>>