class Attribute(base.CyborgObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': object_fields.IntegerField(nullable=False), 'uuid': object_fields.UUIDField(nullable=False), 'deployable_id': object_fields.IntegerField(nullable=False), 'key': object_fields.StringField(nullable=False), 'value': object_fields.StringField(nullable=False) } def create(self, context): """Create an attribute record in the DB.""" if self.deployable_id is None: raise exception.AttributeInvalid() values = self.obj_get_changes() db_attr = self.dbapi.attribute_create(context, values) self._from_db_object(self, db_attr) @classmethod def get(cls, context, uuid): """Find a DB attribute and return an Obj Deployable.""" db_attr = cls.dbapi.attribute_get(context, uuid) obj_attr = cls._from_db_object(cls(context), db_attr) return obj_attr @classmethod def get_by_deployable_id(cls, context, deployable_id): """Get an attribute by deployable_id""" db_attr = cls.dbapi.attribute_get_by_deployable_id( context, deployable_id) return cls._from_db_object_list(db_attr, context) @classmethod def get_by_filter(cls, context, filters): """Get an attribute by specified filters""" db_attr = cls.dbapi.attribute_get_by_filter(context, filters) return cls._from_db_object_list(db_attr, context) def save(self, context): """Update an attribute record in the DB.""" db_attr = self.dbapi.attribute_update(context, self.uuid, self.key, self.value) self._from_db_object(self, db_attr) def destroy(self, context): """Delete an attribute from the DB.""" self.dbapi.attribute_delete(context, self.uuid) self.obj_reset_changes() def set_key_value_pair(self, set_key, set_value): self.key = set_key self.value = set_value @classmethod def get_by_dep_key(cls, context, dep_id, key): """Get the only one attribute with deployable_id and the key.""" attr_filter = {"deployable_id": dep_id, "key": key} attr_list = cls.get_by_filter(context, attr_filter) if len(attr_list) != 0: return attr_list[0] else: return None
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()
class Deployable(base.CyborgObject, object_base.VersionedObjectDictCompat): # 1.0: Initial version # 1.1: Added rp_uuid, driver_name, bitstream_id, num_accel_in_use VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'id': object_fields.IntegerField(nullable=False), 'uuid': object_fields.UUIDField(nullable=False), 'parent_id': object_fields.IntegerField(nullable=True), # parent_id refers to the id of the deployable's parent node 'root_id': object_fields.IntegerField(nullable=True), # root_id refers to the id of the deployable's root to for nested tree 'name': object_fields.StringField(nullable=False), # name of the deployable 'num_accelerators': object_fields.IntegerField(nullable=False), # number of accelerators spawned by this deployable 'device_id': object_fields.IntegerField(nullable=False), # Foreign key constrain to reference device table 'driver_name': object_fields.StringField(nullable=True), # Will change it to non-nullable after other driver report it. 'rp_uuid': object_fields.UUIDField(nullable=True), # UUID of the Resource provider corresponding to this deployable 'bitstream_id': object_fields.UUIDField(nullable=True), } def _get_parent_root_id(self, context): obj_dep = Deployable.get_by_id(context, self.parent_id) return obj_dep.root_id def create(self, context): """Create a Deployable record in the DB.""" # FIXME: Add parent_uuid and root_uuid constrains when DB change to # parent_uuid & root_uuid values = self.obj_get_changes() db_dep = self.dbapi.deployable_create(context, values) self._from_db_object(self, db_dep) self.obj_reset_changes() del self.attributes_list[:] @classmethod def get(cls, context, uuid): """Find a DB Deployable and return an Obj Deployable.""" db_dep = cls.dbapi.deployable_get(context, uuid) obj_dep = cls._from_db_object(cls(context), db_dep) obj_dep.obj_reset_changes() return obj_dep @classmethod def get_by_id(cls, context, id): """Find a DB Deployable and return an Obj Deployable.""" dpl_query = {"id": id} obj_dep = Deployable.get_by_filter(context, dpl_query)[0] obj_dep.obj_reset_changes() return obj_dep @classmethod def get_by_device_rp_uuid(cls, context, devrp_uuid): db_dep = cls.dbapi.deployable_get_by_rp_uuid(context, devrp_uuid) obj_dep = cls._from_db_object(cls(context), db_dep) return obj_dep @classmethod def list(cls, context, filters=None): """Return a list of Deployable objects.""" if filters: sort_dir = filters.pop('sort_dir', 'desc') sort_key = filters.pop('sort_key', 'created_at') limit = filters.pop('limit', None) marker = filters.pop('marker_obj', None) db_deps = cls.dbapi.deployable_get_by_filters(context, filters, sort_dir=sort_dir, sort_key=sort_key, limit=limit, marker=marker) else: db_deps = cls.dbapi.deployable_list(context) obj_dpl_list = cls._from_db_object_list(db_deps, context) return obj_dpl_list def save(self, context): """Update a Deployable record in the DB.""" updates = self.obj_get_changes() # TODO(Xinran): Will remove this if find some better way. updates.pop("uuid", None) updates.pop("created_at", None) if "updated_at" in updates.keys() and \ updates["updated_at"] is not None: updates["updated_at"] = updates["updated_at"].replace(tzinfo=None) db_dep = self.dbapi.deployable_update(context, self.uuid, updates) self.obj_reset_changes() self._from_db_object(self, db_dep) def update(self, context, updates): """Update provided key, value pairs""" self.dbapi.deployable_update(context, self.uuid, updates) def destroy(self, context): """Delete a Deployable from the DB.""" self.dbapi.deployable_delete(context, self.uuid) self.obj_reset_changes() @classmethod def get_by_filter(cls, context, filters): obj_dpl_list = [] db_dpl_list = cls.dbapi.deployable_get_by_filters(context, filters) if db_dpl_list: for db_dpl in db_dpl_list: obj_dpl = cls._from_db_object(cls(context), db_dpl) obj_dpl_list.append(obj_dpl) return obj_dpl_list @staticmethod def _from_db_object(obj, db_obj): """Converts a deployable to a formal object. :param obj: An object of the class. :param db_obj: A DB model of the object :return: The object of the class with the database entity added """ for field in obj.fields: obj[field] = db_obj[field] obj.attributes_list = [] return obj @classmethod def get_list_by_device_id(cls, context, device_id): dep_filter = {'device_id': device_id} dep_obj_list = Deployable.list(context, dep_filter) return dep_obj_list @classmethod def get_by_name_deviceid(cls, context, name, device_id): dep_filter = {'name': name, 'device_id': device_id} dep_obj_list = Deployable.list(context, dep_filter) if len(dep_obj_list) != 0: return dep_obj_list[0] else: return None @classmethod def get_by_name(cls, context, name): dep_filter = {'name': name} dep_obj_list = Deployable.list(context, dep_filter) if len(dep_obj_list) != 0: return dep_obj_list[0] else: return None def get_cpid_list(self, context): query_filter = {"device_id": self.device_id} # TODO(Sundar) We should probably get cpid from objects layer, # not db layer cpid_list = self.dbapi.control_path_get_by_filters( context, query_filter) return cpid_list
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
class ControlpathID(base.CyborgObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Add cpid_info_obj VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'id': object_fields.IntegerField(nullable=False), 'uuid': object_fields.UUIDField(nullable=False), 'device_id': object_fields.IntegerField(nullable=False), 'cpid_type': object_fields.EnumField(valid_values=CPID_TYPE, nullable=False), 'cpid_info': object_fields.StringField(nullable=False) } @property def cpid_info_obj(self): return jsonutils.loads(self.cpid_info) @cpid_info_obj.setter def cpid_info_obj(self, cpid_info_obj): self.cpid_info = jsonutils.dumps(cpid_info_obj) def create(self, context): """Create a ControlPathID record in the DB.""" values = self.obj_get_changes() db_cp = self.dbapi.control_path_create(context, values) self._from_db_object(self, db_cp) @classmethod def get(cls, context, uuid): """Find a DB ControlpathID and return an Obj ControlpathID.""" db_cp = cls.dbapi.control_path_get_by_uuid(context, uuid) obj_cp = cls._from_db_object(cls(context), db_cp) return obj_cp @classmethod def list(cls, context, filters=None): """Return a list of ControlpathID objects.""" if filters: sort_dir = filters.pop('sort_dir', 'desc') sort_key = filters.pop('sort_key', 'created_at') limit = filters.pop('limit', None) marker = filters.pop('marker_obj', None) db_cps = cls.dbapi.control_path_get_by_filters(context, filters, sort_dir=sort_dir, sort_key=sort_key, limit=limit, marker=marker) else: db_cps = cls.dbapi.control_path_list(context) obj_cp_list = cls._from_db_object_list(db_cps, context) return obj_cp_list def save(self, context): """Update an ControlpathID record in the DB""" updates = self.obj_get_changes() db_cps = self.dbapi.control_path_update(context, self.uuid, updates) self._from_db_object(self, db_cps) def destroy(self, context): """Delete a ControlpathID from the DB.""" self.dbapi.control_path_delete(context, self.uuid) self.obj_reset_changes() @classmethod def get_by_device_id(cls, context, device_id): # control_path is unique for one device. cpid_filter = {'device_id': device_id} cpid_obj_list = ControlpathID.list(context, cpid_filter) if len(cpid_obj_list) != 0: return cpid_obj_list[0] else: return None @classmethod def get_by_device_id_cpidinfo(cls, context, device_id, cpid_info): cpid_filter = {'device_id': device_id, 'cpid_info': cpid_info} # the list could have one value or is empty. cpid_obj_list = ControlpathID.list(context, cpid_filter) if len(cpid_obj_list) != 0: return cpid_obj_list[0] else: return None
class AttachHandle(base.CyborgObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': object_fields.IntegerField(nullable=False), 'uuid': object_fields.UUIDField(nullable=False), 'deployable_id': object_fields.IntegerField(nullable=False), 'cpid_id': object_fields.IntegerField(nullable=False), 'attach_type': object_fields.EnumField(valid_values=constants.ATTACH_HANDLE_TYPES, nullable=False), # attach_info should be JSON here. 'attach_info': object_fields.StringField(nullable=False), 'in_use': object_fields.BooleanField(nullable=False, default=False) } def create(self, context): """Create a AttachHandle record in the DB.""" values = self.obj_get_changes() db_ah = self.dbapi.attach_handle_create(context, values) self._from_db_object(self, db_ah) @classmethod def get(cls, context, uuid): """Find a DB AttachHandle and return an Obj AttachHandle.""" db_ah = cls.dbapi.attach_handle_get_by_uuid(context, uuid) obj_ah = cls._from_db_object(cls(context), db_ah) return obj_ah @classmethod def get_by_id(cls, context, id): """Find a DB AttachHandle by ID and return an Obj AttachHandle.""" db_ah = cls.dbapi.attach_handle_get_by_id(context, id) obj_ah = cls._from_db_object(cls(context), db_ah) return obj_ah @classmethod def list(cls, context, filters=None): """Return a list of AttachHandle objects.""" if filters: sort_dir = filters.pop('sort_dir', 'desc') sort_key = filters.pop('sort_key', 'created_at') limit = filters.pop('limit', None) marker = filters.pop('marker_obj', None) db_ahs = cls.dbapi.attach_handle_get_by_filters(context, filters, sort_dir=sort_dir, sort_key=sort_key, limit=limit, marker=marker) else: db_ahs = cls.dbapi.attach_handle_list(context) obj_ah_list = cls._from_db_object_list(db_ahs, context) return obj_ah_list def save(self, context): """Update an AttachHandle record in the DB""" updates = self.obj_get_changes() db_ahs = self.dbapi.attach_handle_update(context, self.uuid, updates) self._from_db_object(self, db_ahs) def destroy(self, context): """Delete a AttachHandle from the DB.""" self.dbapi.attach_handle_delete(context, self.uuid) self.obj_reset_changes() @classmethod def get_ah_list_by_deployable_id(cls, context, deployable_id): ah_filter = {'deployable_id': deployable_id} ah_obj_list = AttachHandle.list(context, ah_filter) return ah_obj_list @classmethod def get_ah_by_depid_attachinfo(cls, context, deployable_id, attach_info): ah_filter = { 'deployable_id': deployable_id, 'attach_info': attach_info } ah_obj_list = AttachHandle.list(context, ah_filter) if len(ah_obj_list) != 0: return ah_obj_list[0] else: return None @classmethod def allocate(cls, context, deployable_id): db_ah = cls.dbapi.attach_handle_allocate(context, deployable_id) obj_ah = cls._from_db_object(cls(context), db_ah) return obj_ah def deallocate(self, context): values = {"in_use": False} self.dbapi.attach_handle_update(context, self.uuid, values)
class ExtARQ(base.CyborgObject, object_base.VersionedObjectDictCompat, utils.FactoryMixin, ExtARQJobMixin): """ExtARQ is a wrapper around ARQ with Cyborg-private fields. Each ExtARQ object contains exactly one ARQ object as a field. But, in the db layer, ExtARQ and ARQ are represented together as a row in a single table. Both share a single UUID. ExtARQ version is bumped up either if any of its fields change or if the ARQ version changes. """ # Version 1.0: Initial version # 1.1: v2 API and Nova integration VERSION = '1.1' dbapi = dbapi.get_instance() fields = { 'arq': object_fields.ObjectField('ARQ'), # Cyborg-private fields # Left substate open now, fill them out during design/implementation # later. 'substate': object_fields.StringField(), 'deployable_uuid': object_fields.UUIDField(nullable=True), # The dp group is copied in to the extarq, so that any changes or # deletions to the device profile do not affect running VMs. 'device_profile_group': object_fields.DictOfStringsField(nullable=True), # For bound ARQs, we keep the attach handle ID here so that # it is easy to deallocate on unbind or delete. 'attach_handle_id': object_fields.IntegerField(nullable=True), } def create(self, context, device_profile_id=None): """Create an ExtARQ record in the DB.""" if 'device_profile_name' not in self.arq and not device_profile_id: raise exception.ObjectActionError( action='create', reason='Device profile name is required in ARQ') self.arq.state = constants.ARQ_INITIAL self.substate = constants.ARQ_INITIAL values = self.obj_get_changes() arq_obj = values.pop('arq', None) if arq_obj is not None: values.update(arq_obj.as_dict()) # Pass devprof id to db layer, to avoid repeated queries if device_profile_id is not None: values['device_profile_id'] = device_profile_id db_extarq = self.dbapi.extarq_create(context, values) self._from_db_object(self, db_extarq, context) return self @classmethod def get(cls, context, uuid, lock=False): """Find a DB ExtARQ and return an Obj ExtARQ.""" db_extarq = cls.dbapi.extarq_get(context, uuid) obj_arq = objects.ARQ(context) obj_extarq = cls(context) obj_extarq['arq'] = obj_arq obj_extarq = cls._from_db_object(obj_extarq, db_extarq, context) return obj_extarq @classmethod def list(cls, context, uuid_range=None): """Return a list of ExtARQ objects.""" db_extarqs = cls.dbapi.extarq_list(context, uuid_range) obj_extarq_list = cls._from_db_object_list(db_extarqs, context) return obj_extarq_list def save(self, context): """Update an ExtARQ record in the DB.""" updates = self.obj_get_changes() db_extarq = self.dbapi.extarq_update(context, self.arq.uuid, updates) self._from_db_object(self, db_extarq, context) def update_state(self, context, state, scope=None): """Update an ExtARQ state record in the DB.""" updates = self.obj_get_changes() updates["state"] = state db_extarq = self.dbapi.extarq_update(context, self.arq.uuid, updates, scope) self._from_db_object(self, db_extarq, context) def update_check_state(self, context, state, scope=None): if self.arq.state == state: LOG.info("ExtARQ(%s) state is %s, no need to update", self.arq.uuid, state) return False old = self.arq.state scope = scope or ARQ_STATES_TRANSFORM_MATRIX[state] self.update_state(context, state, scope) ea = ExtARQ.get(context, self.arq.uuid, lock=True) if not ea: raise exception.ResourceNotFound("Can not find ExtARQ(%s)" % self.arq.uuid) current = ea.arq.state if state != current: msg = ("Failed to change ARQ state from %s to %s, the current " "state is %s" % (old, state, current)) LOG.error(msg) raise exception.ARQInvalidState(msg) return True def destroy(self, context): """Delete an ExtARQ from the DB.""" self.dbapi.extarq_delete(context, self.arq.uuid) self.obj_reset_changes() @classmethod def delete_by_uuid(cls, context, arq_uuid_list): for uuid in arq_uuid_list: obj_extarq = objects.ExtARQ.get(context, uuid) # TODO() Defer deletion to conductor if obj_extarq.arq.state != constants.ARQ_INITIAL: obj_extarq.unbind(context) obj_extarq.destroy(context) @classmethod def delete_by_instance(cls, context, instance_uuid): """Delete all ARQs for given instance.""" obj_extarqs = [ extarq for extarq in objects.ExtARQ.list(context) if extarq.arq['instance_uuid'] == instance_uuid ] for obj_extarq in obj_extarqs: LOG.info('Deleting obj_extarq uuid %s for instance %s', obj_extarq.arq['uuid'], obj_extarq.arq['instance_uuid']) obj_extarq.unbind(context) obj_extarq.destroy(context) def _get_glance_connection(self): default_user = '******' try: auth_user = CONF.image.username or default_user except Exception: auth_user = default_user return connection.Connection(cloud=auth_user) def _allocate_attach_handle(self, context, deployable): try: ah = AttachHandle.allocate(context, deployable.id) self.attach_handle_id = ah.id except Exception as e: LOG.error( "Failed to allocate attach handle for ARQ %s" "from deployable %s. Reason: %s", self.arq.uuid, deployable.uuid, six.text_type(e)) # TODO(Shaohe) Rollback? We have _update_placement, # should cancel it. self.update_check_state(context, constants.ARQ_BIND_FAILED) raise LOG.info('Attach handle(%s) for ARQ(%s) successfully.', ah.uuid, self.arq.uuid) def bind(self, context, deployable): self._allocate_attach_handle(context, deployable) # ARQ state changes get committed here self.update_check_state(context, constants.ARQ_BOUND) LOG.info('Update ARQ %s state to "Bound" successfully.', self.arq.uuid) # TODO(Shaohe) rollback self._unbind and self._delete # if (self.arq.state == constants.ARQ_DELETING # or self.arq.state == ARQ_UNBOUND): def unbind(self, context): arq = self.arq arq.hostname = None arq.device_rp_uuid = None arq.instance_uuid = None arq.state = constants.ARQ_UNBOUND # Unbind: mark attach handles as freed ah_id = self.attach_handle_id if ah_id: attach_handle = AttachHandle.get_by_id(context, ah_id) attach_handle.deallocate(context) self.attach_handle_id = None self.save(context) @classmethod def _fill_obj_extarq_fields(cls, context, db_extarq): """ExtARQ object has some fields that are not present in db_extarq. We fill them out here. """ # From the 2 fields in the ExtARQ, we obtain other fields. devprof_id = db_extarq['device_profile_id'] devprof_group_id = db_extarq['device_profile_group_id'] devprof = cls.dbapi.device_profile_get_by_id(context, devprof_id) db_extarq['device_profile_name'] = devprof['name'] db_extarq['attach_handle_type'] = '' db_extarq['attach_handle_info'] = '' if db_extarq['state'] == 'Bound': # TODO() Do proper bind db_ah = cls.dbapi.attach_handle_get_by_id( context, db_extarq['attach_handle_id']) if db_ah is not None: db_extarq['attach_handle_type'] = db_ah['attach_type'] db_extarq['attach_handle_info'] = db_ah['attach_info'] else: raise exception.ResourceNotFound(resource='attach handle', msg='') if db_extarq['deployable_id']: dep = objects.Deployable.get_by_id(db_extarq['deployable_id']) db_extarq['deployable_uuid'] = dep.uuid else: LOG.debug('Setting deployable UUID to zeroes for db_extarq %s', db_extarq['uuid']) db_extarq['deployable_uuid'] = ( '00000000-0000-0000-0000-000000000000') # Get the device profile group obj_devprof = DeviceProfile.get_by_name(context, devprof['name']) groups = obj_devprof['groups'] db_extarq['device_profile_group'] = groups[devprof_group_id] return db_extarq @classmethod def _from_db_object(cls, extarq, db_extarq, context): """Converts an ExtARQ to a formal object. :param extarq: An object of the class ExtARQ :param db_extarq: A DB model of the object :return: The object of the class with the database entity added """ cls._fill_obj_extarq_fields(context, db_extarq) for field in extarq.fields: if field != 'arq': extarq[field] = db_extarq[field] extarq.arq = objects.ARQ() extarq.arq._from_db_object(extarq.arq, db_extarq) extarq.obj_reset_changes() return extarq @classmethod def _from_db_object_list(cls, db_objs, context): """Converts a list of ExtARQs to a list of formal objects.""" objs = [] for db_obj in db_objs: extarq = cls(context) obj = cls._from_db_object(extarq, db_obj, context) objs.append(obj) return objs def obj_get_changes(self): """Returns a dict of changed fields and their new values.""" changes = {} for key in self.obj_what_changed(): if key != 'arq': changes[key] = getattr(self, key) for key in self.arq.obj_what_changed(): changes[key] = getattr(self.arq, key) return changes
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 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
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