7 months, 2 weeks

Meraki Dashboard API Python Library





The Meraki Dashboard API Python library provides all current Meraki Dashboard API calls to interface with the Cisco Meraki cloud-managed platform. 


You can install it via PyPI:
pip install meraki
The Python library can also take care of error handling, logging, retries, and other convenient processes and options for you automatically.

Consuming Controllers and High-Level Networking APIs with requests
The common architectural style these APIs use is REST, short for REpresentational State Transfer. REST builds on top of the Hyper Text Transfer Protocol (HTTP) and has, since its inception in the early 2000s, become the de facto standard for building web APIs. We will have a look at one specific REST API, known as the Dashboard API, which can be used to interact with the Cisco Meraki family of devices.

The header is a key-value pair, where in our example the key is Authorization and the value is the secret that authenticates us against the API server. 
This secret, commonly referred to as an access token, or simply token, is used to authenticate and authorize requests on behalf of a user. There are different types of tokens, but they generally fall into one of two categories:

• Tokens with an indefinite validity: Once generated, these tokens stay valid until they are revoked by the user. Meraki uses these types of indefinite valid tokens, and they can usually be generated in the web interface of the web services of the API you want to interact with. 
• Tokens with a limited validity: These are tokens that only have a limited time span in which they are valid. This timespan can range from a few minutes to several days or weeks. An example of an API that uses such an approach would be Cisco DNA Center.

Passing a username-password combination as authentication data in a request
Username-password authentication, sometimes also referred to as Basic Auth, uses the Authorization header in a request and specifies the username and password as the value of the header field. These credentials are not transferred in plain text; instead, the username and password, separated by a colon sign, are base64-encoded and prepended with the Basic keyword. This keyword indicates to the server that the HTTP Basic auth schema is being used. 

Authorization: Basic cm9vdDp0ZXN0 
requests offers a convenient way of passing a username/password combination to a request and automatically getting the correctly encoded headers set.
import requests
from requests.auth import HTTPBasicAuth
auth = HTTPBasicAuth("root", "test")
response = requests.get("https://athaenas.com", auth=auth)
print(response.status_code) 
requests provides you with a handy shorthand when using HTTP Basic Auth. While you can import the HTTPBasicAuth class and create a new Auth object, you can also just pass a tuple containing the username/password combination.

Storing authentication metadata between requests using sessions
Follow these steps to authenticate your request against the Meraki API using a Session object and retrieve all organizations:
1. Import the built-in os and sys modules, as well as our requests module:
import os
import sys
import requests

2. Retrieve the API key from our environment variable and check that it is not None. We must also specify the base URL of our API:
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
  print("Please provide an API key. Aborting.")
  sys.exit(-1)
3. Create a new requests Session object:
sess = requests.Session()
4. On that Session, update the headers so that they include our authorization details:
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
5. Create the URL where we will receive a list of all our organizations and send a GET request using our session:
url = f"{base_url}/organizations"
resp = sess.get(url)
6. Check the status code of our response and if it's 200, indicating that the request was successful, parse the JSON the API has sent us into a dictionary and print out all the organizations:
if resp.status_code == 200:
  data = resp.json()
  for org in data:
     print(org['name'])
else:
  print(f"Bad response. Status code: {resp.status_code}")

We can also use the Meraki SDK to achieve the same outcome.
import meraki
dashboard = meraki.DashboardAPI()
orgs = dashboard.organizations.getOrganizations()
for org in orgs:
   print(org['name']) 

Retrieving a list of Meraki networks
Meraki organizes all its information in a hierarchy, where a device belongs to a network and a network, in turn, belongs to an organization that can have multiple networks. A common task when dealing with REST APIs is to retrieve all the information that is currently stored on the system. 

Follow these steps to authenticate your request against the Meraki API and retrieve a list of networks for each of your organizations:
1. Set up a requests session using the API key stored in your environment.
import os
import sys
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
  print("Please provide an API key. Aborting.")
  sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
2. With our session established, we must retrieve all the organizations associated with our account:
orgs_url = f"{base_url}/organizations"
resp_orgs = sess.get(orgs_url)
3. If our request was successful, and thus returned with a status code of 200, we can iterate over all the organizations that were returned:
if resp_orgs.status_code == 200:
   for org in resp_orgs.json():
4. Then, we can extract the organization ID and create a new URL to request all networks for the organization specified by the ID, as well as print out the name of the organization:
 org_id = org['id']
 print(f"Retrieving networks for {org['name']}")
 url = f"{base_url}/organizations/{org_id}/networks"
5. Next, we will send a request to gather all the networks and, if that request is successful, iterate over all the networks and print out the networks' names:
 resp = sess.get(url)
 if resp.status_code == 200:
   for ntwrk in resp.json():
      print(f"- {ntwrk['name']}")
6. We must make sure that we handle any non-successful status codes both from our network and organization requests:
   else:
      print(f"Failed to retrieve network. Status code: {resp.status_code}")
else:
   print(f"Failed to retrieve orgs. Response code: {resp_orgs.status_code}")
We can also use the Meraki SDK to achieve the same outcome, without having to manually do the requests ourselves. 
import meraki
dashboard = meraki.DashboardAPI()
orgs = dashboard.organizations.getOrganizations()
for org in orgs:
 networks = dashboard.organizations.getOrganizationNetworks(org['id'], total_pages='all')
 for ntwrk in networks:
    print(f"- {ntwrk['name']}") 

Retrieving usage details and connected clients for a Meraki network
Follow these steps to authenticate your request against the Meraki API and create a usage report:
1. Set up a requests session using the API key stored in your environment.
import os
import sys
import csv
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
  print("Please provide an API key. Aborting.")
   sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
2. With our session set up, we can get started with our calls. We will start by setting the 
ID of the network that we want to query the clients for and put our URL together:
network_id = "<insert network id here>"
url = f"{base_url}/networks/{network_id}/clients"
3. Request all client information and, if successful, retrieve a list of dictionaries containing all the clients from the past 31 days:
resp = sess.get(url)
if resp.status_code == 200:
   clients = resp.json()

4. Open a new file called clients.csv for writing and create a csv.writer that we will use to export any information that's retrieved from the API:
 with open('clients.csv', 'w') as csvfile:
      out = csv.writer(csvfile, delimiter=',')
5. Next, we must export the keys of our clients as the header for our csv file:
 out.writerow(clients[0].keys())
6. Then, we will iterate over each of our client dictionaries and write the specific information into the csv file:
 for client in clients:
    out.writerow(client.values())
7. Lastly, we must react if our status code is not 200:
else:
   print(f"Request failed. Status code: {resp.status_code}")
We can also use the Meraki SDK to achieve the same outcome, without having to manually do the requests ourselves.
import csv
import meraki
network_id = "<insert network id here>"
dashboard = meraki.DashboardAPI()
clients = dashboard.networks.getNetworkClients(network_id, total_pages='all')
with open('clients.csv', 'w') as csvfile:
   out = csv.writer(csvfile, delimiter=',')
   out.writerow(clients[0].keys())
   for client in clients:
       out.writerow(client.values())

Rebooting a Meraki device
Follow these steps to authenticate your request against the Meraki API and reboot a device based on its serial number:
1. Set up a requests session using the API key stored in the environment.
import os
import sys
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
  print("Please provide an API key. Aborting.")
  sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
2. With our session set up, we can specify the serial number of the device we want to reboot and put together the URL based on that serial number:
serial = "<Insert device serial here>"
url = f"{base_url}/devices/{serial}/reboot"
3. Next, we will use the post() method of our session to kick off the request and save 
the response in resp:
resp = sess.post(url)
4. Finally, we will check the status code and print out a different message to the user, based on whether the request was a success or not:
if resp.status_code == 202:
  print("Rebooted device successfully.")
else:
  print(f"Failed to reboot device. Status code:{resp.status_code}")

We can also use the Meraki SDK to achieve the same outcome, without having to manually do the requests ourselves. You must have the same environment variable (MERAKI_DASHBOARD_API_KEY) set:
import meraki
serial = "<Insert device serial here>"
dashboard = meraki.DashboardAPI()
dashboard.devices.rebootDevice(serial)
if resp.ok:
   print("Request was succesful")

Retrieving channel usage for your Meraki access point
Follow these steps to authenticate your request against the Meraki API and retrieve the total utilization for all your Wi-Fi points in the last 7 days:
1. Set up a requests session using the API key stored in your environment.
import os
import sys
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
   print("Please provide an API key. Aborting.")
   sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
2. With our session established, we can set up the URL. We need a network ID that we want to receive all the information for:
network_id = "<Insert network id here>"
url = f"{base_url}/networks/{network_id}/networkHealth/channelUtilization"
3. Next, we want to specify the query parameters that will be passed on. We can specify them in a dictionary:
params = {
 'timespan': 7
}
4. Using our session, we will execute a GET request and pass the query parameter:
resp = sess.get(url, params=params)
5. If our request was successful, we will retrieve the list of our APs and then, for each network in an AP, print out the total utilization:
if resp.status_code == 200:
  aps = resp.json()
  for ap in aps:
    print(f"Wifies on AP {ap['serial']}")
    for e in ap['wifi0']:
       print(f"{e['utilizationTotal']}")
6. Lastly, we need to react to a non-successful response and print out the status code:
else:
  print(f"Failed to retrieve utilization. Code:{resp.status_code}")

We can also use the Meraki SDK to achieve the same outcome.
import meraki
dashboard = meraki.DashboardAPI()
network_id = "<Insert network id here>"
data = dashboard.networks.
getNetworkNetworkHealthChannelUtilization(network_id, timespan=7, total_pages='all')
for ap in aps:
  print(f"Wifies on AP {ap['serial']}")
  for e in ap['wifi0']:
    print(f"{e['utilizationTotal']}")

