Skip to content

Commit 55154b3

Browse files
committed
coding 102 updates
1 parent ceb9734 commit 55154b3

File tree

3 files changed

+62
-92
lines changed

3 files changed

+62
-92
lines changed

labs/coding-102-rest-python-ga/3.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ These files are located on your workstation in the directory: /DevNetCode/<yo
66
* **create-ticket.py** - Example to create a service ticket. Used in Step 2.
77
* **get-network-hosts.py** – First application to parse the service ticket response and show list of hosts by doing a pretty print of the JSON data
88
* **get-network-devices.py** – Retrieves network device list and parses JSON to display networkDeviceId values
9-
* **manage-users.py** – Shows how to retrieve, add and delete users
9+
* **build-topology.py** – Shows how to retrieve devices and interfaces, and to build a spreadsheet-like topology
1010

1111

1212
#### get-network-hosts.py

labs/coding-102-rest-python-ga/5.md

Lines changed: 61 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Step 5. Manage APIC-EM Users
22

3-
In this step we're going to continue to use functions to get, create and delete users.
3+
In this step we're going to get the topology then parse the data to determine how devices link to one another and their status.
44

55

66
#### manage-users.py
7-
This sample code uses the application REST function call to retrieve a list of the APIC-EM users and their roles. Our goal is to find the users and display information about them. In addition, we'll create a new user and delete it.
7+
This sample code uses the application REST function call to retrieve a list of devices called nodes and links which are the interfaces that connect them. Our goal is to find the devices and display information about them and how they connect to other devices.
88

99

1010
```python
@@ -14,16 +14,12 @@ import requests
1414
#import json library
1515
import json
1616

17-
1817
# Disable warnings
1918
requests.packages.urllib3.disable_warnings()
2019

21-
2220
controller='sandboxapic.cisco.com'
2321

24-
#creates and returns a service ticket.
2522
def getTicket():
26-
print("\nCreating ticket")
2723
# put the ip address or dns of your apic-em controller in this url
2824
url = "https://" + controller + "/api/v1/ticket"
2925

@@ -36,6 +32,8 @@ def getTicket():
3632
#Performs a POST on the specified url to get the service ticket
3733
response= requests.post(url,data=json.dumps(payload), headers=header, verify=False)
3834

35+
print (response)
36+
3937
#convert response to json format
4038
r_json=response.json()
4139

@@ -44,120 +42,92 @@ def getTicket():
4442

4543
return ticket
4644

47-
#Get and display the APIC-EM Users
48-
def getUsers(ticket):
49-
print("\nGetting list of existing users")
50-
# URL for user REST API call to get list of APIC-EM users.
51-
url = "https://" + controller + "/api/v1/user"
5245

53-
#Content type as well as the ticket must be included in the header
54-
header = {"content-type": "application/json", "X-Auth-Token":ticket}
5546

56-
# this statement performs a GET on the specified host url
57-
response = requests.get(url, headers=header, verify=False)
58-
59-
# json.dumps serializes the json into a string and allows us to
60-
# print the response in a 'pretty' format with indentation etc.
61-
print ("Users = ")
62-
print (json.dumps(response.json(), indent=4, separators=(',', ': ')))
63-
64-
65-
#Adds a APIC-EM User
66-
def addUser(ticket):
67-
print("\nAdding new user")
68-
# URL for user REST API call to get list of existing users in the network.
69-
url = "https://" + controller + "/api/v1/user"
47+
def getTopology(ticket):
48+
# URL for topology REST API call to get list of existing devices on the network, and build topology
49+
url = "https://" + controller + "/api/v1/topology/physical-topology"
7050

7151
#Content type as well as the ticket must be included in the header
7252
header = {"content-type": "application/json", "X-Auth-Token":ticket}
7353

74-
username="brett"
75-
#Data for new user
76-
payload={"password":"Brett123!","username":username,"authorization":[{"scope":"ALL","role":"ROLE_OBSERVER"}]}
77-
78-
# this statement performs a Post on the specified user url
79-
response = requests.post(url, data=json.dumps(payload), headers=header, verify=False)
80-
print ("Response after post: " + response.text)
81-
82-
return (username)
83-
84-
85-
#Delete the user that corresponds to the passed in username parameter
86-
def deleteUser(username, ticket):
87-
print("\nRemoving user: " + username)
88-
# URL for a specified user REST API call.
89-
url = "https://" + controller + "/api/v1/user/" + username
90-
91-
#Content type as well as the ticket must be included in the header
92-
header = {"content-type": "application/json", "X-Auth-Token":ticket}
93-
94-
# this statement performs a Delete on the specified user url
95-
response = requests.delete(url, headers=header, verify=False)
96-
print (response.text)
97-
98-
99-
#Show the User that corresponds to the passed in username parameter
100-
def showUser(username, ticket):
101-
print("\nDisplaying user: " + username)
102-
# URL for user REST API call to get APIC-EM user with corresponding name.
103-
url = "https://" + controller + "/api/v1/user/" + username
104-
105-
#Content type as well as the ticket must be included in the header
106-
header = {"content-type": "application/json", "X-Auth-Token":ticket}
107-
108-
# this statement performs a GET on the specified user url
54+
# this statement performs a GET on the specified network device url
10955
response = requests.get(url, headers=header, verify=False)
56+
11057
# json.dumps serializes the json into a string and allows us to
11158
# print the response in a 'pretty' format with indentation etc.
112-
print ("User found = ")
59+
print ("Topology = ")
11360
print (json.dumps(response.json(), indent=4, separators=(',', ': ')))
11461

62+
#convert data to json format.
63+
r_json=response.json()
64+
65+
#Iterate through network device data and list the nodes, their interfaces, status and to what they connect
66+
for n in r_json["response"]["nodes"]:
67+
if "platformId" in n:
68+
print()
69+
print()
70+
print('{:30}'.format("Node") + '{:25}'.format("Family") + '{:20}'.format("label")+ "Management IP")
71+
print('{:30}'.format(n["platformId"]) + '{:25}'.format(n["family"]) + '{:20}'.format(n["label"]) + n["ip"])
72+
found=0 #print header flag
73+
printed=0 #formatting flag
74+
for i in r_json["response"]["links"]:
75+
if "startPortName" in i:
76+
#check that the source device id for the interface matches the node id. Means interface originated from this device.
77+
if i["source"] == n["id"]:
78+
if found==0:
79+
print('{:>20}'.format("Source Interface") + '{:>15}'.format("Status") + '{:>22}'.format("Target Interface") + '{:>18}'.format("Target"))
80+
found=1
81+
printed=1
82+
for n1 in r_json["response"]["nodes"]:
83+
#find name of node to which this one connects
84+
if i["target"] == n1["id"]:
85+
print(" " + '{:<25}'.format(i["startPortName"]) + '{:<12}'.format(i["linkStatus"]) + '{:<28}'.format(i["endPortName"]) + '{:<15}'.format(n1["platformId"]))
86+
break;
87+
found=0
88+
for i in r_json["response"]["links"]:
89+
if "startPortName" in i:
90+
#Find interfaces that link to this one which means this node is the target.
91+
if i["target"] == n["id"]:
92+
if found==0:
93+
if printed==1:
94+
print()
95+
print('{:>20}'.format("Source Interface") + '{:>15}'.format("Status") + '{:>22}'.format("Target Interface") + '{:>18}'.format("Source"))
96+
found=1
97+
for n1 in r_json["response"]["nodes"]:
98+
#find name of node to that connects to this one
99+
if i["source"] == n1["id"]:
100+
#print('{:<30}'.format(i["endPortName"]) + '{:>10}'.format(i["linkStatus"]) + '{:>26}'.format(n1["platformId"]))
101+
print(" " + '{:<25}'.format(i["startPortName"]) + '{:<12}'.format(i["linkStatus"]) + '{:<28}'.format(i["endPortName"]) + '{:<15}'.format(n1["platformId"]))
102+
break;
115103

116104
theTicket=getTicket()
117-
getUsers(theTicket)
118-
name=addUser(theTicket)
119-
showUser(name,theTicket)
120-
getUsers(theTicket)
121-
deleteUser(name,theTicket)
122-
getUsers(theTicket)
105+
getTopology(theTicket)
123106
```
124107

