def __init__(self, conf={}, daoClass=Dao): if any(conf) == False: self._openclosProperty = OpenClosProperty(appName=moduleName) self._conf = self._openclosProperty.getProperties() global webServerRoot webServerRoot = self._conf['outputDir'] else: self._conf = conf self.__daoClass = daoClass self.__dao = daoClass.getInstance() self.openclosDbSessionPlugin = OpenclosDbSessionPlugin(daoClass) if 'httpServer' in self._conf and 'ipAddr' in self._conf[ 'httpServer'] and self._conf['httpServer'][ 'ipAddr'] is not None: self.host = self._conf['httpServer']['ipAddr'] else: self.host = 'localhost' if 'httpServer' in self._conf and 'port' in self._conf['httpServer']: self.port = self._conf['httpServer']['port'] else: self.port = 8080 self.baseUrl = 'http://%s:%d' % (self.host, self.port) self.report = ResourceAllocationReport(self._conf, daoClass) # Create a single instance of l2Report as it holds thread-pool # for device connection. Don't create l2Report multiple times self.l2Report = L2Report(self._conf, daoClass) # Create a single instance of l3Report as it holds thread-pool # for device connection. Don't create l3Report multiple times self.l3Report = L3Report(self._conf, daoClass) self.deviceSku = DeviceSku()
def getIpFabric(self, ipFabricId): report = ResourceAllocationReport(dao = self.dao) ipFabric = report.getIpFabric(ipFabricId) if ipFabric is not None: devices = ipFabric.devices #Detaching the object from session session = Session.object_session(ipFabric) session.expunge(ipFabric) ipFabric.__dict__.pop('_sa_instance_state') ipFabric.__dict__.pop('spineJunosImage') ipFabric.__dict__.pop('leafJunosImage') ipFabric.__dict__.pop('inventoryData') ipFabric.__dict__['devices'] = {'uri': bottle.request.url + '/devices', 'total':len(devices)} ipFabric.__dict__['cablingPlan'] = {'uri': bottle.request.url + '/cabling-plan'} ipFabric.__dict__['deviceConfiguration'] = {'uri': bottle.request.url + '/device-configuration'} ipFabric.__dict__['ztpConfiguration'] = {'uri': bottle.request.url + '/ztp-configuration'} logger.debug('getIpFabric: %s' % (ipFabricId)) #return json.dumps(ipFabric.__dict__) return {'ipFabric': ipFabric.__dict__} else: logger.debug("IpFabric with id: %s not found" % (ipFabricId)) raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId))
def deleteIpFabric(self, ipFabricId): report = ResourceAllocationReport(dao = self.dao) ipFabric = report.getIpFabric(ipFabricId) if ipFabric is not None: report.dao.deleteObject(ipFabric) logger.debug("IpFabric with id: %s deleted" % (ipFabricId)) else: logger.debug("IpFabric with id: %s not found" % (ipFabricId)) raise bottle.HTTPError(204, "IpFabric with id: %s not found" % (ipFabricId)) return bottle.HTTPResponse(status=200)
def deleteIpFabric(self, ipFabricId): report = ResourceAllocationReport(dao=self.dao) ipFabric = report.getIpFabric(ipFabricId) if ipFabric is not None: report.dao.deleteObject(ipFabric) logger.debug("IpFabric with id: %s deleted" % (ipFabricId)) else: logger.debug("IpFabric with id: %s not found" % (ipFabricId)) raise bottle.HTTPError( 204, "IpFabric with id: %s not found" % (ipFabricId)) return bottle.HTTPResponse(status=200)
def handle_deploy_ztp_config(self, pod_id): ## Find the Pod Object report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_object = report._dao.getObjectById(session, Pod, pod_id) podDirectoryName = "%s-%s" % (pod_id, pod_object.name) installedDhcpConf = "/etc/dhcp/dhcpd.conf" ## Generate the path to the dhcp conf generatedDhcpConf = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'out', podDirectoryName, "dhcpd.conf") if not os.path.isfile(generatedDhcpConf): print "DHCP configuration file has not been generated for Pod %s yet, will generate it first" % pod_id ztpServer = ZtpServer() ztpServer.createPodSpecificDhcpConfFile(session, pod_id) if util.isPlatformUbuntu(): os.system('sudo cp ' + generatedDhcpConf + ' ' + installedDhcpConf) print "New configuration file copied to %s " % installedDhcpConf os.system("/etc/init.d/isc-dhcp-server restart") elif util.isPlatformCentos(): os.system('sudo cp ' + generatedDhcpConf + ' ' + installedDhcpConf) print "New configuration file copied to %s " % installedDhcpConf os.system("/etc/rc.d/init.d/dhcpd restart")
def __init__(self, conf = {}, daoClass = Dao): global logger if any(conf) == False: self.__conf = util.loadConfig(appName = moduleName) global webServerRoot webServerRoot = self.__conf['outputDir'] else: self.__conf = conf logger = logging.getLogger(moduleName) self.__daoClass = daoClass self.__dao = daoClass.getInstance() self.openclosDbSessionPlugin = OpenclosDbSessionPlugin(daoClass) if 'httpServer' in self.__conf and 'ipAddr' in self.__conf['httpServer'] and self.__conf['httpServer']['ipAddr'] is not None: self.host = self.__conf['httpServer']['ipAddr'] else: self.host = 'localhost' if 'httpServer' in self.__conf and 'port' in self.__conf['httpServer']: self.port = self.__conf['httpServer']['port'] else: self.port = 8080 self.baseUrl = 'http://%s:%d' % (self.host, self.port) self.report = ResourceAllocationReport(self.__conf, daoClass) # Create a single instance of l2Report as it holds thread-pool # for device connection. Don't create l2Report multiple times self.l2Report = L2Report(self.__conf, daoClass) # Create a single instance of l3Report as it holds thread-pool # for device connection. Don't create l3Report multiple times self.l3Report = L3Report(self.__conf, daoClass)
def handle_show_all_pods_detail(self, *args): print "---------------------------------------------------------------" report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_objects = report._dao.getAll(session, Pod) for pod in pod_objects: self.show_pod_detail(pod) print "---------------------------------------------------------------"
def list_all_pods_from_db(self, prev_macro, add_help=None, *args): ret_list = [] report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_objects = report._dao.getAll(session, Pod) for pod in pod_objects: pod_str = pod.id if (add_help != None): pod_str = pod_str + " <UUID of Pod [" + pod.name + "]>" ret_list.append(pod_str) if (len(ret_list) == 0): ret_list.insert(0, "Error:") ret_list.append("No POD definitions found in the database") return ret_list
def getIpFabric(self, ipFabricId): report = ResourceAllocationReport(dao=self.dao) ipFabric = report.getIpFabric(ipFabricId) if ipFabric is not None: devices = ipFabric.devices #Detaching the object from session session = Session.object_session(ipFabric) session.expunge(ipFabric) ipFabric.__dict__.pop('_sa_instance_state') ipFabric.__dict__.pop('spineJunosImage') ipFabric.__dict__.pop('leafJunosImage') ipFabric.__dict__.pop('inventoryData') ipFabric.__dict__['devices'] = { 'uri': bottle.request.url + '/devices', 'total': len(devices) } ipFabric.__dict__['cablingPlan'] = { 'uri': bottle.request.url + '/cabling-plan' } ipFabric.__dict__['deviceConfiguration'] = { 'uri': bottle.request.url + '/device-configuration' } ipFabric.__dict__['ztpConfiguration'] = { 'uri': bottle.request.url + '/ztp-configuration' } logger.debug('getIpFabric: %s' % (ipFabricId)) #return json.dumps(ipFabric.__dict__) return {'ipFabric': ipFabric.__dict__} else: logger.debug("IpFabric with id: %s not found" % (ipFabricId)) raise bottle.HTTPError( 404, "IpFabric with id: %s not found" % (ipFabricId))
def list_all_devices_from_pod(self, prev_macro, add_help=None, *args): ret_list = [] report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_objects = report._dao.getAll(session, Pod) for pod in pod_objects: pod_spine = pod.spineDeviceType if (add_help != None): pod_spine = pod_spine + " <UUID of Pod [" + pod.name + "]>" if pod_spine != None: ret_list.append(pod_spine) if (len(ret_list) == 0): ret_list.insert(0, "Error:") ret_list.append("No Device definitions found in the database") return ret_list
def handle_update_pods(self, pod_id): l3ClosMediation = L3ClosMediation() ## Get Object for this Pod based on ID ## Get Data from config file report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_object = report._dao.getObjectById(session, Pod, pod_id) pod_name = pod_object.name pods_from_conf = l3ClosMediation.loadClosDefinition() l3ClosMediation.updatePod(pod_id, pods_from_conf[pod_name]) ## Regenerate devices configuration, cabling plan and ZTP configuration l3ClosMediation.createCablingPlan(pod_id) l3ClosMediation.createDeviceConfig(pod_id) ztpServer = ZtpServer() ztpServer.createPodSpecificDhcpConfFile(session, pod_id)
def handle_create_ztp_config(self, pod_name): report = ResourceAllocationReport() with report._dao.getReadSession() as session: ztpServer = ZtpServer() ztpServer.createPodSpecificDhcpConfFile(session, pod_name)
def handle_show_pod_detail(self, pod_id, *args): report = ResourceAllocationReport() with report._dao.getReadSession() as session: pod_object = report._dao.getObjectById(session, Pod, pod_id) self.show_pod_detail(pod_object)
class RestServer(): def __init__(self, conf = {}, daoClass = Dao): global logger if any(conf) == False: self.__conf = util.loadConfig(appName = moduleName) global webServerRoot webServerRoot = self.__conf['outputDir'] else: self.__conf = conf logger = logging.getLogger(moduleName) self.__daoClass = daoClass self.__dao = daoClass.getInstance() self.openclosDbSessionPlugin = OpenclosDbSessionPlugin(daoClass) if 'httpServer' in self.__conf and 'ipAddr' in self.__conf['httpServer'] and self.__conf['httpServer']['ipAddr'] is not None: self.host = self.__conf['httpServer']['ipAddr'] else: self.host = 'localhost' if 'httpServer' in self.__conf and 'port' in self.__conf['httpServer']: self.port = self.__conf['httpServer']['port'] else: self.port = 8080 self.baseUrl = 'http://%s:%d' % (self.host, self.port) self.report = ResourceAllocationReport(self.__conf, daoClass) # Create a single instance of l2Report as it holds thread-pool # for device connection. Don't create l2Report multiple times self.l2Report = L2Report(self.__conf, daoClass) # Create a single instance of l3Report as it holds thread-pool # for device connection. Don't create l3Report multiple times self.l3Report = L3Report(self.__conf, daoClass) def initRest(self): self.addRoutes(self.baseUrl) self.app = bottle.app() self.app.install(loggingPlugin) self.app.install(self.openclosDbSessionPlugin) logger.info('RestServer initRest() done') def _reset(self): """ Resets the state of the rest server and application Used for Test only """ self.app.uninstall(loggingPlugin) self.app.uninstall(OpenclosDbSessionPlugin) def start(self): logger.info('REST server starting at %s:%d' % (self.host, self.port)) debugRest = False if logger.isEnabledFor(logging.DEBUG): debugRest = True if util.isSqliteUsed(self.__conf): bottle.run(self.app, host=self.host, port=self.port, debug=debugRest) else: bottle.run(self.app, host=self.host, port=self.port, debug=debugRest, server='paste') @staticmethod @error(400) def error400(error): bottle.response.headers['Content-Type'] = 'application/json' if error.exception is not None: return json.dumps({'errorCode': error.exception.errorId , 'errorMessage' : error.exception.errorMessage}) else: return json.dumps({'errorCode': 0, 'errorMessage' : 'A generic error occurred'}) def addRoutes(self, baseUrl): self.indexLinks = [] # GET APIs bottle.route('/', 'GET', self.getIndex) bottle.route('/openclos', 'GET', self.getIndex) bottle.route('/openclos/conf', 'GET', self.getOpenClosConfigParams) bottle.route('/openclos/ip-fabrics', 'GET', self.getIpFabrics) bottle.route('/openclos/images/<junosImageName>', 'GET', self.getJunosImage) bottle.route('/openclos/ip-fabrics/<ipFabricId>', 'GET', self.getIpFabric) bottle.route('/openclos/ip-fabrics/<ipFabricId>/cabling-plan', 'GET', self.getCablingPlan) bottle.route('/openclos/ip-fabrics/<ipFabricId>/ztp-configuration','GET', self.getZtpConfig) bottle.route('/openclos/ip-fabrics/<ipFabricId>/device-configuration', 'GET', self.getDeviceConfigsInZip) bottle.route('/openclos/ip-fabrics/<ipFabricId>/leaf-generic-configurations/<deviceModel>', 'GET', self.getLeafGenericConfiguration) bottle.route('/openclos/ip-fabrics/<ipFabricId>/l2-report', 'GET', self.getL2Report) bottle.route('/openclos/ip-fabrics/<ipFabricId>/l3-report', 'GET', self.getL3Report) bottle.route('/openclos/ip-fabrics/<ipFabricId>/devices', 'GET', self.getDevices) bottle.route('/openclos/ip-fabrics/<ipFabricId>/devices/<deviceId>', 'GET', self.getDevice) bottle.route('/openclos/ip-fabrics/<ipFabricId>/devices/<deviceId>/config', 'GET', self.getDeviceConfig) # POST/PUT APIs bottle.route('/openclos/ip-fabrics', 'POST', self.createIpFabric) bottle.route('/openclos/ip-fabrics/<ipFabricId>/cabling-plan', 'PUT', self.createCablingPlan) bottle.route('/openclos/ip-fabrics/<ipFabricId>/device-configuration', 'PUT', self.createDeviceConfiguration) bottle.route('/openclos/ip-fabrics/<ipFabricId>/ztp-configuration', 'PUT', self.createZtpConfiguration) bottle.route('/openclos/ip-fabrics/<ipFabricId>', 'PUT', self.reconfigIpFabric) bottle.route('/openclos/conf/', 'PUT', self.setOpenClosConfigParams) # DELETE APIs bottle.route('/openclos/ip-fabrics/<ipFabricId>', 'DELETE', self.deleteIpFabric) self.createLinkForConfigs() def createLinkForConfigs(self): # index page should show all top level URLs # users whould be able to drill down through navigation self.indexLinks.append(ResourceLink(self.baseUrl, '/openclos/ip-fabrics')) self.indexLinks.append(ResourceLink(self.baseUrl, '/openclos/conf')) def getIndex(self, dbSession=None): if 'openclos' not in bottle.request.url: bottle.redirect(bottle.request.url + 'openclos') jsonLinks = [] for link in self.indexLinks: jsonLinks.append({'link': link.toDict()}) jsonBody = \ {'href': bottle.request.url, 'links': jsonLinks } return jsonBody def getIpFabrics(self, dbSession): url = bottle.request.url ipFabricsData = {} listOfIpFbarics = [] IpFabrics = self.report.getPods(dbSession) logger.debug("count of ipFabrics: %d", len(IpFabrics)) if not IpFabrics : logger.debug("There are no ipFabrics in the system ") for i in range(len(IpFabrics)): ipFabric = {} ipFabric['uri'] = url +'/'+ IpFabrics[i]['id'] ipFabric['id'] = IpFabrics[i]['id'] ipFabric['name'] = IpFabrics[i]['name'] ipFabric['spineDeviceType'] = IpFabrics[i]['spineDeviceType'] ipFabric['spineCount'] = IpFabrics[i]['spineCount'] ipFabric['leafSettings'] = IpFabrics[i]['leafSettings'] ipFabric['leafCount'] = IpFabrics[i]['leafCount'] ipFabric['devicePassword'] = IpFabrics[i]['devicePassword'] listOfIpFbarics.append(ipFabric) ipFabricsData['ipFabric'] = listOfIpFbarics ipFabricsData['total'] = len(listOfIpFbarics) ipFabricsData['uri'] = url return {'ipFabrics' : ipFabricsData} def getIpFabric(self, dbSession, ipFabricId, requestUrl = None): if requestUrl is None: requestUrl = bottle.request.url ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is not None: outputDict = {} devices = ipFabric.devices outputDict['id'] = ipFabric.id outputDict['name'] = ipFabric.name outputDict['description'] = ipFabric.description outputDict['spineAS'] = ipFabric.spineAS outputDict['spineDeviceType'] = ipFabric.spineDeviceType outputDict['spineCount'] = ipFabric.spineCount outputDict['leafAS'] = ipFabric.leafAS outputDict['leafSettings'] = [] for leafSetting in ipFabric.leafSettings: outputDict['leafSettings'].append({'deviceType': leafSetting.deviceFamily, 'junosImage': leafSetting.junosImage}) outputDict['leafCount'] = ipFabric.leafCount outputDict['loopbackPrefix'] = ipFabric.loopbackPrefix outputDict['vlanPrefix'] = ipFabric.vlanPrefix outputDict['interConnectPrefix'] = ipFabric.interConnectPrefix outputDict['managementPrefix'] = ipFabric.managementPrefix outputDict['outOfBandAddressList'] = ipFabric.outOfBandAddressList outputDict['outOfBandGateway'] = ipFabric.outOfBandGateway outputDict['topologyType'] = ipFabric.topologyType outputDict['spineJunosImage'] = ipFabric.spineJunosImage outputDict['devicePassword'] = ipFabric.getCleartextPassword() outputDict['uri'] = requestUrl outputDict['devices'] = {'uri': requestUrl + '/devices', 'total':len(devices)} outputDict['cablingPlan'] = {'uri': requestUrl + '/cabling-plan'} outputDict['deviceConfiguration'] = {'uri': requestUrl + '/device-configuration'} outputDict['ztpConfiguration'] = {'uri': requestUrl + '/ztp-configuration'} outputDict['l2Report'] = {'uri': requestUrl + '/l2-report'} outputDict['l3Report'] = {'uri': requestUrl + '/l3-report'} logger.debug('getIpFabric: %s' % (ipFabricId)) return {'ipFabric': outputDict} else: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) def getCablingPlan(self, dbSession, ipFabricId): header = bottle.request.get_header('Accept') logger.debug('Accept header: %s' % (header)) ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is not None: logger.debug('IpFabric name: %s' % (ipFabric.name)) if header == 'application/json': cablingPlan = ipFabric.cablingPlan if cablingPlan is not None and cablingPlan.json is not None: logger.debug('CablingPlan found in DB') return cablingPlan.json else: raise bottle.HTTPError(404, "IpFabric: %s exists but no CablingPlan found in DB" % (ipFabric.id)) else: ipFabricFolder = ipFabric.id + '-' + ipFabric.name fileName = os.path.join(ipFabricFolder, 'cablingPlan.dot') logger.debug('webServerRoot: %s, fileName: %s, exists: %s' % (webServerRoot, fileName, os.path.exists(os.path.join(webServerRoot, fileName)))) logger.debug('Cabling file name: %s' % (fileName)) cablingPlan = bottle.static_file(fileName, root=webServerRoot) if isinstance(cablingPlan, bottle.HTTPError): raise bottle.HTTPError(404, "IpFabric exists but no CablingPlan found. IpFabric: '%s " % (ipFabricFolder)) return cablingPlan else: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) def getLeafGenericConfiguration(self, dbSession, ipFabricId, deviceModel): ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is None: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) logger.debug('IpFabric name: %s, id: %s' % (ipFabric.name, ipFabricId)) leafSetting = self.__dao.getLeafSetting(dbSession, ipFabricId, deviceModel) if leafSetting is None or leafSetting.config is None: raise bottle.HTTPError(404, "IpFabric exists but no leaf generic config found, probably configuration \ was not created. deviceModel: %s, ipFabric name: '%s', id: '%s'" % (deviceModel, ipFabric.name, ipFabricId)) bottle.response.headers['Content-Type'] = 'application/json' return leafSetting.config def getDeviceConfigsInZip(self, dbSession, ipFabricId): ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is None: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) logger.debug('IpFabric name: %s' % (ipFabric.name)) zippedConfigFiles = self.createZipArchive(ipFabric) if zippedConfigFiles is not None: bottle.response.headers['Content-Type'] = 'application/zip' return zippedConfigFiles else: raise bottle.HTTPError(404, "IpFabric exists but no configs for devices.'%s " % (ipFabric.name)) def createZipArchive(self, ipFabric): buff = StringIO.StringIO() zipArchive = zipfile.ZipFile(buff, mode='w') for device in ipFabric.devices: fileName = device.id + '__' + device.name + '.conf' if device.config is not None: zipArchive.writestr(fileName, device.config.config) if ipFabric.leafSettings is not None: for leafSetting in ipFabric.leafSettings: if leafSetting.config is not None: zipArchive.writestr(leafSetting.deviceFamily + '.conf', leafSetting.config) zipArchive.close() logger.debug('zip file content:\n' + str(zipArchive.namelist())) return buff.getvalue() def getDevices(self, dbSession, ipFabricId): devices = {} listOfDevices = [] ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is not None: for device in ipFabric.devices: outputDict = {} outputDict['id'] = device.id outputDict['name'] = device.name outputDict['role'] = device.role outputDict['family'] = device.family outputDict['macAddress'] = device.macAddress outputDict['managementIp'] = device.managementIp outputDict['serialNumber'] = device.serialNumber outputDict['deployStatus'] = device.deployStatus outputDict['configStatus'] = device.configStatus outputDict['l2Status'] = device.l2Status outputDict['l3Status'] = device.l3Status outputDict['uri'] = bottle.request.url + '/' +device.id listOfDevices.append(outputDict) devices['device'] = listOfDevices devices['uri'] = bottle.request.url devices['total'] = len(ipFabric.devices) return {'devices' : devices} else: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) def getDevice(self, dbSession, ipFabricId, deviceId): device = self.isDeviceExists(dbSession, ipFabricId, deviceId) #ipFabricUri is constructed from url url = bottle.request.url uri = url.split("/") uri.pop() uri.pop() ipFbaricUri = "/".join(uri) if device is not None: outputDict = {} outputDict['id'] = device.id outputDict['name'] = device.name outputDict['role'] = device.role outputDict['family'] = device.family outputDict['username'] = device.username outputDict['password'] = device.getCleartextPassword() outputDict['macAddress'] = device.macAddress outputDict['managementIp'] = device.managementIp outputDict['asn'] = device.asn outputDict['configStatus'] = device.configStatus outputDict['configStatusReason'] = device.configStatusReason outputDict['l2Status'] = device.l2Status outputDict['l2StatusReason'] = device.l2StatusReason outputDict['l3Status'] = device.l3Status outputDict['l3StatusReason'] = device.l3StatusReason outputDict['serialNumber'] = device.serialNumber outputDict['deployStatus'] = device.deployStatus outputDict['uri'] = bottle.request.url outputDict['pod'] = {'uri': ipFbaricUri } outputDict['config'] = {'uri': bottle.request.url + '/config' } return {'device': outputDict} else: raise bottle.HTTPError(404, "device with id: %s not found" % (deviceId)) def getDeviceConfig(self, dbSession, ipFabricId, deviceId): device = self.isDeviceExists(dbSession, ipFabricId, deviceId) if device is None: raise bottle.HTTPError(404, "No device found with ipFabricId: '%s', deviceId: '%s'" % (ipFabricId, deviceId)) config = device.config if config is None: raise bottle.HTTPError(404, "Device exists but no config found, probably fabric script is not ran. ipFabricId: '%s', deviceId: '%s'" % (ipFabricId, deviceId)) bottle.response.headers['Content-Type'] = 'application/json' return config.config def getZtpConfig(self, dbSession, ipFabricId): ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is not None: logger.debug('Fabric name: %s' % (ipFabric.name)) ipFabricFolder = ipFabric.id + '-' + ipFabric.name fileName = os.path.join(ipFabricFolder, "dhcpd.conf") logger.debug('webServerRoot: %s, fileName: %s, exists: %s' % (webServerRoot, fileName, os.path.exists(os.path.join(webServerRoot, fileName)))) ztpConf = bottle.static_file(fileName, root=webServerRoot) if isinstance(ztpConf, bottle.HTTPError): raise bottle.HTTPError(404, "Pod exists but no ztp Config found. Pod name: '%s " % (ipFabric.name)) return ztpConf else: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) def isDeviceExists(self, dbSession, ipFabricId, deviceId): try: device = dbSession.query(Device).join(Pod).filter(Device.id == deviceId).filter(Pod.id == ipFabricId).one() return device except (exc.NoResultFound): raise bottle.HTTPError(404, "No device found with ipFabricId: '%s', deviceId: '%s'" % (ipFabricId, deviceId)) def getJunosImage(self, dbSession, junosImageName): fileName = os.path.join(junosImageRoot, junosImageName) logger.debug('junosImageRoot: %s, image: %s, exists: %s' % (junosImageRoot, junosImageName, os.path.exists(fileName))) config = bottle.static_file(junosImageName, root=junosImageRoot) if isinstance(config, bottle.HTTPError): raise bottle.HTTPError(404, "Junos image file not found. name: '%s'" % (junosImageName)) return config def getOpenClosConfigParams(self, dbSession): supportedDevices = [] for device in self.__conf['deviceFamily']: port = util.getPortNamesForDeviceFamily(device, self.__conf['deviceFamily']) deviceDetail = {} if len(port['uplinkPorts']) > 0: deviceDetail['family'] = device deviceDetail['uplinkStart'] = port['uplinkPorts'][0] deviceDetail['uplinkEnd'] = port['uplinkPorts'][len(port['uplinkPorts'])-1] deviceDetail['role'] = 'leaf' if len(port['downlinkPorts']) > 0: deviceDetail['downlinkStart'] = port['uplinkPorts'][0] deviceDetail['downlinkEnd'] = port['uplinkPorts'][len(port['uplinkPorts'])-1] deviceDetail['role'] = 'leaf' if len(port['uplinkPorts'])==0 and len(port['downlinkPorts']) == 0: if device == 'qfx5100-24q-2p': deviceDetail['role'] = 'spine' deviceDetail['family'] = device deviceDetail['downlinkStart'] = port['ports'][0] deviceDetail['downlinkEnd'] = port['ports'][len(port['ports'])-1] deviceDetail['uplinkStart'] = '' deviceDetail['uplinkEnd'] = '' supportedDevices.append(deviceDetail) confValues = {} confValues.update({'dbUrl': self.__conf['dbUrl']}) confValues.update({'supportedDevices' : supportedDevices }) confValues.update({'dotColors': self.__conf['DOT']['colors'] }) confValues.update({'httpServer' : self.__conf['httpServer']}) confValues.update({'snmpTrap' : self.__conf['snmpTrap']}) return {'OpenClosConf' : confValues } def createIpFabric(self, dbSession): if bottle.request.json is None: raise bottle.HTTPError(400, exception = RestError(0, "No json in request object")) else: pod = bottle.request.json.get('ipFabric') if pod is None: raise bottle.HTTPError(400, exception = RestError(0, "POST body can not be empty")) l3ClosMediation = L3ClosMediation(self.__conf, self.__daoClass) ipFabric = self.getPodFromDict(pod) ipFabricName = ipFabric.pop('name') fabricDevices = self.getDevDictFromDict(pod) try: fabric = l3ClosMediation.createPod(ipFabricName, ipFabric, fabricDevices) url = bottle.request.url + '/' + fabric.id ipFabric = self.getIpFabric(dbSession, fabric.id, url) except ValueError as e: logger.debug('StackTrace: %s' % (traceback.format_exc())) raise bottle.HTTPError(400, exception = RestError(0, e.message)) bottle.response.set_header('Location', url) bottle.response.status = 201 return ipFabric def createCablingPlan(self, dbSession, ipFabricId): try: l3ClosMediation = L3ClosMediation(self.__conf, self.__daoClass) if l3ClosMediation.createCablingPlan(ipFabricId) is True: return bottle.HTTPResponse(status=200) except ValueError: raise bottle.HTTPError(404, "Fabric with id[%s] not found" % (ipFabricId)) def createDeviceConfiguration(self, dbSession, ipFabricId): try: l3ClosMediation = L3ClosMediation(self.__conf, self.__daoClass) if l3ClosMediation.createDeviceConfig(ipFabricId) is True: return bottle.HTTPResponse(status=200) except ValueError: raise bottle.HTTPError(404, "Fabric with id[%s] not found" % (ipFabricId)) def createZtpConfiguration(self, dbSession, ipFabricId): try: ZtpServer.createPodSpecificDhcpConfFile(self, ipFabricId) except ValueError: raise bottle.HTTPError(404, "Fabric with id[%s] not found" % (ipFabricId)) def reconfigIpFabric(self, dbSession, ipFabricId): if bottle.request.json is None: raise bottle.HTTPError(400, exception = RestError(0, "No json in request object")) else: inPod = bottle.request.json.get('ipFabric') if inPod is None: raise bottle.HTTPError(400, exception = RestError(0, "POST body can not be empty")) l3ClosMediation = L3ClosMediation(self.__conf, self.__daoClass) ipFabric = self.getPodFromDict(inPod) #ipFabric['id'] = ipFabricId #ipFabric['uri'] = bottle.request.url fabricDevices = self.getDevDictFromDict(inPod) # Pass the ipFabric and fabricDevices dictionaries to config/update API, then return try: updatedFabric = l3ClosMediation.updatePod(ipFabricId, ipFabric, fabricDevices) url = bottle.request.url + '/' + updatedFabric.id return self.getIpFabric(dbSession, ipFabricId, url) except ValueError as e: raise bottle.HTTPError(400, exception = RestError(0, e.message)) def setOpenClosConfigParams(self): return bottle.HTTPResponse(status=200) def deleteIpFabric(self, dbSession, ipFabricId): ipFabric = self.report.getIpFabric(dbSession, ipFabricId) if ipFabric is not None: self.__dao.deleteObject(dbSession, ipFabric) util.deleteOutFolder(self.__conf, ipFabric) logger.debug("IpFabric with id: %s deleted" % (ipFabricId)) else: raise bottle.HTTPError(404, "IpFabric with id: %s not found" % (ipFabricId)) return bottle.HTTPResponse(status=204) def getPodFromDict(self, podDict): ipFabric = {} ''' # Need to revisit later on to make thing works as below. podDict.pop('devices') ipFabric = Pod(**inPod) ''' if podDict is None: raise bottle.HTTPError(400, exception = RestError(0, "Invalid value in POST/PUT body.")) ipFabric['name'] = podDict.get('name') ipFabric['fabricDeviceType'] = podDict.get('fabricDeviceType') ipFabric['fabricDeviceCount'] = podDict.get('fabricDeviceCount') ipFabric['spineCount'] = podDict.get('spineCount') ipFabric['spineDeviceType'] = podDict.get('spineDeviceType') ipFabric['leafCount'] = podDict.get('leafCount') ipFabric['leafSettings'] = podDict.get('leafSettings') ipFabric['leafUplinkcountMustBeUp'] = podDict.get('leafUplinkcountMustBeUp') ipFabric['interConnectPrefix'] = podDict.get('interConnectPrefix') ipFabric['vlanPrefix'] = podDict.get('vlanPrefix') ipFabric['loopbackPrefix'] = podDict.get('loopbackPrefix') ipFabric['spineAS'] = podDict.get('spineAS') ipFabric['leafAS'] = podDict.get('leafAS') ipFabric['topologyType'] = podDict.get('topologyType') ipFabric['outOfBandAddressList'] = podDict.get('outOfBandAddressList') ipFabric['outOfBandGateway'] = podDict.get('outOfBandGateway') ipFabric['managementPrefix'] = podDict.get('managementPrefix') ipFabric['hostOrVmCountPerLeaf'] = podDict.get('hostOrVmCountPerLeaf') ipFabric['description'] = podDict.get('description') ipFabric['devicePassword'] = podDict.get('devicePassword') return ipFabric def getDevDictFromDict(self, podDict): if podDict is not None: devices = podDict.get('devices') else: raise bottle.HTTPError(400, exception = RestError(0, "Invalid value in POST body.")) fabricDevices = {} spines = [] leaves = [] for device in devices: temp = {} temp['name'] = device.get('name') temp['macAddress'] = device.get('macAddress') temp['role'] = device.get('role') temp['username'] = device.get('username') temp['password'] = device.get('password') temp['family'] = device.get('family') temp['serialNumber'] = device.get('serialNumber') temp['deployStatus'] = device.get('deployStatus') if temp['role'] == 'spine': spines.append(temp) elif temp['role'] == 'leaf': leaves.append(temp) else: raise bottle.HTTPError(400, exception = RestError(0, "Unexpected role value in device inventory list")) fabricDevices['spines'] = spines fabricDevices['leafs'] = leaves return fabricDevices def getL2Report(self, dbSession, ipFabricId): try: cached = bottle.request.query.get('cached', '1') if cached == '1': cachedData = True else: cachedData = False bottle.response.headers['Content-Type'] = 'application/json' return self.l2Report.generateReport(ipFabricId, cachedData) except ValueError: raise bottle.HTTPError(404, "Fabric with id: %s not found" % (ipFabricId)) def getL3Report(self, dbSession, ipFabricId): try: cached = bottle.request.query.get('cached', '1') if cached == '1': cachedData = True else: cachedData = False bottle.response.headers['Content-Type'] = 'application/json' return self.l3Report.generateReport(ipFabricId, cachedData) except ValueError: raise bottle.HTTPError(404, "Fabric with id: %s not found" % (ipFabricId))
def getReport(self): report = ResourceAllocationReport(self.conf, self.dao) return report
class RestServer(): def __init__(self, conf={}, daoClass=Dao): if any(conf) == False: self._openclosProperty = OpenClosProperty(appName=moduleName) self._conf = self._openclosProperty.getProperties() global webServerRoot webServerRoot = self._conf['outputDir'] else: self._conf = conf self.__daoClass = daoClass self.__dao = daoClass.getInstance() self.openclosDbSessionPlugin = OpenclosDbSessionPlugin(daoClass) if 'httpServer' in self._conf and 'ipAddr' in self._conf[ 'httpServer'] and self._conf['httpServer'][ 'ipAddr'] is not None: self.host = self._conf['httpServer']['ipAddr'] else: self.host = 'localhost' if 'httpServer' in self._conf and 'port' in self._conf['httpServer']: self.port = self._conf['httpServer']['port'] else: self.port = 8080 self.baseUrl = 'http://%s:%d' % (self.host, self.port) self.report = ResourceAllocationReport(self._conf, daoClass) # Create a single instance of l2Report as it holds thread-pool # for device connection. Don't create l2Report multiple times self.l2Report = L2Report(self._conf, daoClass) # Create a single instance of l3Report as it holds thread-pool # for device connection. Don't create l3Report multiple times self.l3Report = L3Report(self._conf, daoClass) self.deviceSku = DeviceSku() def initRest(self): self.addRoutes(self.baseUrl) self.app = bottle.app() self.app.install(loggingPlugin) self.app.install(self.openclosDbSessionPlugin) logger.info('RestServer initRest() done') def _reset(self): """ Resets the state of the rest server and application Used for Test only """ self.app.uninstall(loggingPlugin) self.app.uninstall(OpenclosDbSessionPlugin) def start(self): logger.info('REST server starting at %s:%d' % (self.host, self.port)) debugRest = False if logger.isEnabledFor(logging.DEBUG): debugRest = True if self._openclosProperty.isSqliteUsed(): bottle.run(self.app, host=self.host, port=self.port, debug=debugRest) else: bottle.run(self.app, host=self.host, port=self.port, debug=debugRest, server='paste') @staticmethod @error(400) def error400(error): bottle.response.headers['Content-Type'] = 'application/json' if error.exception is not None: return json.dumps({ 'errorCode': error.exception.code, 'errorMessage': error.exception.message }) else: return json.dumps({ 'errorCode': 0, 'errorMessage': 'A generic error occurred' }) @staticmethod @error(404) def error404(error): bottle.response.headers['Content-Type'] = 'application/json' if error.exception is not None: return json.dumps({ 'errorCode': error.exception.code, 'errorMessage': error.exception.message }) else: return json.dumps({ 'errorCode': 0, 'errorMessage': 'A generic error occurred' }) def addRoutes(self, baseUrl): self.indexLinks = [] # GET APIs bottle.route('/', 'GET', self.getIndex) bottle.route('/openclos', 'GET', self.getIndex) bottle.route('/openclos/conf', 'GET', self.getOpenClosConfigParams) bottle.route('/openclos/pods', 'GET', self.getPods) bottle.route('/openclos/images/<junosImageName>', 'GET', self.getJunosImage) bottle.route('/openclos/pods/<podId>', 'GET', self.getPod) bottle.route('/openclos/pods/<podId>/cabling-plan', 'GET', self.getCablingPlan) bottle.route('/openclos/pods/<podId>/ztp-configuration', 'GET', self.getZtpConfig) bottle.route('/openclos/pods/<podId>/device-configuration', 'GET', self.getDeviceConfigsInZip) bottle.route( '/openclos/pods/<podId>/leaf-generic-configurations/<deviceModel>', 'GET', self.getLeafGenericConfiguration) bottle.route('/openclos/pods/<podId>/l2-report', 'GET', self.getL2Report) bottle.route('/openclos/pods/<podId>/l3-report', 'GET', self.getL3Report) bottle.route('/openclos/pods/<podId>/devices', 'GET', self.getDevices) bottle.route('/openclos/pods/<podId>/devices/<deviceId>', 'GET', self.getDevice) bottle.route('/openclos/pods/<podId>/devices/<deviceId>/config', 'GET', self.getDeviceConfig) # POST/PUT APIs bottle.route('/openclos/pods', 'POST', self.createPod) bottle.route('/openclos/pods/<podId>/cabling-plan', 'PUT', self.createCablingPlan) bottle.route('/openclos/pods/<podId>/device-configuration', 'PUT', self.createDeviceConfiguration) bottle.route('/openclos/pods/<podId>/ztp-configuration', 'PUT', self.createZtpConfiguration) bottle.route('/openclos/pods/<podId>', 'PUT', self.reconfigPod) bottle.route('/openclos/conf/', 'PUT', self.setOpenClosConfigParams) # DELETE APIs bottle.route('/openclos/pods/<podId>', 'DELETE', self.deletePod) self.createLinkForConfigs() def createLinkForConfigs(self): # index page should show all top level URLs # users whould be able to drill down through navigation self.indexLinks.append(ResourceLink(self.baseUrl, '/openclos/pods')) self.indexLinks.append(ResourceLink(self.baseUrl, '/openclos/conf')) def getIndex(self, dbSession=None): if 'openclos' not in bottle.request.url: bottle.redirect( str(bottle.request.url).translate(None, ',') + 'openclos') jsonLinks = [] for link in self.indexLinks: jsonLinks.append({'link': link.toDict()}) jsonBody = \ {'href': str(bottle.request.url).translate(None, ','), 'links': jsonLinks } return jsonBody def getPods(self, dbSession): url = str(bottle.request.url).translate(None, ',') podsData = {} listOfIpFbarics = [] pods = self.report.getPods(dbSession) logger.debug("count of pods: %d", len(pods)) if not pods: logger.debug("There are no pods in the system ") for i in range(len(pods)): pod = {} pod['uri'] = url + '/' + pods[i]['id'] pod['id'] = pods[i]['id'] pod['name'] = pods[i]['name'] pod['spineDeviceType'] = pods[i]['spineDeviceType'] pod['spineCount'] = pods[i]['spineCount'] pod['leafSettings'] = pods[i]['leafSettings'] pod['leafCount'] = pods[i]['leafCount'] pod['devicePassword'] = pods[i]['devicePassword'] listOfIpFbarics.append(pod) podsData['pod'] = listOfIpFbarics podsData['total'] = len(listOfIpFbarics) podsData['uri'] = url return {'pods': podsData} def getPodFieldListToCopy(self): return [ 'id', 'name', 'description', 'spineAS', 'spineDeviceType', 'spineCount', 'leafAS', 'leafCount', 'leafUplinkcountMustBeUp', 'loopbackPrefix', 'vlanPrefix', 'interConnectPrefix', 'managementPrefix', 'outOfBandAddressList', 'outOfBandGateway', 'topologyType', 'spineJunosImage', 'hostOrVmCountPerLeaf' ] def getPod(self, dbSession, podId, requestUrl=None): if requestUrl is None: requestUrl = str(bottle.request.url).translate(None, ',') pod = self.report.getPod(dbSession, podId) if pod is not None: outputDict = {} devices = pod.devices for field in self.getPodFieldListToCopy(): outputDict[field] = pod.__dict__.get(field) ''' outputDict['id'] = pod.id outputDict['name'] = pod.name outputDict['description'] = pod.description outputDict['spineAS'] = pod.spineAS outputDict['spineDeviceType'] = pod.spineDeviceType outputDict['spineCount'] = pod.spineCount outputDict['leafAS'] = pod.leafAS outputDict['leafCount'] = pod.leafCount outputDict['loopbackPrefix'] = pod.loopbackPrefix outputDict['vlanPrefix'] = pod.vlanPrefix outputDict['interConnectPrefix'] = pod.interConnectPrefix outputDict['managementPrefix'] = pod.managementPrefix outputDict['outOfBandAddressList'] = pod.outOfBandAddressList outputDict['outOfBandGateway'] = pod.outOfBandGateway outputDict['topologyType'] = pod.topologyType outputDict['spineJunosImage'] = pod.spineJunosImage outputDict['hostOrVmCountPerLeaf'] = pod.hostOrVmCountPerLeaf ''' outputDict['leafSettings'] = [] for leafSetting in pod.leafSettings: outputDict['leafSettings'].append({ 'deviceType': leafSetting.deviceFamily, 'junosImage': leafSetting.junosImage }) outputDict['devicePassword'] = pod.getCleartextPassword() outputDict['uri'] = requestUrl outputDict['devices'] = { 'uri': requestUrl + '/devices', 'total': len(devices) } outputDict['cablingPlan'] = {'uri': requestUrl + '/cabling-plan'} outputDict['deviceConfiguration'] = { 'uri': requestUrl + '/device-configuration' } outputDict['ztpConfiguration'] = { 'uri': requestUrl + '/ztp-configuration' } outputDict['l2Report'] = {'uri': requestUrl + '/l2-report'} outputDict['l3Report'] = {'uri': requestUrl + '/l3-report'} logger.debug('getPod: %s' % (podId)) return {'pod': outputDict} else: raise bottle.HTTPError(404, exception=PodNotFound(podId)) def getCablingPlan(self, dbSession, podId): header = bottle.request.get_header('Accept') logger.debug('Accept header before processing: %s' % (header)) # hack to remove comma character, must be a bug on Bottle header = header.translate(None, ',') logger.debug('Accept header after processing: %s' % (header)) pod = self.report.getPod(dbSession, podId) if pod is not None: logger.debug('Pod name: %s' % (pod.name)) if header == 'application/json': cablingPlan = pod.cablingPlan if cablingPlan is not None and cablingPlan.json is not None: logger.debug('CablingPlan found in DB') return cablingPlan.json else: raise bottle.HTTPError(404, exception=CablingPlanNotFound( pod.id)) else: podFolder = pod.id + '-' + pod.name fileName = os.path.join(podFolder, 'cablingPlan.dot') logger.debug( 'webServerRoot: %s, fileName: %s, exists: %s' % (webServerRoot, fileName, os.path.exists(os.path.join(webServerRoot, fileName)))) logger.debug('Cabling file name: %s' % (fileName)) cablingPlan = bottle.static_file(fileName, root=webServerRoot) if isinstance(cablingPlan, bottle.HTTPError): raise bottle.HTTPError( 404, exception=CablingPlanNotFound(podFolder)) return cablingPlan else: raise bottle.HTTPError(404, exception=PodNotFound(podId)) def getLeafGenericConfiguration(self, dbSession, podId, deviceModel): pod = self.report.getPod(dbSession, podId) if pod is None: raise bottle.HTTPError(404, exception=PodNotFound(podId)) logger.debug('Pod name: %s, id: %s' % (pod.name, podId)) leafSetting = self.__dao.getLeafSetting(dbSession, podId, deviceModel) if leafSetting is None or leafSetting.config is None: raise bottle.HTTPError( 404, exception=DeviceConfigurationNotFound( "Pod exists but no leaf generic config found, probably configuration \ was not created. deviceModel: %s, pod name: '%s', id: '%s'" % (deviceModel, pod.name, podId))) bottle.response.headers['Content-Type'] = 'application/json' return leafSetting.config def getDeviceConfigsInZip(self, dbSession, podId): pod = self.report.getPod(dbSession, podId) if pod is None: raise bottle.HTTPError(404, exception=PodNotFound(podId)) logger.debug('Pod name: %s' % (pod.name)) zippedConfigFiles = self.createZipArchive(pod) if zippedConfigFiles is not None: bottle.response.headers['Content-Type'] = 'application/zip' return zippedConfigFiles else: raise bottle.HTTPError( 404, exception=DeviceConfigurationNotFound( "Pod exists but no configs for devices.'%s " % (pod.name))) def createZipArchive(self, pod): buff = StringIO.StringIO() zipArchive = zipfile.ZipFile(buff, mode='w') for device in pod.devices: fileName = device.id + '__' + device.name + '.conf' if device.config is not None: zipArchive.writestr(fileName, device.config.config) if pod.leafSettings is not None: for leafSetting in pod.leafSettings: if leafSetting.config is not None: zipArchive.writestr(leafSetting.deviceFamily + '.conf', leafSetting.config) zipArchive.close() logger.debug('zip file content:\n' + str(zipArchive.namelist())) return buff.getvalue() def copyAdditionalDeviceFields(self, dict, device): ''' Hook to enhance Device object ''' def getDevices(self, dbSession, podId): devices = {} listOfDevices = [] pod = self.report.getPod(dbSession, podId) if pod is not None: for device in pod.devices: outputDict = {} outputDict['id'] = device.id outputDict['name'] = device.name outputDict['role'] = device.role outputDict['family'] = device.family outputDict['macAddress'] = device.macAddress outputDict['managementIp'] = device.managementIp outputDict['serialNumber'] = device.serialNumber outputDict['deployStatus'] = device.deployStatus outputDict['configStatus'] = device.configStatus outputDict['l2Status'] = device.l2Status outputDict['l3Status'] = device.l3Status outputDict['uri'] = str(bottle.request.url).translate( None, ',') + '/' + device.id self.copyAdditionalDeviceFields(outputDict, device) listOfDevices.append(outputDict) devices['device'] = listOfDevices devices['uri'] = str(bottle.request.url).translate(None, ',') devices['total'] = len(pod.devices) return {'devices': devices} else: raise bottle.HTTPError(404, exception=PodNotFound(podId)) def getDevice(self, dbSession, podId, deviceId): device = self.isDeviceExists(dbSession, podId, deviceId) #podUri is constructed from url url = str(bottle.request.url).translate(None, ',') uri = url.split("/") uri.pop() uri.pop() ipFbaricUri = "/".join(uri) if device is not None: outputDict = {} outputDict['id'] = device.id outputDict['name'] = device.name outputDict['role'] = device.role outputDict['family'] = device.family outputDict['username'] = device.username outputDict['password'] = device.getCleartextPassword() outputDict['macAddress'] = device.macAddress outputDict['managementIp'] = device.managementIp outputDict['asn'] = device.asn outputDict['configStatus'] = device.configStatus outputDict['configStatusReason'] = device.configStatusReason outputDict['l2Status'] = device.l2Status outputDict['l2StatusReason'] = device.l2StatusReason outputDict['l3Status'] = device.l3Status outputDict['l3StatusReason'] = device.l3StatusReason outputDict['serialNumber'] = device.serialNumber outputDict['deployStatus'] = device.deployStatus outputDict['uri'] = str(bottle.request.url).translate(None, ',') outputDict['pod'] = {'uri': ipFbaricUri} outputDict['config'] = { 'uri': str(bottle.request.url).translate(None, ',') + '/config' } self.copyAdditionalDeviceFields(outputDict, device) return {'device': outputDict} else: raise bottle.HTTPError( 404, exception=DeviceNotFound( "No device found with podId: '%s', deviceId: '%s'" % (podId, deviceId))) def getDeviceConfig(self, dbSession, podId, deviceId): device = self.isDeviceExists(dbSession, podId, deviceId) if device is None: raise bottle.HTTPError( 404, exception=DeviceNotFound( "No device found with podId: '%s', deviceId: '%s'" % (podId, deviceId))) config = device.config if config is None: raise bottle.HTTPError( 404, exception=DeviceConfigurationNotFound( "Device exists but no config found, probably fabric script is not ran. podId: '%s', deviceId: '%s'" % (podId, deviceId))) bottle.response.headers['Content-Type'] = 'application/json' return config.config def getZtpConfig(self, dbSession, podId): pod = self.report.getPod(dbSession, podId) if pod is not None: logger.debug('pod name: %s' % (pod.name)) podFolder = pod.id + '-' + pod.name fileName = os.path.join(podFolder, "dhcpd.conf") logger.debug( 'webServerRoot: %s, fileName: %s, exists: %s' % (webServerRoot, fileName, os.path.exists(os.path.join(webServerRoot, fileName)))) ztpConf = bottle.static_file(fileName, root=webServerRoot) if isinstance(ztpConf, bottle.HTTPError): raise bottle.HTTPError( 404, exception=DeviceConfigurationNotFound( "Pod exists but no ztp Config found. Pod name: '%s " % (pod.name))) return ztpConf else: raise bottle.HTTPError(404, exception=PodNotFound(podId)) def isDeviceExists(self, dbSession, podId, deviceId): try: device = dbSession.query(Device).join(Pod).filter( Device.id == deviceId).filter(Pod.id == podId).one() return device except (exc.NoResultFound): raise bottle.HTTPError( 404, exception=DeviceNotFound( "No device found with podId: '%s', deviceId: '%s'" % (podId, deviceId))) def getJunosImage(self, dbSession, junosImageName): fileName = os.path.join(junosImageRoot, junosImageName) logger.debug( 'junosImageRoot: %s, image: %s, exists: %s' % (junosImageRoot, junosImageName, os.path.exists(fileName))) config = bottle.static_file(junosImageName, root=junosImageRoot) if isinstance(config, bottle.HTTPError): raise bottle.HTTPError( 404, exception=ImageNotFound( "Junos image file not found. name: '%s'" % (junosImageName))) return config def getOpenClosConfigParams(self, dbSession): supportedDevices = [] for deviceFamily, value in self.deviceSku.skuDetail.iteritems(): for role, ports in value.iteritems(): uplinks = ports.get('uplinkPorts') downlinks = ports.get('downlinkPorts') deviceDetail = { 'family': deviceFamily, 'role': role, 'uplinkPorts': uplinks, 'downlinkPorts': downlinks } supportedDevices.append(deviceDetail) confValues = {} confValues.update({'dbUrl': self._conf['dbUrl']}) confValues.update({'supportedDevices': supportedDevices}) confValues.update({'dotColors': self._conf['DOT']['colors']}) confValues.update({'httpServer': self._conf['httpServer']}) confValues.update({'snmpTrap': self._conf['snmpTrap']}) return {'OpenClosConf': confValues} def createPod(self, dbSession): if bottle.request.json is None: raise bottle.HTTPError( 400, exception=InvalidRequest("No json in request object")) else: pod = bottle.request.json.get('pod') if pod is None: raise bottle.HTTPError( 400, exception=InvalidRequest("POST body cannot be empty")) l3ClosMediation = L3ClosMediation(self._conf, self.__daoClass) podDevices = self.getDevDictFromDict(pod) pod = self.getPodFromDict(pod) podName = pod.pop('name') try: createdPod = l3ClosMediation.createPod(podName, pod, podDevices) url = str(bottle.request.url).translate(None, ',') + '/' + createdPod.id pod = self.getPod(dbSession, createdPod.id, url) except Exception as e: logger.debug('StackTrace: %s' % (traceback.format_exc())) raise bottle.HTTPError(400, exception=e) bottle.response.set_header('Location', url) bottle.response.status = 201 return pod def createCablingPlan(self, dbSession, podId): try: l3ClosMediation = L3ClosMediation(self._conf, self.__daoClass) if l3ClosMediation.createCablingPlan(podId) is True: return bottle.HTTPResponse(status=200) except PodNotFound as e: raise bottle.HTTPError(404, exception=e) except Exception as e: raise bottle.HTTPError(500, exception=e) def createDeviceConfiguration(self, dbSession, podId): try: l3ClosMediation = L3ClosMediation(self._conf, self.__daoClass) if l3ClosMediation.createDeviceConfig(podId) is True: return bottle.HTTPResponse(status=200) except PodNotFound as e: raise bottle.HTTPError(404, exception=e) except Exception as e: raise bottle.HTTPError(500, exception=e) def createZtpConfiguration(self, dbSession, podId): try: ZtpServer().createPodSpecificDhcpConfFile(dbSession, podId) except PodNotFound as e: raise bottle.HTTPError(404, exception=e) except Exception as e: raise bottle.HTTPError(500, exception=e) def reconfigPod(self, dbSession, podId): if bottle.request.json is None: raise bottle.HTTPError( 400, exception=InvalidRequest("No json in request object")) else: inPod = bottle.request.json.get('pod') if inPod is None: raise bottle.HTTPError( 400, exception=InvalidRequest("POST body cannot be empty")) l3ClosMediation = L3ClosMediation(self._conf, self.__daoClass) pod = self.getPodFromDict(inPod) #pod['id'] = podId #pod['uri'] = str(bottle.request.url).translate(None, ',') podDevices = self.getDevDictFromDict(inPod) # Pass the pod and podDevices dictionaries to config/update API, then return try: updatedPod = l3ClosMediation.updatePod(podId, pod, podDevices) url = str(bottle.request.url).translate(None, ',') + '/' + updatedPod.id return self.getPod(dbSession, podId, url) except Exception as e: raise bottle.HTTPError(400, exception=e) def setOpenClosConfigParams(self): return bottle.HTTPResponse(status=200) def deletePod(self, dbSession, podId): pod = self.report.getPod(dbSession, podId) if pod is not None: self.__dao.deleteObject(dbSession, pod) util.deleteOutFolder(self._conf, pod) logger.debug("Pod with id: %s deleted" % (podId)) else: raise bottle.HTTPError(404, exception=PodNotFound(podId)) return bottle.HTTPResponse(status=204) def getPodFromDict(self, podDict): pod = {} ''' # Need to revisit later on to make thing works as below. podDict.pop('devices') pod = Pod(**inPod) ''' if podDict is None: raise bottle.HTTPError( 400, exception=InvalidRequest("Invalid value in request body.")) for field in self.getPodFieldListToCopy(): pod[field] = podDict.get(field) ''' pod['name'] = podDict.get('name') pod['description'] = podDict.get('description') pod['spineAS'] = podDict.get('spineAS') pod['spineDeviceType'] = podDict.get('spineDeviceType') pod['spineCount'] = podDict.get('spineCount') pod['leafAS'] = podDict.get('leafAS') pod['leafCount'] = podDict.get('leafCount') pod['leafUplinkcountMustBeUp'] = podDict.get('leafUplinkcountMustBeUp') pod['loopbackPrefix'] = podDict.get('loopbackPrefix') pod['vlanPrefix'] = podDict.get('vlanPrefix') pod['interConnectPrefix'] = podDict.get('interConnectPrefix') pod['managementPrefix'] = podDict.get('managementPrefix') pod['outOfBandAddressList'] = podDict.get('outOfBandAddressList') pod['outOfBandGateway'] = podDict.get('outOfBandGateway') pod['topologyType'] = podDict.get('topologyType') pod['topologyType'] = podDict.get('topologyType') pod['spineJunosImage'] = podDict.get('spineJunosImage') pod['hostOrVmCountPerLeaf'] = podDict.get('hostOrVmCountPerLeaf') ''' pod['leafSettings'] = podDict.get('leafSettings') pod['devicePassword'] = podDict.get('devicePassword') return pod def getDevDictFromDict(self, podDict): if podDict is not None: devices = podDict.get('devices') else: raise bottle.HTTPError( 400, exception=InvalidRequest("Invalid value in request body.")) podDevices = {} spines = [] leaves = [] for device in devices: temp = {} temp['name'] = device.get('name') temp['macAddress'] = device.get('macAddress') temp['role'] = device.get('role') temp['username'] = device.get('username') temp['password'] = device.get('password') temp['family'] = device.get('family') temp['serialNumber'] = device.get('serialNumber') temp['deployStatus'] = device.get('deployStatus') if temp['role'] == 'spine': spines.append(temp) elif temp['role'] == 'leaf': leaves.append(temp) else: raise bottle.HTTPError( 400, exception=InvalidRequest( "Unexpected role value in device inventory list")) podDevices['spines'] = spines podDevices['leafs'] = leaves return podDevices def getL2Report(self, dbSession, podId): try: cached = bottle.request.query.get('cached', '1') if cached == '1': cachedData = True else: cachedData = False bottle.response.headers['Content-Type'] = 'application/json' return self.l2Report.generateReport(podId, cachedData) except Exception as e: raise bottle.HTTPError(404, exception=PodNotFound(podId, e)) def getL3Report(self, dbSession, podId): try: cached = bottle.request.query.get('cached', '1') if cached == '1': cachedData = True else: cachedData = False bottle.response.headers['Content-Type'] = 'application/json' return self.l3Report.generateReport(podId, cachedData) except Exception as e: raise bottle.HTTPError(404, exception=PodNotFound(podId, e))