Example #1
0
class ActionPlanPayload(TerseActionPlanPayload):
    SCHEMA = {
        'uuid': ('action_plan', 'uuid'),
        'state': ('action_plan', 'state'),
        'global_efficacy': ('action_plan', 'global_efficacy'),
        'created_at': ('action_plan', 'created_at'),
        'updated_at': ('action_plan', 'updated_at'),
        'deleted_at': ('action_plan', 'deleted_at'),
    }

    # Version 1.0: Initial version
    # Vesrsion 1.1: changed global_efficacy type
    VERSION = '1.1'

    fields = {
        'audit': wfields.ObjectField('TerseAuditPayload'),
        'strategy': wfields.ObjectField('StrategyPayload'),
    }

    def __init__(self, action_plan, audit, strategy, **kwargs):
        if not kwargs.get('audit_uuid'):
            kwargs['audit_uuid'] = audit.uuid

        if strategy and not kwargs.get('strategy_uuid'):
            kwargs['strategy_uuid'] = strategy.uuid

        super(ActionPlanPayload, self).__init__(action_plan,
                                                audit=audit,
                                                strategy=strategy,
                                                **kwargs)
Example #2
0
class AuditPayload(TerseAuditPayload):
    SCHEMA = {
        'uuid': ('audit', 'uuid'),
        'audit_type': ('audit', 'audit_type'),
        'state': ('audit', 'state'),
        'parameters': ('audit', 'parameters'),
        'interval': ('audit', 'interval'),
        'scope': ('audit', 'scope'),
        'created_at': ('audit', 'created_at'),
        'updated_at': ('audit', 'updated_at'),
        'deleted_at': ('audit', 'deleted_at'),
    }

    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'goal': wfields.ObjectField('GoalPayload'),
        'strategy': wfields.ObjectField('StrategyPayload', nullable=True),
    }

    def __init__(self, audit, goal, strategy=None, **kwargs):
        if not kwargs.get('goal_uuid'):
            kwargs['goal_uuid'] = goal.uuid

        if strategy and not kwargs.get('strategy_uuid'):
            kwargs['strategy_uuid'] = strategy.uuid

        super(AuditPayload, self).__init__(audit=audit,
                                           goal=goal,
                                           strategy=strategy,
                                           **kwargs)
Example #3
0
class NotificationBase(NotificationObject):
    """Base class for versioned notifications.

    Every subclass shall define a 'payload' field.
    """

    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'priority': wfields.NotificationPriorityField(),
        'event_type': wfields.ObjectField('EventType'),
        'publisher': wfields.ObjectField('NotificationPublisher'),
    }

    def save(self, context):
        raise exception.UnsupportedError()

    def obj_load_attr(self, attrname):
        raise exception.UnsupportedError()

    def _should_notify(self):
        """Determine whether the notification should be sent.

        A notification is sent when the level of the notification is
        greater than or equal to the level specified in the
        configuration, in the increasing order of DEBUG, INFO, WARNING,
        ERROR, CRITICAL.
        :return: True if notification should be sent, False otherwise.
        """
        if not CONF.notification_level:
            return False
        return (NOTIFY_LEVELS[self.priority] >=
                NOTIFY_LEVELS[CONF.notification_level])

    def _emit(self, context, event_type, publisher_id, payload):
        notifier = rpc.get_notifier(publisher_id)
        notify = getattr(notifier, self.priority)
        LOG.debug("Emitting notification `%s`", event_type)
        notify(context, event_type=event_type, payload=payload)

    def emit(self, context):
        """Send the notification."""
        if not self._should_notify():
            return
        if not self.payload.populated:
            raise exception.NotificationPayloadError(
                class_name=self.__class__.__name__)
        # Note(gibi): notification payload will be a newly populated object
        # therefore every field of it will look changed so this does not carry
        # any extra information so we drop this from the payload.
        self.payload.obj_reset_changes(recursive=False)

        self._emit(
            context,
            event_type=self.event_type.to_notification_event_type_field(),
            publisher_id='%s:%s' %
            (self.publisher.binary, self.publisher.host),
            payload=self.payload.obj_to_primitive())
Example #4
0
class ActionDeleteNotification(notificationbase.NotificationBase):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'payload': wfields.ObjectField('ActionDeletePayload')
    }
