[PYTHON] I tried to operate from Postman using Cisco Guest Shell as an API server

Introduction

Cisco Guest Shell is a Linux-based container environment that is separate from the host device (IOS-XE) and can automatically control IOS-XE settings using Python or the like. This time, I built an API server on Guest Shell using the Python web framework "Flask", got the show command result from Postman, and changed the interface settings.

CSR1000V setup

IOS-XE A virtual interface VirtualPortGroup0 (192.168.30.1) is created on the IOS-XE side and associated with the Guest Shell address (192.168.30.2) to enable external access to the Guest Shell. I will omit it because it depends on the environment, but for Internet access, I also set PAT to convert the Guest Shell address to the Gigabit Ethernet1 address.

Config Config



Router(config)#iox

Router(config)#ip http server

Router(config)#interface GigabitEthernet1
Router(config-if)# ip address 192.168.100.196 255.255.255.0
Router(config-if)# exit

Router(config)#interface VirtualPortGroup0
Router(config-if)# ip address 192.168.30.1 255.255.255.0
Router(config-if)# exit

Router(config)#app-hosting appid guestshell
Router(config-app-hosting)# app-vnic gateway0 virtualportgroup 0 guest-interface 0
Router(config-app-hosting-gateway0)# guest-ipaddress 192.168.30.2 netmask 255.255.255.0
Router(config-app-hosting-gateway0)# app-default-gateway 192.168.30.1 guest-interface 0
Router(config-app-hosting)# name-server0 192.168.100.1
Router(config-app-hosting)# end

Router#guestshell enable

Confirmation command


Router#show iox-service

IOx Infrastructure Summary:
---------------------------
IOx service (CAF) 1.10.0.1 : Running
IOx service (HA)          : Not Supported
IOx service (IOxman)      : Running
IOx service (Sec storage) : Not Supported
Libvirtd   1.3.4          : Running

Router#show app-hosting list
App id                                   State
---------------------------------------------------------
guestshell                               RUNNING

Guest Shell Use the default settings as they are.

Router#guestshell
[guestshell@guestshell ~]$ sudo ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.30.2  netmask 255.255.255.0  broadcast 192.168.30.255
(abridgement)

[guestshell@guestshell ~]$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
0.0.0.0         192.168.30.1    0.0.0.0         UG        0 0          0 eth0
192.168.30.0    0.0.0.0         255.255.255.0   U         0 0          0 eth0

Python package installation

I used the pre-installed Python 2.7.5 to install Flask and the show command parser template ntc_templates.

[guestshell@guestshell ~]$ python -V
Python 2.7.5
[guestshell@guestshell ~]$ pip -V
pip 20.2.3 from /usr/lib/python2.7/site-packages/pip (python 2.7)
[guestshell@guestshell ~]$ pip install flask
[guestshell@guestshell ~]$ pip install ntc_templates

Get show command results with HTTP GET

Python code

I created api.py directly under the home directory of Guest Shell.

[guestshell@guestshell ~]$ pwd
/home/guestshell
[guestshell@guestshell ~]$ touch api.py

The general flow of processing is as follows.

--The execution trigger is HTTP GET from the API client to the URI http: // <Guest Shell IP address> / show / <command name connected with _> --Execute the function getCommand () --Convert'_'at the end of URI to''(space) and generate show command --Run the show command on the pre-installed Cisco CLI Python module --Parse the output result with NTC-templates / TextFSM and return it as JSON --If it fails in the middle, an error message is returned in JSON

Also, in order to access from the outside, host = '0.0.0.0' is specified as an argument of ʻapp.run ()`.

api.py


from flask import Flask, jsonify, request
from cli import configurep, cli
from ntc_templates.parse import parse_output

app = Flask(__name__)

@app.route("/show/<command>", methods=["GET"])
def getCommand(command):
    cmd = "show " + command.replace("_", " ")
    try:
        sh_output = cli(cmd)
        sh_output_parsed = parse_output(platform="cisco_ios", command=cmd, data=sh_output)
        return jsonify(sh_output_parsed)
    except:
        return jsonify([{"result": "Fail to parse the output"}])

if __name__ == '__main__':
    app.run(debug=False, host='0.0.0.0', port=8080)

Python execution / API server start

[guestshell@guestshell ~]$ python api.py
 * Serving Flask app "api" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)

HTTP GET from Postman

Here is an example of getting the result of the show command show ip interface brief from Postman. Enter the URI as follows in GET. Although it is abbreviated as ʻip_int_brief` at the end, it can be parsed without any problem if it is an abbreviation allowed by NTC-templates. 0927_01.png

Change interface settings with HTTP POST

Python code

I added the code to the above api.py. The general flow of processing is as follows.

--The execution is triggered by HTTP POST from the API client to the URI http: // <Guest Shell IP address> / set / interface. Describe the interface setting parameters in JSON format in Body. --Execute the function setInterface () --Generate CLI command according to setting parameters --Change settings and save settings with Cisco CLI Python module --If successful, return a Success message in JSON

After editing, execute Python / start the API server again.

api.py(Additions)


