Coverage for watcher/objects/action.py: 100%
71 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-17 12:22 +0000
1# -*- encoding: utf-8 -*-
2# Copyright 2013 IBM Corp.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
17from watcher.common import exception
18from watcher.common import utils
19from watcher.db import api as db_api
20from watcher import notifications
21from watcher import objects
22from watcher.objects import base
23from watcher.objects import fields as wfields
26class State(object):
27 PENDING = 'PENDING'
28 ONGOING = 'ONGOING'
29 FAILED = 'FAILED'
30 SUCCEEDED = 'SUCCEEDED'
31 DELETED = 'DELETED'
32 CANCELLED = 'CANCELLED'
33 CANCELLING = 'CANCELLING'
36@base.WatcherObjectRegistry.register
37class Action(base.WatcherPersistentObject, base.WatcherObject,
38 base.WatcherObjectDictCompat):
40 # Version 1.0: Initial version
41 # Version 1.1: Added 'action_plan' object field
42 # Version 2.0: Removed 'next' object field, Added 'parents' object field
43 VERSION = '2.0'
45 dbapi = db_api.get_instance()
47 fields = {
48 'id': wfields.IntegerField(),
49 'uuid': wfields.UUIDField(),
50 'action_plan_id': wfields.IntegerField(),
51 'action_type': wfields.StringField(nullable=True),
52 'input_parameters': wfields.DictField(nullable=True),
53 'state': wfields.StringField(nullable=True),
54 'parents': wfields.ListOfStringsField(nullable=True),
56 'action_plan': wfields.ObjectField('ActionPlan', nullable=True),
57 }
58 object_fields = {
59 'action_plan': (objects.ActionPlan, 'action_plan_id'),
60 }
62 @base.remotable_classmethod
63 def get(cls, context, action_id, eager=False):
64 """Find a action based on its id or uuid and return a Action object.
66 :param action_id: the id *or* uuid of a action.
67 :param eager: Load object fields if True (Default: False)
68 :returns: a :class:`Action` object.
69 """
70 if utils.is_int_like(action_id):
71 return cls.get_by_id(context, action_id, eager=eager)
72 elif utils.is_uuid_like(action_id):
73 return cls.get_by_uuid(context, action_id, eager=eager)
74 else:
75 raise exception.InvalidIdentity(identity=action_id)
77 @base.remotable_classmethod
78 def get_by_id(cls, context, action_id, eager=False):
79 """Find a action based on its integer id and return a Action object.
81 :param action_id: the id of a action.
82 :param eager: Load object fields if True (Default: False)
83 :returns: a :class:`Action` object.
84 """
85 db_action = cls.dbapi.get_action_by_id(context, action_id, eager=eager)
86 action = cls._from_db_object(cls(context), db_action, eager=eager)
87 return action
89 @base.remotable_classmethod
90 def get_by_uuid(cls, context, uuid, eager=False):
91 """Find a action based on uuid and return a :class:`Action` object.
93 :param uuid: the uuid of a action.
94 :param context: Security context
95 :param eager: Load object fields if True (Default: False)
96 :returns: a :class:`Action` object.
97 """
98 db_action = cls.dbapi.get_action_by_uuid(context, uuid, eager=eager)
99 action = cls._from_db_object(cls(context), db_action, eager=eager)
100 return action
102 @base.remotable_classmethod
103 def list(cls, context, limit=None, marker=None, filters=None,
104 sort_key=None, sort_dir=None, eager=False):
105 """Return a list of Action objects.
107 :param context: Security context.
108 :param limit: maximum number of resources to return in a single result.
109 :param marker: pagination marker for large data sets.
110 :param filters: Filters to apply. Defaults to None.
111 :param sort_key: column to sort results by.
112 :param sort_dir: direction to sort. "asc" or "desc".
113 :param eager: Load object fields if True (Default: False)
114 :returns: a list of :class:`Action` object.
115 """
116 db_actions = cls.dbapi.get_action_list(context,
117 limit=limit,
118 marker=marker,
119 filters=filters,
120 sort_key=sort_key,
121 sort_dir=sort_dir,
122 eager=eager)
124 return [cls._from_db_object(cls(context), obj, eager=eager)
125 for obj in db_actions]
127 @base.remotable
128 def create(self):
129 """Create an :class:`Action` record in the DB.
131 :returns: An :class:`Action` object.
132 """
133 values = self.obj_get_changes()
134 db_action = self.dbapi.create_action(values)
135 # Note(v-francoise): Always load eagerly upon creation so we can send
136 # notifications containing information about the related relationships
137 self._from_db_object(self, db_action, eager=True)
139 notifications.action.send_create(self.obj_context, self)
141 def destroy(self):
142 """Delete the Action from the DB"""
143 self.dbapi.destroy_action(self.uuid)
144 self.obj_reset_changes()
146 @base.remotable
147 def save(self):
148 """Save updates to this Action.
150 Updates will be made column by column based on the result
151 of self.what_changed().
152 """
153 updates = self.obj_get_changes()
154 db_obj = self.dbapi.update_action(self.uuid, updates)
155 obj = self._from_db_object(self, db_obj, eager=False)
156 self.obj_refresh(obj)
157 notifications.action.send_update(self.obj_context, self)
158 self.obj_reset_changes()
160 @base.remotable
161 def refresh(self, eager=False):
162 """Loads updates for this Action.
164 Loads a action with the same uuid from the database and
165 checks for updated attributes. Updates are applied from
166 the loaded action column by column, if there are any updates.
167 :param eager: Load object fields if True (Default: False)
168 """
169 current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager)
170 self.obj_refresh(current)
172 @base.remotable
173 def soft_delete(self):
174 """Soft Delete the Audit from the DB"""
175 self.state = State.DELETED
176 self.save()
177 db_obj = self.dbapi.soft_delete_action(self.uuid)
178 obj = self._from_db_object(
179 self.__class__(self._context), db_obj, eager=False)
180 self.obj_refresh(obj)
182 notifications.action.send_delete(self.obj_context, self)