Coverage for watcher/decision_engine/goal/efficacy/indicators.py: 90%
116 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 (c) 2016 b<>com
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.
17import abc
18import jsonschema
19from jsonschema import SchemaError
20from jsonschema import ValidationError
22from oslo_log import log
23from oslo_serialization import jsonutils
25from watcher._i18n import _
26from watcher.common import exception
28LOG = log.getLogger(__name__)
31class IndicatorSpecification(object, metaclass=abc.ABCMeta):
33 def __init__(self, name=None, description=None, unit=None, required=True):
34 self.name = name
35 self.description = description
36 self.unit = unit
37 self.required = required
39 @property
40 @abc.abstractmethod
41 def schema(self):
42 """JsonSchema used to validate the indicator value
44 :return: A Schema
45 """
46 raise NotImplementedError()
48 @classmethod
49 def validate(cls, solution):
50 """Validate the given solution
52 :raises: :py:class:`~.InvalidIndicatorValue` when the validation fails
53 """
54 indicator = cls()
55 value = None
56 try:
57 value = getattr(solution, indicator.name)
58 jsonschema.validate(value, cls.schema)
59 except (SchemaError, ValidationError) as exc:
60 LOG.exception(exc)
61 raise
62 except Exception as exc:
63 LOG.exception(exc)
64 raise exception.InvalidIndicatorValue(
65 name=indicator.name, value=value, spec_type=type(indicator))
67 def to_dict(self):
68 return {
69 "name": self.name,
70 "description": self.description,
71 "unit": self.unit,
72 "schema": jsonutils.dumps(self.schema) if self.schema else None,
73 }
75 def __str__(self):
76 return str(self.to_dict())
79class ComputeNodesCount(IndicatorSpecification):
80 def __init__(self):
81 super(ComputeNodesCount, self).__init__(
82 name="compute_nodes_count",
83 description=_("The total number of enabled compute nodes."),
84 unit=None,
85 )
87 @property
88 def schema(self):
89 return {
90 "type": "integer",
91 "minimum": 0
92 }
95class ReleasedComputeNodesCount(IndicatorSpecification):
96 def __init__(self):
97 super(ReleasedComputeNodesCount, self).__init__(
98 name="released_compute_nodes_count",
99 description=_("The number of compute nodes to be released."),
100 unit=None,
101 )
103 @property
104 def schema(self):
105 return {
106 "type": "integer",
107 "minimum": 0
108 }
111class InstancesCount(IndicatorSpecification):
112 def __init__(self):
113 super(InstancesCount, self).__init__(
114 name="instances_count",
115 description=_("The total number of audited instances in "
116 "strategy."),
117 unit=None,
118 required=False,
119 )
121 @property
122 def schema(self):
123 return {
124 "type": "integer",
125 "minimum": 0
126 }
129class InstanceMigrationsCount(IndicatorSpecification):
130 def __init__(self):
131 super(InstanceMigrationsCount, self).__init__(
132 name="instance_migrations_count",
133 description=_("The number of VM migrations to be performed."),
134 unit=None,
135 )
137 @property
138 def schema(self):
139 return {
140 "type": "integer",
141 "minimum": 0
142 }
145class LiveInstanceMigrateCount(IndicatorSpecification):
146 def __init__(self):
147 super(LiveInstanceMigrateCount, self).__init__(
148 name="live_migrate_instance_count",
149 description=_("The number of instances actually live migrated."),
150 unit=None,
151 )
153 @property
154 def schema(self):
155 return {
156 "type": "integer",
157 "minimum": 0
158 }
161class PlannedLiveInstanceMigrateCount(IndicatorSpecification):
162 def __init__(self):
163 super(PlannedLiveInstanceMigrateCount, self).__init__(
164 name="planned_live_migrate_instance_count",
165 description=_("The number of instances planned to live migrate."),
166 unit=None,
167 )
169 @property
170 def schema(self):
171 return {
172 "type": "integer",
173 "minimum": 0
174 }
177class ColdInstanceMigrateCount(IndicatorSpecification):
178 def __init__(self):
179 super(ColdInstanceMigrateCount, self).__init__(
180 name="cold_migrate_instance_count",
181 description=_("The number of instances actually cold migrated."),
182 unit=None,
183 )
185 @property
186 def schema(self):
187 return {
188 "type": "integer",
189 "minimum": 0
190 }
193class PlannedColdInstanceMigrateCount(IndicatorSpecification):
194 def __init__(self):
195 super(PlannedColdInstanceMigrateCount, self).__init__(
196 name="planned_cold_migrate_instance_count",
197 description=_("The number of instances planned to cold migrate."),
198 unit=None,
199 )
201 @property
202 def schema(self):
203 return {
204 "type": "integer",
205 "minimum": 0
206 }
209class VolumeMigrateCount(IndicatorSpecification):
210 def __init__(self):
211 super(VolumeMigrateCount, self).__init__(
212 name="volume_migrate_count",
213 description=_("The number of detached volumes actually migrated."),
214 unit=None,
215 )
217 @property
218 def schema(self):
219 return {
220 "type": "integer",
221 "minimum": 0
222 }
225class PlannedVolumeMigrateCount(IndicatorSpecification):
226 def __init__(self):
227 super(PlannedVolumeMigrateCount, self).__init__(
228 name="planned_volume_migrate_count",
229 description=_("The number of detached volumes planned"
230 " to migrate."),
231 unit=None,
232 )
234 @property
235 def schema(self):
236 return {
237 "type": "integer",
238 "minimum": 0
239 }
242class VolumeUpdateCount(IndicatorSpecification):
243 def __init__(self):
244 super(VolumeUpdateCount, self).__init__(
245 name="volume_update_count",
246 description=_("The number of attached volumes actually"
247 " migrated."),
248 unit=None,
249 )
251 @property
252 def schema(self):
253 return {
254 "type": "integer",
255 "minimum": 0
256 }
259class PlannedVolumeUpdateCount(IndicatorSpecification):
260 def __init__(self):
261 super(PlannedVolumeUpdateCount, self).__init__(
262 name="planned_volume_update_count",
263 description=_("The number of attached volumes planned to"
264 " migrate."),
265 unit=None,
266 )
268 @property
269 def schema(self):
270 return {
271 "type": "integer",
272 "minimum": 0
273 }
276class StandardDeviationValue(IndicatorSpecification):
277 def __init__(self):
278 super(StandardDeviationValue, self).__init__(
279 name="standard_deviation_after_audit",
280 description=_("The value of resulted standard deviation."),
281 unit=None,
282 required=False,
283 )
285 @property
286 def schema(self):
287 return {
288 "type": "number",
289 "minimum": 0
290 }
293class OriginalStandardDeviationValue(IndicatorSpecification):
294 def __init__(self):
295 super(OriginalStandardDeviationValue, self).__init__(
296 name="standard_deviation_before_audit",
297 description=_("The value of original standard deviation."),
298 unit=None,
299 required=False,
300 )
302 @property
303 def schema(self):
304 return {
305 "type": "number",
306 "minimum": 0
307 }