class CyborgPersistentObject(object): """Mixin class for Persistent objects. This adds the fields that we use in common for most persistent objects. """ fields = { 'created_at': object_fields.DateTimeField(nullable=True), 'updated_at': object_fields.DateTimeField(nullable=True), 'deleted_at': object_fields.DateTimeField(nullable=True), 'deleted': object_fields.BooleanField(default=False), }
class DriverAttachHandle(base.DriverObjectBase, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' fields = { 'attach_type': object_fields.StringField(nullable=False), # PCI BDF or mediated device ID... 'attach_info': object_fields.StringField(nullable=False), # The status of attach_handle, is in use or not. 'in_use': object_fields.BooleanField(nullable=False, default=False) } def create(self, context, deployable_id, cpid_id): """Create a driver-side AttachHandle object, call AttachHandle Object to store in DB. """ attach_handle_obj = AttachHandle(context=context, deployable_id=deployable_id, cpid_id=cpid_id, attach_type=self.attach_type, attach_info=self.attach_info, in_use=self.in_use) attach_handle_obj.create(context) def destroy(self, context, deployable_id): ah_obj = AttachHandle.get_ah_by_depid_attachinfo( context, deployable_id, self.attach_info) if ah_obj is not None: ah_obj.destroy(context) @classmethod def list(cls, context, deployable_id): """Form a driver-side attach_handle list for one deployable.""" ah_obj_list = AttachHandle.get_ah_list_by_deployable_id( context, deployable_id) driver_ah_obj_list = [] for ah_obj in ah_obj_list: driver_ah_obj = cls(context=context, attach_type=ah_obj.attach_type, attach_info=ah_obj.attach_info, in_use=ah_obj.in_use) driver_ah_obj_list.append(driver_ah_obj) return driver_ah_obj_list
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
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
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()
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
class DriverDevice(base.DriverObjectBase, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' fields = { 'vendor': object_fields.StringField(nullable=False), 'model': object_fields.StringField(nullable=False), 'type': object_fields.DeviceTypeField(nullable=False), 'std_board_info': object_fields.StringField(nullable=True), # vendor board info should be a dict for driver-specific resource # provider. 'vendor_board_info': object_fields.StringField(nullable=True), # hostname will be set by the agent, so driver don't need to report. # Each controlpath_id corresponds to a different PF. For now # we are sticking with a single cpid. 'controlpath_id': object_fields.ObjectField('DriverControlPathID', nullable=False), 'deployable_list': object_fields.ListOfObjectsField('DriverDeployable', default=[], nullable=False), 'stub': object_fields.BooleanField(nullable=False, default=False) } def create(self, context, host): """Create a driver-side Device Object into DB. This object will be stored in many db tables: device, deployable, attach_handle, controlpath_id etc. by calling related Object. """ # first store in device table through Device Object. device_obj = Device(context=context, type=self.type, vendor=self.vendor, model=self.model, hostname=host) if hasattr(self, 'std_board_info'): device_obj.std_board_info = self.std_board_info if hasattr(self, 'vendor_board_info'): device_obj.vendor_board_info = self.vendor_board_info device_obj.create(context) # for the controlpath_id, call driver_controlpath_id to create. cpid_obj = self.controlpath_id.create(context, device_obj.id) # for deployable_list, call internal layer object: driver_deployable # to create. for driver_deployable in self.deployable_list: driver_deployable.create(context, device_obj.id, cpid_obj.id) def destroy(self, context, host): """Delete a driver-side Device Object from db. This should delete the internal layer objects. """ # get dev_obj_list from hostname device_obj = self.get_device_obj(context, host) # delete deployable_list first. for driver_deployable in self.deployable_list: driver_deployable.destroy(context, device_obj.id) if hasattr(self.controlpath_id, 'cpid_info'): cpid_obj = ControlpathID.get_by_device_id_cpidinfo( context, device_obj.id, self.controlpath_id.cpid_info) # delete controlpath_id cpid_obj.destroy(context) # delete the device device_obj.destroy(context) def get_device_obj(self, context, host): """Get a driver-side Device Object from db. :param context: requested context. :param host: hostname of the node. :return: a device object of current driver device object. It will return on value because it has controlpath_id. """ # get dev_obj_list from hostname device_obj_list = Device.get_list_by_hostname(context, host) # use controlpath_id.cpid_info to identiy one Device. for device_obj in device_obj_list: # get cpid_obj, could be empty or only one value. cpid_obj = ControlpathID.get_by_device_id_cpidinfo( context, device_obj.id, self.controlpath_id.cpid_info) # find the one cpid_obj with cpid_info if cpid_obj is not None: return device_obj @classmethod def list(cls, context, host): """Form driver-side device object list from DB for one host. A list may contains driver_device_object without controlpath_id.(In the case some of controlpath_id can't store successfully but its devices stores successfully.) """ # get dev_obj_list from hostname dev_obj_list = Device.get_list_by_hostname(context, host) driver_dev_obj_list = [] for dev_obj in dev_obj_list: cpid = DriverControlPathID.get(context, dev_obj.id) # NOTE: will not return device without controlpath_id. if cpid is not None: driver_dev_obj = \ cls(context=context, vendor=dev_obj.vendor, model=dev_obj.model, type=dev_obj.type, std_board_info=dev_obj.std_board_info, vendor_board_info=dev_obj.vendor_board_info, controlpath_id=cpid, deployable_list=DriverDeployable.list(context, dev_obj.id) ) driver_dev_obj_list.append(driver_dev_obj) return driver_dev_obj_list def get_device_obj_by_device_id(self, context, device_id): """Get device object by device id. :param context: requested context. :param host: hostname of the node. :return: a device object of current driver device object. It will return on value because it has controlpath_id. """ # get dev_obj_list from hostname device_obj = Device.get_by_device_id(context, device_id) # use controlpath_id.cpid_info to identiy one Device. # get cpid_obj, could be empty or only one value. ControlpathID.get_by_device_id_cpidinfo(context, device_obj.id, self.controlpath_id.cpid_info) # find the one cpid_obj with cpid_info return device_obj