Exemple #1
0
    def _test_reservation_commit(self):
        db_api = dbapi.get_instance()
        reservations = _quota_reserve(self.context, 'project1')
        expected = {'project_id': 'project1',
                    'fpga': {'reserved': 1, 'in_use': 0},
                    'gpu': {'reserved': 2, 'in_use': 0},
                    }
        quota_usages = db_api._get_quota_usages(self.context, 'project1')
        result = {'project_id': "project1"}
        for k, v in quota_usages.items():
            result[v.resource] = dict(in_use=v.in_use, reserved=v.reserved)

        self.assertEqual(expected, result)

        db_api.reservation_commit(self.context, reservations, 'project1')
        expected = {'project_id': 'project1',
                    'fpga': {'reserved': 0, 'in_use': 1},
                    'gpu': {'reserved': 0, 'in_use': 2},
                    }
        quota_usages = db_api._get_quota_usages(self.context, 'project1')
        result = {'project_id': "project1"}
        for k, v in quota_usages.items():
            result[v.resource] = dict(in_use=v.in_use,
                                      reserved=v.reserved)
        self.assertEqual(expected, result)
Exemple #2
0
class Accelerator(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),
        'description': object_fields.StringField(nullable=True),
        'project_id': object_fields.UUIDField(nullable=True),
        'user_id': object_fields.UUIDField(nullable=True),
        'device_type': object_fields.StringField(nullable=False),
        'acc_type': object_fields.StringField(nullable=False),
        'acc_capability': object_fields.StringField(nullable=False),
        'vendor_id': object_fields.StringField(nullable=False),
        'product_id': object_fields.StringField(nullable=False),
        'remotable': object_fields.IntegerField(nullable=False),
    }

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

    def create(self, context=None):
        """Create an Accelerator record in the DB."""
        values = self.obj_get_changes()
        db_accelerator = self.dbapi.accelerator_create(context, values)
        self._from_db_object(context, self, db_accelerator)
Exemple #3
0
class Accelerator(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),
        'description': object_fields.StringField(nullable=True),
        'project_id': object_fields.UUIDField(nullable=True),
        'user_id': object_fields.UUIDField(nullable=True),
        'device_type': object_fields.StringField(nullable=False),
        # The type of the accelerator device, e.g GPU, FPGA, ...
        'acc_type': object_fields.StringField(nullable=False),
        # acc_type defines the usage of the accelerator, e.g Crypto
        'acc_capability': object_fields.StringField(nullable=False),
        # acc_capability defines the specific capability, e.g AES
        'vendor_id': object_fields.StringField(nullable=False),
        # vendor_id refers to ids like NVIDIA, XILINX, INTEL,...
        'product_id': object_fields.StringField(nullable=False),
        # product_id refers to ids like P100
        'remotable': object_fields.IntegerField(nullable=False),
        # remotable ids if remote accelerator is supported
    }

    def create(self, context):
        """Create an Accelerator record in the DB."""
        values = self.obj_get_changes()
        db_acc = self.dbapi.accelerator_create(context, values)
        self._from_db_object(self, db_acc)

    @classmethod
    def get(cls, context, uuid):
        """Find a DB Accelerator and return an Obj Accelerator."""
        db_acc = cls.dbapi.accelerator_get(context, uuid)
        obj_acc = cls._from_db_object(cls(context), db_acc)
        return obj_acc

    @classmethod
    def list(cls, context, limit, marker, sort_key, sort_dir, project_only):
        """Return a list of Accelerator objects."""
        db_accs = cls.dbapi.accelerator_list(context, limit, marker, sort_key,
                                             sort_dir, project_only)
        return cls._from_db_object_list(db_accs, context)

    def save(self, context):
        """Update an Accelerator record in the DB."""
        updates = self.obj_get_changes()
        db_acc = self.dbapi.accelerator_update(context, self.uuid, updates)
        self._from_db_object(self, db_acc)

    def destroy(self, context):
        """Delete the Accelerator from the DB."""
        self.dbapi.accelerator_delete(context, self.uuid)
        self.obj_reset_changes()
Exemple #4
0
def create_test_extarq(context, **kwargs):
    """Create test extend arq entry in DB and return ExtArq DB object.

    Function to be used to create test ExtArq objects in the database.
    :param context: request context.
    :param kwargs: kwargs which override default extend arq attributes.
    :returns: Test ExtArq DB object.
    """
    ext_arq = get_test_extarq(**kwargs)
    dbapi = db_api.get_instance()
    return dbapi.extarq_create(context, ext_arq)
Exemple #5
0
def create_test_device(context, **kwargs):
    """Create test device entry in DB and return Device DB object.

    Function to be used to create test Device objects in the database.
    :param context: request context.
    :param kwargs: kwargs which override default device attributes.
    :returns: Test Device DB object.
    """
    device = get_test_device(**kwargs)
    dbapi = db_api.get_instance()
    return dbapi.device_create(context, device)
