NETCONF 103: Porting Your Scripts to NETCONF

In this Learning Lab you will learn the basics of how to use NETCONF to call Network APIs in Python along with the advantages it offers over scripts performing legacy screen scraping.

Objective

Completion Time: 25 minutes

  • Understand the use and application of screen scraping
  • Run and understand a NETCONF script that performs the same operation
  • Understand the advantages that NETCONF offers over screen scraping

Prerequisites

You will want to make sure you have gone through the Coding 101 lab if you are unfamiliar with retrieving results from a RESTful service. Although this lab will not use a REST API, there are similar concepts that will be useful from this previous lab.

You will also want to make sure you have gone through the NETCONF 101 lab and the NETCONF 102: Generate NETCONF API Calls with Python if you are unfamiliar with the NETCONF protocol.

In this lab, we are going to use Putty or an equivalent Terminal emulator and a simple Python script to connect to a device's NETCONF subsystem.

Also, this lab includes steps in the How to Setup Your Computer section to setup your development environment if needed.

Background

Access to a Device that Supports a NETCONF API

  • If you are working from your own machine, this lab shall shall use CSR1000V running in the Device Programmability Always On Sandbox.

Python

  • To run the code samples, you need to have Python2 installed on your machine.

Virtual Environments

  • This lab uses a venv to run ncclient is 0.5 and avoid issues with existing Python environments.
  • Reference the section How to Set up Your Computer above to learn how to complete this step.

Development Libraries

  • If you are running on a Ubuntu based systems, we'll need the development version of Python, libxml2, and libxslt as well as a few others.
  • Reference the section How to Set up Your Computer above to learn how to complete this step.

NCClient Library

  • These codes samples use the NCClient to simplify making NETCONF API calls.
  • Note that currently, the most recent version of ncclient is 0.4.7. The latest development release in GitHub (0.5.0 at the time this lab was written) has support for Python3 as well as some useful classes that future learning labs shall leverage. The steps below show how to install this version.
  • Reference the section How to Set up Your Computer above to learn how to install the NETCONF Library on your own machine.

Clone Git Repo

  • Clone the NETCONF example code
    • This GitHub repository provides sample code that you can run for this learning lab
  • If you are working from your own computer, clone the git repository.
  • Reference the section How to Set up Your Computer above to see the steps required.

Step 1. Understanding Screen Scraping Scripts

Let's assume that you need to write a script that gets basic information about network interfaces along with their status. This basic network information should be displayed on screen. The status of each interface should be reviewed, and finally, the overall status of all interfaces whether up or down should be displayed.

Below we've created a simple Python script that a network engineer might write to complete this task. Python is a common language utilized by network engineers. The Python script below parses through the output of Command Line Interface (CLI) command 'show ip int brief' which as been saved to text file to get the interface data. This data is then parsed and processed for review.

from interfaces import Interface
import re
import sys


def main():
    """
    Open a file called show_ip_int_brie.txt.

    Parse through interface data and create an Interface object for each one found.
    """
    interfaces = []
    INTERFACE_REGEX = '^(FastEthernet|GigabitEthernet)([0-9]+) .*(up|down)'
    # open the file called 'show_ip_int_brief.txt'
    with open('show_ip_int_brief.txt', 'r') as interface_info:
        for line in interface_info:
            # Iterate over each line and match against the string INTERFACE_REGEX
            m = re.match(INTERFACE_REGEX, line)
            if m is not None:
                # When the line matches the REGEX, create an Interface() object
                interface = Interface(m.group(1) + m.group(2), m.group(3))
                # Append the interface to the list, so we can iterate over it
                interfaces.append(interface)

    # for each interface print the name and status
    for interface in interfaces:
        interface.prints()

    # call the check_down() function to print any interfaces in the down state with a warning
    for interface in interfaces:
        interface.check_down()

if __name__ == '__main__':
    sys.exit(main())

In the script above, notice that we have created a custom module called interfaces.py which provides a class called Interface(). This class some simple methods we can re-use when parsing the interface operational data.

class Interface(object):
    """Basic Interface object to store information."""
    def __init__(self, name, status):
        """
        Constructor for basic interface class.

        Parameters: name of interface and interface status.
        """
        # Instantiate an interface with the name and status
        self.name = name
        self.status = status

    def check_down(self):
        """Basic check if interface is down and if so print a warning."""
        if self.status == 'down':
            print('#############################################')
            print("Warning! Interface: {int_name} is DOWN!".format(int_name=self.name))
            print('#############################################')

    def prints(self):
        """Basic method to print self."""
        print("Interface: {int_name}         Status: {int_status}".format(int_name=self.name,
                                                                          int_status=self.status))

Let's look at what the code is doing.

  • First, the Interfaces() class shown above allows us to create an object for each instance of an interface. To instantiate an interface, we need to have the interface name and the link status.
  • In this class, we also have a class method called prints() to print the interface name and state. We also have a method called check_down() to check if the interface is down.
  • Next going back to the main script, we create a main() method. Here, we open a file that contains the output of 'show ip int brief.'' A regular expression is written to capture the data we require.
    • The returned data is parsed via regular expression and captured by encasing the data to be evaluated in parenthesis which is then used to create instance of an Interface().
    • Note that we would need to create some logic to create this file to begin with. For example, we could use Paramiko to generate an SSH session to issue the command.
    • For simplicity, this logic has been omitted.
  • Next, we iterate through the list of interfaces to print out the names and status of each interface captured.
  • Finally, the status of interfaces is checked using the check_down() method.

Resulting output

Let's see the output from running this script on the file in question. Notice that in our example GigabitEthernet2 and GigabitEthernet3 are down, so we see a warning based on the interface state!

ubuntu$ python screen_scrape_interfaces.py
Interface: GigabitEthernet1   Status: up
Interface: GigabitEthernet2   Status: down
Interface: GigabitEthernet3   Status: down
#############################################
Warning! Interface: GigabitEthernet2 is DOWN!
#############################################
#############################################
Warning! Interface: GigabitEthernet3 is DOWN!
#############################################

Things to Think About

  1. What if we wanted to extend the script's functionality?

    • Suppose we wanted to also have the IP address of the interface as an object variable. What would we need to change?
      • For this script, we would have to consider changing the REGEX and retesting to ensure we could "scrape" the IP address from the command output.
      • This could be troublesome since we may need to test against the output from multiple devices.
  2. What if we have to upgrade code on the device?

    • If we upgrade code on the device, can we ensure that our script still functions correctly?
    • What if the CLI changes from version to version?

Next we'll learn how to complete this operation using NETCONF