RESTCONF with Python
Installation
In this post, we went over a number of use cases. We used POSTMAN to understand the details. Here is the list of use cases for your convenience.
- Use Case 1: Retrieve information (IETF YANG model)
- Use Case 2: Adding Loopback interface (IETF YANG model)
- Use Case 3: Changing Loopback interface description (IETF YANG model)
- Use Case 4: Removing Loopback interface (IETF YANG model)
- Use Case 5: Retrieve information (Cisco YANG model)
- Use Case 6: Adding interface (Cisco YANG model)
- Use Case 7: Changing interface description (Cisco YANG model)
- Use Case 8: Removing interface description (Cisco YANG model)
In this post, we will just create a simple Python script for each of these use cases. It’s dead easy once you understand the REST API through POSTMAN. Mostly, whenever I come across a new REST API, I would experiment a bit with POSTMAN before I write Python scripts. This post will show you it’s very easy once you have gone through the POSTMAN examples.
Disclaimer: the code in this post is not production-grade code obviously. One should never store the username and password in the clear, not in the source code itself. The examples in the post are merely conceptual and for informational purposes.
Use Case 1: Retrieve information (IETF YANG model)
The URL to use is: https://{device['ip']}:{device['port']}/restconf/data/ietf-interfaces:interfaces
Once we have executed the call via Python requests (GET), we just loop over the list of interfaces and print out the name, description and IP address.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "ietf-interfaces:interfaces"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}"
requests.packages.urllib3.disable_warnings()
response = requests.get(url, headers=headers, auth=(device['username'], device['password']), verify=False).json()
interfaces = response['ietf-interfaces:interfaces']['interface']
for interface in interfaces:
if bool(interface['ietf-ip:ipv4']): //check if IP address is available
print(f"{interface['name']} -- {interface['description']} -- {interface['ietf-ip:ipv4']['address'][0]['ip']}")
Output is as follows:
(venv) WAUTERW-M-65P7:RestConf_Python wauterw$ python3 get_interfaces_ietf.py
https://ios-xe-mgmt-latest.cisco.com:9443/restconf/data/ietf-interfaces:interfaces
GigabitEthernet1 -- MANAGEMENT INTERFACE - DON'T TOUCH ME -- 10.10.20.48
GigabitEthernet2 -- Configured through NETCONF -- 10.255.255.1
GigabitEthernet3 -- Configured by RESTCONF -- 10.255.250.2
Code for this one can be found here. A similar example to retrieve the static routes on our IOSXE device can be found here.
Use Case 2: Adding Loopback interface (IETF YANG model)
Next, we’ll be adding an interface. Before we do so, let’s login to the device via SSH and list all interfaces. We use the following URL again https://{device['ip']}:{device['port']}/restconf/data/ietf-interfaces:interfaces
.
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
In terms of Python code, it’s pretty similar to the example above. In order to add an interface, we need to pass a JSON body. Take a look at the POSTMAN equivalent in the previous post, to understand what we need to pass in the body. Also, as we are creating an interface, we need to use the POST verb.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "ietf-interfaces:interfaces"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}"
payload = {
"interface": [
{
"name": "Loopback10000",
"description": "Adding loopback10000",
"type": "iana-if-type:softwareLoopback",
"enabled": "true",
"ietf-ip:ipv4": {
"address": [
{
"ip": "192.0.2.60",
"netmask": "255.255.255.255"
}
]
}
}
]
}
requests.packages.urllib3.disable_warnings()
response = requests.post(url, headers=headers, data=json.dumps(payload), auth=(device['username'], device['password']), verify=False)
if (response.status_code == 201):
print("Successfully added interface")
else:
print("Issue with adding interface")
Let’s check again through SSH to see if it worked:
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
Loopback10000 192.0.2.60 YES other up up
Code for this one can be found here
Use Case 3: Changing Loopback interface description (IETF YANG model)
Next, we will change the description of the interface. Before we do so, let’s see the current description of our loopback interface.
csr1000v-1#show interfaces description
Interface Status Protocol Description
Gi1 up up MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2 up up Configured through NETCONF
Gi3 admin down down Configured by RESTCONF
Lo10000 up up Adding loopback10000
In our Python script, we need to use the following URL https://{device['ip']}:{device['port']}/restconf/data/ietf-interfaces:interfaces/interface=Loopback10000
. As we are changing the description, we are using the put verb.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "ietf-interfaces:interfaces"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}/interface=Loopback10000"
payload = {
"interface": [
{
"name": "Loopback10000",
"description": "Adding loopback10000 - changed",
"type": "iana-if-type:softwareLoopback",
"enabled": "true",
"ietf-ip:ipv4": {
"address": [
{
"ip": "192.0.2.60",
"netmask": "255.255.255.255"
}
]
}
}
]
}
requests.packages.urllib3.disable_warnings()
response = requests.put(url, headers=headers, data=json.dumps(payload), auth=(device['username'], device['password']), verify=False)
if (response.status_code == 204):
print("Successfully updated interface")
else:
print("Issue with updating interface")
Let’s execute the code. You’ll notice our changes went through successfully.
csr1000v-1#show interfaces description
Interface Status Protocol Description
Gi1 up up MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2 up up Configured through NETCONF
Gi3 admin down down Configured by RESTCONF
Lo10000 up up Adding loopback10000 - changed
Code for this one can be found here
Use Case 4: Removing Loopback interface (IETF YANG model)
Lastly, let’s remove our interface. As a reminder, this is the current list of interfaces.
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
Loopback10000 192.0.2.60 YES other up up
In the Python script, we use the delete verb against the URL https://{device['ip']}:{device['port']}/restconf/data/ietf-interfaces:interfaces/interface=Loopback10000
.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "ietf-interfaces:interfaces"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}/interface=Loopback10000"
print(url)
requests.packages.urllib3.disable_warnings()
response = requests.delete(url, headers=headers, auth=(device['username'], device['password']), verify=False)
print(response)
if (response.status_code == 204):
print("Successfully deleted interface")
else:
print("Issue with deleting interface")
And as we can expect, the interface is gone now.
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
Code for this one can be found here
Use Case 5: Retrieve information (Cisco YANG model)
What follows is merely the same as what we did already. Instead of using the IETF models, we will be using the Cisco specific YANG models. You’ll notice the scripts are exactly the same.
Here is the Python script to retrieve a list of all interfaces.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "Cisco-IOS-XE-native:native/interface"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}"
print(url)
requests.packages.urllib3.disable_warnings()
response = requests.get(url, headers=headers, auth=(device['username'], device['password']), verify=False).json()
#pprint(response)
interfaces = response['Cisco-IOS-XE-native:interface']['GigabitEthernet']
for interface in interfaces:
print(f"{interface['name']} -- {interface['description']}")
This results in the following output:
(venv) WAUTERW-M-65P7:RestConf_Python wauterw$ python3 get_interfaces_cisco.py
https://ios-xe-mgmt-latest.cisco.com:9443/restconf/data/Cisco-IOS-XE-native:native/interface
1 -- MANAGEMENT INTERFACE - DON'T TOUCH ME
2 -- Configured through NETCONF
3 -- Configured by RESTCONF
Code for this one can be found here
Use Case 6: Adding interface (Cisco YANG model)
Let’s also add an interface. Current interfaces are:
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
The Python script is exactly the same as use case 2. Do note, we are using a different JSON body (go and look to the corresponding POSTMAN use case in the previous post).
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "Cisco-IOS-XE-native:native/interface"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}"
payload = {
"Cisco-IOS-XE-native:BDI":
{
"name": "60",
"description": "Set via RestCONF Python",
}
}
requests.packages.urllib3.disable_warnings()
response = requests.post(url, headers=headers, data=json.dumps(payload), auth=(device['username'], device['password']), verify=False)
if (response.status_code == 201):
print("Successfully added interface")
else:
print("Issue with adding interface")
Here’s the corresponding output:
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
BDI60 unassigned YES unset down do
Code for this one can be found here
Use Case 7: Changing interface description (Cisco YANG model)
In this once, we’ll change the description of our newly added interface. The current list of interfaces is:
csr1000v-1#show interfaces description
Interface Status Protocol Description
Gi1 up up MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2 up up Configured through NETCONF
Gi3 admin down down Configured by RESTCONF
BD60 down down Set via RestCONF Python
Python code is similar to use case 3 above. Again, note we are using the following URL: https://{device['ip']}:{device['port']}/restconf/data/Cisco-IOS-XE-native:native/interface/BDI=60
.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "Cisco-IOS-XE-native:native/interface"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}/BDI=60"
payload = {
"Cisco-IOS-XE-native:BDI":
{
"name": "60",
"description": "Set via RestCONF Python - changed",
}
}
requests.packages.urllib3.disable_warnings()
response = requests.put(url, headers=headers, data=json.dumps(payload), auth=(device['username'], device['password']), verify=False)
if (response.status_code == 204):
print("Successfully updated interface")
else:
print("Issue with updating interface")
Let’s check if the changes went through successfully. Yes it worked!
csr1000v-1#show interfaces description
Interface Status Protocol Description
Gi1 up up MANAGEMENT INTERFACE - DON'T TOUCH ME
Gi2 up up Configured through NETCONF
Gi3 admin down down Configured by RESTCONF
BD60 down down Set via RestCONF Python - changed
Code for this one can be found here
Use Case 8: Remove interface description (Cisco YANG model)
Lastly, let’s remove the interface. We’ll verify the current list of interfaces.
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
BDI60 unassigned YES unset down down
In the Python script, we will have to use the delete verb again against the real interface.
import requests
import json
from pprint import pprint
device = {
"ip": "ios-xe-mgmt-latest.cisco.com",
"username": "***",
"password": "***",
"port": "9443",
}
headers = {
"Accept" : "application/yang-data+json",
"Content-Type" : "application/yang-data+json",
}
module = "Cisco-IOS-XE-native:native/interface"
url = f"https://{device['ip']}:{device['port']}/restconf/data/{module}/BDI=60"
requests.packages.urllib3.disable_warnings()
response = requests.delete(url, headers=headers, auth=(device['username'], device['password']), verify=False)
if (response.status_code == 204):
print("Successfully deleted interface")
else:
print("Issue with deleting interface")
When you execute above script, you’ll see the interface has been removed.
csr1000v-1#show ip interface brief
Interface IP-Address OK? Method Status Protocol
GigabitEthernet1 10.10.20.48 YES other up up
GigabitEthernet2 10.255.255.2 YES other up up
GigabitEthernet3 10.255.250.2 YES manual administratively down down
Code for this one can be found here
That’s it. A post with quite some redundancy as it’s mostly more of the same. Yet I wanted to provide a complete overview of the CRUD operations against a RESTCONF API.
All code can be found on Github.