@app.route("/set/interface", methods=["POST"])
def setInterface():
    interface_cmd = "interface " + request.json['interface']

    if 'state' in request.json:
        if request.json['state'] == "enabled":
            state_cmd = "no shutdown"
        elif request.json['state']  == "disabled":
            state_cmd = "shutdown"
    else:
            state_cmd = ""

    if 'description' in request.json:
        description_cmd = "description " + request.json['description']
    else:
        description_cmd = ""

    if 'address' in request.json:
        address_cmd = "ip address " + request.json['address'] + " " + request.json['netmask']
    else:
        address_cmd = ""

    configurep([interface_cmd, state_cmd, description_cmd, address_cmd, "end"])
    cli("write")

    return jsonify([{"result": "Success"}])

HTTP POST from Postman

This is an example of setting GigabitEthernet2 Description, IP address, and opening a port from Postman.

Enter the URI as shown below in POST, and specify Content-Type in ʻapplication / json` in Header. 0927_02.png

Describe the setting parameters in Body. Of the following, the interface name ʻinterface is required, but the other open / closed state, Description description, and IP address ʻaddress / netmask are optional. 0927_03.png

Click the Send button, and if successful, the following message will be displayed. 0927_04.png

You can also check the setting status from the terminal screen while api.py is running.

192.168.100.100 - - [27/Sep/2020 05:59:20] "POST /set/interface HTTP/1.1" 200 -
Line 1 SUCCESS: interface GigabitEthernet2
Line 2 SUCCESS: no shutdown
Line 3 SUCCESS: description TEST
Line 4 SUCCESS: ip address 10.1.1.1 255.255.255.0
Line 5 SUCCESS: end

Settings were changed and saved on the IOS-XE side without any problems.

Router#sh conf | begin interface GigabitEthernet2
interface GigabitEthernet2
 description TEST
 ip address 10.1.1.1 255.255.255.0
 negotiation auto
 no mop enabled
 no mop sysid

Finally

As a simple example, I was able to successfully build an API server with Guest Shell. However, Guest Shell can execute show commands / change settings of devices without authentication, so there may be issues from the viewpoint of security and trail management. Also, for this application, it may be better to control with Off-Box using an external tool like Ansible instead of On-Box format like Guest Shell.

Recommended Posts

I tried to operate from Postman using Cisco Guest Shell as an API server
I tried to get data from AS / 400 quickly using pypyodbc
I tried to get data from AS / 400 quickly using pypyodbc Preparation 1
I tried using UnityCloudBuild API from Python
I want to operate DB using Django's ORM from an external application
I tried to get an AMI using AWS Lambda
I tried to become an Ann Man using OpenCV
I tried to create API list.csv in Python from swagger.yaml
I tried to search videos using Youtube Data API (beginner)
I tried to get various information from the codeforces API
I tried to output the access log to the server using Node.js
I tried to create Quip API
I tried to analyze my favorite singer (SHISHAMO) using Spotify API
I tried to touch Tesla's API
I tried sending an email from the Sakura server with flask-mail
[Python] I tried to get various information using YouTube Data API!
I tried using the checkio API
I tried to execute SQL from the local environment using Looker SDK
I tried to extract characters from subtitles (OpenCV: Google Cloud Vision API)
[Python] [Excel] Operate an Excel sheet from Python using openpyxl (using a test sheet as an example)
I tried to summarize various sentences using the automatic summarization API "summpy"
I tried to make PyTorch model API in Azure environment using TorchServe
I tried using Azure Speech to Text.
I tried using Twitter api and Line api
I tried using YOUTUBE Data API V3
I tried to classify text using TensorFlow
I tried using Selective search as R-CNN
I tried to touch the COTOHA API
I tried to make a Web API
I tried using Headless Chrome from Selenium
I tried using the BigQuery Storage API
I tried to predict Covid-19 using Darts
I tried to understand the support vector machine carefully (Part 1: I tried the polynomial / RBF kernel using MakeMoons as an example).
I tried to explain multiple regression analysis as easily as possible using concrete examples.
I tried to extract a line art from an image with Deep Learning
[Python] I tried to get the type name as a string from the type function
I tried to create an environment to check regularly using Selenium with AWS Fargate
I tried to execute Python code from .Net using Pythonnet (Hallo World edition)
I tried using Remote API on GAE / J
I tried hitting the Qiita API from go
I tried to get an image by scraping
I want to email from Gmail using Python.
I tried using the Google Cloud Vision API
I tried to touch the API of ebay
Try to create an HTTP server using Node.js
I tried using firebase for Django's cache server
I tried to operate Linux with Discord Bot
I tried to make a ○ ✕ game using TensorFlow
I tried to notify the update of "Become a novelist" using "IFTTT" and "Become a novelist API"
I tried to score the syntax that was too humorous and humorous using the COTOHA API.
[Pokemon Sword Shield] I tried to visualize the judgment basis of deep learning using the three family classification as an example.
I tried to detect the iris from the camera image
Push notifications from Python to Android using Google's API
I tried to implement an artificial perceptron with python
I tried to approximate the sin function using chainer
I tried APN (remote notification) using Parse.com REST API
I tried to uncover our darkness with Chatwork API
I tried using the API of the salmon data project
[Python] I tried running a local server using flask
I tried using PySpark from Jupyter 4.x on EMR
I tried reading data from a file using Node.js.