def init(self, configurator, **kwargs): """ Abstract function for component initialization. :param configurator: component configurator for configuring adapters :type configurator: :any:`ComponentConfigurator` :param kwargs: optional parameters :type kwargs: dict :return: None """ # Load and initiate adapters using the initiate_adapters() template func self._load_adapters(configurator=configurator, **kwargs) # Skip to start polling if it's set if not self._poll: # Try to request/parse/update Mininet topology if not self._detect_topology(): log.warning("%s domain not confirmed during init!" % self.domain_name) else: # Notify all components for topology change --> this event causes # the DoV updating self.raiseEventNoErrors( DomainChangedEvent, domain=self.domain_name, data=self.internal_topo, cause=DomainChangedEvent.TYPE.DOMAIN_UP) else: log.info("Start polling %s domain..." % self.domain_name) self.start_polling(self.POLL_INTERVAL)
def add_domain(self, domain, nffg): """ Update the global view data with the specific domain info. :param domain: domain name :type domain: str :param nffg: infrastructure info collected from the domain :type nffg: :any:`NFFG` :return: None """ # If the domain is not tracked if domain not in self.__tracked_domains: if not nffg: log.warning("Got empty data. Skip domain addition...") return log.info("Append %s domain to DoV..." % domain) # If DoV is empty if not self.__dov.is_empty(): # Merge domain topo into global view self.__dov.merge_new_domain_into_dov(nffg=nffg) else: # No other domain detected, set NFFG as the whole Global view log.debug( "DoV is empty! Add new domain: %s as the global view!" % domain) self.__dov.set_domain_as_global_view(domain=domain, nffg=nffg) # Add detected domain to cached domains self.__tracked_domains.add(domain) else: log.error( "New domain: %s has already tracked: %s! Abort adding..." % (domain, self.__tracked_domains))
def _detect_topology(self): """ Check the undetected topology is up or not. If the domain is confirmed and detected, the ``internal_topo`` attribute will be updated with the new topology. .. warning:: No :any:`DomainChangedEvent` will be raised internally if the domain is confirmed! :return: detected or not :rtype: bool """ if self.topoAdapter.check_domain_reachable(): log.info(">>> %s domain confirmed!" % self.domain_name) self._detected = True log.info("Requesting resource information from %s domain..." % self.domain_name) topo_nffg = self.topoAdapter.get_topology_resource() if topo_nffg: log.debug("Save detected topology: %s..." % topo_nffg) # Update the received new topo self.internal_topo = topo_nffg else: log.warning("Resource info is missing!") return self._detected
def run(self): """ Abstract function for starting component. :return: None """ log.info("Start DomainManager for %s domain!" % self.domain_name)
def __proceed_installation (self, mapped_nffg, original_request=None): """ Helper function to instantiate the NFFG mapping from different source. :param mapped_nffg: pre-mapped service request :type mapped_nffg: :class:`NFFG` :return: None """ log.getChild('API').info("Invoke install_nffg on %s with NF-FG: %s " % ( self.__class__.__name__, mapped_nffg)) stats.add_measurement_start_entry(type=stats.TYPE_DEPLOY, info=LAYER_NAME) try: deploy_status = self.controller_adapter.install_nffg(mapped_nffg, original_request) except Exception: log.error("Something went wrong during NFFG installation!") self.raiseEventNoErrors(InstallationFinishedEvent, result=InstallationFinishedEvent.DEPLOY_ERROR) raise log.getChild('API').debug("Invoked install_nffg on %s is finished!" % self.__class__.__name__) if not deploy_status.still_pending: id = mapped_nffg.id result = InstallationFinishedEvent.get_result_from_status(deploy_status) log.info("Overall installation result: %s" % result) self.raiseEventNoErrors(InstallationFinishedEvent, id=id, result=result)
def _process_mapping_result(self, nffg_id, fail): """ :param nffg_id: :param fail: :return: """ log.getChild('API').debug("Cache request status...") req_status = self.api_mgr.request_cache.get_request_by_nffg_id(nffg_id) if req_status is None: log.getChild('API').debug( "Request status is missing for NFFG: %s! " "Skip result processing..." % nffg_id) return log.getChild('API').debug("Process mapping result...") message_id = req_status.message_id if message_id is not None: if fail: self.api_mgr.request_cache.set_error_result(id=message_id) else: self.api_mgr.request_cache.set_success_result(id=message_id) log.info("Set request status: %s for message: %s" % (req_status.status, req_status.message_id)) ret = self.api_mgr.invoke_callback(message_id=message_id) if ret is None: log.getChild('API').debug("No callback was defined!") else: log.getChild('API').debug( "Callback: %s has invoked with return value: %s" % (req_status.get_callback(), ret)) RequestScheduler().set_orchestration_finished(id=nffg_id)
def shutdown (self, event): """ .. seealso:: :func:`AbstractAPI.shutdown() <escape.util.api.AbstractAPI.shutdown>` :param event: event object """ log.info("Controller Adaptation Sublayer is going down...") self.controller_adapter.shutdown()
def resume(self): """ Abstract function for resuming a suspended component. .. note:: Not used currently! :return: None """ log.info("Resume DomainManager for %s domain!" % self.domain_name)
def suspend(self): """ Abstract class for suspending a running component. .. note:: Not used currently! :return: None """ log.info("Suspend DomainManager for %s domain!" % self.domain_name)
def shutdown (self, event): """ .. seealso:: :func:`AbstractAPI.shutdown() <escape.util.api.AbstractAPI.shutdown>` :param event: event object :type: :class:`pox.lib.revent.revent.Event` :return: None """ log.info("Controller Adaptation Sublayer is going down...") self.controller_adapter.shutdown()
def clear_initiated_mgrs(self): """ Clear initiated DomainManagers based on the first received config. :return: None """ log.info("Resetting detected domains before shutdown...") for name, mgr in self: try: mgr.clear_domain() except: log.exception("Got exception during domain resetting!")
def __init__ (self, standalone=False, **kwargs): """ .. seealso:: :func:`AbstractAPI.__init__() <escape.util.api.AbstractAPI.__init__>` """ log.info("Starting Controller Adaptation Sublayer...") # Set Infrastructure as a dependency if kwargs['with_infr']: log.debug("Set Infrastructure Layer as a dependency") self.dependencies = self.dependencies + (INFR_LAYER_NAME,) # Mandatory super() call self.controller_adapter = None super(ControllerAdaptationAPI, self).__init__(standalone, **kwargs)
def stop_initiated_mgrs(self): """ Stop initiated DomainManagers. :return: None """ log.info("Shutdown initiated DomainManagers...") for name, mgr in self: try: self.stop_mgr(name=name) except: log.exception("Got exception during domain resetting!") # Do not del mgr in for loop because of the iterator use self.__repository.clear()
def __proceed_installation(self, mapped_nffg, original_request=None, direct_deploy=False): """ Helper function to instantiate the NFFG mapping from different source. :param mapped_nffg: pre-mapped service request :type mapped_nffg: :class:`NFFG` :return: None """ log.getChild('API').info("Invoke install_nffg on %s with NF-FG: %s " % (self.__class__.__name__, mapped_nffg)) stats.add_measurement_start_entry(type=stats.TYPE_DEPLOY, info=LAYER_NAME) try: deploy_status = self.controller_adapter.install_nffg( mapped_nffg=mapped_nffg, original_request=original_request, direct_deploy=direct_deploy) except Exception as e: log.error("Something went wrong during NFFG installation: %s" % e) self._process_mapping_result(nffg_id=mapped_nffg.id, fail=True) self.raiseEventNoErrors( InstallationFinishedEvent, id=mapped_nffg.id, result=InstallationFinishedEvent.DEPLOY_ERROR) return log.getChild('API').debug("Invoked install_nffg on %s is finished!" % self.__class__.__name__) if deploy_status is None: log.error("Deploy status is missing!") self._process_mapping_result(nffg_id=mapped_nffg.id, fail=True) self.raiseEventNoErrors( InstallationFinishedEvent, id=mapped_nffg.id, result=InstallationFinishedEvent.DEPLOY_ERROR) elif not deploy_status.still_pending: result = InstallationFinishedEvent.get_result_from_status( deploy_status) log.info("Overall installation result: %s" % result) is_fail = InstallationFinishedEvent.is_error(result) self._process_mapping_result(nffg_id=mapped_nffg.id, fail=is_fail) self.raiseEventNoErrors(InstallationFinishedEvent, id=mapped_nffg.id, result=result) elif deploy_status.standby: if self._dovapi: RequestScheduler().set_orchestration_standby()
def rest_api_get_config(self): """ Implementation of REST-API RPC: get-config. Return with the global resource as an :class:`NFFG` if it has been changed otherwise return with False. :return: global resource view (DoV) :rtype: :class:`NFFG` or False """ # return self.controller_adapter.DoVManager.dov.get_resource_info() log.getChild('[DOV-API]').debug("Requesting Virtualizer for DoV-API") if self.dov_api_view is not None: # Check the topology is initialized if self.dov_api_view.revision is None: log.getChild('[DOV-API]').debug( "DoV has not initialized yet! " "Force to get default topology...") else: # Check if the resource is changed if self.api_mgr.topology_revision == self.dov_api_view.revision: # If resource has not been changed return False # This causes to response with the cached topology log.debug( "Global resource has not changed (revision: %s)! " % self.dov_api_view.revision) log.debug("Send topology from cache...") if self.api_mgr.last_response is None: log.error("Cached topology is missing!") return else: return self.api_mgr.last_response else: log.getChild('[DOV-API]').debug( "Response cache is outdated " "(new revision: %s)!" % self.dov_api_view.revision) res = self.dov_api_view.get_resource_info() self.api_mgr.topology_revision = self.dov_api_view.revision log.debug("Updated revision number: %s" % self.api_mgr.topology_revision) if CONFIG.get_rest_api_config(self._core_name)['unify_interface']: log.info("Convert internal NFFG to Virtualizer...") res = self.api_mgr.converter.dump_to_Virtualizer(nffg=res) log.debug("Cache acquired topology...") self.api_mgr.last_response = res return res else: log.error("Virtualizer(id=%s) assigned to DoV-API is not found!" % self._core_name)
def remove_domain(self, domain): """ Remove the detected domain from the global view. :param domain: domain name :type domain: str :return: None """ if domain in self.__tracked_domains: log.info("Remove domain: %s from DoV..." % domain) self.__dov.remove_domain_from_dov(domain=domain) self.__tracked_domains.remove(domain) else: log.warning( "Removing domain: %s is not included in tracked domains: %s! " "Skip removing..." % (domain, self.__tracked_domains))
def initialize (self): """ .. seealso:: :func:`AbstractAPI.initialize() <escape.util.api.AbstractAPI.initialize>` """ log.debug("Initializing Controller Adaptation Sublayer...") self.controller_adapter = ControllerAdapter(self, with_infr=self._with_infr) if self._mapped_nffg: try: mapped_request = self._read_data_from_file(self._mapped_nffg) mapped_request = NFFG.parse(mapped_request) self.__proceed_installation(mapped_nffg=mapped_request) except (ValueError, IOError, TypeError) as e: log.error("Can't load service request from file because of: " + str(e)) else: log.debug("Graph representation is loaded successfully!") log.info("Controller Adaptation Sublayer has been initialized!")
def clean_domain(self, domain): """ Clean given domain. :param domain: domain name :type domain: str :return: None """ if domain in self.__tracked_domains: log.info( "Remove initiated VNFs and flowrules from the domain: %s" % domain) self.__dov.clean_domain_from_dov(domain=domain) else: log.error( "Detected domain: %s is not included in tracked domains: %s! Abort " "cleaning..." % (domain, self.__tracked_domains))
def load_default_mgrs(self): """ Initiate and start default DomainManagers defined in CONFIG. :return: None """ log.info("Initialize additional DomainManagers from config...") # very dummy initialization mgrs = CONFIG.get_managers() if not mgrs: log.info("No DomainManager has been configured!") return for mgr_name in mgrs: # Get manager parameters from config mgr_cfg = CONFIG.get_component_params(component=mgr_name) if 'domain_name' in mgr_cfg: if mgr_cfg['domain_name'] in self.domains: log.warning( "Domain name collision! Domain Manager: %s has already " "initiated with the domain name: %s" % (self.get_component_by_domain( domain_name=mgr_cfg['domain_name']), mgr_cfg['domain_name'])) else: # If no domain name was given, use the manager config name by default mgr_cfg['domain_name'] = mgr_name # Get manager class mgr_class = CONFIG.get_component(component=mgr_name) if mgr_class.IS_LOCAL_MANAGER: loaded_local_mgr = [ name for name, mgr in self.__repository.iteritems() if mgr.IS_LOCAL_MANAGER ] if loaded_local_mgr: log.warning( "A local DomainManager has already been initiated with " "the name: %s! Skip initiating DomainManager: %s" % (loaded_local_mgr, mgr_name)) return log.debug("Load DomainManager based on config: %s" % mgr_name) # Start domain manager self.start_mgr(name=mgr_name, mgr_params=mgr_cfg)
def update_domain(self, domain, nffg): """ Update the detected domain in the global view with the given info. :param domain: domain name :type domain: str :param nffg: changed infrastructure info :type nffg: :any:`NFFG` :return: None """ if domain in self.__tracked_domains: log.info("Update domain: %s in DoV..." % domain) if self._remerge: log.debug("Using REMERGE strategy for DoV update...") self.__dov.remerge_domain_in_dov(domain=domain, nffg=nffg) else: log.debug("Using UPDATE strategy for DoV update...") self.__dov.update_domain_in_dov(domain=domain, nffg=nffg) else: log.error( "Detected domain: %s is not included in tracked domains: %s! Abort " "updating..." % (domain, self.__tracked_domains))
def __proceed_installation (self, mapped_nffg): """ Helper function to instantiate the NFFG mapping from different source. :param mapped_nffg: pre-mapped service request :type mapped_nffg: :any:`NFFG` :return: None """ log.getChild('API').info("Invoke install_nffg on %s with NF-FG: %s " % ( self.__class__.__name__, mapped_nffg)) log.info(int(round(time.time() * 1000))) try: install_result = self.controller_adapter.install_nffg(mapped_nffg) except Exception as e: log.error("Something went wrong during NFFG installation!") self.raiseEventNoErrors(InstallationFinishedEvent, result=False, error=e) raise log.getChild('API').debug("Invoked install_nffg on %s is finished" % self.__class__.__name__) log.info(int(round(time.time() * 1000))) self.raiseEventNoErrors(InstallationFinishedEvent, id=mapped_nffg.id, result=install_result)
def _load_adapters(self, configurator, **kwargs): """ Initiate Adapters using given configurator and predefined config. :param configurator: component configurator for configuring adapters :type configurator: :any:`ComponentConfigurator` :param kwargs: optional parameters :type kwargs: dict :return: None """ log.info("Init DomainManager for %s domain!" % self.domain_name) if not self._adapters_cfg: log.fatal("Missing Adapter configurations from DomainManager: %s" % self.domain_name) raise ConfigurationError("Missing configuration for %s" % self.domain_name) log.debug("Init Adapters for domain: %s - adapters: %s" % (self.domain_name, [a['class'] for a in self._adapters_cfg.itervalues()])) # Update Adapters's config with domain name for adapter in self._adapters_cfg.itervalues(): adapter['domain_name'] = self.domain_name # Initiate Adapters self.initiate_adapters(configurator)
def finit(self): """ Abstract function for stopping component. """ log.info("Stop DomainManager for %s domain!" % self.domain_name)
def install_nffg(self, mapped_nffg): """ Start NF-FG installation. Process given :any:`NFFG`, slice information self.__global_nffg on domains and invoke DomainManagers to install domain specific parts. :param mapped_nffg: mapped NF-FG instance which need to be installed :type mapped_nffg: NFFG :return: mapping result :rtype: bool """ log.debug("Invoke %s to install NF-FG(%s)" % (self.__class__.__name__, mapped_nffg.name)) # # Notify remote visualizer about the deployable NFFG if it's needed # notify_remote_visualizer(data=mapped_nffg, id=LAYER_NAME) slices = NFFGToolBox.split_into_domains(nffg=mapped_nffg, log=log) if slices is None: log.warning("Given mapped NFFG: %s can not be sliced! " "Skip domain notification steps" % mapped_nffg) return log.debug("Notify initiated domains: %s" % [d for d in self.domains.initiated]) # TODO - abstract/inter-domain tag rewrite # NFFGToolBox.rewrite_interdomain_tags(slices) mapping_result = True for domain, part in slices: log.debug( "Recreate missing TAG matching fields in domain part: %s..." % domain) # Temporarily rewrite/recreate TAGs here NFFGToolBox.recreate_match_TAGs(nffg=part, log=log) # Get Domain Manager domain_mgr = self.domains.get_component_by_domain( domain_name=domain) if domain_mgr is None: log.warning( "No DomainManager has been initialized for domain: %s! " "Skip install domain part..." % domain) continue log.log(VERBOSE, "Splitted domain: %s part:\n%s" % (domain, part.dump())) log.info("Delegate splitted part: %s to %s" % (part, domain_mgr)) # Rebind requirement link fragments as e2e reqs part = NFFGToolBox.rebind_e2e_req_links(nffg=part, log=log) # Check if need to reset domain before install if CONFIG.reset_domains_before_install(): log.debug("Reset %s domain before deploying mapped NFFG..." % domain_mgr.domain_name) domain_mgr.clear_domain() # Invoke DomainAdapter's install res = domain_mgr.install_nffg(part) # Update the DoV based on the mapping result covering some corner case if not res: log.error("Installation of %s in %s was unsuccessful!" % (part, domain)) # Note result according to others before mapping_result = mapping_result and res # If installation of the domain was performed without error if not res: log.warning("Skip DoV update with domain: %s! Cause: " "Domain installation was unsuccessful!" % domain) continue # If the domain manager does not poll the domain update here # else polling takes care of domain updating if isinstance(domain_mgr, AbstractRemoteDomainManager) and domain_mgr._poll: log.info("Skip explicit DoV update for domain: %s. " "Cause: polling enabled!" % domain) continue # If the internalDM is the only initiated mgr, we can override the # whole DoV if domain_mgr.IS_LOCAL_MANAGER: if mapped_nffg.is_SBB(): # If the request was a cleanup request, we can simply clean the DOV if mapped_nffg.is_bare(): log.debug( "Detected cleanup topology (no NF/Flowrule/SG_hop)! Clean DoV..." ) self.DoVManager.clean_domain(domain=domain) # If the reset contains some VNF, cannot clean or override else: log.warning( "Detected SingleBiSBiS topology! Local domain has been already " "cleared, skip DoV update...") # If the the topology was a GLOBAL view, just override the whole DoV elif not mapped_nffg.is_virtualized(): self.DoVManager.set_global_view(nffg=mapped_nffg) else: log.warning( "Detected virtualized Infrastructure node in mapped NFFG! Skip " "DoV update...") # In case of Local manager skip the rest of the update continue # Explicit domain update self.DoVManager.update_domain(domain=domain, nffg=part) log.debug("NF-FG installation is finished by %s" % self.__class__.__name__) # Post-mapping steps if mapping_result: log.info( "All installation process has been finished with success! ") # Notify remote visualizer about the installation result if it's needed notify_remote_visualizer( data=self.DoVManager.dov.get_resource_info(), id=LAYER_NAME) else: log.error("%s installation was not successful!" % mapped_nffg) return mapping_result
def poll(self): """ Poll the defined domain agent. Handle different connection errors and go to slow/rapid poll. When an agent is (re)detected update the current resource information. :return: None """ # If domain is not detected if not self._detected: # Check the topology is reachable if self._detect_topology(): # Domain is detected and topology is updated -> restart domain polling self.restart_polling() # Notify all components for topology change --> this event causes # the DoV updating self.raiseEventNoErrors( DomainChangedEvent, domain=self.domain_name, data=self.internal_topo, cause=DomainChangedEvent.TYPE.DOMAIN_UP) return # If domain has already detected else: # Check the domain is still reachable changed = self.topoAdapter.check_topology_changed() # No changes if changed is False: # Nothing to do log.log( VERBOSE, "Remote domain: %s has not changed!" % self.domain_name) return # Domain has changed elif isinstance(changed, NFFG): log.info( "Remote domain: %s has changed. Update global domain view..." % self.domain_name) log.debug("Save changed topology: %s" % changed) # Update the received new topo self.internal_topo = changed # Notify all components for topology change --> this event causes # the DoV updating self.raiseEventNoErrors( DomainChangedEvent, domain=self.domain_name, data=self.internal_topo, cause=DomainChangedEvent.TYPE.DOMAIN_CHANGED) return # If changed is None something went wrong, probably remote domain is not # reachable. Step to the other half of the function elif changed is None: log.warning( "Lost connection with %s agent! Going to slow poll..." % self.domain_name) # Clear internal topology log.debug("Clear topology from domain: %s" % self.domain_name) self.internal_topo = None self.raiseEventNoErrors( DomainChangedEvent, domain=self.domain_name, cause=DomainChangedEvent.TYPE.DOMAIN_DOWN) else: log.warning( "Got unexpected return value from check_topology_changed(): %s" % type(changed)) return # If this is the first call of poll() if self._detected is None: log.warning( "Local agent in domain: %s is not detected! Keep trying..." % self.domain_name) self._detected = False elif self._detected: # Detected before -> lost connection = big Problem self._detected = False self.restart_polling() else: # No success but not for the first try -> keep trying silently pass
def rest_api_edit_config(self, id, data, params=None): """ Implement edit-config call for CAS layer. Receive edit-config request from external component and directly forward data for deployment. :param params: request params :type params: dict :return: None """ log.getChild('[DOV-API]').info( "Invoke instantiation on %s with NF-FG: " "%s " % (self.__class__.__name__, id)) if CONFIG.get_rest_api_config(self._core_name)['unify_interface']: log.debug("Virtualizer format enabled! Start conversion step...") if CONFIG.get_rest_api_config(self._core_name)['diff']: log.debug("Diff format enabled! Start patching step...") if self.api_mgr.last_response is None: log.info( "Missing cached Virtualizer! Acquiring topology now..." ) self.rest_api_get_config() stats.add_measurement_start_entry(type=stats.TYPE_PROCESSING, info="RECREATE-FULL-REQUEST") log.info("Patching cached topology with received diff...") full_req = self.api_mgr.last_response.yang_copy() full_req.patch(source=data) stats.add_measurement_end_entry(type=stats.TYPE_PROCESSING, info="RECREATE-FULL-REQUEST") else: full_req = data log.info("Converting full request data...") stats.add_measurement_start_entry(type=stats.TYPE_CONVERSION, info="VIRTUALIZER-->NFFG") nffg = self.api_mgr.converter.parse_from_Virtualizer( vdata=full_req) stats.add_measurement_end_entry(type=stats.TYPE_CONVERSION, info="VIRTUALIZER-->NFFG") else: nffg = data log.debug("Set NFFG id: %s" % id) if nffg.service_id is None: nffg.service_id = nffg.id nffg.id = id if params: nffg.add_metadata(name="params", value=params) log.info("Proceeding request: %s to instantiation..." % id) if CONFIG.get_vnfm_enabled(): deploy_status = self.controller_adapter.status_mgr.get_last_status( ) if deploy_status is None: log.warning( "Received direct DoV rewrite request from external " "component without any preliminary deploy request!") else: if deploy_status.id != nffg.id: log.error( "Received direct deploy request id: %s is different from " "service request under deploy: %s" % (nffg.id, deploy_status.id)) return else: self.controller_adapter.cancel_vnfm_timer() log.getChild('API').debug("Store received DoV request...") msg_id = self.api_mgr.request_cache.cache_request_by_nffg(nffg=nffg) if msg_id is not None: self.api_mgr.request_cache.set_in_progress(id=msg_id) log.getChild('API').debug("Request is stored with id: %s" % msg_id) else: log.getChild('API').warning("No request info detected.") self.__proceed_installation(mapped_nffg=nffg, direct_deploy=True)