Example #5
0
class ActionPayload(notificationbase.NotificationPayloadBase):
    SCHEMA = {
        'uuid': ('action', 'uuid'),

        'action_type': ('action', 'action_type'),
        'input_parameters': ('action', 'input_parameters'),
        'state': ('action', 'state'),
        'parents': ('action', 'parents'),

        'created_at': ('action', 'created_at'),
        'updated_at': ('action', 'updated_at'),
        'deleted_at': ('action', 'deleted_at'),
    }

    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'uuid': wfields.UUIDField(),
        'action_type': wfields.StringField(nullable=False),
        'input_parameters': wfields.DictField(nullable=False, default={}),
        'state': wfields.StringField(nullable=False),
        'parents': wfields.ListOfUUIDsField(nullable=False, default=[]),
        'action_plan_uuid': wfields.UUIDField(),
        'action_plan': wfields.ObjectField('TerseActionPlanPayload'),

        'created_at': wfields.DateTimeField(nullable=True),
        'updated_at': wfields.DateTimeField(nullable=True),
        'deleted_at': wfields.DateTimeField(nullable=True),
    }

    def __init__(self, action, **kwargs):
        super(ActionPayload, self).__init__(**kwargs)
        self.populate_schema(action=action)
Example #6
0
class ActionUpdatePayload(ActionPayload):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'state_update': wfields.ObjectField('ActionStateUpdatePayload'),
    }

    def __init__(self, action, state_update, action_plan):
        super(ActionUpdatePayload, self).__init__(action=action,
                                                  state_update=state_update,
                                                  action_plan=action_plan)
Example #7
0
class ServiceUpdatePayload(ServicePayload):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'status_update': wfields.ObjectField('ServiceStatusUpdatePayload'),
    }

    def __init__(self, failed_service, status_update):
        super(ServiceUpdatePayload,
              self).__init__(failed_service=failed_service,
                             status_update=status_update)
Example #8
0
class ActionCancelPayload(ActionPayload):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
    }

    def __init__(self, action, action_plan, **kwargs):
        super(ActionCancelPayload, self).__init__(action=action,
                                                  action_plan=action_plan,
                                                  **kwargs)
Example #9
0
class ActionPlanCancelPayload(ActionPlanPayload):
    # Version 1.0: Initial version
    # Version 1.1: Changed global_efficacy_type
    VERSION = '1.1'
    fields = {
        'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
    }

    def __init__(self, action_plan, audit, strategy, **kwargs):
        super(ActionPlanCancelPayload, self).__init__(action_plan=action_plan,
                                                      audit=audit,
                                                      strategy=strategy,
                                                      **kwargs)
Example #10
0
class AuditActionPayload(AuditPayload):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
    }

    def __init__(self, audit, goal, strategy, **kwargs):
        super(AuditActionPayload, self).__init__(audit=audit,
                                                 goal=goal,
                                                 goal_uuid=goal.uuid,
                                                 strategy=strategy,
                                                 **kwargs)
Example #11
0
class AuditUpdatePayload(AuditPayload):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {
        'state_update': wfields.ObjectField('AuditStateUpdatePayload'),
    }

    def __init__(self, audit, state_update, goal, strategy):
        super(AuditUpdatePayload, self).__init__(audit=audit,
                                                 state_update=state_update,
                                                 goal=goal,
                                                 goal_uuid=goal.uuid,
                                                 strategy=strategy)
Example #12
0
class ActionPlanUpdatePayload(ActionPlanPayload):
    # Version 1.0: Initial version
    # Version 1.1: Changed global_efficacy_type
    VERSION = '1.1'
    fields = {
        'state_update': wfields.ObjectField('ActionPlanStateUpdatePayload'),
    }

    def __init__(self, action_plan, state_update, audit, strategy):
        super(ActionPlanUpdatePayload,
              self).__init__(action_plan=action_plan,
                             state_update=state_update,
                             audit=audit,
                             strategy=strategy)
Example #13
0
class AuditActionPayload(AuditPayload):
    # Version 1.0: Initial version
    # Version 1.1: Added 'auto_trigger' field,
    #              Added 'next_run_time' field
    VERSION = '1.1'
    fields = {
        'fault': wfields.ObjectField('ExceptionPayload', nullable=True),
    }

    def __init__(self, audit, goal, strategy, **kwargs):
        super(AuditActionPayload, self).__init__(audit=audit,
                                                 goal=goal,
                                                 goal_uuid=goal.uuid,
                                                 strategy=strategy,
                                                 **kwargs)
