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
        """
        self._validate_create_nfd_data(device_data)

        token = device_data['token']
        admin_tenant_id = device_data['admin_tenant_id']
        image_name = self._get_image_name(device_data)

        pre_launch_executor = nfp_executor.TaskExecutor(jobs=3)

        image_id_result = {}
        provider_metadata_result = {}

        pre_launch_executor.add_job('UPDATE_PROVIDER_METADATA',
                                    self._update_provider_metadata_fast,
                                    token,
                                    admin_tenant_id,
                                    image_name,
                                    device_data,
                                    result_store=provider_metadata_result)
        pre_launch_executor.add_job('GET_INTERFACES_FOR_DEVICE_CREATE',
                                    self._get_interfaces_for_device_create,
                                    token, admin_tenant_id, network_handler,
                                    device_data)
        pre_launch_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)

        pre_launch_executor.fire()

        interfaces, image_id, provider_metadata = (
            self._validate_pre_launch_executor_results(
                network_handler, device_data, image_name, image_id_result,
                provider_metadata_result))
        if not interfaces:
            return None

        management_interface = interfaces[0]
        flavor = self._get_service_instance_flavor(device_data)

        interfaces_to_attach = []
        try:
            for interface in interfaces:
                interfaces_to_attach.append({'port': interface['port_id']})
            if provider_metadata.get('supports_hotplug') is False:
                self._update_interfaces_for_non_hotplug_support(
                    network_handler, interfaces, interfaces_to_attach,
                    device_data)
        except Exception as e:
            LOG.error(
                'Failed to fetch list of interfaces to attach'
                ' for device creation %(error)s', {'error': e})
            self._delete_interfaces(device_data,
                                    interfaces,
                                    network_handler=network_handler)
            return None

        instance_name = device_data['name']

        create_instance_executor = nfp_executor.TaskExecutor(jobs=3)
        instance_id_result = {}
        port_details_result = {}
        volume_support = device_data['volume_support']
        volume_size = device_data['volume_size']
        create_instance_executor.add_job(
            'CREATE_INSTANCE',
            self.create_instance,
            self.compute_handler_nova,
            token,
            admin_tenant_id,
            image_id,
            flavor,
            interfaces_to_attach,
            instance_name,
            volume_support,
            volume_size,
            files=device_data.get('files'),
            user_data=device_data.get('user_data'),
            result_store=instance_id_result)

        create_instance_executor.add_job('GET_NEUTRON_PORT_DETAILS',
                                         self.get_neutron_port_details,
                                         network_handler,
                                         token,
                                         management_interface['port_id'],
                                         result_store=port_details_result)

        create_instance_executor.fire()

        instance_id, mgmt_neutron_port_info = (
            self._validate_create_instance_executor_results(
                network_handler, device_data, interfaces, instance_id_result,
                port_details_result))
        if not instance_id:
            return None

        mgmt_ip_address = mgmt_neutron_port_info['ip_address']
        return {
            'id': instance_id,
            'name': instance_name,
            'provider_metadata': provider_metadata,
            '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
    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 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