class AllocationCRUDPayload(notification.NotificationPayloadBase): # Version 1.0: Initial version VERSION = '1.0' SCHEMA = { 'candidate_nodes': ('allocation', 'candidate_nodes'), 'created_at': ('allocation', 'created_at'), 'extra': ('allocation', 'extra'), 'last_error': ('allocation', 'last_error'), 'name': ('allocation', 'name'), 'resource_class': ('allocation', 'resource_class'), 'state': ('allocation', 'state'), 'traits': ('allocation', 'traits'), 'updated_at': ('allocation', 'updated_at'), 'uuid': ('allocation', 'uuid') } fields = { 'uuid': object_fields.UUIDField(nullable=True), 'name': object_fields.StringField(nullable=True), 'node_uuid': object_fields.StringField(nullable=True), 'state': object_fields.StringField(nullable=True), 'last_error': object_fields.StringField(nullable=True), 'resource_class': object_fields.StringField(nullable=True), 'traits': object_fields.ListOfStringsField(nullable=True), 'candidate_nodes': object_fields.ListOfStringsField(nullable=True), 'extra': object_fields.FlexibleDictField(nullable=True), 'created_at': object_fields.DateTimeField(nullable=True), 'updated_at': object_fields.DateTimeField(nullable=True), } def __init__(self, allocation, node_uuid=None): super(AllocationCRUDPayload, self).__init__(node_uuid=node_uuid) self.populate_schema(allocation=allocation)
class Conductor(base.IronicObject): dbapi = db_api.get_instance() fields = { 'id': object_fields.IntegerField(), 'drivers': object_fields.ListOfStringsField(nullable=True), 'hostname': object_fields.StringField(), } @staticmethod def _from_db_object(conductor, db_obj): """Converts a database entity to a formal object.""" for field in conductor.fields: conductor[field] = db_obj[field] conductor.obj_reset_changes() return conductor @base.remotable_classmethod def get_by_hostname(cls, context, hostname): """Get a Conductor record by its hostname. :param hostname: the hostname on which a Conductor is running :returns: a :class:`Conductor` object. """ db_obj = cls.dbapi.get_conductor(hostname) conductor = Conductor._from_db_object(cls(context), db_obj) return conductor def save(self, context): """Save is not supported by Conductor objects.""" raise NotImplementedError( _('Cannot update a conductor record directly.')) @base.remotable def refresh(self, context=None): """Loads and applies updates for this Conductor. Loads a :class:`Conductor` with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded chassis column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Conductor(context) """ current = self.__class__.get_by_hostname(self._context, hostname=self.hostname) self.obj_refresh(current) @base.remotable def touch(self, context): """Touch this conductor's DB record, marking it as up-to-date.""" self.dbapi.touch_conductor(self.hostname)
class Allocation(base.IronicObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' dbapi = dbapi.get_instance() fields = { 'id': object_fields.IntegerField(), 'uuid': object_fields.UUIDField(nullable=True), 'name': object_fields.StringField(nullable=True), 'node_id': object_fields.IntegerField(nullable=True), 'state': object_fields.StringField(nullable=True), 'last_error': object_fields.StringField(nullable=True), 'resource_class': object_fields.StringField(nullable=True), 'traits': object_fields.ListOfStringsField(nullable=True), 'candidate_nodes': object_fields.ListOfStringsField(nullable=True), 'extra': object_fields.FlexibleDictField(nullable=True), 'conductor_affinity': object_fields.IntegerField(nullable=True), } def _convert_to_version(self, target_version, remove_unavailable_fields=True): """Convert to the target version. Convert the object to the target version. The target version may be the same, older, or newer than the version of the object. This is used for DB interactions as well as for serialization/deserialization. :param target_version: the desired version of the object :param remove_unavailable_fields: True to remove fields that are unavailable in the target version; set this to True when (de)serializing. False to set the unavailable fields to appropriate values; set this to False for DB interactions. """ # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get(cls, context, allocation_ident): """Find an allocation by its ID, UUID or name. :param allocation_ident: The ID, UUID or name of an allocation. :param context: Security context :returns: An :class:`Allocation` object. :raises: InvalidIdentity """ if strutils.is_int_like(allocation_ident): return cls.get_by_id(context, allocation_ident) elif uuidutils.is_uuid_like(allocation_ident): return cls.get_by_uuid(context, allocation_ident) elif utils.is_valid_logical_name(allocation_ident): return cls.get_by_name(context, allocation_ident) else: raise exception.InvalidIdentity(identity=allocation_ident) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get_by_id(cls, context, allocation_id): """Find an allocation by its integer ID. :param cls: the :class:`Allocation` :param context: Security context :param allocation_id: The ID of an allocation. :returns: An :class:`Allocation` object. :raises: AllocationNotFound """ db_allocation = cls.dbapi.get_allocation_by_id(allocation_id) allocation = cls._from_db_object(context, cls(), db_allocation) return allocation # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get_by_uuid(cls, context, uuid): """Find an allocation by its UUID. :param cls: the :class:`Allocation` :param context: Security context :param uuid: The UUID of an allocation. :returns: An :class:`Allocation` object. :raises: AllocationNotFound """ db_allocation = cls.dbapi.get_allocation_by_uuid(uuid) allocation = cls._from_db_object(context, cls(), db_allocation) return allocation # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get_by_name(cls, context, name): """Find an allocation based by its name. :param cls: the :class:`Allocation` :param context: Security context :param name: The name of an allocation. :returns: An :class:`Allocation` object. :raises: AllocationNotFound """ db_allocation = cls.dbapi.get_allocation_by_name(name) allocation = cls._from_db_object(context, cls(), db_allocation) return allocation # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def list(cls, context, filters=None, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Allocation objects. :param cls: the :class:`Allocation` :param context: Security context. :param filters: Filters to apply. :param limit: Maximum number of resources to return in a single result. :param marker: Pagination marker for large data sets. :param sort_key: Column to sort results by. :param sort_dir: Direction to sort. "asc" or "desc". :returns: A list of :class:`Allocation` object. :raises: InvalidParameterValue """ db_allocations = cls.dbapi.get_allocation_list(filters=filters, limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return cls._from_db_object_list(context, db_allocations) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def create(self, context=None): """Create a Allocation record in the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Allocation(context) :raises: AllocationDuplicateName, AllocationAlreadyExists """ values = self.do_version_changes_for_db() db_allocation = self.dbapi.create_allocation(values) self._from_db_object(self._context, self, db_allocation) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def destroy(self, context=None): """Delete the Allocation from the DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Allocation(context) :raises: AllocationNotFound """ self.dbapi.destroy_allocation(self.uuid) self.obj_reset_changes() # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def save(self, context=None): """Save updates to this Allocation. Updates will be made column by column based on the result of self.what_changed(). :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Allocation(context) :raises: AllocationNotFound, AllocationDuplicateName """ updates = self.do_version_changes_for_db() updated_allocation = self.dbapi.update_allocation(self.uuid, updates) self._from_db_object(self._context, self, updated_allocation) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def refresh(self, context=None): """Loads updates for this Allocation. Loads an allocation with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded allocation column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Allocation(context) :raises: AllocationNotFound """ current = self.get_by_uuid(self._context, uuid=self.uuid) self.obj_refresh(current) self.obj_reset_changes()
class NodePayload(notification.NotificationPayloadBase): """Base class used for all notification payloads about a Node object.""" # NOTE: This payload does not include the Node fields "chassis_id", # "driver_info", "driver_internal_info", "instance_info", "raid_config", # "reservation", or "target_raid_config". These were excluded for reasons # including: # - increased complexity needed for creating the payload # - sensitive information in the fields that shouldn't be exposed to # external services # - being internal-only or hardware-related fields SCHEMA = { 'clean_step': ('node', 'clean_step'), 'conductor_group': ('node', 'conductor_group'), 'console_enabled': ('node', 'console_enabled'), 'created_at': ('node', 'created_at'), 'deploy_step': ('node', 'deploy_step'), 'driver': ('node', 'driver'), 'extra': ('node', 'extra'), 'inspection_finished_at': ('node', 'inspection_finished_at'), 'inspection_started_at': ('node', 'inspection_started_at'), 'instance_uuid': ('node', 'instance_uuid'), 'last_error': ('node', 'last_error'), 'maintenance': ('node', 'maintenance'), 'maintenance_reason': ('node', 'maintenance_reason'), 'fault': ('node', 'fault'), 'name': ('node', 'name'), 'bios_interface': ('node', 'bios_interface'), 'boot_interface': ('node', 'boot_interface'), 'console_interface': ('node', 'console_interface'), 'deploy_interface': ('node', 'deploy_interface'), 'inspect_interface': ('node', 'inspect_interface'), 'management_interface': ('node', 'management_interface'), 'network_interface': ('node', 'network_interface'), 'power_interface': ('node', 'power_interface'), 'raid_interface': ('node', 'raid_interface'), 'rescue_interface': ('node', 'rescue_interface'), 'storage_interface': ('node', 'storage_interface'), 'vendor_interface': ('node', 'vendor_interface'), 'power_state': ('node', 'power_state'), 'properties': ('node', 'properties'), 'protected': ('node', 'protected'), 'protected_reason': ('node', 'protected_reason'), 'provision_state': ('node', 'provision_state'), 'provision_updated_at': ('node', 'provision_updated_at'), 'resource_class': ('node', 'resource_class'), 'target_power_state': ('node', 'target_power_state'), 'target_provision_state': ('node', 'target_provision_state'), 'updated_at': ('node', 'updated_at'), 'uuid': ('node', 'uuid') } # Version 1.0: Initial version, based off of Node version 1.18. # Version 1.1: Type of network_interface changed to just nullable string # similar to version 1.20 of Node. # Version 1.2: Add nullable to console_enabled and maintenance. # Version 1.3: Add dynamic interfaces fields exposed via API. # Version 1.4: Add storage interface field exposed via API. # Version 1.5: Add rescue interface field exposed via API. # Version 1.6: Add traits field exposed via API. # Version 1.7: Add fault field exposed via API. # Version 1.8: Add bios interface field exposed via API. # Version 1.9: Add deploy_step field exposed via API. # Version 1.10: Add conductor_group field exposed via API. # Version 1.11: Add protected and protected_reason fields exposed via API. VERSION = '1.11' fields = { 'clean_step': object_fields.FlexibleDictField(nullable=True), 'conductor_group': object_fields.StringField(nullable=True), 'console_enabled': object_fields.BooleanField(nullable=True), 'created_at': object_fields.DateTimeField(nullable=True), 'deploy_step': object_fields.FlexibleDictField(nullable=True), 'driver': object_fields.StringField(nullable=True), 'extra': object_fields.FlexibleDictField(nullable=True), 'inspection_finished_at': object_fields.DateTimeField(nullable=True), 'inspection_started_at': object_fields.DateTimeField(nullable=True), 'instance_uuid': object_fields.UUIDField(nullable=True), 'last_error': object_fields.StringField(nullable=True), 'maintenance': object_fields.BooleanField(nullable=True), 'maintenance_reason': object_fields.StringField(nullable=True), 'fault': object_fields.StringField(nullable=True), 'bios_interface': object_fields.StringField(nullable=True), 'boot_interface': object_fields.StringField(nullable=True), 'console_interface': object_fields.StringField(nullable=True), 'deploy_interface': object_fields.StringField(nullable=True), 'inspect_interface': object_fields.StringField(nullable=True), 'management_interface': object_fields.StringField(nullable=True), 'network_interface': object_fields.StringField(nullable=True), 'power_interface': object_fields.StringField(nullable=True), 'raid_interface': object_fields.StringField(nullable=True), 'rescue_interface': object_fields.StringField(nullable=True), 'storage_interface': object_fields.StringField(nullable=True), 'vendor_interface': object_fields.StringField(nullable=True), 'name': object_fields.StringField(nullable=True), 'power_state': object_fields.StringField(nullable=True), 'properties': object_fields.FlexibleDictField(nullable=True), 'protected': object_fields.BooleanField(nullable=True), 'protected_reason': object_fields.StringField(nullable=True), 'provision_state': object_fields.StringField(nullable=True), 'provision_updated_at': object_fields.DateTimeField(nullable=True), 'resource_class': object_fields.StringField(nullable=True), 'target_power_state': object_fields.StringField(nullable=True), 'target_provision_state': object_fields.StringField(nullable=True), 'traits': object_fields.ListOfStringsField(nullable=True), 'updated_at': object_fields.DateTimeField(nullable=True), 'uuid': object_fields.UUIDField() } def __init__(self, node, **kwargs): super(NodePayload, self).__init__(**kwargs) self.populate_schema(node=node) # NOTE(mgoddard): Populate traits with a list of trait names, rather # than the TraitList object. if node.obj_attr_is_set('traits') and node.traits is not None: self.traits = node.traits.get_trait_names() else: self.traits = []
class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Add register() and unregister(), make the context parameter # to touch() optional. # Version 1.2: Add register_hardware_interfaces() and # unregister_all_hardware_interfaces() # Version 1.3: Add conductor_group field. VERSION = '1.3' dbapi = db_api.get_instance() fields = { 'id': object_fields.IntegerField(), 'drivers': object_fields.ListOfStringsField(nullable=True), 'hostname': object_fields.StringField(), 'conductor_group': object_fields.StringField(), } @classmethod def list(cls, context, limit=None, marker=None, sort_key=None, sort_dir=None): """Return a list of Conductor objects. :param cls: the :class:`Conductor` :param context: Security context. :param limit: maximum number of resources to return in a single result. :param marker: pagination marker for large data sets. :param sort_key: column to sort results by. :param sort_dir: direction to sort. "asc" or "desc". :returns: a list of :class:`Conductor` object. """ db_conductors = cls.dbapi.get_conductor_list(limit=limit, marker=marker, sort_key=sort_key, sort_dir=sort_dir) return cls._from_db_object_list(context, db_conductors) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get_by_hostname(cls, context, hostname, online=True): """Get a Conductor record by its hostname. :param cls: the :class:`Conductor` :param context: Security context :param hostname: the hostname on which a Conductor is running :param online: Specify the expected ``online`` field value for the conductor to be retrieved. The ``online`` field is ignored if this value is set to None. :returns: a :class:`Conductor` object. """ db_obj = cls.dbapi.get_conductor(hostname, online=online) conductor = cls._from_db_object(context, cls(), db_obj) return conductor def save(self, context): """Save is not supported by Conductor objects.""" raise NotImplementedError( _('Cannot update a conductor record directly.')) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def refresh(self, context=None): """Loads and applies updates for this Conductor. Loads a :class:`Conductor` with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded chassis column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Conductor(context) """ current = self.get_by_hostname(self._context, hostname=self.hostname) self.obj_refresh(current) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def touch(self, context=None): """Touch this conductor's DB record, marking it as up-to-date.""" self.dbapi.touch_conductor(self.hostname) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable @classmethod def register(cls, context, hostname, drivers, conductor_group, update_existing=False): """Register an active conductor with the cluster. :param cls: the :class:`Conductor` :param context: Security context :param hostname: the hostname on which the conductor will run :param drivers: the list of drivers enabled in the conductor :param conductor_group: conductor group to join, used for node:conductor affinity. :param update_existing: When false, registration will raise an exception when a conflicting online record is found. When true, will overwrite the existing record. Default: False. :raises: ConductorAlreadyRegistered :returns: a :class:`Conductor` object. """ utils.validate_conductor_group(conductor_group) db_cond = cls.dbapi.register_conductor( { 'hostname': hostname, 'drivers': drivers, 'conductor_group': conductor_group.lower(), 'version': cls.get_target_version() }, update_existing=update_existing) return cls._from_db_object(context, cls(), db_cond) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def unregister(self, context=None): """Remove this conductor from the service registry.""" self.unregister_all_hardware_interfaces() self.dbapi.unregister_conductor(self.hostname) def register_hardware_interfaces(self, interfaces): """Register hardware interfaces with the conductor. :param interfaces: List of interface to register, each entry should be a dictionary conaining "hardware_type", "interface_type", "interface_name" and "default", e.g. {'hardware_type': 'hardware-type', 'interface_type': 'deploy', 'interface_name': 'direct', 'default': True} """ self.dbapi.register_conductor_hardware_interfaces(self.id, interfaces) def unregister_all_hardware_interfaces(self): """Unregister all hardware interfaces for this conductor.""" self.dbapi.unregister_conductor_hardware_interfaces(self.id)
class Conductor(base.IronicObject, object_base.VersionedObjectDictCompat): # Version 1.0: Initial version # Version 1.1: Add register() and unregister(), make the context parameter # to touch() optional. # Version 1.2: Add register_hardware_interfaces() and # unregister_all_hardware_interfaces() VERSION = '1.2' dbapi = db_api.get_instance() fields = { 'id': object_fields.IntegerField(), 'drivers': object_fields.ListOfStringsField(nullable=True), 'hostname': object_fields.StringField(), } # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get_by_hostname(cls, context, hostname): """Get a Conductor record by its hostname. :param cls: the :class:`Conductor` :param context: Security context :param hostname: the hostname on which a Conductor is running :returns: a :class:`Conductor` object. """ db_obj = cls.dbapi.get_conductor(hostname) conductor = cls._from_db_object(context, cls(), db_obj) return conductor def save(self, context): """Save is not supported by Conductor objects.""" raise NotImplementedError( _('Cannot update a conductor record directly.')) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def refresh(self, context=None): """Loads and applies updates for this Conductor. Loads a :class:`Conductor` with the same uuid from the database and checks for updated attributes. Updates are applied from the loaded chassis column by column, if there are any updates. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: Conductor(context) """ current = self.get_by_hostname(self._context, hostname=self.hostname) self.obj_refresh(current) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def touch(self, context=None): """Touch this conductor's DB record, marking it as up-to-date.""" self.dbapi.touch_conductor(self.hostname) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable @classmethod def register(cls, context, hostname, drivers, update_existing=False): """Register an active conductor with the cluster. :param cls: the :class:`Conductor` :param context: Security context :param hostname: the hostname on which the conductor will run :param drivers: the list of drivers enabled in the conductor :param update_existing: When false, registration will raise an exception when a conflicting online record is found. When true, will overwrite the existing record. Default: False. :raises: ConductorAlreadyRegistered :returns: a :class:`Conductor` object. """ db_cond = cls.dbapi.register_conductor( {'hostname': hostname, 'drivers': drivers, 'version': cls.get_target_version()}, update_existing=update_existing) return cls._from_db_object(context, cls(), db_cond) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def unregister(self, context=None): """Remove this conductor from the service registry.""" self.unregister_all_hardware_interfaces() self.dbapi.unregister_conductor(self.hostname) def register_hardware_interfaces(self, hardware_type, interface_type, interfaces, default_interface): """Register hardware interfaces with the conductor. :param hardware_type: Name of hardware type for the interfaces. :param interface_type: Type of interfaces, e.g. 'deploy' or 'boot'. :param interfaces: List of interface names to register. :param default_interface: String, the default interface for this hardware type and interface type. """ self.dbapi.register_conductor_hardware_interfaces(self.id, hardware_type, interface_type, interfaces, default_interface) def unregister_all_hardware_interfaces(self): """Unregister all hardware interfaces for this conductor.""" self.dbapi.unregister_conductor_hardware_interfaces(self.id)
class BIOSSetting(base.IronicObject): # Version 1.0: Initial version # Version 1.1: Added registry VERSION = '1.1' dbapi = dbapi.get_instance() registry_fields = ('attribute_type', 'allowable_values', 'lower_bound', 'max_length', 'min_length', 'read_only', 'reset_required', 'unique', 'upper_bound') fields = { 'node_id': object_fields.StringField(nullable=False), 'name': object_fields.StringField(nullable=False), 'value': object_fields.StringField(nullable=True), 'attribute_type': object_fields.StringField(nullable=True), 'allowable_values': object_fields.ListOfStringsField(nullable=True), 'lower_bound': object_fields.IntegerField(nullable=True), 'max_length': object_fields.IntegerField(nullable=True), 'min_length': object_fields.IntegerField(nullable=True), 'read_only': object_fields.BooleanField(nullable=True), 'reset_required': object_fields.BooleanField(nullable=True), 'unique': object_fields.BooleanField(nullable=True), 'upper_bound': object_fields.IntegerField(nullable=True) } # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def create(self, context=None): """Create a BIOS Setting record in DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BIOSSetting(context) :raises: NodeNotFound if the node id is not found. :raises: BIOSSettingAlreadyExists if the setting record already exists. """ values = self.do_version_changes_for_db() settings = {'name': values['name'], 'value': values['value']} for r in self.registry_fields: settings[r] = values.get(r) db_bios_setting = self.dbapi.create_bios_setting_list( values['node_id'], [settings], values['version']) self._from_db_object(self._context, self, db_bios_setting[0]) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable def save(self, context=None): """Save BIOS Setting update in DB. :param context: Security context. NOTE: This should only be used internally by the indirection_api. Unfortunately, RPC requires context as the first argument, even though we don't use it. A context should be set when instantiating the object, e.g.: BIOSSetting(context) :raises: NodeNotFound if the node id is not found. :raises: BIOSSettingNotFound if the bios setting name is not found. """ values = self.do_version_changes_for_db() settings = {'name': values['name'], 'value': values['value']} for r in self.registry_fields: settings[r] = values.get(r) updated_bios_setting = self.dbapi.update_bios_setting_list( values['node_id'], [settings], values['version']) self._from_db_object(self._context, self, updated_bios_setting[0]) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def get(cls, context, node_id, name): """Get a BIOS Setting based on its node_id and name. :param context: Security context. :param node_id: The node id. :param name: BIOS setting name to be retrieved. :raises: NodeNotFound if the node id is not found. :raises: BIOSSettingNotFound if the bios setting name is not found. :returns: A :class:'BIOSSetting' object. """ db_bios_setting = cls.dbapi.get_bios_setting(node_id, name) return cls._from_db_object(context, cls(), db_bios_setting) # NOTE(xek): We don't want to enable RPC on this call just yet. Remotable # methods can be used in the future to replace current explicit RPC calls. # Implications of calling new remote procedures should be thought through. # @object_base.remotable_classmethod @classmethod def delete(cls, context, node_id, name): """Delete a BIOS Setting based on its node_id and name. :param context: Security context. :param node_id: The node id. :param name: BIOS setting name to be deleted. :raises: NodeNotFound if the node id is not found. :raises: BIOSSettingNotFound if the bios setting name is not found. """ cls.dbapi.delete_bios_setting_list(node_id, [name]) def _convert_to_version(self, target_version, remove_unavailable_fields=True): """Convert to the target version. Convert the object to the target version. The target version may be the same, older, or newer than the version of the object. This is used for DB interactions as well as for serialization/deserialization. Version 1.74: remove registry field for unsupported versions if remove_unavailable_fields is True. :param target_version: the desired version of the object :param remove_unavailable_fields: True to remove fields that are unavailable in the target version; set this to True when (de)serializing. False to set the unavailable fields to appropriate values; set this to False for DB interactions. """ target_version = versionutils.convert_version_to_tuple(target_version) for field in self.get_registry_fields(): field_is_set = self.obj_attr_is_set(field) if target_version >= (1, 74): # target version supports the major/minor specified if not field_is_set: # set it to its default value if it is not set setattr(self, field, None) elif field_is_set: # target version does not support the field, and it is set if remove_unavailable_fields: # (De)serialising: remove unavailable fields delattr(self, field) elif self.registry: setattr(self, field, None)