X-Git-Url: https://osm.etsi.org/gitweb/?p=osm%2FRO.git;a=blobdiff_plain;f=RO-VIM-openstack%2Fosm_rovim_openstack%2Fvimconn_openstack.py;fp=RO-VIM-openstack%2Fosm_rovim_openstack%2Fvimconn_openstack.py;h=25e58d57b31411df555edcd0baba0bd941b9e131;hp=9faf98d4f7b90d9ad0246cedd8825d48ca9a68e2;hb=6986244790d12f4ce734fd5cd2599e84b29c3f84;hpb=21c55d66c67cce097adab2f237356388b1a16077 diff --git a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py index 9faf98d4..25e58d57 100644 --- a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py +++ b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py @@ -3451,6 +3451,45 @@ class vimconnector(vimconn.VimConnector): ) ) + def delete_user(self, user_id): + """Delete a user from openstack VIM + Returns the user identifier""" + if self.debug: + print("osconnector: Deleting a user from VIM") + + try: + self._reload_connection() + self.keystone.users.delete(user_id) + + return 1, user_id + except ksExceptions.ConnectionError as e: + error_value = -vimconn.HTTP_Bad_Request + error_text = ( + type(e).__name__ + + ": " + + (str(e) if len(e.args) == 0 else str(e.args[0])) + ) + except ksExceptions.NotFound as e: + error_value = -vimconn.HTTP_Not_Found + error_text = ( + type(e).__name__ + + ": " + + (str(e) if len(e.args) == 0 else str(e.args[0])) + ) + except ksExceptions.ClientException as e: # TODO remove + error_value = -vimconn.HTTP_Bad_Request + error_text = ( + type(e).__name__ + + ": " + + (str(e) if len(e.args) == 0 else str(e.args[0])) + ) + + # TODO insert exception vimconn.HTTP_Unauthorized + # if reaching here is because an exception + self.logger.debug("delete_tenant " + error_text) + + return error_value, error_text + def get_hosts_info(self): """Get the information of deployed hosts Returns the hosts content""" @@ -3524,6 +3563,619 @@ class vimconnector(vimconn.VimConnector): return error_value, error_text + def new_classification(self, name, ctype, definition): + self.logger.debug( + "Adding a new (Traffic) Classification to VIM, named %s", name + ) + + try: + new_class = None + self._reload_connection() + + if ctype not in supportedClassificationTypes: + raise vimconn.VimConnNotSupportedException( + "OpenStack VIM connector does not support provided " + "Classification Type {}, supported ones are: {}".format( + ctype, supportedClassificationTypes + ) + ) + + if not self._validate_classification(ctype, definition): + raise vimconn.VimConnException( + "Incorrect Classification definition for the type specified." + ) + + classification_dict = definition + classification_dict["name"] = name + new_class = self.neutron.create_sfc_flow_classifier( + {"flow_classifier": classification_dict} + ) + + return new_class["flow_classifier"]["id"] + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self.logger.error("Creation of Classification failed.") + self._format_exception(e) + + def get_classification(self, class_id): + self.logger.debug(" Getting Classification %s from VIM", class_id) + filter_dict = {"id": class_id} + class_list = self.get_classification_list(filter_dict) + + if len(class_list) == 0: + raise vimconn.VimConnNotFoundException( + "Classification '{}' not found".format(class_id) + ) + elif len(class_list) > 1: + raise vimconn.VimConnConflictException( + "Found more than one Classification with this criteria" + ) + + classification = class_list[0] + + return classification + + def get_classification_list(self, filter_dict={}): + self.logger.debug( + "Getting Classifications from VIM filter: '%s'", str(filter_dict) + ) + + try: + filter_dict_os = filter_dict.copy() + self._reload_connection() + + if self.api_version3 and "tenant_id" in filter_dict_os: + filter_dict_os["project_id"] = filter_dict_os.pop("tenant_id") + + classification_dict = self.neutron.list_sfc_flow_classifiers( + **filter_dict_os + ) + classification_list = classification_dict["flow_classifiers"] + self.__classification_os2mano(classification_list) + + return classification_list + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def delete_classification(self, class_id): + self.logger.debug("Deleting Classification '%s' from VIM", class_id) + + try: + self._reload_connection() + self.neutron.delete_sfc_flow_classifier(class_id) + + return class_id + except ( + neExceptions.ConnectionFailed, + neExceptions.NeutronException, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def new_sfi(self, name, ingress_ports, egress_ports, sfc_encap=True): + self.logger.debug( + "Adding a new Service Function Instance to VIM, named '%s'", name + ) + + try: + new_sfi = None + self._reload_connection() + correlation = None + + if sfc_encap: + correlation = "nsh" + + if len(ingress_ports) != 1: + raise vimconn.VimConnNotSupportedException( + "OpenStack VIM connector can only have 1 ingress port per SFI" + ) + + if len(egress_ports) != 1: + raise vimconn.VimConnNotSupportedException( + "OpenStack VIM connector can only have 1 egress port per SFI" + ) + + sfi_dict = { + "name": name, + "ingress": ingress_ports[0], + "egress": egress_ports[0], + "service_function_parameters": {"correlation": correlation}, + } + new_sfi = self.neutron.create_sfc_port_pair({"port_pair": sfi_dict}) + + return new_sfi["port_pair"]["id"] + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + if new_sfi: + try: + self.neutron.delete_sfc_port_pair(new_sfi["port_pair"]["id"]) + except Exception: + self.logger.error( + "Creation of Service Function Instance failed, with " + "subsequent deletion failure as well." + ) + + self._format_exception(e) + + def get_sfi(self, sfi_id): + self.logger.debug("Getting Service Function Instance %s from VIM", sfi_id) + filter_dict = {"id": sfi_id} + sfi_list = self.get_sfi_list(filter_dict) + + if len(sfi_list) == 0: + raise vimconn.VimConnNotFoundException( + "Service Function Instance '{}' not found".format(sfi_id) + ) + elif len(sfi_list) > 1: + raise vimconn.VimConnConflictException( + "Found more than one Service Function Instance with this criteria" + ) + + sfi = sfi_list[0] + + return sfi + + def get_sfi_list(self, filter_dict={}): + self.logger.debug( + "Getting Service Function Instances from VIM filter: '%s'", str(filter_dict) + ) + + try: + self._reload_connection() + filter_dict_os = filter_dict.copy() + + if self.api_version3 and "tenant_id" in filter_dict_os: + filter_dict_os["project_id"] = filter_dict_os.pop("tenant_id") + + sfi_dict = self.neutron.list_sfc_port_pairs(**filter_dict_os) + sfi_list = sfi_dict["port_pairs"] + self.__sfi_os2mano(sfi_list) + + return sfi_list + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def delete_sfi(self, sfi_id): + self.logger.debug("Deleting Service Function Instance '%s' from VIM", sfi_id) + + try: + self._reload_connection() + self.neutron.delete_sfc_port_pair(sfi_id) + + return sfi_id + except ( + neExceptions.ConnectionFailed, + neExceptions.NeutronException, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def new_sf(self, name, sfis, sfc_encap=True): + self.logger.debug("Adding a new Service Function to VIM, named '%s'", name) + + try: + new_sf = None + self._reload_connection() + # correlation = None + # if sfc_encap: + # correlation = "nsh" + + for instance in sfis: + sfi = self.get_sfi(instance) + + if sfi.get("sfc_encap") != sfc_encap: + raise vimconn.VimConnNotSupportedException( + "OpenStack VIM connector requires all SFIs of the " + "same SF to share the same SFC Encapsulation" + ) + + sf_dict = {"name": name, "port_pairs": sfis} + new_sf = self.neutron.create_sfc_port_pair_group( + {"port_pair_group": sf_dict} + ) + + return new_sf["port_pair_group"]["id"] + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + if new_sf: + try: + self.neutron.delete_sfc_port_pair_group( + new_sf["port_pair_group"]["id"] + ) + except Exception: + self.logger.error( + "Creation of Service Function failed, with " + "subsequent deletion failure as well." + ) + + self._format_exception(e) + + def get_sf(self, sf_id): + self.logger.debug("Getting Service Function %s from VIM", sf_id) + filter_dict = {"id": sf_id} + sf_list = self.get_sf_list(filter_dict) + + if len(sf_list) == 0: + raise vimconn.VimConnNotFoundException( + "Service Function '{}' not found".format(sf_id) + ) + elif len(sf_list) > 1: + raise vimconn.VimConnConflictException( + "Found more than one Service Function with this criteria" + ) + + sf = sf_list[0] + + return sf + + def get_sf_list(self, filter_dict={}): + self.logger.debug( + "Getting Service Function from VIM filter: '%s'", str(filter_dict) + ) + + try: + self._reload_connection() + filter_dict_os = filter_dict.copy() + + if self.api_version3 and "tenant_id" in filter_dict_os: + filter_dict_os["project_id"] = filter_dict_os.pop("tenant_id") + + sf_dict = self.neutron.list_sfc_port_pair_groups(**filter_dict_os) + sf_list = sf_dict["port_pair_groups"] + self.__sf_os2mano(sf_list) + + return sf_list + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def delete_sf(self, sf_id): + self.logger.debug("Deleting Service Function '%s' from VIM", sf_id) + + try: + self._reload_connection() + self.neutron.delete_sfc_port_pair_group(sf_id) + + return sf_id + except ( + neExceptions.ConnectionFailed, + neExceptions.NeutronException, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def new_sfp(self, name, classifications, sfs, sfc_encap=True, spi=None): + self.logger.debug("Adding a new Service Function Path to VIM, named '%s'", name) + + try: + new_sfp = None + self._reload_connection() + # In networking-sfc the MPLS encapsulation is legacy + # should be used when no full SFC Encapsulation is intended + correlation = "mpls" + + if sfc_encap: + correlation = "nsh" + + sfp_dict = { + "name": name, + "flow_classifiers": classifications, + "port_pair_groups": sfs, + "chain_parameters": {"correlation": correlation}, + } + + if spi: + sfp_dict["chain_id"] = spi + + new_sfp = self.neutron.create_sfc_port_chain({"port_chain": sfp_dict}) + + return new_sfp["port_chain"]["id"] + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + if new_sfp: + try: + self.neutron.delete_sfc_port_chain(new_sfp["port_chain"]["id"]) + except Exception: + self.logger.error( + "Creation of Service Function Path failed, with " + "subsequent deletion failure as well." + ) + + self._format_exception(e) + + def get_sfp(self, sfp_id): + self.logger.debug(" Getting Service Function Path %s from VIM", sfp_id) + + filter_dict = {"id": sfp_id} + sfp_list = self.get_sfp_list(filter_dict) + + if len(sfp_list) == 0: + raise vimconn.VimConnNotFoundException( + "Service Function Path '{}' not found".format(sfp_id) + ) + elif len(sfp_list) > 1: + raise vimconn.VimConnConflictException( + "Found more than one Service Function Path with this criteria" + ) + + sfp = sfp_list[0] + + return sfp + + def get_sfp_list(self, filter_dict={}): + self.logger.debug( + "Getting Service Function Paths from VIM filter: '%s'", str(filter_dict) + ) + + try: + self._reload_connection() + filter_dict_os = filter_dict.copy() + + if self.api_version3 and "tenant_id" in filter_dict_os: + filter_dict_os["project_id"] = filter_dict_os.pop("tenant_id") + + sfp_dict = self.neutron.list_sfc_port_chains(**filter_dict_os) + sfp_list = sfp_dict["port_chains"] + self.__sfp_os2mano(sfp_list) + + return sfp_list + except ( + neExceptions.ConnectionFailed, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def delete_sfp(self, sfp_id): + self.logger.debug("Deleting Service Function Path '%s' from VIM", sfp_id) + + try: + self._reload_connection() + self.neutron.delete_sfc_port_chain(sfp_id) + + return sfp_id + except ( + neExceptions.ConnectionFailed, + neExceptions.NeutronException, + ksExceptions.ClientException, + neExceptions.NeutronException, + ConnectionError, + ) as e: + self._format_exception(e) + + def refresh_sfps_status(self, sfp_list): + """Get the status of the service function path + Params: the list of sfp identifiers + Returns a dictionary with: + vm_id: #VIM id of this service function path + status: #Mandatory. Text with one of: + # DELETED (not found at vim) + # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) + # OTHER (Vim reported other status not understood) + # ERROR (VIM indicates an ERROR status) + # ACTIVE, + # CREATING (on building process) + error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR + vim_info: #Text with plain information obtained from vim (yaml.safe_dump)F + """ + sfp_dict = {} + self.logger.debug( + "refresh_sfps status: Getting tenant SFP information from VIM" + ) + + for sfp_id in sfp_list: + sfp = {} + + try: + sfp_vim = self.get_sfp(sfp_id) + + if sfp_vim["spi"]: + sfp["status"] = vmStatus2manoFormat["ACTIVE"] + else: + sfp["status"] = "OTHER" + sfp["error_msg"] = "VIM status reported " + sfp["status"] + + sfp["vim_info"] = self.serialize(sfp_vim) + + if sfp_vim.get("fault"): + sfp["error_msg"] = str(sfp_vim["fault"]) + except vimconn.VimConnNotFoundException as e: + self.logger.error("Exception getting sfp status: %s", str(e)) + sfp["status"] = "DELETED" + sfp["error_msg"] = str(e) + except vimconn.VimConnException as e: + self.logger.error("Exception getting sfp status: %s", str(e)) + sfp["status"] = "VIM_ERROR" + sfp["error_msg"] = str(e) + + sfp_dict[sfp_id] = sfp + + return sfp_dict + + def refresh_sfis_status(self, sfi_list): + """Get the status of the service function instances + Params: the list of sfi identifiers + Returns a dictionary with: + vm_id: #VIM id of this service function instance + status: #Mandatory. Text with one of: + # DELETED (not found at vim) + # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) + # OTHER (Vim reported other status not understood) + # ERROR (VIM indicates an ERROR status) + # ACTIVE, + # CREATING (on building process) + error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR + vim_info: #Text with plain information obtained from vim (yaml.safe_dump) + """ + sfi_dict = {} + self.logger.debug( + "refresh_sfis status: Getting tenant sfi information from VIM" + ) + + for sfi_id in sfi_list: + sfi = {} + + try: + sfi_vim = self.get_sfi(sfi_id) + + if sfi_vim: + sfi["status"] = vmStatus2manoFormat["ACTIVE"] + else: + sfi["status"] = "OTHER" + sfi["error_msg"] = "VIM status reported " + sfi["status"] + + sfi["vim_info"] = self.serialize(sfi_vim) + + if sfi_vim.get("fault"): + sfi["error_msg"] = str(sfi_vim["fault"]) + except vimconn.VimConnNotFoundException as e: + self.logger.error("Exception getting sfi status: %s", str(e)) + sfi["status"] = "DELETED" + sfi["error_msg"] = str(e) + except vimconn.VimConnException as e: + self.logger.error("Exception getting sfi status: %s", str(e)) + sfi["status"] = "VIM_ERROR" + sfi["error_msg"] = str(e) + + sfi_dict[sfi_id] = sfi + + return sfi_dict + + def refresh_sfs_status(self, sf_list): + """Get the status of the service functions + Params: the list of sf identifiers + Returns a dictionary with: + vm_id: #VIM id of this service function + status: #Mandatory. Text with one of: + # DELETED (not found at vim) + # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) + # OTHER (Vim reported other status not understood) + # ERROR (VIM indicates an ERROR status) + # ACTIVE, + # CREATING (on building process) + error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR + vim_info: #Text with plain information obtained from vim (yaml.safe_dump) + """ + sf_dict = {} + self.logger.debug("refresh_sfs status: Getting tenant sf information from VIM") + + for sf_id in sf_list: + sf = {} + + try: + sf_vim = self.get_sf(sf_id) + + if sf_vim: + sf["status"] = vmStatus2manoFormat["ACTIVE"] + else: + sf["status"] = "OTHER" + sf["error_msg"] = "VIM status reported " + sf_vim["status"] + + sf["vim_info"] = self.serialize(sf_vim) + + if sf_vim.get("fault"): + sf["error_msg"] = str(sf_vim["fault"]) + except vimconn.VimConnNotFoundException as e: + self.logger.error("Exception getting sf status: %s", str(e)) + sf["status"] = "DELETED" + sf["error_msg"] = str(e) + except vimconn.VimConnException as e: + self.logger.error("Exception getting sf status: %s", str(e)) + sf["status"] = "VIM_ERROR" + sf["error_msg"] = str(e) + + sf_dict[sf_id] = sf + + return sf_dict + + def refresh_classifications_status(self, classification_list): + """Get the status of the classifications + Params: the list of classification identifiers + Returns a dictionary with: + vm_id: #VIM id of this classifier + status: #Mandatory. Text with one of: + # DELETED (not found at vim) + # VIM_ERROR (Cannot connect to VIM, VIM response error, ...) + # OTHER (Vim reported other status not understood) + # ERROR (VIM indicates an ERROR status) + # ACTIVE, + # CREATING (on building process) + error_msg: #Text with VIM error message, if any. Or the VIM connection ERROR + vim_info: #Text with plain information obtained from vim (yaml.safe_dump) + """ + classification_dict = {} + self.logger.debug( + "refresh_classifications status: Getting tenant classification information from VIM" + ) + + for classification_id in classification_list: + classification = {} + + try: + classification_vim = self.get_classification(classification_id) + + if classification_vim: + classification["status"] = vmStatus2manoFormat["ACTIVE"] + else: + classification["status"] = "OTHER" + classification["error_msg"] = ( + "VIM status reported " + classification["status"] + ) + + classification["vim_info"] = self.serialize(classification_vim) + + if classification_vim.get("fault"): + classification["error_msg"] = str(classification_vim["fault"]) + except vimconn.VimConnNotFoundException as e: + self.logger.error("Exception getting classification status: %s", str(e)) + classification["status"] = "DELETED" + classification["error_msg"] = str(e) + except vimconn.VimConnException as e: + self.logger.error("Exception getting classification status: %s", str(e)) + classification["status"] = "VIM_ERROR" + classification["error_msg"] = str(e) + + classification_dict[classification_id] = classification + + return classification_dict + def new_affinity_group(self, affinity_group_data): """Adds a server group to VIM affinity_group_data contains a dictionary with information, keys: