📜 ⬆️ ⬇️

Getting Started with Junos PyEZ

The topic of network automation is very popular now. One of the tools for such automation in the Juniper world is the PyEZ library, developed by the team of Jeremy Schulman (Jeremy Schulman). PyEZ is a micro-framework for remote control and automation of Juniper devices, written in Python. The main advantage of PyEZ is its simplicity and focus on the audience of network engineers, not programmers.

Some features of PyEZ:

In this article I would like to dwell on the possibility of extracting operational information on the example of the EX4200 switch.

Preparation for work


  1. Installing the framework itself comes down to one command:

    pip install junos-eznc 

    On my Ubuntu 14.04, everything was established without problems, but if suddenly - I recommend reading the official wiki page.
  2. To access network devices, PyEZ uses the NETCONF protocol, which must be enabled.
    ')
     set system services netconf ssh 

    NETCONF, in turn, works on top of SSH, so make sure that SSH is configured and an account is created to access the device.


At this stage, everything should be ready to go. To check, you can try to connect to the device and remove the basic information.

 dteslya@ubuntu:~$ python Python 2.7.6 (default, Mar 22 2014, 22:59:56) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from pprint import pprint >>> from jnpr.junos import Device >>> dev = Device(host='1.2.3.4') >>> dev Device(1.2.3.4) >>> dev.open() Device(1.2.3.4) >>> pprint(dev.facts) {'2RE': True, 'HOME': '/var/home/dteslya', 'RE0': {'last_reboot_reason': 'Router rebooted after a normal shutdown.', 'mastership_state': 'master', 'model': 'EX4200-24F', 'status': 'OK', 'up_time': '2 days, 3 hours, 34 minutes, 40 seconds'}, 'domain': None, 'fqdn': 'SW1', 'hostname': 'SW1', 'ifd_style': 'SWITCH', 'master': 'RE0', 'model': 'EX4200-24F', 'personality': 'SWITCH', 'serialnumber': '', 'switch_style': 'VLAN', 'vc_capable': True, 'version': '12.3R8.7', 'version_RE0': '12.3R8.7', 'version_info': junos.version_info(major=(12, 3), type=R, minor=8, build=7)} >>> dev.close() >>> 


I will explain what is happening here. First, two classes are imported: standard pprint for formatted output and Device from the PyEZ library. Next, the device itself is announced to which we will connect. When a device is declared, it is enough to specify only an IP address, then key authentication will be applied, and the user name will be taken from the $ USER environment variable. Optionally, you can specify a username and password for password authentication (more details on the wiki ). Then there is the connection to the device and the collection of "facts" that are displayed using pprint, after which the connection is closed.

Now you can move on to more interesting examples of using PyEZ.

Formulation of the problem


Consider the task of polling switches and removing information about the topology of Spanning Tree. Roughly speaking, you need to go through the switches and display a list of ports of each switch, indicating the status of the STP.

Junos CLI


Let's see how to get this information using the CLI.

 dteslya@SW1> show spanning-tree interface Spanning tree interface parameters for instance 0 Interface Port ID Designated Designated Port State Role port ID bridge ID Cost ge-0/0/23.0 128:536 128:536 32768.54e032fdeb41 20000 DIS DIS xe-0/1/0.0 128:561 128:691 32768.3c94d5902981 2000 FWD ROOT xe-0/1/2.0 128:563 128:563 32768.54e032fdeb41 2000 FWD DESG {master:0} 


Junos XML


