FEBRUARY 15, 202
This blog post will run through how we can use the PyEZ python library to interact with network devices running Juniper JunOS, in a slightly different way than usual. This is something I learned recently and thought it would be useful to share. Some of you may be confused to see PyEz and screen scraping mentioned in the same sentence, but bear with me..
Below is a quick reminder of how we may typically use PyEZ to interact with a network device running Juniper JunOS. Here we create a NETCONF session to the device and execute the show version command on it via an RPC and receive XML output.
from jnpr.junos import Device
from lxml import etree
# Connect to the device using context manager
with Device(host="cr1.cloudnetdev.io", user="x", password="x") as dev:
# Execute show version rpc
cr = dev.rpc.get_software_information()
# Print XML output
print(etree.tostring(cr, encoding="unicode"))
PyEz also provides us with other Modules and Classes that do a myriad of things. From displaying operational data in pre-defined tables, transferring files to network devices using SCP, and even creating compressing folders or files into TGZ format.
I recently came across some edge cases in our environment where these provided modules did not successfully achieve what I wanted. We were trying to programmatically compress logs into a TGZ file on some of our core routers and found that the operation took rather long (over 10 minutes). The RPC would eventually fail and thus the desired file would not be created. Fiddling with the RPC timeouts was to no avail either.
PyEZ actually provides us with a way we can create an SSH session to a device and send show commands to it as we usually would when screen scraping with a python library such as Netmiko. The example below shows how we can use the PyEZ *StartShell* class to connect to a network device and run some CLI commands via the .run() method. Notice how we also prefix the commands with cli -c.
from jnpr.junos import Device
from jnpr.junos.utils.start_shell import StartShell
# Connect to the device using context manager
with Device(host="cr1.cloudnetdev.io", user="x", password="x") as dev:
# Create shell connection
with StartShell(dev) as ss:
# Send CLI command to compress logs into .tgz file
ss.run('cli -c "file archive compress source /var/log/* destination /var/tmp/re0.tgz"')
ver = ss.run('cli -c "show version"')
print(ver)
The truncated output of this script for brevity:
(False, '\\r \\rHostname: cr1\\r\\nModel: mx204\\r\\nJunos: 19.1R8\\r\\nJUNOS Base OS boot [19.1R1.8]\\r\\n ...)
The .run() method returns a tuple where the 1st element represents the exit code and the 2nd element is the actual returned command output from the network device.
There may be some situations where we just want clean raw output, that is unstructured and easier to consume for humans compared to XML. A situation where this could be useful is during troubleshooting. This example shows how we can set the format attribute of the XML RPC to get it to return text instead of the usual XML.
from jnpr.junos import Device
from lxml import etree
with Device(host='cr1.cloudnetdev.io', user='x', password='x') as dev:
# Determine RPC for show bgp summary command
rpc = dev.display_xml_rpc("show bgp summary")
if type(rpc) is etree._Element:
# Set XML attribute to get text format
rpc.attrib['format']='text'
# Execute RPC and print output
result = dev.rpc(rpc)
print(result.text)
else:
print(f"XML RPC for command not available: {rpc}")