def __process_info_result(self, status, fail): """ Perform common tasks after an Info request was processed and responses were collected. :param status: deploy status :type status: :any:`DomainRequestStatus` :param fail: mark the Info step was failed :type fail: bool :return: None """ self.log.debug("Cache collected 'info' request status...") req_status = self.api_mgr.request_cache.get_request( message_id=status.id) if req_status is None: self.log.debug("Request status is missing: %s! " "Skip result processing..." % status.id) return self.log.debug("Process collected info result...") if fail: self.api_mgr.request_cache.set_error_result(id=status.id) body = None else: self.api_mgr.request_cache.set_success_result(id=status.id) body = status.data[0] body = body.xml() if isinstance(body, Info) else str(body) log.info("Set request status: %s for message: %s" % (req_status.status, req_status.message_id)) log.log(VERBOSE, "Collected Info data:\n%s" % body) ret = self.api_mgr.invoke_callback(message_id=status.id, body=body) if ret is None: self.log.debug("No callback was defined!") else: self.log.info("Callback: %s has invoked with return value: %s" % (req_status.get_callback(), ret))
def _proceed_to_install_NFFG(self, mapped_nffg): """ Send mapped :any:`NFFG` to Controller Adaptation Sublayer in an implementation-specific way. General function which is used from microtask and Python thread also. This function contains the last steps before the mapped NFFG will be sent to the next layer. :param mapped_nffg: mapped NF-FG :type mapped_nffg: :any:`NFFG` :return: None """ # Non need to rebind req links --> it will be done in Adaptation layer # Log verbose mapping result in unified way (threaded/non-threaded) log.log( VERBOSE, "Mapping result of Orchestration Layer:\n%s" % mapped_nffg.dump()) # Notify remote visualizer about the mapping result if it's needed notify_remote_visualizer(data=mapped_nffg, id=LAYER_NAME) # Sending NF-FG to Adaptation layer as an Event # Exceptions in event handlers are caught by default in a non-blocking way self.raiseEventNoErrors(InstallNFFGEvent, mapped_nffg) log.getChild('API').info( "Mapped NF-FG: %s has been sent to Adaptation..." % mapped_nffg)
def __manage_neo4j_service(self): """ Manage neo4j service. :return: None """ if not CONFIG.get_manage_neo4j_service(): log.debug("Skip Neo4j service management...") return log.debug("Detected Neo4j service name: %s" % self.service_name) if check_service_status(self.service_name): log.debug("%s service is already running..." % self.service_name) return log.info("Starting service: %s..." % self.service_name) ret = run_cmd('sudo service %s start' % self.service_name) if "failed" in ret: log.error("Neo4j service initiation status: %s" % ret) return log.log(VERBOSE, "Neo4j service initiation status: %s" % ret) # Check if the service has been started - only 5 try if port_tester(host=self.DB_HOST, port=self.DB_PORT, interval=1, period=10, log=log): log.debug("Neo4j service has been verified!") else: log.error("Neo4j service has not started correctly!")
def finalize(self): """ Finalize function for the class. :return: None """ if CONFIG.get_manage_neo4j_service(): log.info("Stopping %s service..." % self.service_name) ret = run_cmd('sudo service %s stop' % self.service_name) log.log(VERBOSE, "Neo4j service shutdown status: %s" % ret)
def __collect_binding(dov, nfs): """ Collect mapping of given NFs on the global view(DoV). :param dov: global topology :type dov: :class:`NFFG` :param nfs: list of NFs :type nfs: list :return: mapping :rtype: list of dict """ mappings = [] # Process NFs for nf_id in nfs: mapping = {} # Get the connected infra node if nf_id not in dov: log.warning( "NF: %s is not found in the global topology(DoV)!" % nf_id) continue bisbis = [n.id for n in dov.infra_neighbors(nf_id)] log.log(VERBOSE, "Detected mapped BiSBiS node:" % bisbis) if len(bisbis) != 1: log.warning("Detected unexpected number of BiSBiS node: %s!" % bisbis) continue bisbis = bisbis.pop() # Add NF id nf = {"id": nf_id, "ports": []} for dyn_link in dov.network[nf_id][bisbis].itervalues(): port = OrderedDict(id=dyn_link.src.id) if dyn_link.src.l4 is not None: try: port['management'] = ast.literal_eval(dyn_link.src.l4) except SyntaxError: log.warning( "L4 address entry: %s is not valid Python expression! " "Add the original string..." % dyn_link.src.l4) port['management'] = dyn_link.src.l4 nf['ports'].append(port) mapping['nf'] = nf # Add infra node ID and domain name bisbis = bisbis.split('@') bb_mapping = { "id": bisbis[0], "domain": bisbis[1] if len(bisbis) > 1 else None } mapping['bisbis'] = bb_mapping mappings.append(mapping) return mappings
def instantiate_nffg (self, nffg): """ Main API function for NF-FG instantiation. :param nffg: NFFG instance :type nffg: :any:`NFFG` :return: mapped NFFG instance :rtype: :any:`NFFG` """ log.debug("Invoke %s to instantiate given NF-FG" % self.__class__.__name__) # Store newly created NF-FG self.nffgManager.save(nffg) # Get Domain Virtualizer to acquire global domain view global_view = self.virtualizerManager.dov # Notify remote visualizer about resource view of this layer if it's needed notify_remote_visualizer(data=global_view.get_resource_info(), id=LAYER_NAME) # Log verbose mapping request log.log(VERBOSE, "Orchestration Layer request graph:\n%s" % nffg.dump()) # Start Orchestrator layer mapping print nffg.dump() if global_view is not None: if isinstance(global_view, AbstractVirtualizer): # If the request is a bare NFFG, it is probably an empty topo for domain # deletion --> skip mapping to avoid BadInputException and forward # topo to adaptation layer if nffg.is_bare(): log.warning("No valid service request (VNFs/Flowrules/SGhops) has " "been detected in SG request! Skip orchestration in " "layer: %s and proceed with the bare %s..." % (LAYER_NAME, nffg)) if nffg.is_virtualized(): if nffg.is_SBB(): log.debug("Request is a bare SingleBiSBiS representation!") else: log.warning( "Detected virtualized representation with multiple BiSBiS " "nodes! Currently this type of virtualization is nut fully" "supported!") else: log.debug("Detected full view representation!") # Return with the original request return nffg else: log.info("Request check: detected valid content!") try: # Run Nf-FG mapping orchestration log.debug("Starting request preprocession...") log.info(int(round(time.time() * 1000))) self.preprocess_nffg(nffg) log.debug("Preprocession ended, start mapping") log.info(int(round(time.time() * 1000))) mapped_nffg = self.mapper.orchestrate(nffg, global_view) log.debug("NF-FG instantiation is finished by %s" % self.__class__.__name__) log.info(int(round(time.time() * 1000))) return mapped_nffg except ProcessorError as e: log.warning("Mapping pre/post processing was unsuccessful! " "Cause: %s" % e) else: log.warning("Global view is not subclass of AbstractVirtualizer!") else: log.warning("Global view is not acquired correctly!") log.error("Abort orchestration process!")
def _perform_mapping(self, input_graph, resource_view): """ Orchestrate mapping of given NF-FG on given global resource. :param input_graph: Network Function Forwarding Graph :type input_graph: :any:`NFFG` :param resource_view: global resource view :type resource_view: :any:`DomainVirtualizer` :return: mapped Network Function Forwarding Graph :rtype: :any:`NFFG` """ if input_graph is None: log.error( "Missing mapping request information! Abort mapping process!") return None log.debug("Request %s to launch orchestration on NF-FG: %s with View: " "%s" % (self.__class__.__name__, input_graph, resource_view)) # Steps before mapping (optional) log.debug("Request global resource info...") virt_resource = resource_view.get_resource_info() if virt_resource is None: log.error("Missing resource information! Abort mapping process!") return None # log a warning if resource is empty --> possibly mapping will be failed if virt_resource.is_empty(): log.warning("Resource information is empty!") # Log verbose resource view if it is exist log.log( VERBOSE, "Orchestration Layer resource graph:\n%s" % virt_resource.dump()) # Check if the mapping algorithm is enabled if not CONFIG.get_mapping_enabled(LAYER_NAME): log.warning("Mapping algorithm in Layer: %s is disabled! " "Skip mapping step and return service request " "to lower layer..." % LAYER_NAME) # virt_resource.id = input_graph.id # return virt_resource # Send request forward (probably to Remote ESCAPE) return input_graph # Run actual mapping algorithm if self._threaded: # Schedule a microtask which run mapping algorithm in a Python thread log.info("Schedule mapping algorithm: %s in a worker thread" % self.strategy.__name__) call_as_coop_task(self._start_mapping, graph=input_graph, resource=virt_resource) log.info("NF-FG: %s orchestration is finished by %s" % (input_graph, self.__class__.__name__)) # Return with None return None else: mapped_nffg = self.strategy.map(graph=input_graph, resource=virt_resource) if mapped_nffg is None: log.error( "Mapping process is failed! Abort orchestration process.") else: # Steps after mapping (optional) log.info( "NF-FG: %s orchestration is finished by %s successfully!" % (input_graph, self.__class__.__name__)) return mapped_nffg
def _perform_mapping(self, input_graph, resource_view, continued=False): """ Orchestrate mapping of given NF-FG on given global resource. :param input_graph: Network Function Forwarding Graph :type input_graph: :class:`NFFG` :param resource_view: global resource view :type resource_view: :any:`DomainVirtualizer` :return: mapped Network Function Forwarding Graph :rtype: :class:`NFFG` """ if input_graph is None: log.error( "Missing mapping request information! Abort mapping process!") return None log.debug( "Request %s to launch orchestration on NF-FG: %s with View: " "%s, continued remap: %s" % (self.__class__.__name__, input_graph, resource_view, continued)) # Steps before mapping (optional) log.debug("Request global resource info...") virt_resource = resource_view.get_resource_info() if virt_resource is None: log.error("Missing resource information! Abort mapping process!") return None # log a warning if resource is empty --> possibly mapping will be failed if virt_resource.is_empty(): log.warning("Resource information is empty!") # Log verbose resource view if it is exist log.log( VERBOSE, "Orchestration Layer resource graph:\n%s" % virt_resource.dump()) # Check if the mapping algorithm is enabled if not CONFIG.get_mapping_enabled(LAYER_NAME): log.warning("Mapping algorithm in Layer: %s is disabled! " "Skip mapping step and return service request " "to lower layer..." % LAYER_NAME) # virt_resource.id = input_graph.id # return virt_resource # Send request forward (probably to Remote ESCAPE) input_graph.status = NFFG.MAP_STATUS_SKIPPED log.debug("Mark NFFG status: %s!" % input_graph.status) return input_graph # Run actual mapping algorithm if self._threaded: # Schedule a microtask which run mapping algorithm in a Python thread log.info("Schedule mapping algorithm: %s in a worker thread" % self.strategy.__name__) call_as_coop_task(self._start_mapping, graph=input_graph, resource=virt_resource) log.info("NF-FG: %s orchestration is finished by %s" % (input_graph, self.__class__.__name__)) # Return with None return None else: state = self.last_mapping_state if continued else None mapping_result = self.strategy.map( graph=input_graph, resource=virt_resource, persistent=self.persistent_state, pre_state=state) if isinstance(mapping_result, tuple or list): if len(mapping_result) == 2: mapped_nffg = mapping_result[0] self.persistent_state = mapping_result[1] log.debug("Cache returned persistent state: %s" % self.persistent_state) elif len(mapping_result) == 3: mapped_nffg = mapping_result[0] self.persistent_state = mapping_result[1] log.debug("Cache returned persistent state: %s" % self.persistent_state) self.last_mapping_state = mapping_result[2] log.debug("Cache returned mapping state: %s" % self.last_mapping_state) else: log.error("Mapping result is invalid: %s" % repr(mapping_result)) mapped_nffg = None else: mapped_nffg = mapping_result # Check error result if mapped_nffg is None: log.error( "Mapping process is failed! Abort orchestration process.") else: # Steps after mapping (optional) log.info( "NF-FG: %s orchestration is finished by %s successfully!" % (input_graph, self.__class__.__name__)) log.debug("Last mapping state: %s" % self.last_mapping_state) if self.last_mapping_state: log.debug("Mapping iteration: %s" % self.last_mapping_state.get_number_of_trials() if self.last_mapping_state else None) return mapped_nffg
def __proceed_instantiation(self, nffg, resource_nffg): """ Helper function to instantiate the NFFG mapping from different source. :param nffg: pre-mapped service request :type nffg: :class:`NFFG` :return: None """ self.log.info("Invoke instantiation on %s with NF-FG: %s" % (self.__class__.__name__, nffg.name)) stats.add_measurement_start_entry(type=stats.TYPE_ORCHESTRATION, info=LAYER_NAME) # Get shown topology view if resource_nffg is None: log.error("Missing resource for difference calculation!") return log.debug("Got resource view for difference calculation: %s" % resource_nffg) self.log.debug("Store received NFFG request info...") 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) self.log.debug("Request is stored with id: %s" % msg_id) else: self.log.debug("No request info detected.") # Check if mapping mode is set globally in CONFIG mapper_params = CONFIG.get_mapping_config(layer=LAYER_NAME) if 'mode' in mapper_params and mapper_params['mode'] is not None: mapping_mode = mapper_params['mode'] log.info("Detected mapping mode from configuration: %s" % mapping_mode) elif nffg.mode is not None: mapping_mode = nffg.mode log.info("Detected mapping mode from NFFG: %s" % mapping_mode) else: mapping_mode = None log.info("No mapping mode was defined explicitly!") if not CONFIG.get_mapping_enabled(layer=LAYER_NAME): log.warning("Mapping is disabled! Skip difference calculation...") elif nffg.status == NFFG.MAP_STATUS_SKIPPED: log.debug("Detected NFFG map status: %s! " "Skip difference calculation and " "proceed with original request..." % nffg.status) elif mapping_mode != NFFG.MODE_REMAP: # Calculated ADD-DELETE difference log.debug("Calculate ADD - DELETE difference with mapping mode...") # Recreate SG-hops for diff calc. log.debug("Recreate SG hops for difference calculation...") NFFGToolBox.recreate_all_sghops(nffg=nffg) NFFGToolBox.recreate_all_sghops(nffg=resource_nffg) log.log(VERBOSE, "New NFFG:\n%s" % nffg.dump()) log.log(VERBOSE, "Resource NFFG:\n%s" % resource_nffg.dump()) # Calculate difference add_nffg, del_nffg = NFFGToolBox.generate_difference_of_nffgs( old=resource_nffg, new=nffg, ignore_infras=True) log.log(VERBOSE, "Calculated ADD NFFG:\n%s" % add_nffg.dump()) log.log(VERBOSE, "Calculated DEL NFFG:\n%s" % del_nffg.dump()) if not add_nffg.is_bare() and del_nffg.is_bare(): nffg = add_nffg log.info("DEL NFFG is bare! Calculated mapping mode: %s" % nffg.mode) elif add_nffg.is_bare() and not del_nffg.is_bare(): nffg = del_nffg log.info("ADD NFFG is bare! Calculated mapping mode: %s" % nffg.mode) elif not add_nffg.is_bare() and not del_nffg.is_bare(): log.warning("Both ADD / DEL mode is not supported currently") self.__process_mapping_result(nffg_id=nffg.id, fail=True) stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION, info=LAYER_NAME + "-FAILED") self.raiseEventNoErrors( InstantiationFinishedEvent, id=nffg.id, result=InstantiationFinishedEvent.ABORTED) return else: log.debug("Difference calculation resulted empty subNFFGs!") log.warning( "No change has been detected in request! Skip mapping...") self.log.debug("Invoked instantiation on %s is finished!" % self.__class__.__name__) self.__process_mapping_result(nffg_id=nffg.id, fail=False) stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION, info=LAYER_NAME + "-SKIPPED") return else: log.debug( "Mode: %s detected from config! Skip difference calculation..." % mapping_mode) try: if CONFIG.get_mapping_enabled(layer=LAYER_NAME): # Initiate request mapping mapped_nffg = self.orchestrator.instantiate_nffg(nffg=nffg) else: log.warning("Mapping is disabled! Skip instantiation step...") mapped_nffg = nffg mapped_nffg.status = NFFG.MAP_STATUS_SKIPPED log.debug("Mark NFFG status: %s!" % mapped_nffg.status) # Rewrite REMAP mode for backward compatibility if mapped_nffg is not None and mapping_mode == NFFG.MODE_REMAP: mapped_nffg.mode = mapping_mode log.debug("Rewrite mapping mode: %s into mapped NFFG..." % mapped_nffg.mode) else: log.debug("Skip mapping mode rewriting! Mode remained: %s" % mapping_mode) self.log.debug("Invoked instantiate_nffg on %s is finished!" % self.__class__.__name__) # If mapping is not threaded and finished with OK if mapped_nffg is not None and not self.orchestrator.mapper.threaded: self._proceed_to_install_NFFG(mapped_nffg=mapped_nffg, original_request=nffg) else: log.warning( "Something went wrong in service request instantiation: " "mapped service request is missing!") self.__process_mapping_result(nffg_id=nffg.id, fail=True) stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION, info=LAYER_NAME + "-FAILED") self.raiseEventNoErrors( InstantiationFinishedEvent, id=nffg.id, result=InstantiationFinishedEvent.MAPPING_ERROR) except ProcessorError as e: self.__process_mapping_result(nffg_id=nffg.id, fail=True) stats.add_measurement_end_entry(type=stats.TYPE_ORCHESTRATION, info=LAYER_NAME + "-DENIED") self.raiseEventNoErrors( InstantiationFinishedEvent, id=nffg.id, result=InstantiationFinishedEvent.REFUSED_BY_VERIFICATION, error=e)
def __collect_binding(dov, nfs): """ Collect mapping of given NFs on the global view(DoV) with the structure: .. code-block:: json [ { "bisbis": { "domain": null, "id": "EE2" }, "nf": { "id": "fwd", "ports": [ { "id": 1, "management": { "22/tcp": [ "0.0.0.0", 20000 ] } } ] } } ] :param dov: global topology :type dov: :class:`NFFG` :param nfs: list of NFs :type nfs: list :return: mapping :rtype: list of dict """ mappings = [] # Process NFs for nf_id in nfs: mapping = {} # Get the connected infra node if nf_id not in dov: log.warning("NF: %s in to in the global topology(DoV)!" % nf_id) continue bisbis = [n.id for n in dov.infra_neighbors(nf_id)] log.log(VERBOSE, "Detected mapped BiSBiS node:" % bisbis) if len(bisbis) != 1: log.warning("Detected unexpected number of BiSBiS node: %s!" % bisbis) continue bisbis = bisbis.pop() # Add NF id nf = {"id": nf_id, "ports": []} for dyn_link in dov.network[nf_id][bisbis].itervalues(): port = OrderedDict(id=dyn_link.src.id) if dyn_link.src.l4 is not None: try: port['management'] = ast.literal_eval(dyn_link.src.l4) except SyntaxError: log.warning( "L4 address entry: %s is not valid Python expression! " "Add the original string..." % dyn_link.src.l4) port['management'] = dyn_link.src.l4 nf['ports'].append(port) mapping['nf'] = nf # Add infra node ID and domain name bisbis = bisbis.split('@') bb_mapping = { "id": bisbis[0], "domain": bisbis[1] if len(bisbis) > 1 else None } if bb_mapping.get("domain"): domain_url = CONFIG.get_domain_url( domain=bb_mapping.get("domain")) log.debug("Domain: %s - Detected URL: %s" % (bb_mapping.get("domain"), domain_url)) if domain_url is not None: bb_mapping["url"] = domain_url else: log.warning("Missing URL for domain: %s!" % bb_mapping["domain"]) mapping['bisbis'] = bb_mapping mappings.append(mapping) return mappings
def instantiate_nffg(self, nffg, continued_request_id=None): """ Main API function for NF-FG instantiation. :param nffg: NFFG instance :type nffg: :class:`NFFG` :param continued_request_id: use explicit request id if request is continued after a trial and error (default: False) :type continued_request_id: str or None :return: mapped NFFG instance :rtype: :class:`NFFG` """ log.debug("Invoke %s to instantiate given NF-FG" % self.__class__.__name__) if not continued_request_id: # Store newly created NF-FG self.nffgManager.save(nffg) else: # Use the original NFFG requested for getting the original request nffg = self.nffgManager.get(nffg_id=continued_request_id) log.info("Using original request for remapping: %s" % nffg) # Get Domain Virtualizer to acquire global domain view global_view = self.virtualizerManager.dov # Notify remote visualizer about resource view of this layer if it's needed # notify_remote_visualizer(data=global_view.get_resource_info(), # id=LAYER_NAME) # Log verbose mapping request log.log(VERBOSE, "Orchestration Layer request graph:\n%s" % nffg.dump()) # Start Orchestrator layer mapping if global_view is not None: # If the request is a bare NFFG, it is probably an empty topo for domain # deletion --> skip mapping to avoid BadInputException and forward # topo to adaptation layer if not continued_request_id: if nffg.is_bare(): log.warning( "No valid service request (VNFs/Flowrules/SGhops) has " "been detected in SG request! Skip orchestration in " "layer: %s and proceed with the bare %s..." % (LAYER_NAME, nffg)) if nffg.is_virtualized(): if nffg.is_SBB(): log.debug( "Request is a bare SingleBiSBiS representation!" ) else: log.warning( "Detected virtualized representation with multiple BiSBiS " "nodes! Currently this type of virtualization is nut fully " "supported!") else: log.debug("Detected full view representation!") # Return with the original request return nffg else: log.info("Request check: detected valid NFFG content!") try: # Run NF-FG mapping orchestration mapped_nffg = self.mapper.orchestrate( input_graph=nffg, resource_view=global_view, continued=bool(continued_request_id)) log.debug("NF-FG instantiation is finished by %s" % self.__class__.__name__) return mapped_nffg except ProcessorError as e: log.warning("Mapping pre/post processing was unsuccessful! " "Cause: %s" % e) # Propagate the ProcessError to API layer raise else: log.warning("Global view is not acquired correctly!") log.error("Abort orchestration process!")