def _get_amphorae_network_config(self, context, loadbalancer_dict, loadbalancer_o_obj): loadbalancer_n_obj = n_data_models.LoadBalancer.from_dict( copy.deepcopy(loadbalancer_dict)) amphorae_network_config = {} for amp in loadbalancer_o_obj.amphorae: if amp.status != constants.DELETED: # Get vip_subnet vip_subnet = None for subnet_dict in context['service_info']['subnets']: if subnet_dict['id'] == loadbalancer_n_obj.vip_subnet_id: vip_subnet = n_data_models.Subnet.from_dict( copy.deepcopy(subnet_dict)) break if vip_subnet is None: raise exceptions.IncompleteData( "VIP subnet information is not found") sc_metadata = ast.literal_eval( loadbalancer_dict['description']) vrrp_port = n_data_models.Port( mac_address=sc_metadata['provider_interface_mac']) if vrrp_port is None: raise exceptions.IncompleteData( "VRRP port information is not found") amphorae_network_config[amp.id] = \ network_data_models.AmphoraNetworkConfig( amphora=amp, vip_subnet=vip_subnet, vrrp_port=vrrp_port) return amphorae_network_config
def select_network_function_device(self, devices, device_data, network_handler=None): """ Select a NFD which is eligible for sharing :param devices: NFDs :type devices: list :param device_data: NFD data :type device_data: dict :returns: None -- when device sharing is not supported, or when no device is eligible for sharing :return: dict -- NFD which is eligible for sharing :raises: exceptions.IncompleteData """ if (any(key not in device_data for key in ['ports']) or type(device_data['ports']) is not list or any(key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model']) or type(devices) is not list or any(key not in device for device in devices for key in ['interfaces_in_use'])): raise exceptions.IncompleteData() token = self._get_token(device_data.get('token')) if not token: return None image_name = self._get_image_name(device_data) if image_name: self._update_vendor_data(device_data, device_data.get('token')) if not self._is_device_sharing_supported(): return None
def get_network_function_device_sharing_info(self, device_data): """ Get filters for NFD sharing :param device_data: NFD data :type device_data: dict :returns: None -- when device sharing is not supported :returns: dict -- It has the following scheme { 'filters': { 'key': 'value', ... } } :raises: exceptions.IncompleteData """ if (any(key not in device_data for key in ['tenant_id', 'service_details']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor'])): raise exceptions.IncompleteData() if not self._is_device_sharing_supported(): return None
def get_network_function_device_healthcheck_info(self, device_data): """ Get the health check information for NFD :param device_data: NFD :type device_data: dict :returns: dict -- It has the following scheme { 'config': [ { 'resource': 'healthmonitor', 'resource_data': { ... } } ] } :raises: exceptions.IncompleteData """ if (any(key not in device_data for key in ['id', 'mgmt_ip_address'])): raise exceptions.IncompleteData() return { 'config': [{ 'resource': nfp_constants.HEALTHMONITOR_RESOURCE, 'resource_data': { 'vmid': device_data['id'], 'mgmt_ip': device_data['mgmt_ip_address'], 'periodicity': 'initial' } }] }
def delete_network_function_device(self, device_data, network_handler=None): """ Delete the NFD :param device_data: NFD :type device_data: dict :returns: None -- Both on success and Failure :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['service_details', 'mgmt_port_id']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or type(device_data['mgmt_port_id']) is not dict or any( key not in device_data['mgmt_port_id'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) image_name = self._get_image_name(device_data) if image_name: self._update_vendor_data(device_data, device_data.get('token')) token = self._get_token(device_data.get('token')) if not token: return None if device_data.get('id'): # delete the device instance # # this method will be invoked again # once the device instance deletion is completed try: self.compute_handler_nova.delete_instance( token, self._get_admin_tenant_id(token=token), device_data['id']) except Exception: LOG.error(_LE('Failed to delete %(instance)s instance'), { 'instance': device_data['service_details']['device_type'] }) else: # device instance deletion is done, delete remaining resources try: interfaces = [device_data['mgmt_port_id']] self._delete_interfaces(device_data, interfaces, network_handler=network_handler) except Exception as e: LOG.error( _LE('Failed to delete the management data port(s). ' 'Error: %(error)s'), {'error': e})
def unplug_network_function_device_interfaces(self, device_data, network_handler=None): """ Detach the network interfaces for NFD :param device_data: NFD :type device_data: dict :returns: bool -- False on failure and True on Success :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['id', 'service_details', 'ports']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or any(key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = self._get_token(device_data.get('token')) if not token: return None image_name = self._get_image_name(device_data) provider_metadata = {} if image_name: provider_metadata = (self._update_provider_metadata_fast( token, device_data['tenant_id'], image_name, device_data)) if not provider_metadata: LOG.debug('Failed to get provider metadata for' ' device deletion.') if provider_metadata.get('supports_hotplug') is False: return True with nfp_ctx_mgr.NovaContextManager.new(suppress=(Exception, )) as ncm: for port in device_data['ports']: port_id = self._get_port_from_pt(device_data, port['id']) ncm.retry(self.compute_handler_nova.detach_interface, token, device_data['tenant_id'], device_data['id'], port_id) # Async change self._delete_port(token, port_id) # Async change: Delete stale l2ps try: self._delete_l2ps(token, device_data, network_handler) except Exception: pass return True
def delete_network_function_device(self, device_data, network_handler=None): """ Delete the NFD :param device_data: NFD :type device_data: dict :returns: None -- Both on success and Failure :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['service_details', 'mgmt_port_id']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or type(device_data['mgmt_port_id']) is not dict or any( key not in device_data['mgmt_port_id'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = self._get_token(device_data.get('token')) if not token: return None if device_data.get('id'): # delete the device instance # # this method will be invoked again # once the device instance deletion is completed with nfp_ctx_mgr.NovaContextManager.new( suppress=(Exception, )) as ncm: ncm.retry(self.compute_handler_nova.delete_instance, token, device_data['tenant_id'], device_data['id']) else: # device instance deletion is done, delete remaining resources try: interfaces = [device_data['mgmt_port_id']] self._delete_interfaces(device_data, interfaces, network_handler=network_handler) except Exception as e: LOG.error( 'Failed to delete the management data port(s). ' 'Error: %(error)s', {'error': e})
def get_network_function_device_status(self, device_data, ignore_failure=False): """ Get the status of NFD :param device_data: NFD :type device_data: dict :returns: None -- On failure :return: str -- status string :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if ( any(key not in device_data for key in ['id', 'service_details']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) ): raise exceptions.IncompleteData() if ( device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE ): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = self._get_token(device_data.get('token')) if not token: return None try: device = self.compute_handler_nova.get_instance( device_data['token'], device_data['tenant_id'], device_data['id']) except Exception: if ignore_failure: return None LOG.error(_LE('Failed to get %(instance)s instance details'), {'instance': device_data['service_details']['device_type']}) return None # TODO(RPM): should we raise an Exception here? return device['status']
def unplug_network_function_device_interfaces(self, device_data, network_handler=None): """ Detach the network interfaces for NFD :param device_data: NFD :type device_data: dict :returns: bool -- False on failure and True on Success :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['id', 'service_details', 'ports']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or any(key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) image_name = self._get_image_name(device_data) if image_name: self._update_vendor_data(device_data, device_data.get('token')) token = self._get_token(device_data.get('token')) if not token: return None try: for port in device_data['ports']: port_id = network_handler.get_port_id(token, port['id']) self.compute_handler_nova.detach_interface( token, self._get_admin_tenant_id(token=token), device_data['id'], port_id) except Exception as e: LOG.error( _LE('Failed to unplug interface(s) from the device.' 'Error: %(error)s'), {'error': e}) return None else: return True
def add_amphora(self, context, loadbalancer_id, description, status=constants.ACTIVE): sc_metadata = ast.literal_eval(description) rdata = self.parse.parse_data(common_const.LOADBALANCERV2, context) if not (rdata['mgmt_ip'] and sc_metadata.get('network_function_id')): raise exceptions.IncompleteData( "Amphora information is missing") if not self.get_amphora(loadbalancer_id): # REVISIT(jiahao): use network_function_id as amphora id amp = o_data_models.Amphora( lb_network_ip=rdata['mgmt_ip'], id=sc_metadata['network_function_id'], status=status) self.amphorae[loadbalancer_id] = [amp]
def add_amphora(self, loadbalancer_id, description, status=constants.ACTIVE): sc_metadata = ast.literal_eval(description) if not (sc_metadata.get('floating_ip') and sc_metadata.get('network_function_id')): raise exceptions.IncompleteData("Amphora information is missing") if not self.get_amphora(loadbalancer_id): # REVISIT(jiahao): use network_function_id as amphora id amp = o_data_models.Amphora( lb_network_ip=sc_metadata['floating_ip'], id=sc_metadata['network_function_id'], status=status) self.amphorae[loadbalancer_id] = [amp]
def _validate_create_nfd_data(self, device_data): if (any(key not in device_data for key in [ 'service_details', 'name', 'management_network_info', 'ports' ]) or type(device_data['service_details']) is not dict or any( key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or any(key not in device_data['management_network_info'] for key in ['id']) or type(device_data['ports']) is not list or any( key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type'])
def get_loadbalancer_octavia_model(self, loadbalancer_dict): loadbalancer = n_data_models.LoadBalancer.from_dict( copy.deepcopy(loadbalancer_dict)) ret = o_data_models.LoadBalancer() args = self._get_common_args(loadbalancer) vip = o_data_models.Vip( load_balancer_id=loadbalancer.id, ip_address=loadbalancer.vip_address, subnet_id=loadbalancer.vip_subnet_id, port_id=loadbalancer.vip_port.id, load_balancer=ret ) amphorae = self.driver.get_amphora(loadbalancer.id) if not amphorae: raise exceptions.IncompleteData( "Amphora information is missing") # REVISIT(jiahao): cluster_group, topology, affinity_group_id are not # included yet args.update({ 'vip': vip, 'amphorae': amphorae, 'provisioning_status': loadbalancer.provisioning_status, }) if loadbalancer_dict.get('listeners'): listeners = [] pools = [] for listener_dict in loadbalancer_dict.get('listeners'): listener = self.get_listener_octavia_model(listener_dict) listener.load_balancer = ret listeners.append(listener) pools.extend(listener.pools) for pool in listener.pools: if pool.id not in [pool.id for pool in pools]: pools.append(pool) args.update({ 'listeners': listeners, 'pools': pools, }) ret = self._update(ret, args) return ret
def _root_loadbalancer_id(self, obj_type, obj_dict): """Returns the loadbalancer id this instance is attached to.""" try: # For Mitaka if obj_type == lb_const.LOADBALANCER: lb = obj_dict['id'] elif obj_type == lb_const.LISTENER: lb = obj_dict[lb_const.LOADBALANCER]['id'] elif obj_type == lb_const.L7POLICY: lb = obj_dict[lb_const.LISTENER][lb_const.LOADBALANCER]['id'] elif obj_type == lb_const.L7RULE: lb = obj_dict['policy'][lb_const.LISTENER][ lb_const.LOADBALANCER]['id'] elif obj_type == lb_const.POOL: lb = obj_dict[lb_const.LOADBALANCER]['id'] elif obj_type == lb_const.SNI: lb = obj_dict[lb_const.LISTENER][lb_const.LOADBALANCER]['id'] else: # Pool Member or Health Monitor lb = obj_dict[lb_const.POOL][lb_const.LOADBALANCER]['id'] # For Liberty # if obj_type == lb_const.LOADBALANCER: # lb = obj_dict['id'] # elif obj_type == lb_const.LISTENER: # lb = obj_dict[lb_const.LOADBALANCER]['id'] # elif obj_type == lb_const.POOL: # lb = obj_dict[lb_const.LISTENER][lb_const.LOADBALANCER]['id'] # elif obj_type == lb_const.SNI: # lb = obj_dict[lb_const.LISTENER][lb_const.LOADBALANCER]['id'] # else: # # Pool Member or Health Monitor # lb = obj_dict[lb_const.POOL][lb_const.LISTENER][ # lb_const.LOADBALANCER]['id'] except Exception: raise exceptions.IncompleteData( 'Root loadbalancer id was not found') else: return lb
def get_network_function_device_status(self, device_data, ignore_failure=False): """ Get the status of NFD :param device_data: NFD :type device_data: dict :returns: None -- On failure :return: str -- status string :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['id', 'service_details']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = self._get_token(device_data.get('token')) if not token: return None with nfp_ctx_mgr.NovaContextManager.new(suppress=(Exception, )) as ncm: device = ncm.retry(self.compute_handler_nova.get_instance, device_data['token'], device_data['tenant_id'], device_data['id']) return device['status']
def plug_network_function_device_interfaces(self, device_data, network_handler=None): """ Attach the network interfaces for NFD :param device_data: NFD :type device_data: dict :returns: bool -- False on failure and True on Success :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in ['id', 'service_details', 'ports']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or type(device_data['ports']) is not list or any( key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = device_data['token'] tenant_id = device_data['tenant_id'] provider_metadata = device_data['provider_metadata'] enable_port_security = device_data.get('enable_port_security') if provider_metadata.get('supports_hotplug') is False: return True try: executor = nfp_executor.TaskExecutor(jobs=10) for port in device_data['ports']: if port['port_classification'] == nfp_constants.PROVIDER: service_type = device_data['service_details'][ 'service_type'].lower() if service_type.lower() in [ nfp_constants.FIREWALL.lower(), nfp_constants.VPN.lower() ]: executor.add_job( 'SET_PROMISCUOS_MODE', network_handler.set_promiscuos_mode_fast, token, port['id'], enable_port_security) executor.add_job( 'ATTACH_INTERFACE', self.compute_handler_nova.attach_interface, token, tenant_id, device_data['id'], port['id']) break executor.fire() for port in device_data['ports']: if port['port_classification'] == nfp_constants.CONSUMER: service_type = device_data['service_details'][ 'service_type'].lower() if service_type.lower() in [ nfp_constants.FIREWALL.lower(), nfp_constants.VPN.lower() ]: executor.add_job( 'SET_PROMISCUOS_MODE', network_handler.set_promiscuos_mode_fast, token, port['id'], enable_port_security) executor.add_job( 'ATTACH_INTERFACE', self.compute_handler_nova.attach_interface, token, tenant_id, device_data['id'], port['id']) break executor.fire() except Exception as e: LOG.error( 'Failed to plug interface(s) to the device.' 'Error: %(error)s', {'error': e}) return None else: return True
def get_network_function_device_config_info(self, device_data, network_handler=None): """ Get the configuration information for NFD :param device_data: NFD :type device_data: dict :returns: None -- On Failure :returns: dict -- It has the following scheme { 'config': [ { 'resource': 'interfaces', 'resource_data': { ... } }, { 'resource': 'routes', 'resource_data': { ... } } ] } :raises: exceptions.IncompleteData """ if (any(key not in device_data for key in ['service_details', 'mgmt_ip_address', 'ports']) or type(device_data['service_details']) is not dict or any(key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or type(device_data['ports']) is not list or any( key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() token = self._get_token(device_data.get('token')) if not token: return None provider_ip = None provider_mac = None provider_cidr = None consumer_ip = None consumer_mac = None consumer_cidr = None consumer_gateway_ip = None for port in device_data['ports']: if port['port_classification'] == nfp_constants.PROVIDER: try: (provider_ip, provider_mac, provider_cidr, dummy) = (network_handler.get_port_details( token, port['id'])) except Exception: LOG.error( _LE('Failed to get provider port details' ' for get device config info operation')) return None elif port['port_classification'] == nfp_constants.CONSUMER: try: (consumer_ip, consumer_mac, consumer_cidr, consumer_gateway_ip) = (network_handler.get_port_details( token, port['id'])) except Exception: LOG.error( _LE('Failed to get consumer port details' ' for get device config info operation')) return None return { 'config': [{ 'resource': nfp_constants.INTERFACE_RESOURCE, 'resource_data': { 'mgmt_ip': device_data['mgmt_ip_address'], 'provider_ip': provider_ip, 'provider_cidr': provider_cidr, 'provider_interface_index': 2, 'stitching_ip': consumer_ip, 'stitching_cidr': consumer_cidr, 'stitching_interface_index': 3, 'provider_mac': provider_mac, 'stitching_mac': consumer_mac, } }, { 'resource': nfp_constants.ROUTES_RESOURCE, 'resource_data': { 'mgmt_ip': device_data['mgmt_ip_address'], 'source_cidrs': ([provider_cidr, consumer_cidr] if consumer_cidr else [provider_cidr]), 'destination_cidr': consumer_cidr, 'provider_mac': provider_mac, 'gateway_ip': consumer_gateway_ip, 'provider_interface_index': 2 } }] }
def create_network_function_device(self, device_data, network_handler=None): """ Create a NFD :param device_data: NFD data :type device_data: dict :returns: None -- when there is a failure in creating NFD :return: dict -- NFD created :raises: exceptions.IncompleteData, exceptions.ComputePolicyNotSupported """ if (any(key not in device_data for key in [ 'service_details', 'name', 'management_network_info', 'ports' ]) or type(device_data['service_details']) is not dict or any( key not in device_data['service_details'] for key in ['service_vendor', 'device_type', 'network_mode']) or any(key not in device_data['management_network_info'] for key in ['id']) or type(device_data['ports']) is not list or any( key not in port for port in device_data['ports'] for key in ['id', 'port_classification', 'port_model'])): raise exceptions.IncompleteData() if (device_data['service_details']['device_type'] != nfp_constants.NOVA_MODE): raise exceptions.ComputePolicyNotSupported( compute_policy=device_data['service_details']['device_type']) token = device_data['token'] admin_tenant_id = device_data['admin_tenant_id'] image_name = self._get_image_name(device_data) executor = nfp_executor.TaskExecutor(jobs=3) image_id_result = {} executor.add_job('UPDATE_VENDOR_DATA', self._update_vendor_data_fast, token, admin_tenant_id, image_name, device_data) executor.add_job('GET_INTERFACES_FOR_DEVICE_CREATE', self._get_interfaces_for_device_create, token, admin_tenant_id, network_handler, device_data) executor.add_job('GET_IMAGE_ID', self.get_image_id, self.compute_handler_nova, token, admin_tenant_id, image_name, result_store=image_id_result) executor.fire() interfaces = device_data.pop('interfaces', None) if not interfaces: LOG.exception(_LE('Failed to get interfaces for device creation.')) return None else: management_interface = interfaces[0] image_id = image_id_result.get('result', None) if not image_id: LOG.error(_LE('Failed to get image id for device creation.')) self._delete_interfaces(device_data, interfaces, network_handler=network_handler) return None if device_data['service_details'].get('flavor'): flavor = device_data['service_details']['flavor'] else: LOG.info( _LI("No Device flavor provided in service profile's " "service flavor field, using default " "flavor: m1.medium")) flavor = 'm1.medium' interfaces_to_attach = [] for interface in interfaces: interfaces_to_attach.append({'port': interface['port_id']}) instance_name = device_data['name'] instance_id_result = {} port_details_result = {} executor.add_job('CREATE_INSTANCE', self.create_instance, self.compute_handler_nova, token, admin_tenant_id, image_id, flavor, interfaces_to_attach, instance_name, result_store=instance_id_result) executor.add_job('GET_NEUTRON_PORT_DETAILS', self.get_neutron_port_details, network_handler, token, management_interface['port_id'], result_store=port_details_result) executor.fire() instance_id = instance_id_result.get('result', None) if not instance_id: LOG.error(_LE('Failed to create %(device_type)s instance.')) self._delete_interfaces(device_data, interfaces, network_handler=network_handler) return None mgmt_ip_address = None mgmt_neutron_port_info = port_details_result.get('result', None) if not mgmt_neutron_port_info: LOG.error(_LE('Failed to get management port details. ')) try: self.compute_handler_nova.delete_instance( token, admin_tenant_id, instance_id) except Exception as e: LOG.error( _LE('Failed to delete %(device_type)s instance.' 'Error: %(error)s'), { 'device_type': (device_data['service_details']['device_type']), 'error': e }) self._delete_interfaces(device_data, interfaces, network_handler=network_handler) return None mgmt_ip_address = mgmt_neutron_port_info['ip_address'] return { 'id': instance_id, 'name': instance_name, 'mgmt_ip_address': mgmt_ip_address, 'mgmt_port_id': interfaces[0], 'mgmt_neutron_port_info': mgmt_neutron_port_info, 'max_interfaces': self.maximum_interfaces, 'interfaces_in_use': len(interfaces_to_attach), 'description': '' } # TODO(RPM): what should be the description