Coverage for watcher/objects/audit_template.py: 100%
62 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.
17"""
18An :ref:`Audit <audit_definition>` may be launched several times with the same
19settings (:ref:`Goal <goal_definition>`, thresholds, ...). Therefore it makes
20sense to save those settings in some sort of Audit preset object, which is
21known as an :ref:`Audit Template <audit_template_definition>`.
23An :ref:`Audit Template <audit_template_definition>` contains at least the
24:ref:`Goal <goal_definition>` of the :ref:`Audit <audit_definition>`.
26It may also contain some error handling settings indicating whether:
28- :ref:`Watcher Applier <watcher_applier_definition>` stops the
29 entire operation
30- :ref:`Watcher Applier <watcher_applier_definition>` performs a rollback
32and how many retries should be attempted before failure occurs (also the latter
33can be complex: for example the scenario in which there are many first-time
34failures on ultimately successful :ref:`Actions <action_definition>`).
36Moreover, an :ref:`Audit Template <audit_template_definition>` may contain some
37settings related to the level of automation for the
38:ref:`Action Plan <action_plan_definition>` that will be generated by the
39:ref:`Audit <audit_definition>`.
40A flag will indicate whether the :ref:`Action Plan <action_plan_definition>`
41will be launched automatically or will need a manual confirmation from the
42:ref:`Administrator <administrator_definition>`.
44Last but not least, an :ref:`Audit Template <audit_template_definition>` may
45contain a list of extra parameters related to the
46:ref:`Strategy <strategy_definition>` configuration. These parameters can be
47provided as a list of key-value pairs.
48"""
50from watcher.common import exception
51from watcher.common import utils
52from watcher.db import api as db_api
53from watcher import objects
54from watcher.objects import base
55from watcher.objects import fields as wfields
58@base.WatcherObjectRegistry.register
59class AuditTemplate(base.WatcherPersistentObject, base.WatcherObject,
60 base.WatcherObjectDictCompat):
62 # Version 1.0: Initial version
63 # Version 1.1: Added 'goal' and 'strategy' object field
64 VERSION = '1.1'
66 dbapi = db_api.get_instance()
68 fields = {
69 'id': wfields.IntegerField(),
70 'uuid': wfields.UUIDField(),
71 'name': wfields.StringField(),
72 'description': wfields.StringField(nullable=True),
73 'scope': wfields.FlexibleListOfDictField(nullable=True),
74 'goal_id': wfields.IntegerField(),
75 'strategy_id': wfields.IntegerField(nullable=True),
77 'goal': wfields.ObjectField('Goal', nullable=True),
78 'strategy': wfields.ObjectField('Strategy', nullable=True),
79 }
81 object_fields = {
82 'goal': (objects.Goal, 'goal_id'),
83 'strategy': (objects.Strategy, 'strategy_id'),
84 }
86 @base.remotable_classmethod
87 def get(cls, context, audit_template_id, eager=False):
88 """Find an audit template based on its id or uuid
90 :param context: Security context. NOTE: This should only
91 be used internally by the indirection_api.
92 Unfortunately, RPC requires context as the first
93 argument, even though we don't use it.
94 A context should be set when instantiating the
95 object, e.g.: AuditTemplate(context)
96 :param audit_template_id: the id *or* uuid of a audit_template.
97 :param eager: Load object fields if True (Default: False)
98 :returns: a :class:`AuditTemplate` object.
99 """
100 if utils.is_int_like(audit_template_id):
101 return cls.get_by_id(context, audit_template_id, eager=eager)
102 elif utils.is_uuid_like(audit_template_id):
103 return cls.get_by_uuid(context, audit_template_id, eager=eager)
104 else:
105 raise exception.InvalidIdentity(identity=audit_template_id)
107 @base.remotable_classmethod
108 def get_by_id(cls, context, audit_template_id, eager=False):
109 """Find an audit template based on its integer id
111 :param context: Security context. NOTE: This should only
112 be used internally by the indirection_api.
113 Unfortunately, RPC requires context as the first
114 argument, even though we don't use it.
115 A context should be set when instantiating the
116 object, e.g.: AuditTemplate(context)
117 :param audit_template_id: the id of a audit_template.
118 :param eager: Load object fields if True (Default: False)
119 :returns: a :class:`AuditTemplate` object.
120 """
121 db_audit_template = cls.dbapi.get_audit_template_by_id(
122 context, audit_template_id, eager=eager)
123 audit_template = cls._from_db_object(
124 cls(context), db_audit_template, eager=eager)
125 return audit_template
127 @base.remotable_classmethod
128 def get_by_uuid(cls, context, uuid, eager=False):
129 """Find an audit template based on uuid
131 :param context: Security context. NOTE: This should only
132 be used internally by the indirection_api.
133 Unfortunately, RPC requires context as the first
134 argument, even though we don't use it.
135 A context should be set when instantiating the
136 object, e.g.: AuditTemplate(context)
137 :param uuid: the uuid of a audit_template.
138 :param eager: Load object fields if True (Default: False)
139 :returns: a :class:`AuditTemplate` object.
140 """
141 db_audit_template = cls.dbapi.get_audit_template_by_uuid(
142 context, uuid, eager=eager)
143 audit_template = cls._from_db_object(
144 cls(context), db_audit_template, eager=eager)
145 return audit_template
147 @base.remotable_classmethod
148 def get_by_name(cls, context, name, eager=False):
149 """Find an audit template based on name
151 :param name: the logical name of a audit_template.
152 :param context: Security context
153 :param eager: Load object fields if True (Default: False)
154 :returns: a :class:`AuditTemplate` object.
155 """
156 db_audit_template = cls.dbapi.get_audit_template_by_name(
157 context, name, eager=eager)
158 audit_template = cls._from_db_object(
159 cls(context), db_audit_template, eager=eager)
160 return audit_template
162 @base.remotable_classmethod
163 def list(cls, context, filters=None, limit=None, marker=None,
164 sort_key=None, sort_dir=None, eager=False):
165 """Return a list of :class:`AuditTemplate` objects.
167 :param context: Security context. NOTE: This should only
168 be used internally by the indirection_api.
169 Unfortunately, RPC requires context as the first
170 argument, even though we don't use it.
171 A context should be set when instantiating the
172 object, e.g.: AuditTemplate(context)
173 :param filters: dict mapping the filter key to a value.
174 :param limit: maximum number of resources to return in a single result.
175 :param marker: pagination marker for large data sets.
176 :param sort_key: column to sort results by.
177 :param sort_dir: direction to sort. "asc" or "desc".
178 :param eager: Load object fields if True (Default: False)
179 :returns: a list of :class:`AuditTemplate` object.
180 """
181 db_audit_templates = cls.dbapi.get_audit_template_list(
182 context,
183 filters=filters,
184 limit=limit,
185 marker=marker,
186 sort_key=sort_key,
187 sort_dir=sort_dir,
188 eager=eager)
190 return [cls._from_db_object(cls(context), obj, eager=eager)
191 for obj in db_audit_templates]
193 @base.remotable
194 def create(self):
195 """Create a :class:`AuditTemplate` record in the DB
197 :returns: An :class:`AuditTemplate` object.
198 """
199 values = self.obj_get_changes()
200 db_audit_template = self.dbapi.create_audit_template(values)
201 # Note(v-francoise): Always load eagerly upon creation so we can send
202 # notifications containing information about the related relationships
203 self._from_db_object(self, db_audit_template, eager=True)
205 def destroy(self):
206 """Delete the :class:`AuditTemplate` from the DB"""
207 self.dbapi.destroy_audit_template(self.uuid)
208 self.obj_reset_changes()
210 @base.remotable
211 def save(self):
212 """Save updates to this :class:`AuditTemplate`.
214 Updates will be made column by column based on the result
215 of self.what_changed().
216 """
217 updates = self.obj_get_changes()
218 db_obj = self.dbapi.update_audit_template(self.uuid, updates)
219 obj = self._from_db_object(self, db_obj, eager=False)
220 self.obj_refresh(obj)
221 self.obj_reset_changes()
223 @base.remotable
224 def refresh(self, eager=False):
225 """Loads updates for this :class:`AuditTemplate`.
227 Loads a audit_template with the same uuid from the database and
228 checks for updated attributes. Updates are applied from
229 the loaded audit_template column by column, if there are any updates.
230 :param eager: Load object fields if True (Default: False)
231 """
232 current = self.get_by_uuid(self._context, uuid=self.uuid, eager=eager)
233 self.obj_refresh(current)
235 @base.remotable
236 def soft_delete(self):
237 """Soft Delete the :class:`AuditTemplate` from the DB"""
238 db_obj = self.dbapi.soft_delete_audit_template(self.uuid)
239 obj = self._from_db_object(
240 self.__class__(self._context), db_obj, eager=False)
241 self.obj_refresh(obj)