Skip to content

Instantly share code, notes, and snippets.

@Elektordi
Created September 14, 2017 16:48
Show Gist options
  • Save Elektordi/fe4a9bd59674bcf671f8c78246caa5e0 to your computer and use it in GitHub Desktop.
Save Elektordi/fe4a9bd59674bcf671f8c78246caa5e0 to your computer and use it in GitHub Desktop.
Python class to access Meraki dashboard as objects
import logging
import httplib
import json
import re
from urlparse import urlparse
LOGGING_NAME = "meraki"
LOG = logging.getLogger("%s.%s" % (LOGGING_NAME, __name__))
class dashboard:
def __init__(self, key):
self.key = key
self.host = "dashboard.meraki.com"
self.conn = httplib.HTTPSConnection(self.host)
def call(self, url, method = "GET", data = None, loop = 0):
if loop > 3:
raise MerakiException("Internal loop", url)
LOG.debug("Dashboard call: %s %s (%r)", method, url, data)
headers = {'X-Cisco-Meraki-API-Key': self.key}
if not data is None:
postdata = json.dumps(data)
headers['Content-Type'] = 'application/json';
else:
postdata = None
try:
self.conn.request(method, "/api/v0/%s"%(url), postdata, headers)
r = self.conn.getresponse()
except httplib.BadStatusLine, httplib.CannotSendRequest:
LOG.debug("httplib error, restarting api client")
self.conn = httplib.HTTPSConnection(self.host)
return self.call(url, method, data, loop+1)
body = r.read()
if r.status >= 500:
if not body:
body = r.reason
raise MerakiException("Server error", url, r.status, body)
if r.status >= 400:
if not body:
body = r.reason
raise MerakiException("Request error", url, r.status, body)
if r.status >= 300:
headers = dict(r.getheaders())
if not 'location' in headers:
raise MerakiException("Redirect without location", url, r.status, r.reason)
parsedurl = urlparse(headers['location'])
if self.host == parsedurl.netloc:
raise MerakiException("Redirect loop: %s"%(headers['location']), url, r.status, r.reason)
self.host = parsedurl.netloc
LOG.debug("Redirected to host %s", self.host)
self.conn.close() # Force reconnect
self.conn = httplib.HTTPSConnection(self.host)
return self.call(url, method, data, loop+1)
try:
body = body.strip()
if body == '':
return None
return json.loads(body)
except ValueError as e:
raise MerakiException("Invalid data", url, r.status, body, e)
def getOrganizations(self):
#BUG API?
return self.call('organizations')
def getOrganization(self, id):
data = self.call('organizations/%d'%(id))
return organization(self, data)
def searchOrganizations(self, name):
#BUG API?
datalist = self.dashboard.call('organizations')
return [network(self.dashboard, data) for data in datalist if data['name'] == name]
class organization:
def __init__(self, dashboard, data):
self.dashboard = dashboard
self._update(data)
def _update(self, data):
self.id = int(data['id'])
self.name = data['name']
def __repr__(self):
return "Meraki Organization '%s'"%(self.name.encode('ascii','replace'))
def getNetworks(self):
datalist = self.dashboard.call('organizations/%d/networks'%(self.id))
return [network(self.dashboard, data) for data in datalist]
def getNetwork(self,id):
data = self.dashboard.call('organizations/%d/networks/%s'%(self.id, id))
return network(self.dashboard, data)
def searchNetworks(self, name):
datalist = self.dashboard.call('organizations/%d/networks'%(self.id))
return [network(self.dashboard, data) for data in datalist if data['name'] == name]
def getInventory(self):
datalist = self.dashboard.call('organizations/%d/inventory'%(self.id))
return [inventory_device(self.dashboard, data) for data in datalist]
def getInventoryDeviceBySerial(self, serial):
datalist = self.dashboard.call('organizations/%d/inventory'%(self.id))
return [inventory_device(self.dashboard, data) for data in datalist if data['serial'] == serial]
def getInventoryDeviceByMac(self, mac):
mac = mac.lower()
datalist = self.dashboard.call('organizations/%d/inventory'%(self.id))
return [inventory_device(self.dashboard, data) for data in datalist if data['mac'] == mac]
def getInventoryRaw(self):
datalist = self.dashboard.call('organizations/%d/inventory'%(self.id))
return datalist
def getConfigTemplates(self):
datalist = self.dashboard.call('organizations/%d/configTemplates'%(self.id))
return [config_template(self.dashboard, data) for data in datalist]
def searchConfigTemplates(self, name):
datalist = self.dashboard.call('organizations/%d/configTemplates'%(self.id))
return [config_template(self.dashboard, data) for data in datalist if data['name'] == name]
def isLicenseOK(self):
datalist = self.dashboard.call('organizations/%d/licenseState'%(self.id))
return datalist['status'] == 'OK'
def getLicenseRaw(self):
datalist = self.dashboard.call('organizations/%d/licenseState'%(self.id))
return datalist
def createNetwork(self, name, tags = 'created_from_api', tz = 'Europe/Paris', type = 'wireless switch'):
post = {'name': name, 'type': type, 'tags': tags, 'timeZone': tz}
data = self.dashboard.call('organizations/%d/networks'%(self.id), 'POST', post)
return network(self.dashboard, data)
class network:
def __init__(self, dashboard, data):
self.dashboard = dashboard
self._update(data)
def _update(self, data):
self.id = data['id']
self.name = data['name']
self.organizationId = int(data['organizationId'])
self.tags = data['tags']
self.timeZone = data['timeZone']
self.type = data['type']
def __repr__(self):
return "Meraki Network '%s'"%(self.name.encode('ascii','replace'))
def getParentOrganization(self):
data = self.dashboard.call('organizations/%d'%(self.organizationId))
return organization(self.dashboard, data)
def getDevices(self):
datalist = self.dashboard.call('networks/%s/devices'%(self.id))
return [device(self.dashboard, data) for data in datalist]
def getDevice(self, serial):
data = self.dashboard.call('networks/%s/devices/%s'%(self.id, serial))
return device(self.dashboard, data)
def addDevices(self, serial):
r = self.dashboard.call('networks/%s/devices/claim'%(self.id), 'POST', {'serial': serial})
return r is None
def removeDevices(self, serial):
r = self.dashboard.call('networks/%s/devices/%s/remove'%(self.id, serial), 'POST')
return r is None
def updateData(self, data):
data = self.dashboard.call('networks/%s'%(self.id), 'PUT', data)
self._update(data)
return True
def bindTemplate(self, template, autobind = True):
r = self.dashboard.call('networks/%s/bind'%(self.id), 'POST', {'configTemplateId': template, 'autoBind': autobind})
return r is None
def unbindTemplate(self):
r = self.dashboard.call('networks/%s/unbind'%(self.id), 'POST')
return r is None
def deleteNetwork(self):
r = self.dashboard.call('networks/%s'%(self.id), 'DELETE')
return r is None
class device:
def __init__(self, dashboard, data):
self.dashboard = dashboard
self._update(data)
def _update(self, data):
self.lat = data['lat']
self.lng = data['lng']
self.address = data['address']
self.lanIp = data['lanIp']
self.serial = data['serial']
self.mac = data['mac']
self.tags = ''
if 'tags' in data:
self.tags = data['tags']
self.name = data['name']
if self.name is None:
self.name = ''
self.model = data['model']
self.networkId = data['networkId']
def __repr__(self):
return "Meraki Device %s '%s' (%s)"%(self.model.encode('ascii','replace'), self.name.encode('ascii','replace'), self.serial.encode('ascii','replace'))
def getParentNetwork(self):
data = self.dashboard.call('networks/%s'%(self.networkId))
return network(self.dashboard, data)
def getUplinks(self):
datalist = self.dashboard.call('networks/%s/devices/%s/uplink'%(self.networkId, self.serial))
return [device_uplink(self.dashboard, data, self) for data in datalist]
def getMainUplink(self):
datalist = self.dashboard.call('networks/%s/devices/%s/uplink'%(self.networkId, self.serial))
if len(datalist)==0:
return None
return device_uplink(self.dashboard, datalist[0], self)
def removeFromNetwork(self):
r = self.dashboard.call('networks/%s/devices/%s/remove'%(self.networkId, self.serial), 'POST')
return r is None
def updateData(self, data):
data = self.dashboard.call('networks/%s/devices/%s'%(self.networkId, self.serial), 'PUT', data)
self._update(data)
return True
class inventory_device:
def __init__(self, dashboard, data):
self.dashboard = dashboard
self._update(data)
def _update(self, data):
self.claimedAt = data['claimedAt']
self.mac = data['mac']
self.model = data['model']
self.networkId = data['networkId']
self.serial = data['serial']
def __repr__(self):
return "Meraki Inventory device %s (%s)"%(self.model.encode('ascii','replace'), self.serial.encode('ascii','replace'))
def getParentNetwork(self):
data = self.dashboard.call('networks/%s'%(self.networkId))
return network(self.dashboard, data)
def isAffected(self):
return not (self.networkId is None)
def getDevice(self):
if self.networkId is None:
return None
data = self.dashboard.call('networks/%s/devices/%s'%(self.networkId, self.serial))
return device(self.dashboard, data)
def addToNetwork(self, network):
r = self.dashboard.call('networks/%s/devices/claim'%(network), 'POST', {'serial': self.serial})
return r is None
def removeFromNetwork(self):
r = self.dashboard.call('networks/%s/devices/%s/remove'%(self.networkId, self.serial), 'POST')
return r is None
class config_template:
def __init__(self, dashboard, data):
self.dashboard = dashboard
self._update(data)
def _update(self, data):
self.id = data['id']
self.name = data['name']
def __repr__(self):
return "Meraki Config template '%s'"%(self.name.encode('ascii','replace'))
class device_uplink:
def __init__(self, dashboard, data, device):
self.dashboard = dashboard
self.device = device
self._update(data)
def _update(self, data):
self.interface = data['interface']
self.status = data['status']
if 'ip' in data:
self.ip = data['ip']
self.gateway = data['gateway']
self.publicIp = data['publicIp']
self.dns = data['dns']
self.usingStaticIp = data['usingStaticIp']
else:
self.ip = None
self.gateway = None
self.publicIp = None
self.dns = None
self.usingStaticIp = None
def getParentDevice(self):
return self.device
def isOK(self):
return self.status == 'Active'
def __repr__(self):
return "Meraki device uplink %s (%s)"%(self.interface.encode('ascii','replace'), self.device.name.encode('ascii','replace'))
class MerakiException(Exception):
def __init__(self, msg, url, code = 0, data = None, parent = None):
self.msg = msg
self.url = url
self.code = code
self.data = data
self.parent = parent
def __str__(self):
if self.parent:
return "%s %r (URL=%s)"%(self.msg, self.parent, self.url)
else:
return "%s %d %s (URL=%s)"%(self.msg, self.code, self.data, self.url)
def __repr__(self):
if self.parent:
return "%s (%r)"%(self.msg, self.parent)
else:
return "%s (%d)"%(self.msg, self.code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment