Esempio n. 1
0
class Attribute(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'deployable_id': object_fields.IntegerField(nullable=False),
        'key': object_fields.StringField(nullable=False),
        'value': object_fields.StringField(nullable=False)
    }

    def create(self, context):
        """Create an attribute record in the DB."""
        if self.deployable_id is None:
            raise exception.AttributeInvalid()

        values = self.obj_get_changes()
        db_attr = self.dbapi.attribute_create(context, values)
        self._from_db_object(self, db_attr)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB attribute and return an Obj Deployable."""
        db_attr = cls.dbapi.attribute_get(context, uuid)
        obj_attr = cls._from_db_object(cls(context), db_attr)
        return obj_attr

    @classmethod
    def get_by_deployable_id(cls, context, deployable_id):
        """Get an attribute by deployable_id"""
        db_attr = cls.dbapi.attribute_get_by_deployable_id(
            context, deployable_id)
        return cls._from_db_object_list(db_attr, context)

    @classmethod
    def get_by_filter(cls, context, filters):
        """Get an attribute by specified filters"""
        db_attr = cls.dbapi.attribute_get_by_filter(context, filters)
        return cls._from_db_object_list(db_attr, context)

    def save(self, context):
        """Update an attribute record in the DB."""
        db_attr = self.dbapi.attribute_update(context, self.uuid, self.key,
                                              self.value)
        self._from_db_object(self, db_attr)

    def destroy(self, context):
        """Delete an attribute from the DB."""
        self.dbapi.attribute_delete(context, self.uuid)
        self.obj_reset_changes()

    def set_key_value_pair(self, set_key, set_value):
        self.key = set_key
        self.value = set_value

    @classmethod
    def get_by_dep_key(cls, context, dep_id, key):
        """Get the only one attribute with deployable_id and the key."""
        attr_filter = {"deployable_id": dep_id, "key": key}
        attr_list = cls.get_by_filter(context, attr_filter)
        if len(attr_list) != 0:
            return attr_list[0]
        else:
            return None
Esempio n. 2
0
class Port(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'uuid': object_fields.UUIDField(nullable=False),
        'computer_node': object_fields.UUIDField(nullable=False),
        'phy_port_name': object_fields.StringField(nullable=True),
        'pci_slot': object_fields.StringField(nullable=True),
        'product_id': object_fields.StringField(nullable=True),
        'vendor_id': object_fields.StringField(nullable=False),
        'is_used': object_fields.IntegerField(nullable=False),
        'accelerator_id': object_fields.UUIDField(nullable=True),
        'bind_instance_id': object_fields.UUIDField(nullable=True),
        'bind_port_id': object_fields.UUIDField(nullable=True),
        'device_type': object_fields.StringField(nullable=True),
    }

    def __init__(self, *args, **kwargs):
        super(Port, self).__init__(*args, **kwargs)

    def create(self, context=None):
        """Create an Port record in the DB, this can be used by cyborg-agents
        to auto register physical port of network cards."""
        values = self.obj_get_changes()
        db_port= self.dbapi.port_create(context, values)
        self._from_db_object(self, db_port)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Port and return an Ojb Port."""
        db_port = cls.dbapi.port_get(context, uuid)
        obj_port = cls._from_db_object(cls(context), db_port)
        return obj_port

    @classmethod
    def get(cls, context, phy_port_name, pci_slot, computer_node):
        """Return a list of Port objects."""
        db_port = cls.dbapi.port_get(context, phy_port_name=phy_port_name,
                                     pci_slot=pci_slot, computer_node=computer_node)
        if db_port:
            obj_port = cls._from_db_object(cls(context), db_port)
            return obj_port
        else:
            return None

    @classmethod
    def list(cls, context, limit, marker, sort_key, sort_dir):
        """Return a list of Port objects."""
        db_ports = cls.dbapi.port_list(context, limit, marker, sort_key,
                                             sort_dir)
        obj_ports = cls._from_db_object_list(context, db_ports)
        return obj_ports

    def save(self, context):
        """Update a Port record in the DB."""
        updates = self.obj_get_changes()
        db_port = self.dbapi.port_update(context, self.uuid, updates)
        self._from_db_object(self, db_port)

    def destory(self, context):
        """Delete the Port record in the DB."""
        self.dbapi.port_destory(context, self.uuid)
        self.obj_reset_changes()
Esempio n. 3
0
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # 1.0: Initial version
    # 1.1: Added rp_uuid, driver_name, bitstream_id, num_accel_in_use
    VERSION = '1.1'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'parent_id': object_fields.IntegerField(nullable=True),
        # parent_id refers to the id of the deployable's parent node
        'root_id': object_fields.IntegerField(nullable=True),
        # root_id refers to the id of the deployable's root to for nested tree
        'name': object_fields.StringField(nullable=False),
        # name of the deployable
        'num_accelerators': object_fields.IntegerField(nullable=False),
        # number of accelerators spawned by this deployable
        'device_id': object_fields.IntegerField(nullable=False),
        # Foreign key constrain to reference device table
        'driver_name': object_fields.StringField(nullable=True),
        # Will change it to non-nullable after other driver report it.
        'rp_uuid': object_fields.UUIDField(nullable=True),
        # UUID of the Resource provider corresponding to this deployable
        'bitstream_id': object_fields.UUIDField(nullable=True),
    }

    def _get_parent_root_id(self, context):
        obj_dep = Deployable.get_by_id(context, self.parent_id)
        return obj_dep.root_id

    def create(self, context):
        """Create a Deployable record in the DB."""

        # FIXME: Add parent_uuid and root_uuid constrains when DB change to
        # parent_uuid & root_uuid

        values = self.obj_get_changes()
        db_dep = self.dbapi.deployable_create(context, values)
        self._from_db_object(self, db_dep)
        self.obj_reset_changes()
        del self.attributes_list[:]

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Deployable and return an Obj Deployable."""
        db_dep = cls.dbapi.deployable_get(context, uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        obj_dep.obj_reset_changes()
        return obj_dep

    @classmethod
    def get_by_id(cls, context, id):
        """Find a DB Deployable and return an Obj Deployable."""
        dpl_query = {"id": id}
        obj_dep = Deployable.get_by_filter(context, dpl_query)[0]
        obj_dep.obj_reset_changes()
        return obj_dep

    @classmethod
    def get_by_device_rp_uuid(cls, context, devrp_uuid):
        db_dep = cls.dbapi.deployable_get_by_rp_uuid(context, devrp_uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        return obj_dep

    @classmethod
    def list(cls, context, filters=None):
        """Return a list of Deployable objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_deps = cls.dbapi.deployable_get_by_filters(context,
                                                          filters,
                                                          sort_dir=sort_dir,
                                                          sort_key=sort_key,
                                                          limit=limit,
                                                          marker=marker)
        else:
            db_deps = cls.dbapi.deployable_list(context)
        obj_dpl_list = cls._from_db_object_list(db_deps, context)
        return obj_dpl_list

    def save(self, context):
        """Update a Deployable record in the DB."""
        updates = self.obj_get_changes()
        # TODO(Xinran): Will remove this if find some better way.
        updates.pop("uuid", None)
        updates.pop("created_at", None)
        if "updated_at" in updates.keys() and \
                updates["updated_at"] is not None:
            updates["updated_at"] = updates["updated_at"].replace(tzinfo=None)
        db_dep = self.dbapi.deployable_update(context, self.uuid, updates)
        self.obj_reset_changes()
        self._from_db_object(self, db_dep)

    def update(self, context, updates):
        """Update provided key, value pairs"""
        self.dbapi.deployable_update(context, self.uuid, updates)

    def destroy(self, context):
        """Delete a Deployable from the DB."""
        self.dbapi.deployable_delete(context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def get_by_filter(cls, context, filters):
        obj_dpl_list = []
        db_dpl_list = cls.dbapi.deployable_get_by_filters(context, filters)

        if db_dpl_list:
            for db_dpl in db_dpl_list:
                obj_dpl = cls._from_db_object(cls(context), db_dpl)
                obj_dpl_list.append(obj_dpl)

        return obj_dpl_list

    @staticmethod
    def _from_db_object(obj, db_obj):
        """Converts a deployable to a formal object.

        :param obj: An object of the class.
        :param db_obj: A DB model of the object
        :return: The object of the class with the database entity added
        """
        for field in obj.fields:
            obj[field] = db_obj[field]
        obj.attributes_list = []

        return obj

    @classmethod
    def get_list_by_device_id(cls, context, device_id):
        dep_filter = {'device_id': device_id}
        dep_obj_list = Deployable.list(context, dep_filter)
        return dep_obj_list

    @classmethod
    def get_by_name_deviceid(cls, context, name, device_id):
        dep_filter = {'name': name, 'device_id': device_id}
        dep_obj_list = Deployable.list(context, dep_filter)
        if len(dep_obj_list) != 0:
            return dep_obj_list[0]
        else:
            return None

    @classmethod
    def get_by_name(cls, context, name):
        dep_filter = {'name': name}
        dep_obj_list = Deployable.list(context, dep_filter)
        if len(dep_obj_list) != 0:
            return dep_obj_list[0]
        else:
            return None

    def get_cpid_list(self, context):
        query_filter = {"device_id": self.device_id}
        # TODO(Sundar) We should probably get cpid from objects layer,
        # not db layer
        cpid_list = self.dbapi.control_path_get_by_filters(
            context, query_filter)
        return cpid_list
Esempio n. 4
0
class Device(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: Add AICHIP, GENERIC type
    VERSION = '1.1'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'type': object_fields.EnumField(valid_values=constants.DEVICE_TYPE,
                                        nullable=False),
        'vendor': object_fields.StringField(nullable=False),
        'model': object_fields.StringField(nullable=False),
        'std_board_info': object_fields.StringField(nullable=True),
        'vendor_board_info': object_fields.StringField(nullable=True),
        'hostname': object_fields.StringField(nullable=False),
    }

    def create(self, context):
        """Create a device record in the DB."""
        values = self.obj_get_changes()
        db_device = self.dbapi.device_create(context, values)
        self._from_db_object(self, db_device)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Device and return an Obj Device."""
        db_device = cls.dbapi.device_get(context, uuid)
        obj_device = cls._from_db_object(cls(context), db_device)
        return obj_device

    @classmethod
    def list(cls, context, filters=None):
        """Return a list of Device objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_devices = cls.dbapi.device_list_by_filters(
                context, filters, sort_dir=sort_dir, sort_key=sort_key,
                limit=limit, marker=marker)
        else:
            db_devices = cls.dbapi.device_list(context)
        return cls._from_db_object_list(db_devices, context)

    def save(self, context):
        """Update a Device record in the DB."""
        updates = self.obj_get_changes()
        db_device = self.dbapi.device_update(context, self.uuid, updates)
        self._from_db_object(self, db_device)

    def destroy(self, context):
        """Delete the Device from the DB."""
        self.dbapi.device_delete(context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def get_list_by_hostname(cls, context, hostname):
        """get device object list from the hostname. return [] if not
        exist.
        """
        dev_filter = {'hostname': hostname}
        device_obj_list = Device.list(context, dev_filter)
        return device_obj_list

    @classmethod
    def get_by_device_id(cls, context, device_id):
        """get device object by the device ID."""
        db_device = cls.dbapi.device_get_by_id(context, device_id)
        obj_device = cls._from_db_object(cls(context), db_device)
        return obj_device
Esempio n. 5
0
class ControlpathID(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    # Version 1.1: Add cpid_info_obj
    VERSION = '1.1'

    dbapi = dbapi.get_instance()

    fields = {
        'id':
        object_fields.IntegerField(nullable=False),
        'uuid':
        object_fields.UUIDField(nullable=False),
        'device_id':
        object_fields.IntegerField(nullable=False),
        'cpid_type':
        object_fields.EnumField(valid_values=CPID_TYPE, nullable=False),
        'cpid_info':
        object_fields.StringField(nullable=False)
    }

    @property
    def cpid_info_obj(self):
        return jsonutils.loads(self.cpid_info)

    @cpid_info_obj.setter
    def cpid_info_obj(self, cpid_info_obj):
        self.cpid_info = jsonutils.dumps(cpid_info_obj)

    def create(self, context):
        """Create a ControlPathID record in the DB."""
        values = self.obj_get_changes()
        db_cp = self.dbapi.control_path_create(context, values)
        self._from_db_object(self, db_cp)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB ControlpathID and return an Obj ControlpathID."""
        db_cp = cls.dbapi.control_path_get_by_uuid(context, uuid)
        obj_cp = cls._from_db_object(cls(context), db_cp)
        return obj_cp

    @classmethod
    def list(cls, context, filters=None):
        """Return a list of ControlpathID objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_cps = cls.dbapi.control_path_get_by_filters(context,
                                                           filters,
                                                           sort_dir=sort_dir,
                                                           sort_key=sort_key,
                                                           limit=limit,
                                                           marker=marker)
        else:
            db_cps = cls.dbapi.control_path_list(context)
        obj_cp_list = cls._from_db_object_list(db_cps, context)
        return obj_cp_list

    def save(self, context):
        """Update an ControlpathID record in the DB"""
        updates = self.obj_get_changes()
        db_cps = self.dbapi.control_path_update(context, self.uuid, updates)
        self._from_db_object(self, db_cps)

    def destroy(self, context):
        """Delete a ControlpathID from the DB."""
        self.dbapi.control_path_delete(context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def get_by_device_id(cls, context, device_id):
        # control_path is unique for one device.
        cpid_filter = {'device_id': device_id}
        cpid_obj_list = ControlpathID.list(context, cpid_filter)
        if len(cpid_obj_list) != 0:
            return cpid_obj_list[0]
        else:
            return None

    @classmethod
    def get_by_device_id_cpidinfo(cls, context, device_id, cpid_info):
        cpid_filter = {'device_id': device_id, 'cpid_info': cpid_info}
        # the list could have one value or is empty.
        cpid_obj_list = ControlpathID.list(context, cpid_filter)
        if len(cpid_obj_list) != 0:
            return cpid_obj_list[0]
        else:
            return None
Esempio n. 6
0
class AttachHandle(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id':
        object_fields.IntegerField(nullable=False),
        'uuid':
        object_fields.UUIDField(nullable=False),
        'deployable_id':
        object_fields.IntegerField(nullable=False),
        'cpid_id':
        object_fields.IntegerField(nullable=False),
        'attach_type':
        object_fields.EnumField(valid_values=constants.ATTACH_HANDLE_TYPES,
                                nullable=False),
        # attach_info should be JSON here.
        'attach_info':
        object_fields.StringField(nullable=False),
        'in_use':
        object_fields.BooleanField(nullable=False, default=False)
    }

    def create(self, context):
        """Create a AttachHandle record in the DB."""
        values = self.obj_get_changes()
        db_ah = self.dbapi.attach_handle_create(context, values)
        self._from_db_object(self, db_ah)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB AttachHandle and return an Obj AttachHandle."""
        db_ah = cls.dbapi.attach_handle_get_by_uuid(context, uuid)
        obj_ah = cls._from_db_object(cls(context), db_ah)
        return obj_ah

    @classmethod
    def get_by_id(cls, context, id):
        """Find a DB AttachHandle by ID and return an Obj AttachHandle."""
        db_ah = cls.dbapi.attach_handle_get_by_id(context, id)
        obj_ah = cls._from_db_object(cls(context), db_ah)
        return obj_ah

    @classmethod
    def list(cls, context, filters=None):
        """Return a list of AttachHandle objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_ahs = cls.dbapi.attach_handle_get_by_filters(context,
                                                            filters,
                                                            sort_dir=sort_dir,
                                                            sort_key=sort_key,
                                                            limit=limit,
                                                            marker=marker)
        else:
            db_ahs = cls.dbapi.attach_handle_list(context)
        obj_ah_list = cls._from_db_object_list(db_ahs, context)
        return obj_ah_list

    def save(self, context):
        """Update an AttachHandle record in the DB"""
        updates = self.obj_get_changes()
        db_ahs = self.dbapi.attach_handle_update(context, self.uuid, updates)
        self._from_db_object(self, db_ahs)

    def destroy(self, context):
        """Delete a AttachHandle from the DB."""
        self.dbapi.attach_handle_delete(context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def get_ah_list_by_deployable_id(cls, context, deployable_id):
        ah_filter = {'deployable_id': deployable_id}
        ah_obj_list = AttachHandle.list(context, ah_filter)
        return ah_obj_list

    @classmethod
    def get_ah_by_depid_attachinfo(cls, context, deployable_id, attach_info):
        ah_filter = {
            'deployable_id': deployable_id,
            'attach_info': attach_info
        }
        ah_obj_list = AttachHandle.list(context, ah_filter)
        if len(ah_obj_list) != 0:
            return ah_obj_list[0]
        else:
            return None

    @classmethod
    def allocate(cls, context, deployable_id):
        db_ah = cls.dbapi.attach_handle_allocate(context, deployable_id)
        obj_ah = cls._from_db_object(cls(context), db_ah)
        return obj_ah

    def deallocate(self, context):
        values = {"in_use": False}
        self.dbapi.attach_handle_update(context, self.uuid, values)
Esempio n. 7
0
class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat,
             utils.FactoryMixin, ExtARQJobMixin):
    """ExtARQ is a wrapper around ARQ with Cyborg-private fields.
       Each ExtARQ object contains exactly one ARQ object as a field.
       But, in the db layer, ExtARQ and ARQ are represented together
       as a row in a single table. Both share a single UUID.
       ExtARQ version is bumped up either if any of its fields change
       or if the ARQ version changes.
    """
    # Version 1.0: Initial version
    # 1.1: v2 API and Nova integration
    VERSION = '1.1'

    dbapi = dbapi.get_instance()

    fields = {
        'arq': object_fields.ObjectField('ARQ'),
        # Cyborg-private fields
        # Left substate open now, fill them out during design/implementation
        # later.
        'substate': object_fields.StringField(),
        'deployable_uuid': object_fields.UUIDField(nullable=True),

        # The dp group is copied in to the extarq, so that any changes or
        # deletions to the device profile do not affect running VMs.
        'device_profile_group':
        object_fields.DictOfStringsField(nullable=True),
        # For bound ARQs, we keep the attach handle ID here so that
        # it is easy to deallocate on unbind or delete.
        'attach_handle_id': object_fields.IntegerField(nullable=True),
    }

    def create(self, context, device_profile_id=None):
        """Create an ExtARQ record in the DB."""
        if 'device_profile_name' not in self.arq and not device_profile_id:
            raise exception.ObjectActionError(
                action='create',
                reason='Device profile name is required in ARQ')
        self.arq.state = constants.ARQ_INITIAL
        self.substate = constants.ARQ_INITIAL
        values = self.obj_get_changes()
        arq_obj = values.pop('arq', None)
        if arq_obj is not None:
            values.update(arq_obj.as_dict())

        # Pass devprof id to db layer, to avoid repeated queries
        if device_profile_id is not None:
            values['device_profile_id'] = device_profile_id

        db_extarq = self.dbapi.extarq_create(context, values)
        self._from_db_object(self, db_extarq, context)
        return self

    @classmethod
    def get(cls, context, uuid, lock=False):
        """Find a DB ExtARQ and return an Obj ExtARQ."""
        db_extarq = cls.dbapi.extarq_get(context, uuid)
        obj_arq = objects.ARQ(context)
        obj_extarq = cls(context)
        obj_extarq['arq'] = obj_arq
        obj_extarq = cls._from_db_object(obj_extarq, db_extarq, context)
        return obj_extarq

    @classmethod
    def list(cls, context, uuid_range=None):
        """Return a list of ExtARQ objects."""
        db_extarqs = cls.dbapi.extarq_list(context, uuid_range)
        obj_extarq_list = cls._from_db_object_list(db_extarqs, context)
        return obj_extarq_list

    def save(self, context):
        """Update an ExtARQ record in the DB."""
        updates = self.obj_get_changes()
        db_extarq = self.dbapi.extarq_update(context, self.arq.uuid, updates)
        self._from_db_object(self, db_extarq, context)

    def update_state(self, context, state, scope=None):
        """Update an ExtARQ state record in the DB."""
        updates = self.obj_get_changes()
        updates["state"] = state
        db_extarq = self.dbapi.extarq_update(context, self.arq.uuid, updates,
                                             scope)
        self._from_db_object(self, db_extarq, context)

    def update_check_state(self, context, state, scope=None):
        if self.arq.state == state:
            LOG.info("ExtARQ(%s) state is %s, no need to update",
                     self.arq.uuid, state)
            return False
        old = self.arq.state
        scope = scope or ARQ_STATES_TRANSFORM_MATRIX[state]
        self.update_state(context, state, scope)
        ea = ExtARQ.get(context, self.arq.uuid, lock=True)
        if not ea:
            raise exception.ResourceNotFound("Can not find ExtARQ(%s)" %
                                             self.arq.uuid)
        current = ea.arq.state
        if state != current:
            msg = ("Failed to change ARQ state from %s to %s, the current "
                   "state is %s" % (old, state, current))
            LOG.error(msg)
            raise exception.ARQInvalidState(msg)
        return True

    def destroy(self, context):
        """Delete an ExtARQ from the DB."""
        self.dbapi.extarq_delete(context, self.arq.uuid)
        self.obj_reset_changes()

    @classmethod
    def delete_by_uuid(cls, context, arq_uuid_list):
        for uuid in arq_uuid_list:
            obj_extarq = objects.ExtARQ.get(context, uuid)
            # TODO() Defer deletion to conductor
            if obj_extarq.arq.state != constants.ARQ_INITIAL:
                obj_extarq.unbind(context)
            obj_extarq.destroy(context)

    @classmethod
    def delete_by_instance(cls, context, instance_uuid):
        """Delete all ARQs for given instance."""
        obj_extarqs = [
            extarq for extarq in objects.ExtARQ.list(context)
            if extarq.arq['instance_uuid'] == instance_uuid
        ]
        for obj_extarq in obj_extarqs:
            LOG.info('Deleting obj_extarq uuid %s for instance %s',
                     obj_extarq.arq['uuid'], obj_extarq.arq['instance_uuid'])
            obj_extarq.unbind(context)
            obj_extarq.destroy(context)

    def _get_glance_connection(self):
        default_user = '******'
        try:
            auth_user = CONF.image.username or default_user
        except Exception:
            auth_user = default_user
        return connection.Connection(cloud=auth_user)

    def _allocate_attach_handle(self, context, deployable):
        try:
            ah = AttachHandle.allocate(context, deployable.id)
            self.attach_handle_id = ah.id
        except Exception as e:
            LOG.error(
                "Failed to allocate attach handle for ARQ %s"
                "from deployable %s. Reason: %s", self.arq.uuid,
                deployable.uuid, six.text_type(e))
            # TODO(Shaohe) Rollback? We have _update_placement,
            # should cancel it.
            self.update_check_state(context, constants.ARQ_BIND_FAILED)
            raise
        LOG.info('Attach handle(%s) for ARQ(%s) successfully.', ah.uuid,
                 self.arq.uuid)

    def bind(self, context, deployable):
        self._allocate_attach_handle(context, deployable)
        # ARQ state changes get committed here
        self.update_check_state(context, constants.ARQ_BOUND)
        LOG.info('Update ARQ %s state to "Bound" successfully.', self.arq.uuid)
        # TODO(Shaohe) rollback self._unbind and self._delete
        # if (self.arq.state == constants.ARQ_DELETING
        #         or self.arq.state == ARQ_UNBOUND):

    def unbind(self, context):
        arq = self.arq
        arq.hostname = None
        arq.device_rp_uuid = None
        arq.instance_uuid = None
        arq.state = constants.ARQ_UNBOUND

        # Unbind: mark attach handles as freed
        ah_id = self.attach_handle_id
        if ah_id:
            attach_handle = AttachHandle.get_by_id(context, ah_id)
            attach_handle.deallocate(context)
        self.attach_handle_id = None
        self.save(context)

    @classmethod
    def _fill_obj_extarq_fields(cls, context, db_extarq):
        """ExtARQ object has some fields that are not present
           in db_extarq. We fill them out here.
        """
        # From the 2 fields in the ExtARQ, we obtain other fields.
        devprof_id = db_extarq['device_profile_id']
        devprof_group_id = db_extarq['device_profile_group_id']

        devprof = cls.dbapi.device_profile_get_by_id(context, devprof_id)
        db_extarq['device_profile_name'] = devprof['name']

        db_extarq['attach_handle_type'] = ''
        db_extarq['attach_handle_info'] = ''
        if db_extarq['state'] == 'Bound':  # TODO() Do proper bind
            db_ah = cls.dbapi.attach_handle_get_by_id(
                context, db_extarq['attach_handle_id'])
            if db_ah is not None:
                db_extarq['attach_handle_type'] = db_ah['attach_type']
                db_extarq['attach_handle_info'] = db_ah['attach_info']
            else:
                raise exception.ResourceNotFound(resource='attach handle',
                                                 msg='')

        if db_extarq['deployable_id']:
            dep = objects.Deployable.get_by_id(db_extarq['deployable_id'])
            db_extarq['deployable_uuid'] = dep.uuid
        else:
            LOG.debug('Setting deployable UUID to zeroes for db_extarq %s',
                      db_extarq['uuid'])
            db_extarq['deployable_uuid'] = (
                '00000000-0000-0000-0000-000000000000')

        # Get the device profile group
        obj_devprof = DeviceProfile.get_by_name(context, devprof['name'])
        groups = obj_devprof['groups']
        db_extarq['device_profile_group'] = groups[devprof_group_id]

        return db_extarq

    @classmethod
    def _from_db_object(cls, extarq, db_extarq, context):
        """Converts an ExtARQ to a formal object.
        :param extarq: An object of the class ExtARQ
        :param db_extarq: A DB model of the object
        :return: The object of the class with the database entity added
        """
        cls._fill_obj_extarq_fields(context, db_extarq)

        for field in extarq.fields:
            if field != 'arq':
                extarq[field] = db_extarq[field]
        extarq.arq = objects.ARQ()
        extarq.arq._from_db_object(extarq.arq, db_extarq)
        extarq.obj_reset_changes()
        return extarq

    @classmethod
    def _from_db_object_list(cls, db_objs, context):
        """Converts a list of ExtARQs to a list of formal objects."""
        objs = []
        for db_obj in db_objs:
            extarq = cls(context)
            obj = cls._from_db_object(extarq, db_obj, context)
            objs.append(obj)
        return objs

    def obj_get_changes(self):
        """Returns a dict of changed fields and their new values."""
        changes = {}
        for key in self.obj_what_changed():
            if key != 'arq':
                changes[key] = getattr(self, key)

        for key in self.arq.obj_what_changed():
            changes[key] = getattr(self.arq, key)

        return changes
Esempio n. 8
0
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()
    attributes_list = []

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'name': object_fields.StringField(nullable=False),
        'parent_uuid': object_fields.UUIDField(nullable=True),
        # parent_uuid refers to the id of the VF's parent node
        'root_uuid': object_fields.UUIDField(nullable=True),
        # root_uuid refers to the id of the VF's root which has to be a PF
        'address': object_fields.StringField(nullable=False),
        # if interface_type is pci(/mdev), address is the pci_address(/path)
        'host': object_fields.StringField(nullable=False),
        'board': object_fields.StringField(nullable=False),
        # board refers to a specific acc board type, e.g P100 GPU card
        'vendor': object_fields.StringField(nullable=False),
        'version': object_fields.StringField(nullable=False),
        'type': object_fields.StringField(nullable=False),
        # type of deployable, e.g, pf/vf/*f
        'interface_type': object_fields.StringField(nullable=False),
        # interface to hypervisor(libvirt), e.g, pci/mdev...
        'assignable': object_fields.BooleanField(nullable=False),
        # identify if an accelerator is in use
        'instance_uuid': object_fields.UUIDField(nullable=True),
        # The id of the virtualized accelerator instance
        'availability': object_fields.StringField(nullable=False),
        # identify the state of acc, e.g released/claimed/...
        'accelerator_id': object_fields.IntegerField(nullable=False)
        # Foreign key constrain to reference accelerator table
    }

    def _get_parent_root_uuid(self):
        obj_dep = Deployable.get(None, self.parent_uuid)
        return obj_dep.root_uuid

    def create(self, context):
        """Create a Deployable record in the DB."""
        if 'uuid' not in self:
            raise exception.ObjectActionError(action='create',
                                              reason='uuid is required')

        if not hasattr(self, 'parent_uuid') or self.parent_uuid is None:
            self.root_uuid = self.uuid
        else:
            self.root_uuid = self._get_parent_root_uuid()

        values = self.obj_get_changes()

        db_dep = self.dbapi.deployable_create(context, values)
        self._from_db_object(self, db_dep)
        del self.attributes_list[:]

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Deployable and return an Obj Deployable."""
        db_dep = cls.dbapi.deployable_get(context, uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        # retrieve all the attrobutes for this deployable
        query = {"deployable_id": obj_dep.id}
        attr_get_list = Attribute.get_by_filter(context, query)
        obj_dep.attributes_list = attr_get_list
        return obj_dep

    @classmethod
    def get_by_host(cls, context, host):
        """Get a Deployable by host."""
        db_deps = cls.dbapi.deployable_get_by_host(context, host)
        obj_dpl_list = cls._from_db_object_list(db_deps, context)
        for obj_dpl in obj_dpl_list:
            query = {"deployable_id": obj_dpl.id}
            attr_get_list = Attribute.get_by_filter(context, query)
            obj_dpl.attributes_list = attr_get_list
        return obj_dpl_list

    @classmethod
    def list(cls, context, filters={}):
        """Return a list of Deployable objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'create_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_deps = cls.dbapi.deployable_get_by_filters(context,
                                                          filters,
                                                          sort_dir=sort_dir,
                                                          sort_key=sort_key,
                                                          limit=limit,
                                                          marker=marker)
        else:
            db_deps = cls.dbapi.deployable_list(context)
        obj_dpl_list = cls._from_db_object_list(db_deps, context)
        for obj_dpl in obj_dpl_list:
            query = {"deployable_id": obj_dpl.id}
            attr_get_list = Attribute.get_by_filter(context, query)
            obj_dpl.attributes_list = attr_get_list
        return obj_dpl_list

    def save(self, context):
        """Update a Deployable record in the DB."""
        updates = self.obj_get_changes()
        db_dep = self.dbapi.deployable_update(context, self.uuid, updates)
        self._from_db_object(self, db_dep)
        query = {"deployable_id": self.id}
        attr_get_list = Attribute.get_by_filter(context, query)
        self.attributes_list = attr_get_list

    def destroy(self, context):
        """Delete a Deployable from the DB."""
        del self.attributes_list[:]
        self.dbapi.deployable_delete(context, self.uuid)
        self.obj_reset_changes()

    def add_attribute(self, context, key, value):
        """add a attribute object to the attribute_list.
        If the attribute already exists, it will update the value,
        otherwise, the vf will be appended to the list
        """

        for exist_attr in self.attributes_list:
            if key == exist_attr.key:
                LOG.warning("The attribute already exists")
                if value != exist_attr.value:
                    exist_attr.value = value
                    exist_attr.save(context)
                return None
        # The attribute does not exist yet. Create it.
        attr_vals = {'deployable_id': self.id, 'key': key, 'value': value}
        attr = Attribute(context, **attr_vals)
        attr.create(context)
        self.attributes_list.append(attr)

    def delete_attribute(self, context, attribute):
        """remove an attribute from the attributes_list
        if the attribute does not exist, ignore it
        """

        idx = 0
        for exist_attribute in self.attributes_list:
            if base.obj_equal_prims(attribute, exist_attribute):
                removed_attribute = self.attributes_list.pop(idx)
                removed_attribute.destroy(context)
                return
            idx = idx + 1
        LOG.warning("The removing attribute does not exist!")

    @classmethod
    def get_by_filter(cls, context, filters):
        obj_dpl_list = []
        db_dpl_list = cls.dbapi.deployable_get_by_filters_with_attributes(
            context, filters)

        if db_dpl_list:
            for db_dpl in db_dpl_list:
                obj_dpl = cls._from_db_object(cls(context), db_dpl)
                query = {"deployable_id": obj_dpl.id}
                attr_get_list = Attribute.get_by_filter(context, query)
                obj_dpl.attributes_list = attr_get_list
                obj_dpl_list.append(obj_dpl)

        return obj_dpl_list

    @classmethod
    def _from_db_object(cls, obj, db_obj):
        """Converts a deployable to a formal object.

        :param obj: An object of the class.
        :param db_obj: A DB model of the object
        :return: The object of the class with the database entity added
        """
        obj = base.CyborgObject._from_db_object(obj, db_obj)
        obj.attributes_list = []

        return obj
Esempio n. 9
0
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'uuid': object_fields.UUIDField(nullable=False),
        'name': object_fields.StringField(nullable=False),
        'parent_uuid': object_fields.UUIDField(nullable=True),
        # parent_uuid refers to the id of the VF's parent node
        'root_uuid': object_fields.UUIDField(nullable=True),
        # root_uuid refers to the id of the VF's root which has to be a PF
        'pcie_address': object_fields.StringField(nullable=False),
        'host': object_fields.StringField(nullable=False),
        'board': object_fields.StringField(nullable=False),
        # board refers to a specific acc board type, e.g P100 GPU card
        'vendor': object_fields.StringField(nullable=False),
        'version': object_fields.StringField(nullable=False),
        'type': object_fields.StringField(nullable=False),
        # similar to the acc_type in accelerator.py
        'assignable': object_fields.BooleanField(nullable=False),
        # identify if an accelerator is in use
        'instance_uuid': object_fields.UUIDField(nullable=True),
        # The id of the virtualized accelerator instance
        'availability': object_fields.StringField(nullable=False),
        # identify the state of acc, e.g released/claimed/...
    }

    def _get_parent_root_uuid(self):
        obj_dep = Deployable.get(None, self.parent_uuid)
        return obj_dep.root_uuid

    def create(self, context):
        """Create a Deployable record in the DB."""
        if 'uuid' not in self:
            raise exception.ObjectActionError(action='create',
                                              reason='uuid is required')

        if self.parent_uuid is None:
            self.root_uuid = self.uuid
        else:
            self.root_uuid = self._get_parent_root_uuid()

        values = self.obj_get_changes()
        db_dep = self.dbapi.deployable_create(context, values)
        self._from_db_object(self, db_dep)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Deployable and return an Obj Deployable."""
        db_dep = cls.dbapi.deployable_get(context, uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        return obj_dep

    @classmethod
    def get_by_host(cls, context, host):
        """Get a Deployable by host."""
        db_deps = cls.dbapi.deployable_get_by_host(context, host)
        return cls._from_db_object_list(db_deps, context)

    @classmethod
    def list(cls, context):
        """Return a list of Deployable objects."""
        db_deps = cls.dbapi.deployable_list(context)
        return cls._from_db_object_list(db_deps, context)

    def save(self, context):
        """Update a Deployable record in the DB."""
        updates = self.obj_get_changes()
        db_dep = self.dbapi.deployable_update(context, self.uuid, updates)
        self._from_db_object(self, db_dep)

    def destroy(self, context):
        """Delete a Deployable from the DB."""
        self.dbapi.deployable_delete(context, self.uuid)
        self.obj_reset_changes()
Esempio n. 10
0
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()
    attributes_list = []

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'name': object_fields.StringField(nullable=False),
        'parent_uuid': object_fields.UUIDField(nullable=True),
        # parent_uuid refers to the id of the VF's parent node
        'root_uuid': object_fields.UUIDField(nullable=True),
        # root_uuid refers to the id of the VF's root which has to be a PF
        'pcie_address': object_fields.StringField(nullable=False),
        'host': object_fields.StringField(nullable=False),
        'board': object_fields.StringField(nullable=False),
        # board refers to a specific acc board type, e.g P100 GPU card
        'vendor': object_fields.StringField(nullable=False),
        'version': object_fields.StringField(nullable=False),
        'type': object_fields.StringField(nullable=False),
        # similar to the acc_type in accelerator.py
        'assignable': object_fields.BooleanField(nullable=False),
        # identify if a instance is in use
        'instance_uuid': object_fields.UUIDField(nullable=True),
        # The id of the virtualized accelerator instance
        'availability': object_fields.StringField(nullable=False),
        # identify the state of acc, e.g released/claimed/...
        # 'accelerator_id': object_fields.IntegerField(nullable=False)
        # Foreign key constrain to reference accelerator table.
    }

    def _get_parent_root_uuid(self):
        obj_dep = Deployable.get(None, self.parent_uuid)
        return obj_dep.root_uuid

    def create(self, context):
        """Create a Deployable record in the DB."""
        if 'uuid' not in self:
            raise exception.ObjectActionError(action='create',
                                              reason='uuid is required')

        if self.parent_uuid is None:
            self.root_uuid = self.uuid
        else:
            self.root_uuid = self._get_parent_root_uuid()

        values = self.obj_get_changes()
        db_dep = self.dbapi.deployable_create(context, values)
        self._from_db_object(self, db_dep)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Deployable and return an Obj Deployable."""
        db_dep = cls.dbapi.deployable_get(context, uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        return obj_dep

    @classmethod
    def get_by_host(cls, context, host):
        """Get a Deployable by host."""
        db_deps = cls.dbapi.deployable_get_by_host(context, host)
        return cls._from_db_object_list(context, db_deps)

    @classmethod
    def list(cls, context):
        """Return a list of Deployable objects."""
        db_deps = cls.dbapi.deployable_list(context)
        return cls._from_db_object_list(context, db_deps)

    def save(self, context):
        """Update a Deployable record in the DB."""
        updates = self.obj_get_changes()
        db_dep = self.dbapi.deployable_update(context, self.uuid, updates)
        self._from_db_object(self, db_dep)

    def destroy(self, context):
        """Delete a Deployable from the DB."""
        self.dbapi.deployable_delete(context, self.uuid)
        self.obj_reset_changes()

    def add_attribute(self, attribute):
        """add a attribute object to the attribute_list.
        If the attribute already exists, it will update the value,
        otherwise, the vf will be appended to the list.
        """
        if not isinstance(attribute, Attribute):
            raise exception.InvalidDeployType()
        for exist_attr in self.attributes_list:
            if base.obj_equal_prims(vf, exist_attr):
                LOG.warning("The attribute already exists.")
                return None

    @classmethod
    def get_by_filter(cls,
                      context,
                      filters,
                      sort_key='created_at',
                      sort_dir='desc',
                      limit=None,
                      marker=None,
                      join=None):
        obj_dpl_list = []
        db_dpl_list = cls.dbapi.deployable_get_by_filters(context,
                                                          filters,
                                                          sort_key=sort_key,
                                                          sort_dir=sort_dir,
                                                          limit=limit,
                                                          marker=marker,
                                                          join_columns=join)
        for db_dpl in db_dpl_list:
            obj_dpl = cls._from_db_object(cls(context), db_dpl)
            obj_dpl_list.append(obj_dpl)
        return obj_dpl_list
Esempio n. 11
0
class DeviceProfile(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '1.0'

    dbapi = dbapi.get_instance()

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'name': object_fields.StringField(nullable=False),
        'profile_json': object_fields.StringField(nullable=False),
    }

    def create(self, context):
        """Create a device_profile record in the DB."""
        values = self.obj_get_changes()
        db_device_profile = self.dbapi.device_profile_create(context, values)
        self._from_db_object(self, db_device_profile)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Device_profile and return a Obj Device_profile."""
        db_device_profile = cls.dbapi.device_profile_get_by_uuid(context, uuid)
        obj_device_profile = cls._from_db_object(cls(context),
                                                 db_device_profile)
        return obj_device_profile

    @classmethod
    def list(cls, context, filters={}):
        """Return a list of Device_profile objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_device_profiles = cls.dbapi.device_profile_list_by_filters(
                context,
                filters,
                sort_dir=sort_dir,
                sort_key=sort_key,
                limit=limit,
                marker=marker)
        else:
            db_device_profiles = cls.dbapi.device_profile_list(context)
        return cls._from_db_object_list(db_device_profiles, context)

    def save(self, context):
        """Update a Device_profile record in the DB."""
        updates = self.obj_get_changes()
        db_device_profile = self.dbapi.device_profile_update(
            context, self.uuid, updates)
        self._from_db_object(self, db_device_profile)

    def destroy(self, context):
        """Delete the Device_profile from the DB."""
        self.dbapi.device_profile_delete(context, self.uuid)
        self.obj_reset_changes()

    @classmethod
    def get_by_id(cls, context, id):
        """Find a device_profile and return an Obj DeviceProfile."""
        db_dp = cls.dbapi.device_profile_get_by_id(context, id)
        obj_dp = cls._from_db_object(cls(context), db_dp)
        return obj_dp
Esempio n. 12
0
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    VERSION = '2.0'

    dbapi = dbapi.get_instance()
    attributes_list = []

    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'parent_id': object_fields.IntegerField(nullable=True),
        # parent_id refers to the id of the deployable's parent node
        'root_id': object_fields.IntegerField(nullable=True),
        # root_id refers to the id of the deployable's root to for nested tree
        'name': object_fields.StringField(nullable=False),
        # name of the deployable
        'num_accelerators': object_fields.IntegerField(nullable=False),
        # number of accelerators spawned by this deployable
        'device_id': object_fields.IntegerField(nullable=False)
        # Foreign key constrain to reference device table
    }

    def _get_parent_root_id(self, context):
        obj_dep = Deployable.get_by_id(context, self.parent_id)
        return obj_dep.root_id

    def create(self, context):
        """Create a Deployable record in the DB."""

        # FIXME: Add parent_uuid and root_uuid constrains when DB change to
        # parent_uuid & root_uuid

        values = self.obj_get_changes()
        db_dep = self.dbapi.deployable_create(context, values)
        self._from_db_object(self, db_dep)
        self.obj_reset_changes()
        del self.attributes_list[:]

    @classmethod
    def get(cls, context, uuid, with_attribute_list=True):
        """Find a DB Deployable and return an Obj Deployable."""
        db_dep = cls.dbapi.deployable_get(context, uuid)
        obj_dep = cls._from_db_object(cls(context), db_dep)
        # retrieve all the attributes for this deployable
        if with_attribute_list:
            query = {"deployable_id": obj_dep.id}
            attr_get_list = Attribute.get_by_filter(context,
                                                    query)
            obj_dep.attributes_list = attr_get_list

        obj_dep.obj_reset_changes()
        return obj_dep

    @classmethod
    def get_by_id(cls, context, id):
        """Find a DB Deployable and return an Obj Deployable."""
        dpl_query = {"id": id}
        obj_dep = Deployable.get_by_filter(context, dpl_query)[0]
        obj_dep.obj_reset_changes()
        return obj_dep

    @classmethod
    def list(cls, context, filters={}):
        """Return a list of Deployable objects."""
        if filters:
            sort_dir = filters.pop('sort_dir', 'desc')
            sort_key = filters.pop('sort_key', 'created_at')
            limit = filters.pop('limit', None)
            marker = filters.pop('marker_obj', None)
            db_deps = cls.dbapi.deployable_get_by_filters(context, filters,
                                                          sort_dir=sort_dir,
                                                          sort_key=sort_key,
                                                          limit=limit,
                                                          marker=marker)
        else:
            db_deps = cls.dbapi.deployable_list(context)
        obj_dpl_list = cls._from_db_object_list(db_deps, context)
        for obj_dpl in obj_dpl_list:
            query = {"deployable_id": obj_dpl.id}
            attr_get_list = Attribute.get_by_filter(context,
                                                    query)
            obj_dpl.attributes_list = attr_get_list
        return obj_dpl_list

    def save(self, context):
        """Update a Deployable record in the DB."""
        updates = self.obj_get_changes()
        db_dep = self.dbapi.deployable_update(context, self.uuid, updates)
        self.obj_reset_changes()
        self._from_db_object(self, db_dep)
        query = {"deployable_id": self.id}
        attr_get_list = Attribute.get_by_filter(context,
                                                query)
        self.attributes_list = attr_get_list

    def destroy(self, context):
        """Delete a Deployable from the DB."""
        del self.attributes_list[:]
        self.dbapi.deployable_delete(context, self.uuid)
        self.obj_reset_changes()

    def add_attribute(self, context, key, value):
        """Add an attribute object to the attribute_list.
        If the attribute already exists, it will update the value,
        otherwise, the attribute will be appended to the list
        """

        for exist_attr in self.attributes_list:
            if key == exist_attr.key:
                LOG.warning("The attribute already exists")
                if value != exist_attr.value:
                    exist_attr.value = value
                    exist_attr.save(context)
                return None
        # The attribute does not exist yet. Create it.
        attr_vals = {
            'deployable_id': self.id,
            'key': key,
            'value': value
        }
        attr = Attribute(context, **attr_vals)
        attr.create(context)
        self.attributes_list.append(attr)

    def delete_attribute(self, context, attribute):
        """Remove an attribute from the attributes_list
        if the attribute does not exist, ignore it
        """

        idx = 0
        for exist_attribute in self.attributes_list:
            if base.obj_equal_prims(attribute, exist_attribute):
                removed_attribute = self.attributes_list.pop(idx)
                removed_attribute.destroy(context)
                return
            idx = idx + 1
        LOG.warning("The removing attribute does not exist!")

    @classmethod
    def get_by_filter(cls, context,
                      filters):
        obj_dpl_list = []
        db_dpl_list = cls.dbapi.deployable_get_by_filters_with_attributes(
            context,
            filters)

        if db_dpl_list:
            for db_dpl in db_dpl_list:
                obj_dpl = cls._from_db_object(cls(context), db_dpl)
                query = {"deployable_id": obj_dpl.id}
                attr_get_list = Attribute.get_by_filter(context,
                                                        query)
                obj_dpl.attributes_list = attr_get_list
                obj_dpl_list.append(obj_dpl)

        return obj_dpl_list

    @staticmethod
    def _from_db_object(obj, db_obj):
        """Converts a deployable to a formal object.

        :param obj: An object of the class.
        :param db_obj: A DB model of the object
        :return: The object of the class with the database entity added
        """
        for field in obj.fields:
            obj[field] = db_obj[field]
        obj.attributes_list = []

        return obj

    @classmethod
    def get_list_by_device_id(cls, context, device_id):
        dep_filter = {'device_id': device_id}
        dep_obj_list = Deployable.list(context, dep_filter)
        return dep_obj_list

    @classmethod
    def get_by_name_deviceid(cls, context, name, device_id):
        dep_filter = {'name': name, 'device_id': device_id}
        dep_obj_list = Deployable.list(context, dep_filter)
        if len(dep_obj_list) != 0:
            return dep_obj_list[0]
        else:
            return None