fix 988. Use provider-network:physical-network at openstack network creation
[osm/RO.git] / RO-VIM-openstack / osm_rovim_openstack / vimconn_openstack.py
index 1c2b072..f6bba2f 100644 (file)
@@ -143,6 +143,9 @@ class vimconnector(vimconn.vimconnector):
         else:
             self.endpoint_type = None
 
+        logging.getLogger('urllib3').setLevel(logging.WARNING)
+        logging.getLogger('keystoneauth').setLevel(logging.WARNING)
+        logging.getLogger('novaclient').setLevel(logging.WARNING)
         self.logger = logging.getLogger('openmano.vim.openstack')
 
         # allow security_groups to be a list or a single string
@@ -491,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, vlan=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
@@ -511,7 +514,7 @@ 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
-            'vlan': in case of a data or ptp net_type, the intended vlan tag to be used for the network
+            'provider_network_profile': (optional) contains {segmentation-id: vlan, provider-network: vim_netowrk}
         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.
@@ -520,31 +523,58 @@ class vimconnector(vimconn.vimconnector):
         """
         self.logger.debug("Adding a new network to VIM name '%s', type '%s'", net_name, net_type)
         # self.logger.debug(">>>>>>>>>>>>>>>>>> IP profile %s", str(ip_profile))
+
         try:
+            vlan = None
+            if provider_network_profile:
+                vlan = provider_network_profile.get("segmentation-id")
             new_net = None
             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:physical_network"] = provider_physical_network
                     network_dict["provider:network_type"] = "vlan"
-                    if vlan!=None:
-                        network_dict["provider: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
@@ -553,17 +583,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"):
@@ -819,7 +845,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:
@@ -1777,7 +1803,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:
@@ -1789,17 +1815,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')))
 
 
@@ -2221,3 +2247,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