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;h=8cb19ffece3996c0f2aa449dafd2848daeb038d2;hp=dad8eb63b121deb5d983cd68103ad98d4d581e09;hb=64b39c5deaba0dceb9c5f4844a235c1af84a8bee;hpb=a0a356e35607e143f4c5143dca450a54dc5c0674 diff --git a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py index dad8eb63..8cb19ffe 100644 --- a/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py +++ b/RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py @@ -72,8 +72,8 @@ netStatus2manoFormat={'ACTIVE':'ACTIVE','PAUSED':'PAUSED','INACTIVE':'INACTIVE', supportedClassificationTypes = ['legacy_flow_classifier'] #global var to have a timeout creating and deleting volumes -volume_timeout = 600 -server_timeout = 600 +volume_timeout = 1800 +server_timeout = 1800 class SafeDumper(yaml.SafeDumper): @@ -395,17 +395,17 @@ class vimconnector(vimconn.vimconnector): # method before the implemented VIM connectors are called. def _format_exception(self, exception): - '''Transform a keystone, nova, neutron exception into a vimconn exception''' + """Transform a keystone, nova, neutron exception into a vimconn exception discovering the cause""" - message_error = exception.message + message_error = str(exception) if isinstance(exception, (neExceptions.NetworkNotFoundClient, nvExceptions.NotFound, ksExceptions.NotFound, gl1Exceptions.HTTPNotFound)): raise vimconn.vimconnNotFoundException(type(exception).__name__ + ": " + message_error) elif isinstance(exception, (HTTPException, gl1Exceptions.HTTPException, gl1Exceptions.CommunicationError, - ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed)): + ConnectionError, ksExceptions.ConnectionError, neExceptions.ConnectionFailed)): raise vimconn.vimconnConnectionException(type(exception).__name__ + ": " + message_error) - elif isinstance(exception, (KeyError, nvExceptions.BadRequest, ksExceptions.BadRequest)): + elif isinstance(exception, (KeyError, nvExceptions.BadRequest, ksExceptions.BadRequest)): raise vimconn.vimconnException(type(exception).__name__ + ": " + message_error) elif isinstance(exception, (nvExceptions.ClientException, ksExceptions.ClientException, neExceptions.NeutronException)): @@ -494,10 +494,10 @@ class vimconnector(vimconn.vimconnector): else: self.keystone.tenants.delete(tenant_id) return tenant_id - except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.NotFound, ConnectionError) as e: + except (ksExceptions.ConnectionError, ksExceptions.ClientException, ksExceptions.NotFound, ConnectionError) as e: self._format_exception(e) - def new_network(self,net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): + def new_network(self, net_name, net_type, ip_profile=None, shared=False, provider_network_profile=None): """Adds a tenant network to VIM Params: 'net_name': name of the network @@ -514,7 +514,8 @@ class vimconnector(vimconn.vimconnector): 'dhcp_start_address': ip_schema, first IP to grant 'dhcp_count': number of IPs to grant. 'shared': if this network can be seen/use by other tenants/organization - 'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk} + 'provider_network_profile': (optional) contains {segmentation-id: vlan, network-type: vlan|vxlan, + physical-network: physnet-label} Returns a tuple with the network identifier and created_items, or raises an exception on error created_items can be None or a dictionary where this method can include key-values that will be passed to the method delete_network. Can be used to store created segments, created l2gw connections, etc. @@ -532,26 +533,52 @@ class vimconnector(vimconn.vimconnector): created_items = {} self._reload_connection() network_dict = {'name': net_name, 'admin_state_up': True} - if net_type=="data" or net_type=="ptp": - if self.config.get('dataplane_physical_net') == None: - raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at config value before creating sriov network") + if net_type in ("data", "ptp"): + provider_physical_network = None + if provider_network_profile and provider_network_profile.get("physical-network"): + provider_physical_network = provider_network_profile.get("physical-network") + # provider-network must be one of the dataplane_physcial_netowrk if this is a list. If it is string + # or not declared, just ignore the checking + if isinstance(self.config.get('dataplane_physical_net'), (tuple, list)) and \ + provider_physical_network not in self.config['dataplane_physical_net']: + raise vimconn.vimconnConflictException( + "Invalid parameter 'provider-network:physical-network' for network creation. '{}' is not " + "one of the declared list at VIM_config:dataplane_physical_net".format( + provider_physical_network)) + if not provider_physical_network: # use the default dataplane_physical_net + provider_physical_network = self.config.get('dataplane_physical_net') + # if it is non empty list, use the first value. If it is a string use the value directly + if isinstance(provider_physical_network, (tuple, list)) and provider_physical_network: + provider_physical_network = provider_physical_network[0] + + if not provider_physical_network: + raise vimconn.vimconnConflictException("You must provide a 'dataplane_physical_net' at VIM_config " + "for creating underlay networks. or use the NS instantiation" + " parameter provider-network:physical-network for the VLD") + if not self.config.get('multisegment_support'): - network_dict["provider:physical_network"] = self.config[ - 'dataplane_physical_net'] # "physnet_sriov" #TODO physical - network_dict["provider:network_type"] = "vlan" - if vlan!=None: - network_dict["provider:network_type"] = vlan + network_dict["provider:physical_network"] = provider_physical_network + if provider_network_profile and "network-type" in provider_network_profile: + network_dict["provider:network_type"] = provider_network_profile["network-type"] + else: + network_dict["provider:network_type"] = self.config.get('dataplane_network_type','vlan') + if vlan: + network_dict["provider:segmentation_id"] = vlan else: - ###### Multi-segment case ###### + # Multi-segment case segment_list = [] - segment1_dict = {} - segment1_dict["provider:physical_network"] = '' - segment1_dict["provider:network_type"] = 'vxlan' + segment1_dict = { + "provider:physical_network": '', + "provider:network_type": 'vxlan' + } segment_list.append(segment1_dict) - segment2_dict = {} - segment2_dict["provider:physical_network"] = self.config['dataplane_physical_net'] - segment2_dict["provider:network_type"] = "vlan" - if self.config.get('multisegment_vlan_range'): + segment2_dict = { + "provider:physical_network": provider_physical_network, + "provider:network_type": "vlan" + } + if vlan: + segment2_dict["provider:segmentation_id"] = vlan + elif self.config.get('multisegment_vlan_range'): vlanID = self._generate_multisegment_vlanID() segment2_dict["provider:segmentation_id"] = vlanID # else @@ -560,17 +587,13 @@ class vimconnector(vimconn.vimconnector): segment_list.append(segment2_dict) network_dict["segments"] = segment_list - ####### VIO Specific Changes ######### - if self.vim_type == "VIO": - if vlan is not None: - network_dict["provider:segmentation_id"] = vlan - else: - if self.config.get('dataplane_net_vlan_range') is None: - raise vimconn.vimconnConflictException("You must provide "\ - "'dataplane_net_vlan_range' in format [start_ID - end_ID]"\ - "at config value before creating sriov network with vlan tag") - - network_dict["provider:segmentation_id"] = self._generate_vlanID() + # VIO Specific Changes. It needs a concrete VLAN + if self.vim_type == "VIO" and vlan is None: + if self.config.get('dataplane_net_vlan_range') is None: + raise vimconn.vimconnConflictException( + "You must provide 'dataplane_net_vlan_range' in format [start_ID - end_ID] at VIM_config " + "for creating underlay networks") + network_dict["provider:segmentation_id"] = self._generate_vlanID() network_dict["shared"] = shared if self.config.get("disable_network_port_security"): @@ -826,7 +849,7 @@ class vimconnector(vimconn.vimconnector): def process_resource_quota(self, quota, prefix, extra_specs): """ :param prefix: - :param extra_specs: + :param extra_specs: :return: """ if 'limit' in quota: @@ -1784,7 +1807,7 @@ class vimconnector(vimconn.vimconnector): Returns: vlanID """ - #Get used VLAN IDs + # Get used VLAN IDs usedVlanIDs = [] networks = self.get_network_list() for net in networks: @@ -1796,17 +1819,17 @@ class vimconnector(vimconn.vimconnector): usedVlanIDs.append(segment.get('provider:segmentation_id')) used_vlanIDs = set(usedVlanIDs) - #find unused VLAN ID + # find unused VLAN ID for vlanID_range in self.config.get('multisegment_vlan_range'): try: - start_vlanid , end_vlanid = map(int, vlanID_range.replace(" ", "").split("-")) + start_vlanid, end_vlanid = map(int, vlanID_range.replace(" ", "").split("-")) for vlanID in range(start_vlanid, end_vlanid + 1): if vlanID not in used_vlanIDs: return vlanID except Exception as exp: raise vimconn.vimconnException("Exception {} occurred while generating VLAN ID.".format(exp)) else: - raise vimconn.vimconnConflictException("Unable to create the VLAN segment."\ + raise vimconn.vimconnConflictException("Unable to create the VLAN segment." " All VLAN IDs {} are in use.".format(self.config.get('multisegment_vlan_range'))) @@ -2228,3 +2251,180 @@ class vimconnector(vimconn.vimconnector): 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 " + vm_vim['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 " + vm_vim['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 " + vm_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 " + vm_vim['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