Table of Contents

In this section, we will write python scripts that use the restconf protocol to connect to Cisco NSO and manage network devices.

Cisco NSO restconf Examples with Python

From the beginning of the course we used CLI, GUI and Python maagic library to connect to Cisco NSO and manage network devices.

restconf as cisco NSO northbound API
restconf as cisco NSO northbound API

In the previous section, we started using the latest method, the restocnf protocol, to connect to Cisco NSO using the software “postman” and Cisco NSO postman collection.

In this section, we continue to use the restconf protocol as the northbound connection method, but via python scripts.

get NSO restconf python code from postman

The easiest way to prepare the first release of restconf python scripts is to use the postman software to extract the equivalent python code for each existing restconf API samples.

In the last section, we discussed how to extract python code or code with any other programming language from postman software.

get python code from postman restconf api
get python code from postman restconf api

get list of interfaces via Cisco NSO restconf

For our first example, we get the list of interfaces from router R1 in Cisco NSO. However, we will use the exact python script generated in the postman software without any modifications.

import requests

url = "http://192.168.2.101:8080/restconf/data/tailf-ncs:devices/device=R1/config/tailf-ned-cisco-ios:interface/"

payload = {}
headers = {
  'Accept': 'application/yang-data+json',
  'Authorization': 'Basic YWRtaW46YWRtaW4='
}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)

It uses python library “requests” to connect to cisco nso through http protocol.

It uses IP address “192.168.2.101” and port “8080” to connect to Cisco NSO. Then “/restconf/data/“ is always fixed.

How do I extract the remaining part of the configuration? We’ve discussed many times how to get it via the “display xpath” option in cisco nso.

We use the “requests.request” method to send the HTTPGET” command to the specified URL to Cisco NSO.

The parameter “payload” is empty, since we get information and do not send any payload.

The data encoding format accepted by the script and the authentication information are specified in the header field.

Let’s run the script and see the result.

{
  "tailf-ned-cisco-ios:interface": {
    "Loopback": [
      {
        "name": "100",
        "ip": {
          "address": {
            "primary": {
              "address": "4.5.6.7",
              "mask": "255.255.255.0"
            }
          }
        }
      },
...
    ],
    "GigabitEthernet": [
      {
        "name": "1",
        "negotiation": {
          "auto": true
        },
        "mop": {
          "xenabled": false,
          "sysid": false
        },
        "ip": {
          "address": {
            "primary": {
              "address": "192.168.2.91",
              "mask": "255.255.255.0"
            }
          }
        }
      },
...
    ]
  }
}

As we expect, the list of interfaces and their IP address will be displayed in the output.

But now we modify the first script in order to parameterize the script, which makes it easier to read, debug, and reuse.

import requests

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/config/tailf-ned-cisco-ios:interface/"

payload = {}
headers = {
  'Accept': 'application/yang-data+json',
}

response = requests.request("GET", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

Then I use four variables: “HOST”, “PORT”, “USER” and “PASSWORD” which can easily be changed depending on the environment in which you want to run the script.

It is also possible to keep and secure these variable out of the script, which is out of scope of this course but is already discussed in the course CLI-based network automation.

In the URL, HOST and PORT variable are used in the middle of string with the help of “F-String”.

F-strings in python provide a way to embed expressions inside string values.

The other change is that authentication information, including username and password, is added in the HTTP request command using the “auth” header field.

If you run the script, you will receive the same result as the previous script that we have extracted from postman software.

All of the other scripts discussing in this section are also taken from the postman software and I’ve only parameterized them to make it easier for you to understand and reuse it.

Cisco NSO restconf Example2: add a new loopback interface

The second script is used to add a new loopback interface in the router R1.

Compared to the previous script, the first difference is using “POST” command instead of “GET” command since we are adding a configuration to the router.

import requests
import json

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/config/tailf-ned-cisco-ios:interface/"

payload = json.dumps({
  "Loopback": [
    {
      "name": "300",
      "ip": {
        "address": {
          "primary": {
            "address": "4.5.16.17",
            "mask": "255.255.255.255"
          }
        }
      }
    }
  ]
})
headers = {
  'Accept': 'application/yang-data+json',
  'Content-Type': 'application/yang-data+json'
}

response = requests.request("POST", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

The payload is no longer empty because we need to send the new configuration to the router.

It is in JSON format. Therefore, a new header field, “Content-Type“, specifies the format of the payload sent via the POST command.

How do we prepare the payload? It is easy. In the previous script, we got the list of interfaces in JSON format. I just copied an loopback interface JSON output and changed the name and IP address.

The payload is converted to a correct JSON file using “json.dumps” method. This method is used to convert Python objects such as a dictionary, list, string, integer, float, boolean, and None to JSON string objects.

Now we run the script to make sure that new loopback interface is added in router R1.

Before that you can check router R1 to delete interface loopback 300 if already exist.

majid@majid-ubuntu:~/devnet/cisco_nso/13.restconf$ python3 13.2.restconf_add_loopback_interface.py
R1#show ip int brief
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       192.168.2.91    YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback100            4.5.6.7         YES NVRAM  up                    up
Loopback150            1.1.1.1         YES NVRAM  up                    up
Loopback300            4.5.16.17       YES manual up                    up
R1#

Cisco NSO restconf Example 3: delete loopback interface

In the third script, we delete the new loopback interface created in the previous script.

import requests
import json

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/config/tailf-ned-cisco-ios:interface/Loopback=300"

payload={}
headers = {
  'Content-Type': 'application/yang-data+json',
  'Accept': 'application/yang-data+json',
}

response = requests.request("DELETE", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

The URL is as the previous script. Just we add “Loopback=300”, in order to delete interface loopback 300.

The only other difference is using HTTPDELETE” command instead of “GET” or “POST” commands.

Payload is also empty, since we do not send any content to the network device.

Now let’s run the script to make sure that interface loopback 300 is deleted from the router.

majid@majid-ubuntu:~/devnet/cisco_nso/13.restconf$ python3 13.3.restconf_delete_loopback_interface.py
R1#show ip int brief
Interface              IP-Address      OK? Method Status                Protocol
GigabitEthernet1       192.168.2.91    YES NVRAM  up                    up
GigabitEthernet2       unassigned      YES NVRAM  administratively down down
GigabitEthernet3       unassigned      YES NVRAM  administratively down down
Loopback100            4.5.6.7         YES NVRAM  up                    up
Loopback150            1.1.1.1         YES NVRAM  up                    up

get live-status output from network devices

In the next three script we receive operational output fro network devices using cisco nso “live-status” feature.

import requests
import json

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/live-status"

payload={}
headers = {
  'Content-Type': 'application/yang-data+json',
  'Accept': 'application/yang-data+json',
}

response = requests.request("GET", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

I got the URL from postman software. But it is easy. Just adding “live-status” keyword at the end of URL after choosing interesting device.

HTTP “GET” command is used to get the operational output.

If we run the script, In the output you see the operational status and statistics including interfaces counters, ARP information, interface names, IP addresses and MAC addresses and device and software model, version and licensing information.

{
  "tailf-ncs:live-status": {
    "ietf-interfaces:interfaces-state": {
... // interface counters
    },
    "tailf-ned-cisco-ios-stats:arp": {
... // arp information
    },
    "tailf-ned-cisco-ios-stats:interfaces": 
...	 // interface name, IP address and MAC address
    "tailf-ned-cisco-ios-stats:inventory": 
...
    "tailf-ned-cisco-ios-stats:running-config": {
      "license": {
        "udi": {
          "pid": "CSR1000V",
          "sn": "97G01N142F8"
        }
      }
    },
    "tailf-ned-cisco-ios-stats:version": {
      "name": "ios",
      "version": "17.01.01",
      "model": "CSR1000V",
      "serial-number": "97G01N142F8",
      "license": {
        "level": "ax",
        "type": "N/A(Smart"
      }
    },
...
  }
}

get arp information from live-status feature

The next script is exactly the same as “live-status” script, but the output is limited to only arp information from live status feature. This is done with adding “tailf-ned-cisco-ios-stats:arp” at the end of URL after “live-status” keyword.

import requests
import json

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/live-status/tailf-ned-cisco-ios-stats:arp"

payload={}
headers = {
  'Content-Type': 'application/yang-data+json',
  'Accept': 'application/yang-data+json',
}

response = requests.request("GET", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

Let’s run the script and see the ARP information stored in router R1.

{
  "tailf-ned-cisco-ios-stats:arp": {
    "address": [
      {
        "ip": "192.168.2.1",
        "protocol": "Internet",
        "age-mins": 0,
        "hardware-addr": "f086.2099.a458",
        "type": "ARPA",
        "interface": "GigabitEthernet1"
      },
...
      {
        "ip": "192.168.2.91",
        "protocol": "Internet",
        "hardware-addr": "000c.29e8.3ce3",
        "type": "ARPA",
        "interface": "GigabitEthernet1"
      }
    ]
  }
}

send an exec command through live-status

In the last script, we send an exec command to network device to be executed.

import requests
import json

HOST = "192.168.2.101"
PORT = "8080"
USER = "admin"
PASSWORD = "admin"

url = f"http://{HOST}:{PORT}/restconf/data/tailf-ncs:devices/device=R1/live-status/tailf-ned-cisco-ios-stats:exec/any"

payload = json.dumps({
  "input": {
    "args": "show ip interface brief"
  }
})
headers = {
  'Accept': 'application/yang-data+json',
  'Content-Type': 'application/yang-data+json',
}

response = requests.request("POST", url, headers=headers, auth=(USER, PASSWORD), data=payload)

print(response.text)

The result is not JSON structured and you will get the result exactly when you enter the command directly from the CLI.

To send an exec command in iOS devices, we specify the keyword “tailf-ned-cisco-ios-stats:exec/any” at the end of the URL and after “live-status” keyword and the command itself must be passed as a payload and via an argument to the input variable.

For sending exec command we also need to use POST command in HTTP request.

Let’s run command and see the result.

majid@majid-ubuntu:~/devnet/cisco_nso/13.restconf$ python3 13.6.restconf_live_status_send_any_exec_command.py
{
  "tailf-ned-cisco-ios-stats:output": {
    "result": "\r\nInterface              IP-Address      OK? Method Status                Protocol\r\nGigabitEthernet1       192.168.2.91    YES NVRAM  up                    up      \r\nGigabitEthernet2       unassigned      YES NVRAM  administratively down down    \r\nGigabitEthernet3       unassigned      YES NVRAM  administratively down down    \r\nLoopback100            4.5.6.7         YES NVRAM  up                    up      \r\nLoopback150            1.1.1.1         YES NVRAM  up                    up      \r\nR1#"
  }
}
Back to: Network Automation and Service Orchestration using Cisco NSO > managen NSO via RESTCONF

Leave a Reply

Your email address will not be published. Required fields are marked *


Post comment