125108
Let's look at what the code is doing. We'll focus on the key code changes.
126-
* *def addUser(theTicket):*
127-
* We define the function named addUser. This function creates a payload with user information and adds it. The passed in parameter 'theTicket' is used for authorization purposes.
128-
* *def deleteUser(username,theTicket):*
129-
* We define the function named deleteUser which removes a user with the name of the passed in parameter 'username'. The passed in parameter 'theTicket' is used for authorization purposes.
109+
* *def getTopology(theTicket):*
110+
* We define the function named getTopology. This function reads in the topology data. It parses the nodes which are devices on the network and displays some information about them. It also parses the link data which are interfaces that connect the nodes and displays information about how they connect the devices and their status. The passed in parameter 'theTicket' is used for authorization purposes.
130111

131112
To run this code sample:
132113
1. Go to directory **coding102-REST-python-ga**. In the terminal type:
133114
**cd \DevNetCode\&lt;your-name&gt;\coding-skills-sample-code\coding102-REST-python-ga**
134115
2. Assign the APIC-EM Controller IP address or DNS to the **controller** variable.
135-
* Open the file **manage-users.py**. For example, in Windows type: **notepad manage-users.py**
116+
* Open the file **build-topology.py**. For example, in Windows type: **notepad build-topology.py**
136117
* *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: [sandboxapic.cisco.com](https://sandboxapic.cisco.com)
137118
* controller='sandboxapic.cisco.com'
138119
3. Save the file. If encoding type is an option select **UTF-8**.
139120
4. Type the python command and then the filename at the command prompt, and press the return key.
140-
* *On Windows type*: **py -3 manage-users.py**. Or type: **python manage-users.py**
141-
* *On Mac OS or Linux type*: **python3 manage-users.py**
121+
* *On Windows type*: **py -3 build-topology.py**. Or type: **python build-topology.py**
122+
* *On Mac OS or Linux type*: **python3 build-topology.py**
142123
5. The program should execute or display an error message.
143124

144125
You should see a result like the following.
145126

146-
Create service ticket and list users
147-
![](/posts/files/coding-102-rest-python-ga/assets/images/manage-users-1.png)
148-
<br/><br/>
149-
Add and list user
150-
![](/posts/files/coding-102-rest-python-ga/assets/images/manage-users-2.png)
151-
<br/><br/>
152-
List all users
153-
![](/posts/files/coding-102-rest-python-ga/assets/images/manage-users-3.png)
154-
<br/><br/>
155-
Remove the added user and list remaining users
156-
![](/posts/files/coding-102-rest-python-ga/assets/images/manage-users-4.png)
157-
<br/><br/>
127+
![](/posts/files/coding-102-rest-python-ga/assets/images/build-topology.png)
158128

159129

160130
## Things to Try
161-
* Comment out the call to deleteUser(name,theTicket) which would then show as *#deleteUser(name,theTicket)*, and run the program twice. What error occurs when you try to add an already existing user?
162-
* Remove the pound sign # from the deleteUser function so reads as *deleteUser(name,theTicket)* then run the program twice. Is the problem corrected?
163-
* In the showUser(name,theTicket) function call change the name parameter to string 'joe' so the function call reads as *showUser('joe',theTicket)* . What happens when the user to be shown is not found?
131+
* After running the script, review the node data printed. Replace the label attribute that is printed with another attribute such as role or nodeType.
132+
* You may have noticed that no host devices are printed. Review the data and the source code, and determine why this is so along with how you would print this data.
133+
* Modify the source code so that host devices are printed as well.
Loading

0 commit comments

Comments
 (0)