Example #14
0
class ActionPlanPayload(notificationbase.NotificationPayloadBase):
    SCHEMA = {
        'uuid': ('action_plan', 'uuid'),

        'state': ('action_plan', 'state'),
        'global_efficacy': ('action_plan', 'global_efficacy'),
        'audit_uuid': ('audit', 'uuid'),
        'strategy_uuid': ('strategy', 'uuid'),

        'created_at': ('action_plan', 'created_at'),
        'updated_at': ('action_plan', 'updated_at'),
        'deleted_at': ('action_plan', 'deleted_at'),
    }

    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {
        'uuid': wfields.UUIDField(),
        'state': wfields.StringField(),
        'global_efficacy': wfields.FlexibleDictField(nullable=True),
        'audit_uuid': wfields.UUIDField(),
        'strategy_uuid': wfields.UUIDField(),
        'audit': wfields.ObjectField('TerseAuditPayload'),
        'strategy': wfields.ObjectField('StrategyPayload'),

        'created_at': wfields.DateTimeField(nullable=True),
        'updated_at': wfields.DateTimeField(nullable=True),
        'deleted_at': wfields.DateTimeField(nullable=True),
    }

    def __init__(self, action_plan, audit, strategy, **kwargs):
        super(ActionPlanPayload, self).__init__(
            audit=audit, strategy=strategy, **kwargs)
        self.populate_schema(
            action_plan=action_plan, audit=audit, strategy=strategy)
Example #15
0
class AuditUpdatePayload(AuditPayload):
    # Version 1.0: Initial version
    # Version 1.1: Added 'auto_trigger' field,
    #              Added 'next_run_time' field
    VERSION = '1.1'
    fields = {
        'state_update': wfields.ObjectField('AuditStateUpdatePayload'),
    }

    def __init__(self, audit, state_update, goal, strategy):
        super(AuditUpdatePayload, self).__init__(audit=audit,
                                                 state_update=state_update,
                                                 goal=goal,
                                                 goal_uuid=goal.uuid,
                                                 strategy=strategy)
Example #16
0
class ExceptionNotification(notificationbase.NotificationBase):
    # Version 1.0: Initial version
    VERSION = '1.0'
    fields = {'payload': wfields.ObjectField('ExceptionPayload')}
Example #17
0
class ServiceUpdateNotification(notificationbase.NotificationBase):
    # Version 1.0: Initial version
    VERSION = '1.0'

    fields = {'payload': wfields.ObjectField('ServiceUpdatePayload')}
