Python/PyEZ

Python Concepts
Overview of Pythong concepts and syntax

Why Python?
-Easy to read, uses whitespace for structure.
-Heavily used in DevOps. Ansible and Salt are written in Python, and many other networking vendors (such as cisco) have chosen to use Python for automation.
-Large community, it’s the most popular scripting language in the world.

Attributes of Python
-Interpreted Language – Interpreted at runtime as opposed to ahead of time.
-Object Oriented
-2 versions of Python are largely in use, and come preinstalled on many devices (Python2 and Python3).

I know Python reasonably well so I’m not going to spend much time on what Python is.

PyEZ

PyEZ is a micro-framework developed by Juniper in aid of automation of JunOS devices.
It can be used to reduce the work that goes into connection handling, so more time can be spent automating devices and less time figuring out how to interface with a device.
Primarily we will use the Device class and resulting object when interacting with the Juniper Devices.

RPCs

We can gather what the RPC of a command would be in Junos by piping the command to | display xml rpc

In order to use these RPCs in PyEZ we use the rpc attribute, but we need to swap the hyphens (-) for underscores (_) in our Python code.

arp_table = dev.rpc.get_arp_table_information()
print(arp_table)

This returns the arp table information element in XML.

Now we have that data we can interate through it, if we want to we can use an xpath expression xml_doc.xpath(‘xpath_expression’), or perhaps simpler in Python we can use the find or findall methods to look for search patterns, returning either the first match, or all matches of a search pattern.

output of code
code to retrieve the arp table, and then print values

PyEZ makes every RPC available in Python.

utils is a directory in the PyEZ package containing more targeted modules:

config – provides classes and methods for managing junos configuration
fs – provides classes and methods for managing junos file system
scp – provides methods to copy files to a remote device via scp
start_shell – provides methods to interact with the bsd BSD shell on a remote device
sw – provides classes and methods for managing junos software upgrades

PyEZ Config Module
Used to interact with the config database:
-Locking and unlocking the configuration database
-Loading configuration in text, set or XML formats
-Printing configuration diff (show | compare)
-Committing and rolling back configuration changes

#!pip install junos-eznc
from jnpr.junos import Device
from jnpr.junos.utils.config import Config

ROUTER = "10.1.1.1"
PWD = "juniper123"
USER = "root"
dev = Device(host=ROUTER, password=PWD, user=USER)
dev.open()
conf = Config(dev)
data = "set interfaces ge-0/0/1.0 family inet address 172.17.1.150/24"
conf.lock()
conf.load(data, format="set")
conf.pdiff()
if conf.commit_check():
    conf.commit()
else:
    conf.rollback()
conf.unlock()
dev.close()

And the output it would return is:

eve@ubuntu:~/Desktop$ python3 sendConfig.py
[edit interfaces]
+    ge-0/0/1 {
+       unit 0 {
+           family inet {
+               address 172.17.1.150/24;
+           }
+       }
+    } 

Instead of using commands, you can also use text style config (also using context managers):

#!pip install junos-eznc
from jnpr.junos import Device
from jnpr.junos.utils.config import Config 

ROUTER = "10.1.1.1"
PWD = "juniper123"
USER = "root"
data = """interfaces{
    ge-0/0/1 {
        unit 0 {
            family inet {
                address 172.17.2.151;
            }
        }
    }
}"""
with Device(host=ROUTER, password=PWD, user=USER) as dev:
    with Config(dev, mode="exclusive") as conf:
        conf.load(data, format="text")
        if conf.diff() is None:
            print("Config is already applied")
        else:
            print(conf.diff())
            conf.commit()

Note – the above code will work when configuring unconfigured interfaces but it will not remove what is already there.

Using the sw module

You can install software updates using this too, as well as additional packages such as OpenConfig. (package is on the network device, not the on the computer running the script)

from jnpr.junos import Device
from jnpr.junos.utils.sw import SW
PACKAGE = "/var/tmp/junos-openconfig-x86-32-0.0.1.2.tgz"
ROUTER = "10.1.1.1"
PWD = "juniper123"
USER = "root"

def progress_report(dev, report):
    print(report)
dev = Device(host=ROUTER, password=PWD, user=USER) dev.open() sw = SW(dev) installation = sw.install(package=PACKAGE, no_copy=True, validate=False, progress=progress_report) dev.close()

Exception Handling

How we handle exceptions in Python, and the PyEZ tools available that are more specific for handling errors related to Juniper devices

A Python exception is a Python object that represents an error. It occurs when the interpreter encounters a situation it cannot cope with and will cause a script to terminate immediately unless it is handles.
These exceptions are handled with try: and except: blocks. Different types of exceptions can be handled differently.

The jnpr.junos.exception library brings the capability to handle these PyEZ specific errors. It allows for easier debugging and more informative error messages. (commit errors, config load errors.etc)

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
from jnpr.junos.exception import *

ROUTER = "10.1.1.1"
PWD = "juniper123"
USER = "root" 
dev = Device(host=ROUTER, password=PWD, user=USER) 

try:
    dev.open()
    conf = Config(dev)
    conf.lock()
    conf.load(path="config.conf", format="set", merge=True)
    conf.commit()
    conf.unlock()
    print("Configuration applied successfully!")
except ConnectAuthError:
    print("ERROR: Authentication failed")
except ConnectTimeoutError:
    print("ERROR: NETCONF connection timed out")
except ConnectError as e:
    print("ERROR: Unknown connection error {0}".format(str(e)))
except ConfigLoadError:
    print("ERROR: Failure when loading configuration")
except Exception as e:
    print("Some unknown exception occurred: {0}".format(str(e)))
finally:
    dev.close() 
eve@ubuntu:~/Desktop$ python3 ExceptionHandling.py

Some unknown exception occurred: [Errno 2] No such file or directory: 'config.conf'

Full documentation here