Exemple #6
0
def create_test_attach_handle(context, **kwargs):
    """Create test attach handle entry in DB and return
    AttachHandle DB object.

    Function to be used to create test AttachHandle objects in the database.
    :param context: request context.
    :param kwargs: kwargs which override default attach handle attributes.
    :returns: Test AttachHandle DB object.
    """
    attach_handle = get_test_attach_handle(**kwargs)
    dbapi = db_api.get_instance()
    return dbapi.attach_handle_create(context, attach_handle)
Exemple #7
0
    def setUp(self):
        super(DbTestCase, self).setUp()

        self.dbapi = dbapi.get_instance()

        global _DB_CACHE
        if not _DB_CACHE:
            engine = enginefacade.get_legacy_facade().get_engine()
            _DB_CACHE = Database(engine,
                                 migration,
                                 sql_connection=CONF.database.connection)
        self.useFixture(_DB_CACHE)
Exemple #8
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, self.key, self.value)
        self._from_db_object(self, db_attr)

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

    @classmethod
    def attribute_get_by_deployable_uuid(cls, context, deployable_uuid):
        """Get an attribute by deployable uuid."""
        db_attr = cls.dbapi.attribute_get_by_deployable_uuid(
            context, deployable_uuid)
        return cls._from_db_object_list(db_attr, context)

    def save(self, context):
        """Update an attribute record in the DB."""
        updates = self.obj_get_changes()
        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
Exemple #9
0
class ARQ(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),
        'state': object_fields.ARQStateField(nullable=False),
        'device_profile': object_fields.ObjectField('DeviceProfile',
                                                    nullable=True),
        'hostname': object_fields.StringField(nullable=True),
        'device_rp_uuid': object_fields.UUIDField(nullable=True),
        'device_instance_uuid': object_fields.UUIDField(nullable=True),
        'attach_handle': object_fields.ObjectField('AttachHandle',
                                                   nullable=True),
    }

    @staticmethod
    def _from_db_object(arq, db_extarq):
        """Converts an ARQ to a formal object.

        :param arq: An object of the class ARQ
        :param db_extarq: A DB model of the object
        :return: The object of the class with the database entity added
        """
        device_profile_id = db_extarq.pop('device_profile_id', None)
        attach_handle_id = db_extarq.pop('attach_handle_id', None)

        for field in arq.fields:
            # if field == 'device_profile':
            #     arq._load_device_profile(device_profile_id)
            # if field == 'attach_handle':
            #     arq._load_device_profile(attach_handle_id)
            arq[field] = db_extarq[field]

        arq.obj_reset_changes()
        return arq

    def _load_device_profile(self, device_profile_id):
        self.device_profile = objects.DeviceProfile.\
            get_by_id(self._context, device_profile_id)

    def _load_attach_handle(self, attach_handle_id):
        self.attach_handle = objects.AttachHandle.\
            get_by_id(self._context, attach_handle_id)
Exemple #10
0
class ARQ(base.CyborgObject, object_base.VersionedObjectDictCompat):
    # Version 1.0: Initial version
    # 1.1: v2 API and Nova integration
    VERSION = '1.1'

    dbapi = dbapi.get_instance()
    fields = {
        'id': object_fields.IntegerField(nullable=False),
        'uuid': object_fields.UUIDField(nullable=False),
        'state': object_fields.ARQStateField(nullable=False),
        'device_profile_name': object_fields.StringField(nullable=False),
        'device_profile_group_id':
            object_fields.IntegerField(nullable=False),

        # Fields populated by Nova after scheduling for binding
        'hostname': object_fields.StringField(nullable=True),
        'device_rp_uuid': object_fields.StringField(nullable=True),
        'instance_uuid': object_fields.StringField(nullable=True),

        # Fields populated by Cyborg after binding
        'attach_handle_type': object_fields.StringField(nullable=True),
        'attach_handle_info': object_fields.DictOfStringsField(nullable=True),
    }

    @staticmethod
    def _from_db_object(arq, db_extarq):
        """Converts an ARQ to a formal object.

        :param arq: An object of the class ARQ
        :param db_extarq: A DB model of the object
        :return: The object of the class with the database entity added
        """
        ahi = db_extarq['attach_handle_info']
        if ahi is not None and ahi != '':
            d = jsonutils.loads(ahi)
            db_extarq['attach_handle_info'] = d
        else:
            db_extarq['attach_handle_info'] = {}

        for field in arq.fields:
            arq[field] = db_extarq[field]
        arq.obj_reset_changes()
        return arq