Now let's see how it looks “in reality”, i.e. in xml.
show spanning-tree interface | display xml
 dteslya@SW1> show spanning-tree interface | display xml <rpc-reply xmlns:junos="http://xml.juniper.net/junos/12.3R8/junos"> <stp-interface-information> <stp-instance> <instance-id>0</instance-id> <stp-interfaces junos:style="brief"> <stp-interface-entry> <interface-name>ge-0/0/23.0</interface-name> <port-number junos:format="128:536"> 536 </port-number> <port-priority>128</port-priority> <designated-port-number junos:format="128:536"> 536 </designated-port-number> <designated-port-priority>128</designated-port-priority> <port-cost>20000</port-cost> <port-state>DIS</port-state> <designated-bridge-mac junos:format="32768.54e032fdeb41"> 54e032fdeb41 </designated-bridge-mac> <designated-bridge-priority>32768</designated-bridge-priority> <port-role>DIS</port-role> </stp-interface-entry> <stp-interface-entry> <interface-name>xe-0/1/0.0</interface-name> <port-number junos:format="128:561"> 561 </port-number> <port-priority>128</port-priority> <designated-port-number junos:format="128:691"> 691 </designated-port-number> <designated-port-priority>128</designated-port-priority> <port-cost>2000</port-cost> <port-state>FWD</port-state> <designated-bridge-mac junos:format="32768.3c94d5902981"> 3c94d5902981 </designated-bridge-mac> <designated-bridge-priority>32768</designated-bridge-priority> <port-role>ROOT</port-role> </stp-interface-entry> <stp-interface-entry> <interface-name>xe-0/1/2.0</interface-name> <port-number junos:format="128:563"> 563 </port-number> <port-priority>128</port-priority> <designated-port-number junos:format="128:563"> 563 </designated-port-number> <designated-port-priority>128</designated-port-priority> <port-cost>2000</port-cost> <port-state>FWD</port-state> <designated-bridge-mac junos:format="32768.54e032fdeb41"> <designated-port-priority>128</designated-port-priority> <port-cost>20000</port-cost> <port-state>DIS</port-state> <designated-bridge-mac junos:format="32768.54e032fdeb41"> 54e032fdeb41 </designated-bridge-mac> <designated-bridge-priority>32768</designated-bridge-priority> <port-role>DIS</port-role> </stp-interface-entry> <stp-interface-entry> <interface-name>xe-0/1/0.0</interface-name> <port-number junos:format="128:561"> 561 </port-number> <port-priority>128</port-priority> <designated-port-number junos:format="128:691"> 691 </designated-port-number> <designated-port-priority>128</designated-port-priority> <port-cost>2000</port-cost> <port-state>FWD</port-state> <designated-bridge-mac junos:format="32768.3c94d5902981"> 3c94d5902981 </designated-bridge-mac> <designated-bridge-priority>32768</designated-bridge-priority> <port-role>ROOT</port-role> </stp-interface-entry> <stp-interface-entry> <interface-name>xe-0/1/2.0</interface-name> <port-number junos:format="128:563"> 563 </port-number> <port-priority>128</port-priority> <designated-port-number junos:format="128:563"> 563 </designated-port-number> <designated-port-priority>128</designated-port-priority> <port-cost>2000</port-cost> <port-state>FWD</port-state> <designated-bridge-mac junos:format="32768.54e032fdeb41"> 54e032fdeb41 </designated-bridge-mac> <designated-bridge-priority>32768</designated-bridge-priority> <port-role>DESG</port-role> </stp-interface-entry> </stp-interfaces> </stp-instance> </stp-interface-information> <cli> <banner>{master:0}</banner> </cli> </rpc-reply> {master:0} 

Here it is worth making a digression and tell about the approach used by PyEZ to extract configuration and operational (running state) information from devices. For this, the concepts of tables (Tables) and selections (Views) are introduced. If we draw an analogy with databases, then in Junos there is an “operational database”, which consists of a set of tables. For example, using the show route command, you can view the routing table, and using the show interfaces command, you can see the interface table. In turn, Views, i.e. sampling is a way of representing information from tables. For example, show route protocol ospf will show only routes received via OSPF, i.e. sampling from the entire routing table.

Yaml


Let's return to the received XML. We are interested in the <stp-interface-entry> elements and <interface-name>, <port-state> and <port-role> elements included in them. To access these elements, you need to define a table and a selection. This is done in a separate YAML file.

 --- STPInterfaces: rpc: get-stp-bridge-interface-information item: stp-instance/stp-interfaces/stp-interface-entry key: interface-name view: STPInterfacesView STPInterfacesView: fields: state: port-state role: port-role 


Go through the contents:

Finally, in STPInterfacesView, we define the fields of interest.

In my opinion, to correctly compile a YAML file is the most difficult in the entire described process. I highly recommend reading the XPath tutorial .

Python shell


Now let's see how this can be used in Python. Suppose the YAML file was saved as stp.yml.
 Python 2.7.6 (default, Mar 22 2014, 22:59:56) [GCC 4.8.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from jnpr.junos import Device >>> from jnpr.junos.factory import loadyaml >>> yml_file = "stp.yml" >>> globals().update(loadyaml(yml_file)) >>> dev = Device(host='1.2.3.4') >>> dev.open() Device(1.2.3.4) >>> tbl = STPInterfaces(dev) >>> tbl.get() STPInterfaces:1.2.3.4: 3 items >>> for key in tbl: ... print key.name, key.role, key.state ... ge-0/0/23.0 DIS DIS xe-0/1/0.0 ROOT FWD xe-0/1/2.0 DESG FWD >>> dev.close() >>> 

We get the same list of ports as in the CLI.

Useful links:


Source: https://habr.com/ru/post/261775/


All Articles