Created
September 14, 2017 16:48
-
-
Save Elektordi/fe4a9bd59674bcf671f8c78246caa5e0 to your computer and use it in GitHub Desktop.
Python class to access Meraki dashboard as objects
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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