Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
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 = []
Ejemplo n.º 5
0
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)
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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)