Ejemplo n.º 1
0
    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()
Ejemplo n.º 2
0
    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))
Ejemplo n.º 3
0
 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)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
    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")
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
 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 "---------------------------------------------------------------"
Ejemplo n.º 8
0
    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
Ejemplo n.º 9
0
    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))
Ejemplo n.º 10
0
    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
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
 def handle_create_ztp_config(self, pod_name):
     report = ResourceAllocationReport()
     with report._dao.getReadSession() as session:
         ztpServer = ZtpServer()
         ztpServer.createPodSpecificDhcpConfFile(session, pod_name)
Ejemplo n.º 13
0
 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)
Ejemplo n.º 14
0
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))
Ejemplo n.º 15
0
 def getReport(self):
     report = ResourceAllocationReport(self.conf, self.dao)
     return report
Ejemplo n.º 16
0
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))