Use Meraki API to get VLAN information

Solved
hewithaname
Here to help

Use Meraki API to get VLAN information

Hello There,

 

I just started a new job and have been tasked with gathering information from our Meraki switches. I have not worked with Meraki's API before and am having some trouble getting the information I want.  

 

My primary goal is to get a list of every vlan and its cidr network.  Example:

10, 10.0.1.0/24

20, 192.168.0.0/16

...

100, 10.0.5.0/24

 

My follow up goal is to get a list of all devices, their macs, and what vlan they are on. Example:

hostname, mac, vlan

 

I have been reading the API Docs to try and figure out how to do this but am stuck.  I am using their python module to do this.  I got it from their GitHub.  I am still very new to this so I apologize for my lack of progress here.

 

import meraki

dashboard = meraki.DashboardAPI()
my_orgs = dashboard.organizations.getOrganizations()
org_id = my_orgs[0]['id']

print(dashboard)
print(my_orgs)

 

However I can not seem to get the information I need from this.  I took a look at the get network vlans page since it seemed to have the information I wanted, but when I tried to call this method, I got an error.

 

>> dashboard.organizations.networks('111111')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Organizations' object has no attribute 'networks'

 

If anyone could help me figure this all out I would be forever grateful.  I feel like these two exports of information are relatively easy and I am just missing something simple.

 

Thanks!

1 Accepted Solution
hewithaname
Here to help

So I am fairly confident I narrowed down the issue.  It would seem that if I install any of the other meraki modules it will cause errors.  For example, if I start a project and only install meraki, it will work.  However, if I also install merakiapi, it will error out.  Maybe there is a confliction.  

Now that I have a better understanding of the API, I can rephrase what I am looking for.

 

1) I want a list of all the VLANs currently in use on the network.

 

