In the previous articles, I’ve described how to execute REST API calls using Postman software. This time we will dive into Python.
Tools
To run REST API calls we will use Python3 with the requests library. It’s not installed by default, so make sure it’s present before jumping further.
Environment
We will use the Cisco Meraki Always on sandbox. It’s a free lab environment that everybody can access to test various Meraki functionalities.
The base URL for API calls will be https://api.meraki.com/api/v1
For authentication we will use a API key, at the time of this article writing, API key is: 6bec40cf957de430a6f1f2baa056b99a4fac9ea0
You can find Cisco Meraki API documentation here.
API Calls
The following chapters are containing Python source code. If you’re interested in running those scripts on your local machine, you can easily access them in the Cisco Meraki Automation Examples repository.
Organizations
We will start with script that gathers information about all organizations.
import requests
import json
BASE_URL = 'https://api.meraki.com/api/v1'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print(f'Failed to get organizations')
exit(1)
parsed_response = json.loads(call_response.text)
for organization in parsed_response:
print('ID: {id}, Name: {name}'.format(id=organization['id'], name=organization['name']))
First of all, we’re importing the necessary libraries. Requests will be used for REST API calls. The API call returns a JSON string, so the JSON library will be used for conversion to the python data structures.
BASE_URL variable contains a URL to the Cisco Meraki environment. Our API call URL’s will be created by appending the appropriate string.
We will use the API key for authorization. In the headers dictionary, there is one key/value pair with authorization details.
RESOURCE variable determines the resource that we want to access with the REST API call. You can find a complete list of available options in the official documentation.
Since we have all necessary information, let’s execute our first REST API call!
We want to execute a GET request, that’s why we’re using a get method from the requests library. The first argument is the combination of the basic URL with a specified resource, that we want to access. The resulting string is as follows.
https://api.meraki.com/api/v1/organizations
A second argument is a dictionary with authorization details. We’re passing it explicitly as a header.
Let’s pause here for a second before jumping to the following line codes.
After execution of the REST API call, we’re receiving following object.
The requests.Response object was returned by the GET method. As we can see, there is a response code 200, which determines, that the call was successful. The call_response variable now has plenty of properties, but we will focus on the text, which returns the REST API response in the Unicode text.
Since the response is encoded in the JSON format, it’s convenient to convert it to the native python structures. It can be easily accomplished using the JSON library. The loads method takes the JSON string and converts it to the python data structures. After decoding, the parse_response variable is a list with dictionary elements.
From now on, the data can be easily accessed via native python utilities. Let’s loop through all organizations first. The single organization is built of a dictionary with keys of id, name, and url.
Let’s say that we want to print just id and name of the organization. Since it’s a dictionary, we can access the data with the standard Python syntax.
The output from the script is as follows.
ID: 681155, Name: DeLab
ID: 566327653141842188, Name: DevNetAssoc
ID: 575334852396582607, Name: 123456
ID: 575334852396582606, Name: TriDeptrai
ID: 575334852396582605, Name: My organization
ID: 575334852396582604, Name: thanh
ID: 575334852396582603, Name: 123456
ID: 575334852396582602, Name: My organization
ID: 575334852396582601, Name: 123
ID: 575334852396582600, Name:vnPro
ID: 575334852396582591, Name: Ftreqah organization
ID: 575334852396582590, Name: Ftreqah organization
ID: 575334852396582587, Name:vnPro
ID: 549236, Name: DevNet Sandbox
ID: 52636, Name: Forest City - Other
ID: 865776, Name: Cisco Live US 2019
ID: 463308, Name: DevNet San Jose
Networks
Now let’s jump to networks. In Meraki, an organization can have assigned one or more networks. Let’s say that we want to print all organizations and networks.
import requests
import json
BASE_URL = 'https://api.meraki.com/api/v1'
headers = { 'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0' }
RESOURCE = '/organizations'
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print(f'Failed to get organizations')
exit(1)
organizations = json.loads(call_response.text)
for organization in organizations:
RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print('Failed to get networks for organization {organization}'.format(organization=organization["name"]))
continue
networks = json.loads(call_response.text)
if len(networks) > 0:
print('Printing networks for organization {name}:'.format(name=organization['name']))
for network in networks:
print('\tID: {id}, Name: {name}, TimeZone: {timezone}'.format(id=network['id'],
name=network['name'],
timezone=network['timeZone']))
else:
print('There are no networks assigned to organization {name}'.format(name=organization['name']))
First of all, we have to grab a list of organizations. After that, we have to loop through each organization(first for loop) and grab an organization id. Now we can build an API call gathering all networks assigned to a specified organization.
Down below you can find a syntax of the REST API call, that returns a list of networks assigned to a particular organization.
https://api.meraki.com/api/v1/organizations/{organization_id}/networks
If a particular organization has assigned networks, we’re looping through them and printing information in the second for loop. On the screenshot below you can find attributes of each network.
In this case, we want to print a network id, name, and time zone. In the following snippet, you can find the result.
Printing networks for organization DeLab
ID: L_566327653141843049, Name: Lyoli, Timezone: America/New_York
ID: L_566327653141846927, Name: Vegas Apartment, Timezone: America/Los_Angeles
ID: L_566327653141856854, Name: DNEAlertsNet, Timezone: America/Los_Angeles
ID: L_783626335162466320, Name: DevNetLab, Timezone: America/Los_Angeles
ID: L_783626335162466514, Name: DevNetLab2, Timezone: America/Los_Angeles
ID: L_783626335162466515, Name: DevNetLab3, Timezone: America/Los_Angeles
ID: N_566327653141899127, Name: Nolan, Timezone: America/Los_Angeles
ID: N_566327653141902646, Name: Lyoli MDM, Timezone: America/Los_Angeles
Printing networks for organization DevNetAssoc
ID: L_566327653141858539, Name: DevNetAssoc1, Timezone: America/Los_Angeles
ID: L_566327653141858540, Name: DevNetAssoc2, Timezone: America/Los_Angeles
ID: L_566327653141858541, Name: DevNetAssoc3, Timezone: America/Los_Angeles
ID: L_566327653141858542, Name: DevNetAssoc4, Timezone: America/Los_Angeles
ID: L_566327653141858543, Name: DevNetAssoc5, Timezone: America/Los_Angeles
Printing networks for organization Hi Cory
ID: L_573083052582908089, Name: San Jose Lab, Timezone: America/Los_Angeles
ID: L_573083052582981640, Name: OTG Test Network, Timezone: America/Los_Angeles
ID: L_573083052582987951, Name: WinNet1, Timezone: America/Los_Angeles
ID: L_573083052582987953, Name: WinNet2, Timezone: America/Los_Angeles
ID: N_573083052583231323, Name: Cisco Live Network2, Timezone: America/Los_Angeles
ID: N_573083052583231354, Name: Cisco Live Network3, Timezone: America/Los_Angeles
ID: N_573083052583231356, Name: Cisco Live Network4, Timezone: America/Los_Angeles
ID: N_573083052583231376, Name: Another Device Name, Timezone: America/Los_Angeles
ID: N_573083052583232041, Name: Cisco Live Network77, Timezone: America/Los_Angeles
ID: N_573083052583236732, Name: ll, Timezone: America/Los_Angeles
ID: N_573083052583236733, Name: jj, Timezone: America/Los_Angeles
ID: N_573083052583236734, Name: hh, Timezone: America/Los_Angeles
ID: N_573083052583236735, Name: uu, Timezone: America/Los_Angeles
Printing networks for organization organization with name changed
ID: L_573083052582985912, Name: New_name, Timezone: America/Los_Angeles
ID: L_573083052582990676, Name: New Apartment, Timezone: America/Los_Angeles
Printing networks for organization Jacks_test_net
ID: L_573083052582993027, Name: Main Office, Timezone: America/Los_Angeles
ID: N_573083052583225773, Name: NewLong Island Office, Timezone: America/Los_Angeles
Printing networks for organization New Meraki Org
ID: L_573083052582989294, Name: Long Island Office test, Timezone: America/Los_Angeles
ID: L_573083052582989297, Name: LongCKtest, Timezone: America/Los_Angeles
ID: N_573083052583233224, Name: rhb-vmx-test-nw, Timezone: America/Los_Angeles
ID: N_573083052583235085, Name: vMX Test, Timezone: America/Los_Angeles
ID: N_573083052583235087, Name: newTest, Timezone: America/Los_Angeles
ID: N_573083052583236066, Name: test7, Timezone: America/Los_Angeles
ID: N_573083052583237700, Name: my automated network, Timezone: America/Los_Angeles
ID: N_573083052583237701, Name: my new automated network, Timezone: America/Los_Angeles
ID: N_573083052583238204, Name: my brand new automated network, Timezone: America/Los_Angeles
ID: N_573083052583249835, Name: my new automated network10, Timezone: America/Los_Angeles
[...]
Devices
The last example is pretty similar to the previous one. In this case, we’re listing devices, that are assigned to each network.
import requests
import json
BASE_URL = 'https://api.meraki.com/api/v1'
headers = {'X-Cisco-Meraki-API-Key': '6bec40cf957de430a6f1f2baa056b99a4fac9ea0'}
RESOURCE = '/organizations'
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print(f'Failed to get organizations')
exit(1)
organizations = json.loads(call_response.text)
for organization in organizations:
RESOURCE = '/organizations/{id}/networks'.format(id=organization['id'])
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print('Failed to get networks for organization {organization}'.format(organization=organization["name"]))
continue
networks = json.loads(call_response.text)
for network in networks:
RESOURCE = '/networks/{id}/devices'.format(id=network['id'])
call_response = requests.get(BASE_URL + RESOURCE, headers=headers)
if call_response.status_code != 200:
print('Failed to get devices for {network}'.format(network=network["name"]))
continue
devices = json.loads(call_response.text)
if len(devices) > 0:
print('Devices assigned to network {network}'.format(network=network['name']))
for device in devices:
if 'name' in device:
print('\tName: {name}, Model: {model}, Serial: {serial}'.format(name=device['name'],
model=device['model'],
serial=device['serial']))
else:
print('\tModel: {model}, Serial: {serial}'.format(model=device['model'],
serial=device['serial']))
else:
print('There are no devices assigned to the network {network}'.format(network=network['name']))
To list devices assigned to a particular network, we need to gather all networks. We’re doing it the same way as in the previous example. After we have a network id’s, we’re ready to list devices for each network. The API call to accomplish this is the following.
https://api.meraki.com/api/v1/networks/{network_id}/devices
After the API call execution, we have a list of devices. The attributes of each device are as follows.
Since we have all the necessary information, we can print the information. We’re grabbing the name, model, and serial of each network device. The result of the script is down below.
Devices assigned to network Lyoli
Name: BigCat, Model: MX250, Serial: Q2SW-SWQ2-HZ9L
Name: 1st Floor AP, Model: MR52, Serial: Q2LD-GYL3-KEHX
Name: 2nd Floor AP, Model: MR52, Serial: Q2LD-AN9B-S6AJ
Name: Sun Room, Model: MR84, Serial: Q2EK-UKGM-XSD9
Name: Office AP, Model: MR52, Serial: Q2LD-ZWCZ-UA77
Name: Basement AP, Model: MR52, Serial: Q2LD-3Y7V-7Y2X
Model: MV12W, Serial: Q2GV-LDX2-53ZA
Name: Big Office Switch, Model: MS250-48FP, Serial: Q2QW-W2W4-MCNR
Name: Bedroom Switch, Model: MS220-8P, Serial: Q2HP-WEUW-2PQD
Name: Basement switch, Model: MS220-8P, Serial: Q2HP-225A-XA5C
Devices assigned to network Vegas Apartment
Model: MV71, Serial: Q2CV-V49B-RCMZ
Name: Alex’s MR32, Model: MR32, Serial: Q2JD-7RNY-EB7Z
Name: Alex's MR84 - 1, Model: MR84, Serial: Q2EK-2LYB-PCZP
Name: Vegas Balcony MR84, Model: MR84, Serial: Q2EK-D4XP-235S
Model: MR84, Serial: Q2EK-ACGE-URXL
Name: Vegas Living Room MR84, Model: MR84, Serial: Q2EK-3UBE-RRUY
Model: MX65, Serial: Q2QN-Y5ED-P57W
Devices assigned to network Nolan
Model: MR52, Serial: Q2LD-X2S2-AG2U
Model: MR52, Serial: Q2LD-N2U5-D83H
There are no devices assigned to the network Lyoli MDM
[...]
Summary
As you can probably deduce, REST API calls are a powerful tool in the network engineer hands. They can be used in a variety of different ways. Do you have a network device stocktaking? You can easily gather all the necessary information and save it in a convenient way. It’s just one use case that can save you a lot of work and time.
Hi, I was excited to try out this script which is exactly what I needed but when I tried it seems its is going on loop. I am not sure what is the cause though. Any ideas? Thank you.
Hi,
Which script you’re referring to?