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

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. 

16 

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 

24 

25 

26class State(object): 

27 PENDING = 'PENDING' 

28 ONGOING = 'ONGOING' 

29 FAILED = 'FAILED' 

30 SUCCEEDED = 'SUCCEEDED' 

31 DELETED = 'DELETED' 

32 CANCELLED = 'CANCELLED' 

33 CANCELLING = 'CANCELLING' 

34 

35 

36@base.WatcherObjectRegistry.register 

37class Action(base.WatcherPersistentObject, base.WatcherObject, 

38 base.WatcherObjectDictCompat): 

39 

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' 

44 

45 dbapi = db_api.get_instance() 

46 

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), 

55 

56 'action_plan': wfields.ObjectField('ActionPlan', nullable=True), 

57 } 

58 object_fields = { 

59 'action_plan': (objects.ActionPlan, 'action_plan_id'), 

60 } 

61 

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. 

65 

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) 

76 

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. 

80 

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 

88 

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. 

92 

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 

101 

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. 

106 

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) 

123 

124 return [cls._from_db_object(cls(context), obj, eager=eager) 

125 for obj in db_actions] 

126 

127 @base.remotable 

128 def create(self): 

129 """Create an :class:`Action` record in the DB. 

130 

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) 

138 

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

140 

141 def destroy(self): 

142 """Delete the Action from the DB""" 

143 self.dbapi.destroy_action(self.uuid) 

144 self.obj_reset_changes() 

145 

146 @base.remotable 

147 def save(self): 

148 """Save updates to this Action. 

149 

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() 

159 

160 @base.remotable 

161 def refresh(self, eager=False): 

162 """Loads updates for this Action. 

163 

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) 

171 

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) 

181 

182 notifications.action.send_delete(self.obj_context, self)