Creating a Cisco SDWAN Chatbot with Azure App Services + Python

In a previous blog-post I confessed my affinity for ‘ChatOps’, and how instant messaging clients can be used to help network operations teams (using a framework like stackstorm and ‘event’ driven automation).

I wanted to explore this idea a bit more with another post. However, this time focusing on how the network administrator might actively request data as opposed to its being posted based on a failure event/trigger generated by something like a syslog or other telemetry data.

I decided to prototype a quick Cisco SDWAN chatbot. In the high majority of cases, the Cisco SDWAN vManage controller is an internet-facing device, making it the perfect fit for a use-case such as this. With other ‘on-prem’ SDN controllers there might be a bit more work required, such as VPN’s back to on-prem infrastructure (depending on where the bot is hosted) but nothing out of the reach of possibility.

Below highlights a quick overview of the prototype solution workflow.

  1. A request is made in the WebexTeams Client
  2. The webex service makes a HTTP callback to out bot-endpoint (Hosted in Azure)
  3. Out bot looks and parses the request and makes a request to the vManage controller for whatever data was requested.
  4. Our bot posts the data back to the originating room within webex teams

I already had a pre-existing bot in my Webex teams channel from my previous blog post, I just needed to request the access token again. Creating a bot is a really simple and well-documented process over at https://developer.webex.com

The webhook is essentially a HTTP request that is specified to trigger upon certain conditions. The creation of the webhook is typically done through the API, however, to save writing code it’s quick to do this via the Webex teams API explorer and fill in the variables We want the HTTP callback to trigger when ‘messages’ are ‘created’, messages being the resource and created being the event. The target URL is where our SDWAN chatbot will be hosted.

The actual bot endpoint will be hosted in the Microsoft Azure App Services PaaS platform. As Azure is the cloud platform I am most familiar with I chose this by default, but as long as the bot has access to/from the general internet then it shouldn’t be an issue.

I am linking the App Service into my GitHub as the deployment option – so whenever I commit changes to the repo the deployment happens automagically! Pretty cool!? can anyone say CI/CD ?

The runtime stack has been chosen as Python 3.8 as that is what our bot is written in, but again it could be whatever language you are familiar with.

The actual bot code is below. I am leveraging the Flask framework – but the concepts still apply with whatever python Web Framework you are using (Flask, Django, FastAPI) – This code is NOT production-grade, please do not bake credentials into your production code, this is just for demo purposes.

from flask import Flask, request
import requests
from webexteamssdk import WebexTeamsAPI, Webhook
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


username = 'devnetuser'
password = 'RG!_Yw919_83'
vManage = 'sandbox-sdwan-1.cisco.com'
authurl = 'https://{}/j_security_check'.format(vManage)
authbody = {'j_username': f'{username}', 'j_password': f'{password}'}
url = f'https://{vManage}/dataservice/'
token_url = url + 'client/token'

app = Flask(__name__)
api = WebexTeamsAPI()


@app.route('/events', methods=['GET', 'POST'])
def webex_teams_webhook_events():
    if request.method == 'GET':
        return ("""
                   <html>
                       <head>
                           <title>SDWAN Chatbot!</title>
                       </head>
                   <body>
                   <p>
                   <h1>SDWAN Chatbot</h1>
                   <h2>The App is running!</h2> 
                   </p>
                   </body>
                   </html>
                """)

    elif request.method == 'POST':
        json_data = request.json
        print('\n webhook data \n')
        print(json_data)

        webhook_data = Webhook(json_data)
        room = api.rooms.get(webhook_data.data.roomId)
        message = api.messages.get(webhook_data.data.id)


        bot = api.people.me()

        if message.personId == bot.id:
            return 'OK'

        else:
            if "sdwan controller status" in message.text:
                viptela = requests.session()
                viptela.post(url=authurl, data=authbody, verify=False)
                login_token = viptela.get(url=token_url, verify=False)
                viptela.headers['X-XSRF-TOKEN'] = login_token.content
                getStatus = viptela.get(
                    url=f"https://{vManage}:443/dataservice/device/monitor", verify=False).json()

                deviceStatus = []
                for device in getStatus['data']:
                    deviceStatus.append(
                        device['host-name']+f' Status: {device["status"]}')
                api.messages.create(room.id, text=str(deviceStatus))
            return 'OK'


if __name__ == '__main__':
    app.run()

I am also using the Cisco SDWAN sandbox as the vManage endpoint, one shortcoming of this is that there are no cEdge/vEdge devices associated with this controller. So I was limited with what data I could pull back, I was limited to the actual controllers themselves.

Without doing a line by line rundown of the code, what we are essentially looking for is the string ‘sdwan controller status’ in the message that was sent to the bot in our webhook. If we see this string then we perform an API call to vManage requesting the status of the controllers and then we post it back into the originating room.

To abstract alot of the functionality, we are using the webexteams SDK Webhook class. One thing to be mindful of is that the Webhook class requires an access token to be specified at runtime, I have set this as an environment variable in Azure App Services as below:

To test the bot endpoint is working we can trigger the “get” endpoint by browsing to the url

In order to get the bot to perform the webhook, we have to mention the bot in the webex teams chat using @NetDevOps

We can ask the bot the status of the controllers by specifying a message that contains the string ‘sdwan controller status’

Awesome!

We could take the concept further by requesting specific device informantion, individual device configuration of and even alarms and events!

Thanks for reading!

All code on my github

https://github.com/thecraigus/sdwanchatbot

Leave a comment