Example #18
0
class Audit(base.WatcherPersistentObject, base.WatcherObject,
            base.WatcherObjectDictCompat):

    # Version 1.0: Initial version
    # Version 1.1: Added 'goal' and 'strategy' object field
    # Version 1.2  Added 'auto_trigger' boolean field
    VERSION = '1.2'

    dbapi = db_api.get_instance()

    fields = {
        'id': wfields.IntegerField(),
        'uuid': wfields.UUIDField(),
        'audit_type': wfields.StringField(),
        'state': wfields.StringField(),
        'parameters': wfields.FlexibleDictField(nullable=True),
        'interval': wfields.IntegerField(nullable=True),
        'scope': wfields.FlexibleListOfDictField(nullable=True),
        'goal_id': wfields.IntegerField(),
        'strategy_id': wfields.IntegerField(nullable=True),
        'auto_trigger': wfields.BooleanField(),

        'goal': wfields.ObjectField('Goal', nullable=True),
        'strategy': wfields.ObjectField('Strategy', nullable=True),
    }

    object_fields = {
        'goal': (objects.Goal, 'goal_id'),
        'strategy': (objects.Strategy, 'strategy_id'),
    }

    # Proxified field so we can keep the previous value after an update
    _state = None
    _old_state = None

    # NOTE(v-francoise): The way oslo.versionedobjects works is by using a
    # __new__ that will automatically create the attributes referenced in
    # fields. These attributes are properties that raise an exception if no
    # value has been assigned, which means that they store the actual field
    # value in an "_obj_%(field)s" attribute. So because we want to proxify a
    # value that is already proxified, we have to do what you see below.
    @property
    def _obj_state(self):
        return self._state

    @property
    def _obj_old_state(self):
        return self._old_state

    @property
    def old_state(self):
        return self._old_state

    @_obj_old_state.setter
    def _obj_old_state(self, value):
        self._old_state = value

    @_obj_state.setter
    def _obj_state(self, value):
        if self._old_state is None and self._state is None:
            self._state = value
        else:
            self._old_state, self._state = self._state, value

    @base.remotable_classmethod
    def get(cls, context, audit_id, eager=False):
        """Find a audit based on its id or uuid and return a Audit object.

        :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.: Audit(context)
        :param audit_id: the id *or* uuid of a audit.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Audit` object.
        """
        if utils.is_int_like(audit_id):
            return cls.get_by_id(context, audit_id, eager=eager)
        elif utils.is_uuid_like(audit_id):
            return cls.get_by_uuid(context, audit_id, eager=eager)
        else:
            raise exception.InvalidIdentity(identity=audit_id)

    @base.remotable_classmethod
    def get_by_id(cls, context, audit_id, eager=False):
        """Find a audit based on its integer id and return a Audit object.

        :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.: Audit(context)
        :param audit_id: the id of a audit.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Audit` object.
        """
        db_audit = cls.dbapi.get_audit_by_id(context, audit_id, eager=eager)
        audit = cls._from_db_object(cls(context), db_audit, eager=eager)
        return audit

    @base.remotable_classmethod
    def get_by_uuid(cls, context, uuid, eager=False):
        """Find a audit based on uuid and return a :class:`Audit` object.

        :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.: Audit(context)
        :param uuid: the uuid of a audit.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Audit` object.
        """

        db_audit = cls.dbapi.get_audit_by_uuid(context, uuid, eager=eager)
        audit = cls._from_db_object(cls(context), db_audit, eager=eager)
        return audit

    @base.remotable_classmethod
    def list(cls, context, limit=None, marker=None, filters=None,
             sort_key=None, sort_dir=None, eager=False):
        """Return a list of Audit objects.

        :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.: Audit(context)
        :param limit: maximum number of resources to return in a single result.
        :param marker: pagination marker for large data sets.
        :param filters: Filters to apply. Defaults to None.
        :param sort_key: column to sort results by.
        :param sort_dir: direction to sort. "asc" or "desc".
        :param eager: Load object fields if True (Default: False)
        :returns: a list of :class:`Audit` object.

        """
        db_audits = cls.dbapi.get_audit_list(context,
                                             limit=limit,
                                             marker=marker,
                                             filters=filters,
                                             sort_key=sort_key,
                                             sort_dir=sort_dir,
                                             eager=eager)
        return [cls._from_db_object(cls(context), obj, eager=eager)
                for obj in db_audits]

    @base.remotable
    def create(self):
        """Create an :class:`Audit` record in the DB.

        :returns: An :class:`Audit` object.
        """
        values = self.obj_get_changes()
        db_audit = self.dbapi.create_audit(values)
        # Note(v-francoise): Always load eagerly upon creation so we can send
        # notifications containing information about the related relationships
        self._from_db_object(self, db_audit, eager=True)

        def _notify():
            notifications.audit.send_create(self._context, self)

        _notify()

    @base.remotable
    def destroy(self):
        """Delete the Audit from the DB."""
        self.dbapi.destroy_audit(self.uuid)
        self.obj_reset_changes()

    @base.remotable
    def save(self):
        """Save updates to this Audit.

        Updates will be made column by column based on the result
        of self.what_changed().
        """
        updates = self.obj_get_changes()
        db_obj = self.dbapi.update_audit(self.uuid, updates)
        obj = self._from_db_object(
            self.__class__(self._context), db_obj, eager=False)
        self.obj_refresh(obj)

        def _notify():
            notifications.audit.send_update(
                self._context, self, old_state=self.old_state)

        _notify()

        self.obj_reset_changes()

    @base.remotable
    def refresh(self, eager=False):
        """Loads updates for this Audit.

        Loads a audit with the same uuid from the database and
        checks for updated attributes. Updates are applied from
        the loaded audit column by column, if there are any updates.
        :param eager: Load object fields if True (Default: False)
        """
        current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager)
        self.obj_refresh(current)

    @base.remotable
    def soft_delete(self):
        """Soft Delete the Audit from the DB."""
        self.state = State.DELETED
        self.save()
        db_obj = self.dbapi.soft_delete_audit(self.uuid)
        obj = self._from_db_object(
            self.__class__(self._context), db_obj, eager=False)
        self.obj_refresh(obj)

        def _notify():
            notifications.audit.send_delete(self._context, self)

        _notify()
Example #19
0
class Strategy(base.WatcherPersistentObject, base.WatcherObject,
               base.WatcherObjectDictCompat):

    # Version 1.0: Initial version
    # Version 1.1: Added Goal object field
    VERSION = '1.1'

    dbapi = db_api.get_instance()

    fields = {
        'id': wfields.IntegerField(),
        'uuid': wfields.UUIDField(),
        'name': wfields.StringField(),
        'display_name': wfields.StringField(),
        'goal_id': wfields.IntegerField(),
        'parameters_spec': wfields.FlexibleDictField(nullable=True),
        'goal': wfields.ObjectField('Goal', nullable=True),
    }

    object_fields = {'goal': (objects.Goal, 'goal_id')}

    @base.remotable_classmethod
    def get(cls, context, strategy_id, eager=False):
        """Find a strategy based on its id or uuid

        :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.: Strategy(context)
        :param strategy_id: the id *or* uuid of a strategy.
        :param eager: Load object fields if True (Default: False)
        :returns: A :class:`Strategy` object.
        """
        if utils.is_int_like(strategy_id):
            return cls.get_by_id(context, strategy_id, eager=eager)
        elif utils.is_uuid_like(strategy_id):
            return cls.get_by_uuid(context, strategy_id, eager=eager)
        else:
            raise exception.InvalidIdentity(identity=strategy_id)

    @base.remotable_classmethod
    def get_by_id(cls, context, strategy_id, eager=False):
        """Find a strategy based on its integer id

        :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.: Strategy(context)
        :param strategy_id: the id of a strategy.
        :param eager: Load object fields if True (Default: False)
        :returns: A :class:`Strategy` object.
        """
        db_strategy = cls.dbapi.get_strategy_by_id(context,
                                                   strategy_id,
                                                   eager=eager)
        strategy = cls._from_db_object(cls(context), db_strategy, eager=eager)
        return strategy

    @base.remotable_classmethod
    def get_by_uuid(cls, context, uuid, eager=False):
        """Find a strategy based on uuid

        :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.: Strategy(context)
        :param uuid: the uuid of a strategy.
        :param eager: Load object fields if True (Default: False)
        :returns: A :class:`Strategy` object.
        """

        db_strategy = cls.dbapi.get_strategy_by_uuid(context,
                                                     uuid,
                                                     eager=eager)
        strategy = cls._from_db_object(cls(context), db_strategy, eager=eager)
        return strategy

    @base.remotable_classmethod
    def get_by_name(cls, context, name, eager=False):
        """Find a strategy based on name

        :param context: Security context
        :param name: the name of a strategy.
        :param eager: Load object fields if True (Default: False)
        :returns: A :class:`Strategy` object.
        """

        db_strategy = cls.dbapi.get_strategy_by_name(context,
                                                     name,
                                                     eager=eager)
        strategy = cls._from_db_object(cls(context), db_strategy, eager=eager)
        return strategy

    @base.remotable_classmethod
    def list(cls,
             context,
             limit=None,
             marker=None,
             filters=None,
             sort_key=None,
             sort_dir=None,
             eager=False):
        """Return a list of :class:`Strategy` objects.

        :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.: Strategy(context)
        :param limit: maximum number of resources to return in a single result.
        :param marker: pagination marker for large data sets.
        :param filters: dict mapping the filter key to a value.
        :param sort_key: column to sort results by.
        :param sort_dir: direction to sort. "asc" or "desc`".
        :param eager: Load object fields if True (Default: False)
        :returns: a list of :class:`Strategy` object.
        """
        db_strategies = cls.dbapi.get_strategy_list(context,
                                                    filters=filters,
                                                    limit=limit,
                                                    marker=marker,
                                                    sort_key=sort_key,
                                                    sort_dir=sort_dir)

        return [
            cls._from_db_object(cls(context), obj, eager=eager)
            for obj in db_strategies
        ]

    @base.remotable
    def create(self, context=None):
        """Create a :class:`Strategy` 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.: Strategy(context)
        :returns: A :class:`Strategy` object.
        """

        values = self.obj_get_changes()
        db_strategy = self.dbapi.create_strategy(values)
        # Note(v-francoise): Always load eagerly upon creation so we can send
        # notifications containing information about the related relationships
        self._from_db_object(self, db_strategy, eager=True)

    def destroy(self, context=None):
        """Delete the :class:`Strategy` 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.: Strategy(context)
        """
        self.dbapi.destroy_strategy(self.id)
        self.obj_reset_changes()

    @base.remotable
    def save(self, context=None):
        """Save updates to this :class:`Strategy`.

        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.: Strategy(context)
        """
        updates = self.obj_get_changes()
        self.dbapi.update_strategy(self.id, updates)

        self.obj_reset_changes()

    @base.remotable
    def refresh(self, context=None, eager=False):
        """Loads updates for this :class:`Strategy`.

        Loads a strategy with the same uuid from the database and
        checks for updated attributes. Updates are applied from
        the loaded strategy 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.: Strategy(context)
        :param eager: Load object fields if True (Default: False)
        """
        current = self.__class__.get_by_id(self._context,
                                           strategy_id=self.id,
                                           eager=eager)
        for field in self.fields:
            if (hasattr(self, base.get_attrname(field))
                    and self[field] != current[field]):
                self[field] = current[field]

    @base.remotable
    def soft_delete(self, context=None):
        """Soft Delete the :class:`Strategy` 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.: Strategy(context)
        """
        self.dbapi.soft_delete_strategy(self.id)