Updating the switchport configuration of a Meraki device
We are going to change the switchport maximum number of sticky MAC addresses allowed on our switch port to 10. 
Follow these steps to authenticate your request against the Meraki API and update the switch port configuration:
1. Set up a requests session using the API key stored in the environment.
import os
import sys
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
  print("Please provide an API key. Aborting.")
  sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})
2. With our session established, we need a device serial number and the ID of the port to update, such as port 1. Make sure that this port has been configured with the access policy type; that is, Sticky MAC allow list:
serial = "<INSERT Serial here>"
port = <Insert port number here>
url = f"{base_url}/devices/{serial}/switch/ports/{port}"
3. Next, we are going to retrieve the current configuration using a GET request:
resp = sess.get(url)
4. If our GET request is successful, we can retrieve the current configuration of our switch port as a Python dictionary and change the value – in our case, the number of allowed sticky mac addresses – and send a PUT request to the same URL to change the configuration:
if resp.status_code == 200:
 conf = resp.json()
 conf['stickyMacAllowListLimit'] = 10
 resp_update = sess.put(url, json=conf)
 if resp_update.status_code == 200:
    print("Config updated!")
5. Lastly, we need to respond to any of our requests failing:
  else:
   print(f"Failed to update. Status:{resp_update.status_code}")
else:
  print(f"Failed to get config. Status: {resp.status_code}")

Deleting the QoS rules on a Meraki device
Follow these steps to authenticate your request against the Meraki API so that you can retrieve a list of QoS rules for a specific network and then delete them:
1. Set up a requests session using the API key stored in your environment.
import os
import sys
import requests
base_url = "https://api.meraki.com/api/v1"
key = os.environ.get("MERAKI_DASHBOARD_API_KEY", None)
if key is None:
   print("Please provide an API key. Aborting.")
   sys.exit(-1)
sess = requests.Session()
sess.headers.update({
 " X-Cisco-Meraki-API-Key": key
})

2. With our session set up, we can specify the network ID where we want to delete all our QoS rules and, based on that, specify the URL to retrieve all rules:
network_id = "<Insert network id here>"
url = f"{base_url}/networks/{network_id}/switch/qosRules"
3. Retrieve all the rules that are present:
resp = sess.get(url)
if resp.status_code == 200:
   rules = resp.json()
4. Iterate over all the rules and send a DELETE request using our session, the network ID, and the ID of the rule we want to delete:
 for rule in rules:
   url_del = "{base_url}/networks/{network_id}/switch/qosRules/{rule['id']}"
   resp_del = sess.delete(url_del)
   if resp_del.status_code == 204:
      print(f"Deleted QoS rule {rule['id']}")
5. Finally, we need to check for failing requests and handle them by displaying the status code to the user for further investigation:
  else:
    print(f"Failed on delete request.Status: {resp_del.status_code}")
else:
  print(f"Failed to retrieve rules. Status: {resp.status_code}")

We can also use the Meraki SDK to achieve the same outcome.
import meraki
network_id = "<Insert network id here>"
dashboard = meraki.DashboardAPI()
rules = dashboard.switch.getNetworkSwitchQosRules(network_id)
for rule in rules:
   dashboard.switch.deleteNetworkQosRule(network_id, rule['id'])

ngrok
Ngrok is a tool that provides a secure tunnel for a local application to access the Internet, and for the Internet to access it. This tunneling comes in handy when demoing or testing web sites without having to deploy them. For instance, if you're building an application that subscribes to webhooks, and those webhooks need a callback URL to access the application on your machine, ngrok would provide that address for the webhooks to call.User is required to sign up in order to generate auth token. Supports all 3 protocols.(HTTP / HTTPS, SSH)

Using webhooks to programmatically react to an AP going down
We will also need a HTTP tunnel since the Meraki cloud needs a way of sending a POST request to a server running on your local machine. You can use ngrok for this (https://ngrok.com/). After installation, you can start a new HTTP tunnel by opening a new terminal window and running the ngrok http 8080 command.
You have to set up a webhook from your dashboard that points to the forwarding address specified by ngrok. You can find a guide on how to set up a webhook here: https://documentation.meraki.com/General_Administration/Other_Topics/Webhooks.
Follow these steps to create a lightweight web server that you can receive your Meraki 
webhooks on:
1. Import flask:
from flask import Flask, request
2. Create a new Flask app:
app = Flask("webhook_receiver")
3. In Flask, every HTTP request that gets sent to the server can be handled by a Python function. Set up a function for the root directory of our web server:
@app.route('/', methods=['POST'])
def webhook():
4. Within the webhook function, retrieve the data that is sent by the Meraki webhook:
  data = request.get_json()
5. Check if the alert type is from Air Marshal about a rogue AP and, if that's the case, print out information to the user:
 if data['alertType'] == "Air Marshal - Rogue AP detected":
    print("Rogue AP detected!")
    return {'success': True}
6. Start the Flask app:
if __name__ == "__main__":
   app.run(host='0.0.0.0', port=8080)


 


Responses(0)