2) I want a list of all hosts and their mac/ips that are getting an ip from the dhcp server that is running on our meraki ms425.  The end goal here is to migrate off of meraki dhcp and onto windows server dhcp.  However, in order to do that we would need a csv of { hostname, mac, ip ( and any other information meraki could provide if possible ( ie dns, gateway, etc) }.  Powershell can take care of the rest.  

 

Here is the updated script for anyone that would like it

 

import meraki as mer
from pprint import pprint as pp
import csv

'''
Utility functions to be made as we go
'''
# This will get us all of our network ids
def getNetworkIDS(inventory):
network_ids = set() # a set keeps unique values

for device in inventory:
network_id = device["networkId"]
if network_id is not None:
network_ids.add(network_id)
return network_ids

# This will output our inventory as a csv file for further reading
def dictToCSV(inventory):
keys = inventory[0].keys()
with open('inventory.csv', 'w', encoding='utf8', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, fieldnames=inventory[0].keys())
dict_writer.writeheader()
dict_writer.writerows(inventory)

# Start our API calls by creating a dashboard instance
dashboard = mer.DashboardAPI(api_key = "fdgssgdffgdsfdghshgsfd", print_console=False)

# Next we get our organization information
organizations = dashboard.organizations.getOrganizations()

# Next we will get an inventory of our devices
inventory = dashboard.organizations.getOrganizationInventory(organizations[0]['id'])

# Since our inventory consists of APs we will need to filter those out
network_ids = set()
for item in inventory:
if not item['model'] == 'MR42' and item["networkId"]:
network_ids.add(item["networkId"])

vlan_csv = 'Network ID, VLAN ID,VLAN Name,Gateway,CIDR,DNS Servers\n'
for network_id in network_ids:

'''
This does not print out anything useful but it was an attempt
{'defaultPolicy': 'allow', 'blockedServers': []}
'''
try:
print(dashboard.switch_settings.getNetworkSwitchSettingsDhcpServerPolicy(network_id))
except mer.exceptions.APIError as err:
# Error handling is hard so I make it easy by doing something terrible
print("There was an error trying to get the DHCP information from %s \n %s" % (network_id, err))

'''
The goal here is to go into each switch, and see what vlans each port is advertising.
I want to get a list of all VLANs currently in the network
'''
try:
for vlan in dashboard.vlans.getNetworkVlans(network_id):
print("\nWorking with Network ID : %s\n" % network_id)

vlan_id = str(vlan['id'])
name = str(vlan['name'])
gateway = str(vlan['applianceIp'])
cidr = str(vlan['subnet'])
dns = str(str(vlan['dnsNameservers']).replace("\n", ":"))
dhcpHandling = str(vlan['dhcpHandling'])
#dhcpBootOptionsEnabled = vlan['dhcpBootOptionsEnabled']
row = str(','.join([network_id, vlan_id, name, gateway, cidr, dns, dhcpHandling])) + "\n"
vlan_csv += row
except mer.exceptions.APIError as err:
# Error handling is hard so I make it easy by doing something terrible
print("There was an error trying to get the VLANS from %s \n %s" % (network_id, err))

print("\n RESULTS \n")
print(vlan_csv)

 

 

View solution in original post

10 Replies 10
BrechtSchamp
Kind of a big deal

Two things. First, I'd have a good look at the API reference to determine a plan that'll get you the information you need.

 

For example. You can find out what devices you have in the network by querying the inventory. That'll likely save you some other steps:

https://www.apimatic.io/api-docs/meraki-api/v/0_6_0#/rest/api-endpoints/organizations/get-organizati...

 

To get the VLANs you'll need the following call:

https://www.apimatic.io/api-docs/meraki-api/v/0_6_0#/rest/api-endpoints/vlans/get-network-vlans

 

That call needs the network IDs so you'll also need a list of networks. But as you will see, the inventory call also returned the network IDs of the devices, so you could compile a list from there.

 

Now for the actual code. I'd recommend to setup a Python project in PyCharm or something alike. As soon as you've imported the meraki module into it, it can start giving you code hints. That'll make everything much easier for you:

image.png

 

To do that, in short, you need to create a project in pyCharm and the key is to go to the project properties like this:

image.png

 

In there you can add the meraki library to your project like this:

image.png

 

You may also want to try to simulate your plan via Postman first... That will allow you to test the calls and see their results before actually starting the coding:

https://developer.cisco.com/meraki/build/meraki-postman-collection-getting-started/

 

hewithaname
Here to help

Thank you so much for all of this information.  I completely forgot about pycharm as it has been a while since I have coded in python.  I also did not know about postman and I will work with that as well.  This should be enough information for me to go on for now so I will continue diving and come back later if I run into any issues 

hewithaname
Here to help

I think pycharm is not happy with the meraki module.  After following your steps I get the error of " AttributeError: module 'meraki' has no attribute 'DashboardAPI' ".  My code is literally just 

 

import meraki
dashboard = meraki.DashboardAPI(api_key="1234567890abcdefghijk")

 

Edit: turns out I just needed to look at the source code.  

 

import meraki

dashboard = meraki.Dashboard(api_key="1234567890abcdefghijk")
hewithaname
Here to help

So I hit a wall with this.  I can see in the meraki package that there are two folders, api and modules.  If I want to get an instance of a module I need to do the following:

import meraki

dashboard = meraki.Dashboard(api_key="1234567890abcdefghijk")
organizations = dashboard.__getattr__(name="organizations"
networks = dashboard.__getattr__(name="networks")

 

By looking at the source code, I can see the functions that I can use for each of those instances.  For some reason, pycharm does not show what I can use so I have been manually looking.  

 

I am currently working on getting the VLANS

https://www.apimatic.io/api-docs/meraki-api/v/0_6_0#/rest/api-endpoints/vlans/get-network-vlans

 

I have a list of all the network ids that I have gathered from performing the inventory call on my organization.  However, I do not know how I can make the above API call.  The networks class has no "vlans" function and "vlans.py" is located in the api folder with no references made to it.  So how would I access this module?

 

Thank you again for your help!

 

 

My current (messy w.i.p.) code:

import meraki
from pprint import pprint as pp
import csv

'''
Utility functions to be made as we go
'''
# This will get us all of our network ids
def getNetworkIDS(inventory):
network_ids = list()
for dicts in inventory:
# This will make sure that we are only adding valid network ids
id = dicts['networkId']
if id:
network_ids.append(id)
return network_ids

# This will output our inventory as a csv file for further reading
def dictToCSV(inventory):
keys = inventory[0].keys()
with open('inventory.csv', 'w', encoding='utf8', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, fieldnames=inventory[0].keys())
dict_writer.writeheader()
dict_writer.writerows(inventory)

# Start our API calls by creating a dashboard instance
dashboard = meraki.Dashboard(api_key="1234567890abcdefghijk")

# In order to access the modules, we need to use the __getattr__ function
# It will return to us an instance of that module
# Other modules include admins, base, clients, devices, networks, organizations, and ssids
organizations = dashboard.__getattr__(name="organizations")
networks = dashboard.__getattr__(name="networks")


# Next we will get an inventory of our devices
# inventory = organizations.inventory(org='123456')
# network_ids = getNetworkIDS(inventory)

vlans = meraki.api.vlans()
BrechtSchamp
Kind of a big deal

This should get you a bit further. I think you used an older method to create the dashboard object. It think that's why it wasn't showing the code hints (Dashboard() vs DashboardAPI())

 


import meraki
from pprint import pprint as pp
import csv

'''
Utility functions to be made as we go
'''
# This will get us all of our network ids
def getNetworkIDS(inventory):
    network_ids = set() # a set keeps unique values

    for device in inventory:
        network_id = device["networkId"]
        if network_id is not None:
            network_ids.add(network_id)
    return network_ids

# This will output our inventory as a csv file for further reading
def dictToCSV(inventory):
    keys = inventory[0].keys()
    with open('inventory.csv', 'w', encoding='utf8', newline='') as output_file:
        dict_writer = csv.DictWriter(output_file, fieldnames=inventory[0].keys())
        dict_writer.writeheader()
        dict_writer.writerows(inventory)

# Start our API calls by creating a dashboard instance
dashboard = meraki.DashboardAPI(api_key = "aaabbbbccccdddd12345678")

# In order to access the modules, we need to use the __getattr__ function
# It will return to us an instance of that module
# Other modules include admins, base, clients, devices, networks, organizations, and ssids
organizations = dashboard.organizations.getOrganizations()



# Next we will get an inventory of our devices
inventory = dashboard.organizations.getOrganizationInventory(1234567)
network_ids = getNetworkIDS(inventory)

print(network_ids)

for network_id in network_ids:
    print(network_id, ":")
    print(dashboard.vlans.getNetworkVlans(network_id))

 

hewithaname
Here to help

I apologize as I probably should have included this but I tried using DashboardAPI() but ran into errors.  I eventually found a way around it which was to use the Dashboard().  

 

C:/Users/user/PycharmProjects/meraki/Get-VLANInfo.py
Traceback (most recent call last):
File "C:/Users/adam.littrell/PycharmProjects/meraki/Get-VLANInfo.py", line 27, in <module>
dashboard = meraki.DashboardAPI(api_key="1234567890abcdefghijk")
AttributeError: module 'meraki' has no attribute 'DashboardAPI'

 

BrechtSchamp
Kind of a big deal

I wonder if you're using an older version of the module.

 

What version does it say in the project settings (where you add the meraki module)? I'm using 0.80.3.

 

Also, what version of Python are you using?  I'm using 3.7.

hewithaname
Here to help

I will take a look at getting python 3.7 installed and setup a new project with it and see if that helps.  In the meantime, here is all the information

 

Python Version: 

C:\WINDOWS\system32› python --version
Python 3.8.2

 

PyCharm Version:

hewithaname_0-1583328164862.png

 

Meraki Module Version:

hewithaname_1-1583328211530.png

 

 

 

 

hewithaname
Here to help

Python 3.7.6 works????  Very interesting.......  It would appear things are working correctly now.  I have all the auto complete features too.  Maybe this is a bug with their module?  Not sure.  Regardless.  Thank you very much for taking the time to help me out.  Once I have a completed script I will post it here so that the people that come after me can use it.  

hewithaname
Here to help

So I am fairly confident I narrowed down the issue.  It would seem that if I install any of the other meraki modules it will cause errors.  For example, if I start a project and only install meraki, it will work.  However, if I also install merakiapi, it will error out.  Maybe there is a confliction.  

Now that I have a better understanding of the API, I can rephrase what I am looking for.

 

1) I want a list of all the VLANs currently in use on the network.

 

2) I want a list of all hosts and their mac/ips that are getting an ip from the dhcp server that is running on our meraki ms425.  The end goal here is to migrate off of meraki dhcp and onto windows server dhcp.  However, in order to do that we would need a csv of { hostname, mac, ip ( and any other information meraki could provide if possible ( ie dns, gateway, etc) }.  Powershell can take care of the rest.  

 

Here is the updated script for anyone that would like it

 

import meraki as mer
from pprint import pprint as pp
import csv

'''
Utility functions to be made as we go
'''
# This will get us all of our network ids
def getNetworkIDS(inventory):
network_ids = set() # a set keeps unique values

for device in inventory:
network_id = device["networkId"]
if network_id is not None:
network_ids.add(network_id)
return network_ids

# This will output our inventory as a csv file for further reading
def dictToCSV(inventory):
keys = inventory[0].keys()
with open('inventory.csv', 'w', encoding='utf8', newline='') as output_file:
dict_writer = csv.DictWriter(output_file, fieldnames=inventory[0].keys())
dict_writer.writeheader()
dict_writer.writerows(inventory)

# Start our API calls by creating a dashboard instance
dashboard = mer.DashboardAPI(api_key = "fdgssgdffgdsfdghshgsfd", print_console=False)

# Next we get our organization information
organizations = dashboard.organizations.getOrganizations()

# Next we will get an inventory of our devices
inventory = dashboard.organizations.getOrganizationInventory(organizations[0]['id'])

# Since our inventory consists of APs we will need to filter those out
network_ids = set()
for item in inventory:
if not item['model'] == 'MR42' and item["networkId"]:
network_ids.add(item["networkId"])

vlan_csv = 'Network ID, VLAN ID,VLAN Name,Gateway,CIDR,DNS Servers\n'
for network_id in network_ids:

'''
This does not print out anything useful but it was an attempt
{'defaultPolicy': 'allow', 'blockedServers': []}
'''
try:
print(dashboard.switch_settings.getNetworkSwitchSettingsDhcpServerPolicy(network_id))
except mer.exceptions.APIError as err:
# Error handling is hard so I make it easy by doing something terrible
print("There was an error trying to get the DHCP information from %s \n %s" % (network_id, err))

'''
The goal here is to go into each switch, and see what vlans each port is advertising.
I want to get a list of all VLANs currently in the network
'''
try:
for vlan in dashboard.vlans.getNetworkVlans(network_id):
print("\nWorking with Network ID : %s\n" % network_id)

vlan_id = str(vlan['id'])
name = str(vlan['name'])
gateway = str(vlan['applianceIp'])
cidr = str(vlan['subnet'])
dns = str(str(vlan['dnsNameservers']).replace("\n", ":"))
dhcpHandling = str(vlan['dhcpHandling'])
#dhcpBootOptionsEnabled = vlan['dhcpBootOptionsEnabled']
row = str(','.join([network_id, vlan_id, name, gateway, cidr, dns, dhcpHandling])) + "\n"
vlan_csv += row
except mer.exceptions.APIError as err:
# Error handling is hard so I make it easy by doing something terrible
print("There was an error trying to get the VLANS from %s \n %s" % (network_id, err))

print("\n RESULTS \n")
print(vlan_csv)

 

 

Get notified when there are additional replies to this discussion.