|
| 1 | +# Step 6. Build Network Topology and Graphically Display it |
| 2 | + |
| 3 | +In this step we're going to get the network topology data and have a separate graphical tool Cisco [NeXt UI](https://developer.cisco.com/site/neXt/) parse the data and graphically render the topology. We'll also use a web server tool called [Flask](http://flask.pocoo.org/) which well use to interface with NeXt UI. Flask is a Python module |
| 4 | + |
| 5 | +Let's take a high level view of how this process works in a step-by-step manner then we'll look at more detail in the source code. Please see the flow chart below as well. |
| 6 | +1. When you start the python script build-topology-web-server.py it starts Flask which is a web server. |
| 7 | +2. Flask will call the index() function located in the build-topology-web-server.py which sets off a chain of events. |
| 8 | +3. The index() function loads the file topology.html which has javascript in it that uses the NeXt UI toolkit libraries. |
| 9 | +4. NeXt calls the topology() function in file build-topology-web-server.py to get the topology data in JSON format |
| 10 | +5. NeXt then parses and renders the network topology from the data. |
| 11 | + |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +Now let's dig into the source code. We'll focus just on the python script. |
| 16 | +#### build-topology-web-server.py |
| 17 | +This sample code starts the Flask web application and provides functions that are called to retrieve a list of devices called nodes and links which are the interfaces that connect them. This script along with Flask and NeXt UI read the network topology and graphically display it as a web page. |
| 18 | + |
| 19 | + |
| 20 | +```python |
| 21 | +# import requests library |
| 22 | +import requests |
| 23 | + |
| 24 | +# import json library |
| 25 | +import json |
| 26 | + |
| 27 | +# import flask web framework |
| 28 | +from flask import Flask |
| 29 | + |
| 30 | +# from flask import render_template function |
| 31 | +from flask import render_template, jsonify |
| 32 | + |
| 33 | +controller = 'devnetapi.cisco.com/sandbox/apic_em' |
| 34 | + |
| 35 | + |
| 36 | +def getTicket(): |
| 37 | + # put the ip address or dns of your apic-em controller in this url |
| 38 | + url = "https://" + controller + "/api/v1/ticket" |
| 39 | + |
| 40 | + # the username and password to access the APIC-EM Controller |
| 41 | + payload = {"username": "devnetuser", "password": "Cisco123!"} |
| 42 | + |
| 43 | + # Content type must be included in the header |
| 44 | + header = {"content-type": "application/json"} |
| 45 | + |
| 46 | + # Performs a POST on the specified url to get the service ticket |
| 47 | + response = requests.post(url, data=json.dumps(payload), headers=header, verify=False) |
| 48 | + |
| 49 | + print(response) |
| 50 | + |
| 51 | + # convert response to json format |
| 52 | + r_json = response.json() |
| 53 | + |
| 54 | + # parse the json to get the service ticket |
| 55 | + ticket = r_json["response"]["serviceTicket"] |
| 56 | + |
| 57 | + return ticket |
| 58 | + |
| 59 | + |
| 60 | +def getTopology(ticket): |
| 61 | + # URL for network-device REST API call to get list of exisiting devices on the network. |
| 62 | + url = "https://" + controller + "/api/v1/topology/physical-topology" |
| 63 | + |
| 64 | + # Content type as well as the ticket must be included in the header |
| 65 | + header = {"content-type": "application/json", "X-Auth-Token": ticket} |
| 66 | + |
| 67 | + # this statement performs a GET on the specified network device url |
| 68 | + response = requests.get(url, headers=header, verify=False) |
| 69 | + |
| 70 | + # convert data to json format. |
| 71 | + r_json = response.json() |
| 72 | + |
| 73 | + # return json object |
| 74 | + return r_json["response"] |
| 75 | + |
| 76 | + |
| 77 | +# intialize a web app |
| 78 | +app = Flask(__name__) |
| 79 | + |
| 80 | + |
| 81 | +# define index route to return topology.html |
| 82 | +@app.route("/") |
| 83 | +def index(): |
| 84 | + # when called '/' which is the default index page, render the template 'topology.html' |
| 85 | + return render_template("topology.html") |
| 86 | + |
| 87 | + |
| 88 | +# define an reset api to get topology data |
| 89 | +@app.route("/api/topology") |
| 90 | +def topology(): |
| 91 | + # get ticket |
| 92 | + theTicket = getTicket() |
| 93 | + |
| 94 | + # get topology data and return `jsonify` string to request |
| 95 | + return jsonify(getTopology(theTicket)) |
| 96 | + |
| 97 | + |
| 98 | +if __name__ == "__main__": |
| 99 | + app.run() |
| 100 | +``` |
| 101 | + |
| 102 | +Let's look at what the code is doing. We'll focus on the key code changes. |
| 103 | +* *from flask import Flask* |
| 104 | + * From the flask python module imports the Flask object |
| 105 | +* *from flask import render_template, jsonify* |
| 106 | + * From the flask python module imports a couple of functions which are render_template and jsonify. |
| 107 | +* *app = Flask(__name__)* |
| 108 | + * Instanitates the Flask web application. |
| 109 | +* *@app.route("/")* |
| 110 | + * Tags the function below it "def index()" and specifies that it is called as the default web page for the Flask web application variable 'app'. |
| 111 | +* *def index():* |
| 112 | + * The index function that calls the Flask function render_template that loads the topology.html web page. |
| 113 | +* *@app.route("/api/topology")* |
| 114 | + * Tags the function below it "def topology()" and is called by NeXt UI. Identifies as web page for the Flask web application variable 'app' |
| 115 | +* *def topology():* |
| 116 | + * Returns the network topology data in JSON format. |
| 117 | +* *if __name__ == "__main__":* |
| 118 | + * Optional code that specifies that if this module is run, rather than just importing it and calling it's functions, that below this point is where the script should begin running. Python typically knows already has this information, but this prevents any ambiguity. |
| 119 | +* *app.run()* |
| 120 | + * Starts the Flask web application. |
| 121 | + |
| 122 | + |
| 123 | +To run this code sample: |
| 124 | +1. Go to directory **coding102-REST-python-ga**. In the terminal type: |
| 125 | + **cd \DevNetCode\<your-name>\coding-skills-sample-code\coding102-REST-python-ga** |
| 126 | +2. Assign the APIC-EM Controller IP address or DNS to the **controller** variable. |
| 127 | + * Open the file **build-topology-web-server.py**. For example, in Windows type: **notepad build-topology-web-server.py** |
| 128 | + * *If you are not using your own APIC-EM Controller*, use the [DevNet Sandbox](https://developer.cisco.com/site/devnet/sandbox/) Always-On APIC-EM Lab: https[]()://devnetapi.cisco.com/sandbox/apic_em |
| 129 | + * controller='devnetapi.cisco.com/sandbox/apic_em' |
| 130 | +3. Save the file. If encoding type is an option select **UTF-8**. |
| 131 | +4. Type the python command and then the filename at the command prompt, and press the return key. |
| 132 | + * *On Windows type*: **py -3 build-topology-web-server.py**. Or type: **python build-topology-web-server.py** |
| 133 | + * *On Mac OS or Linux type*: **python3 build-topology-web-server.py** |
| 134 | +5. The program will start listening at IP 128.0.0.1 port 5000. If the error: *"ImportError: No module named 'flask'"* is given click on "How to Set up Your Computer" on the top of this web page. |
| 135 | + |
| 136 | +6. Open a web browser such as Chrome or Safari and in the URL field enter the URL **http://127.0.0.1:5000** . You should see a result like the following below. |
| 137 | + |
| 138 | + |
| 139 | + |
| 140 | +## Things to Try |
| 141 | +* Compare the first three layers of the topology to what you drew in step 5. Do they match? |
| 142 | +* Go to the templates directory and open the file topology.html. In the javascript block identified within block *<script type="text/javascript">* change the width and height from 800 to 400. Rerun the program. What's changed? |
| 143 | + |
| 144 | + |
| 145 | +##Congratulations! You've completed Coding 102! |
0 commit comments