Exemple #11
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
Exemple #12
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(resources='ExtARQ',
                                             msg="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.ARQBadState(state=current,
                                        uuid=self.arq.uuid,
                                        expected=list(state))
        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):
        """Delete a list of ARQs based on their UUIDs.

        This is not idempotent, i.e., if the first call to delete an
        ARQ has succeeded, second and later calls to delete the same ARQ
        will get errored out, but it will raise the exception only after
        all input arq being operated.
        """
        unexisted = []
        for uuid in arq_uuid_list:
            try:
                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)
            except exception.ResourceNotFound:
                unexisted.append(uuid)
                continue
        if unexisted:
            LOG.warning('There are unexisted arqs: %s', unexisted)
            raise exception.ResourceNotFound(resource='ARQ',
                                             msg='with uuids %s' % unexisted)

    @classmethod
    def delete_by_instance(cls, context, instance_uuid):
        """Delete all ARQs for given instance.

        This is idempotent, i.e., it would have the same effect if called
        repeatedly with the same instance UUID. In other words, it would
        not raise an error on the second and later attempts even if the
        first one has deleted the ARQs.
        """
        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, str(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 = DeviceProfile.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='with uuid=%s' %
                                                 db_extarq['attach_handle_id'])

        if db_extarq['deployable_id']:
            dep = objects.Deployable.get_by_id(context,
                                               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')

        groups = 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.get(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
Exemple #13
0
class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat):
    """ 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
    VERSION = '1.0'

    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(nullable=True),
    }

    def create(self, context, device_profile_id=None):
        """Create an ExtARQ record in the DB."""
        if 'device_profile' not in self.arq and not device_profile_id:
            raise exception.ObjectActionError(
                action='create', reason='Device profile is required in ARQ')
        self.arq.state = constants.ARQINITIAL
        self.substate = constants.ARQINITIAL
        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)
        return self

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

    @classmethod
    def list(cls, context, limit, marker, sort_key, sort_dir):
        """Return a list of ExtARQ objects."""
        db_extarqs = cls.dbapi.extarq_list(context, limit, marker, sort_key,
                                           sort_dir)
        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)

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

    def bind(self, context, host_name, devrp_uuid, instance_uuid):
        """ Given a device rp UUID, get the deployable UUID and
            an attach handle.
        """
        # For the fake device, we just set the state to 'Bound'
        # TODO(wangzhh): Move bind logic and unbind logic to the agent later.
        arq = self.arq
        arq.host_name = host_name
        arq.device_rp_uuid = devrp_uuid
        arq.instance_uuid = instance_uuid
        arq.state = constants.ARQBOUND

        self.save(context)

    def unbind(self, context):
        arq = self.arq
        arq.host_name = ''
        arq.device_rp_uuid = ''
        arq.instance_uuid = ''
        arq.state = constants.ARQUNBOUND

        self.save(context)

    @staticmethod
    def _from_db_object(extarq, db_extarq):
        """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
        """
        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

    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
Exemple #14
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
Exemple #15
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()

    @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

    @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
Exemple #16
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
Exemple #17
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=ATTACH_TYPE,
                                               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={}):
        """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
Exemple #18
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
Exemple #19
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()
Exemple #20
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.StringField(nullable=False),
        'name': object_fields.StringField(nullable=False),
        'groups': object_fields.ListOfDictOfNullableStringsField(),
    }

    def _to_profile_json(self, obj_changes):
        if 'groups' in obj_changes:  # Convert to profile_json string
            d = {"groups": obj_changes['groups']}
            profile_json = jsonutils.dumps(d)
            obj_changes['profile_json'] = profile_json
            obj_changes.pop('groups', None)  # del 'groups'
        else:
            raise exception.DeviceProfileGroupsExpected()

    def create(self, context):
        """Create a Device Profile record in the DB."""
        # TODO() validate with a JSON schema
        if 'name' not in self:
            raise exception.ObjectActionError(action='create',
                                              reason='name is required')

        values = self.obj_get_changes()
        self._to_profile_json(values)

        db_devprof = self.dbapi.device_profile_create(context, values)
        self._from_db_object(self, db_devprof)

    @classmethod
    def get_by_uuid(cls, context, uuid):
        """Find a DB Device_profile and return an Obj Device_profile."""
        db_devprof = cls.dbapi.device_profile_get_by_uuid(context, uuid)
        obj_devprof = cls._from_db_object(cls(context), db_devprof)
        return obj_devprof

    @classmethod
    def get_by_name(cls, context, name):
        """Find a DB Device Profile and return an Obj Device Profile."""
        db_devprof = cls.dbapi.device_profile_get(context, name)
        obj_devprof = cls._from_db_object(cls(context), db_devprof)
        return obj_devprof

    @classmethod
    def list(cls, context):
        # TODO() add filters, limits, pagination, etc.
        """Return a list of Device Profile objects."""
        db_devprofs = cls.dbapi.device_profile_list(context)
        obj_dp_list = cls._from_db_object_list(db_devprofs, context)
        return obj_dp_list

    def save(self, context):
        """Update a Device Profile record in the DB."""
        updates = self.obj_get_changes()
        self._to_profile_json(updates)

        db_devprof = self.dbapi.device_profile_update(context,
                                                      self.name, updates)
        self._from_db_object(self, db_devprof)

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

    @classmethod
    def _from_db_object(cls, obj, db_obj):
        """Converts a device_profile 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
        """
        # Convert from profile_json to 'groups' ListOfDictOfStrings
        d = jsonutils.loads(db_obj['profile_json'])
        db_obj['groups'] = d['groups']
        obj = base.CyborgObject._from_db_object(obj, db_obj)
        return obj
Exemple #21
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 a 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 a 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 a 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 a attribute record in the DB."""
        updates = self.obj_get_changes()
        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 a 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
Exemple #22
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
Exemple #23
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=constants.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
Exemple #24
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()