Example #20
0
class Action(base.WatcherPersistentObject, base.WatcherObject,
             base.WatcherObjectDictCompat):

    # Version 1.0: Initial version
    # Version 1.1: Added 'action_plan' object field
    # Version 2.0: Removed 'next' object field, Added 'parents' object field
    VERSION = '2.0'

    dbapi = db_api.get_instance()

    fields = {
        'id': wfields.IntegerField(),
        'uuid': wfields.UUIDField(),
        'action_plan_id': wfields.IntegerField(),
        'action_type': wfields.StringField(nullable=True),
        'input_parameters': wfields.DictField(nullable=True),
        'state': wfields.StringField(nullable=True),
        'parents': wfields.ListOfStringsField(nullable=True),

        'action_plan': wfields.ObjectField('ActionPlan', nullable=True),
    }
    object_fields = {
        'action_plan': (objects.ActionPlan, 'action_plan_id'),
    }

    @base.remotable_classmethod
    def get(cls, context, action_id, eager=False):
        """Find a action based on its id or uuid and return a Action object.

        :param action_id: the id *or* uuid of a action.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Action` object.
        """
        if utils.is_int_like(action_id):
            return cls.get_by_id(context, action_id, eager=eager)
        elif utils.is_uuid_like(action_id):
            return cls.get_by_uuid(context, action_id, eager=eager)
        else:
            raise exception.InvalidIdentity(identity=action_id)

    @base.remotable_classmethod
    def get_by_id(cls, context, action_id, eager=False):
        """Find a action based on its integer id and return a Action object.

        :param action_id: the id of a action.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Action` object.
        """
        db_action = cls.dbapi.get_action_by_id(context, action_id, eager=eager)
        action = cls._from_db_object(cls(context), db_action, eager=eager)
        return action

    @base.remotable_classmethod
    def get_by_uuid(cls, context, uuid, eager=False):
        """Find a action based on uuid and return a :class:`Action` object.

        :param uuid: the uuid of a action.
        :param context: Security context
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Action` object.
        """
        db_action = cls.dbapi.get_action_by_uuid(context, uuid, eager=eager)
        action = cls._from_db_object(cls(context), db_action, eager=eager)
        return action

    @base.remotable_classmethod
    def list(cls, context, limit=None, marker=None, filters=None,
             sort_key=None, sort_dir=None, eager=False):
        """Return a list of Action objects.

        :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 filters: Filters to apply. Defaults to None.
        :param sort_key: column to sort results by.
        :param sort_dir: direction to sort. "asc" or "desc".
        :param eager: Load object fields if True (Default: False)
        :returns: a list of :class:`Action` object.
        """
        db_actions = cls.dbapi.get_action_list(context,
                                               limit=limit,
                                               marker=marker,
                                               filters=filters,
                                               sort_key=sort_key,
                                               sort_dir=sort_dir,
                                               eager=eager)

        return [cls._from_db_object(cls(context), obj, eager=eager)
                for obj in db_actions]

    @base.remotable
    def create(self):
        """Create an :class:`Action` record in the DB.

        :returns: An :class:`Action` object.
        """
        values = self.obj_get_changes()
        db_action = self.dbapi.create_action(values)
        # Note(v-francoise): Always load eagerly upon creation so we can send
        # notifications containing information about the related relationships
        self._from_db_object(self, db_action, eager=True)

        notifications.action.send_create(self.obj_context, self)

    def destroy(self):
        """Delete the Action from the DB"""
        self.dbapi.destroy_action(self.uuid)
        self.obj_reset_changes()

    @base.remotable
    def save(self):
        """Save updates to this Action.

        Updates will be made column by column based on the result
        of self.what_changed().
        """
        updates = self.obj_get_changes()
        db_obj = self.dbapi.update_action(self.uuid, updates)
        obj = self._from_db_object(self, db_obj, eager=False)
        self.obj_refresh(obj)
        notifications.action.send_update(self.obj_context, self)
        self.obj_reset_changes()

    @base.remotable
    def refresh(self, eager=False):
        """Loads updates for this Action.

        Loads a action with the same uuid from the database and
        checks for updated attributes. Updates are applied from
        the loaded action column by column, if there are any updates.
        :param eager: Load object fields if True (Default: False)
        """
        current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager)
        self.obj_refresh(current)

    @base.remotable
    def soft_delete(self):
        """Soft Delete the Audit from the DB"""
        self.state = State.DELETED
        self.save()
        db_obj = self.dbapi.soft_delete_action(self.uuid)
        obj = self._from_db_object(
            self.__class__(self._context), db_obj, eager=False)
        self.obj_refresh(obj)

        notifications.action.send_delete(self.obj_context, self)
Example #21
0
 class TestNotificationEmptySchema(notificationbase.NotificationBase):
     VERSION = '1.0'
     fields = {
         'payload': wfields.ObjectField(
             'TestNotificationPayloadEmptySchema')
     }
Example #22
0
class ActionPlan(base.WatcherPersistentObject, base.WatcherObject,
                 base.WatcherObjectDictCompat):

    # Version 1.0: Initial version
    # Version 1.1: Added 'audit' and 'strategy' object field
    # Version 1.2: audit_id is not nullable anymore
    # Version 2.0: Removed 'first_action_id' object field
    VERSION = '2.0'

    dbapi = db_api.get_instance()

    fields = {
        'id': wfields.IntegerField(),
        'uuid': wfields.UUIDField(),
        'audit_id': wfields.IntegerField(),
        'strategy_id': wfields.IntegerField(),
        'state': wfields.StringField(nullable=True),
        'global_efficacy': wfields.FlexibleDictField(nullable=True),
        'audit': wfields.ObjectField('Audit', nullable=True),
        'strategy': wfields.ObjectField('Strategy', nullable=True),
    }

    object_fields = {
        'audit': (objects.Audit, 'audit_id'),
        'strategy': (objects.Strategy, 'strategy_id'),
    }

    # Proxified field so we can keep the previous value after an update
    _state = None
    _old_state = None

    # NOTE(v-francoise): The way oslo.versionedobjects works is by using a
    # __new__ that will automatically create the attributes referenced in
    # fields. These attributes are properties that raise an exception if no
    # value has been assigned, which means that they store the actual field
    # value in an "_obj_%(field)s" attribute. So because we want to proxify a
    # value that is already proxified, we have to do what you see below.
    @property
    def _obj_state(self):
        return self._state

    @property
    def _obj_old_state(self):
        return self._old_state

    @property
    def old_state(self):
        return self._old_state

    @_obj_old_state.setter
    def _obj_old_state(self, value):
        self._old_state = value

    @_obj_state.setter
    def _obj_state(self, value):
        if self._old_state is None and self._state is None:
            self._state = value
        else:
            self._old_state, self._state = self._state, value

    @base.remotable_classmethod
    def get(cls, context, action_plan_id, eager=False):
        """Find a action_plan based on its id or uuid and return a Action object.

        :param action_plan_id: the id *or* uuid of a action_plan.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`Action` object.
        """
        if utils.is_int_like(action_plan_id):
            return cls.get_by_id(context, action_plan_id, eager=eager)
        elif utils.is_uuid_like(action_plan_id):
            return cls.get_by_uuid(context, action_plan_id, eager=eager)
        else:
            raise exception.InvalidIdentity(identity=action_plan_id)

    @base.remotable_classmethod
    def get_by_id(cls, context, action_plan_id, eager=False):
        """Find a action_plan based on its integer id and return a ActionPlan object.

        :param action_plan_id: the id of a action_plan.
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`ActionPlan` object.
        """
        db_action_plan = cls.dbapi.get_action_plan_by_id(context,
                                                         action_plan_id,
                                                         eager=eager)
        action_plan = cls._from_db_object(cls(context),
                                          db_action_plan,
                                          eager=eager)
        return action_plan

    @base.remotable_classmethod
    def get_by_uuid(cls, context, uuid, eager=False):
        """Find a action_plan based on uuid and return a :class:`ActionPlan` object.

        :param uuid: the uuid of a action_plan.
        :param context: Security context
        :param eager: Load object fields if True (Default: False)
        :returns: a :class:`ActionPlan` object.
        """
        db_action_plan = cls.dbapi.get_action_plan_by_uuid(context,
                                                           uuid,
                                                           eager=eager)
        action_plan = cls._from_db_object(cls(context),
                                          db_action_plan,
                                          eager=eager)
        return action_plan

    @base.remotable_classmethod
    def list(cls,
             context,
             limit=None,
             marker=None,
             filters=None,
             sort_key=None,
             sort_dir=None,
             eager=False):
        """Return a list of ActionPlan objects.

        :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 filters: Filters to apply. Defaults to None.
        :param sort_key: column to sort results by.
        :param sort_dir: direction to sort. "asc" or "desc".
        :param eager: Load object fields if True (Default: False)
        :returns: a list of :class:`ActionPlan` object.
        """
        db_action_plans = cls.dbapi.get_action_plan_list(context,
                                                         limit=limit,
                                                         marker=marker,
                                                         filters=filters,
                                                         sort_key=sort_key,
                                                         sort_dir=sort_dir,
                                                         eager=eager)

        return [
            cls._from_db_object(cls(context), obj, eager=eager)
            for obj in db_action_plans
        ]

    @base.remotable
    def create(self):
        """Create an :class:`ActionPlan` record in the DB.

        :returns: An :class:`ActionPlan` object.
        """
        values = self.obj_get_changes()
        db_action_plan = self.dbapi.create_action_plan(values)
        # Note(v-francoise): Always load eagerly upon creation so we can send
        # notifications containing information about the related relationships
        self._from_db_object(self, db_action_plan, eager=True)

        def _notify():
            notifications.action_plan.send_create(self._context, self)

        _notify()

    @base.remotable
    def destroy(self):
        """Delete the action plan from the DB"""
        related_efficacy_indicators = objects.EfficacyIndicator.list(
            context=self._context, filters={"action_plan_uuid": self.uuid})

        # Cascade soft_delete of related efficacy indicators
        for related_efficacy_indicator in related_efficacy_indicators:
            related_efficacy_indicator.destroy()

        self.dbapi.destroy_action_plan(self.uuid)
        self.obj_reset_changes()

    @base.remotable
    def save(self):
        """Save updates to this Action plan.

        Updates will be made column by column based on the result
        of self.what_changed().
        """
        updates = self.obj_get_changes()
        db_obj = self.dbapi.update_action_plan(self.uuid, updates)
        obj = self._from_db_object(self.__class__(self._context),
                                   db_obj,
                                   eager=False)
        self.obj_refresh(obj)

        def _notify():
            notifications.action_plan.send_update(self._context,
                                                  self,
                                                  old_state=self.old_state)

        _notify()

        self.obj_reset_changes()

    @base.remotable
    def refresh(self, eager=False):
        """Loads updates for this Action plan.

        Loads a action_plan with the same uuid from the database and
        checks for updated attributes. Updates are applied from
        the loaded action_plan column by column, if there are any updates.
        :param eager: Load object fields if True (Default: False)
        """
        current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager)
        self.obj_refresh(current)

    @base.remotable
    def soft_delete(self):
        """Soft Delete the Action plan from the DB"""
        related_actions = objects.Action.list(
            context=self._context, filters={"action_plan_uuid": self.uuid})

        # Cascade soft_delete of related actions
        for related_action in related_actions:
            related_action.soft_delete()

        related_efficacy_indicators = objects.EfficacyIndicator.list(
            context=self._context, filters={"action_plan_uuid": self.uuid})

        # Cascade soft_delete of related efficacy indicators
        for related_efficacy_indicator in related_efficacy_indicators:
            related_efficacy_indicator.soft_delete()

        self.state = State.DELETED
        self.save()
        db_obj = self.dbapi.soft_delete_action_plan(self.uuid)
        obj = self._from_db_object(self.__class__(self._context),
                                   db_obj,
                                   eager=False)
        self.obj_refresh(obj)

        def _notify():
            notifications.action_plan.send_delete(self._context, self)

        _notify()