Coverage for watcher/common/exception.py: 95%
247 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) 2015 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.
17"""Watcher base exception handling.
19Includes decorator for re-raising Watcher-type exceptions.
21SHOULD include dedicated exception logging.
23"""
25import functools
26import sys
28from http import HTTPStatus
29from keystoneclient import exceptions as keystone_exceptions
30from oslo_config import cfg
31from oslo_log import log
33from watcher._i18n import _
35LOG = log.getLogger(__name__)
37CONF = cfg.CONF
40def wrap_keystone_exception(func):
41 """Wrap keystone exceptions and throw Watcher specific exceptions."""
42 @functools.wraps(func)
43 def wrapped(*args, **kw):
44 try:
45 return func(*args, **kw)
46 except keystone_exceptions.AuthorizationFailure:
47 raise AuthorizationFailure(
48 client=func.__name__, reason=sys.exc_info()[1])
49 except keystone_exceptions.ClientException:
50 raise AuthorizationFailure(
51 client=func.__name__,
52 reason=(_('Unexpected keystone client error occurred: %s')
53 % sys.exc_info()[1]))
54 return wrapped
57class WatcherException(Exception):
58 """Base Watcher Exception
60 To correctly use this class, inherit from it and define
61 a 'msg_fmt' property. That msg_fmt will get printf'd
62 with the keyword arguments provided to the constructor.
64 """
65 msg_fmt = _("An unknown exception occurred")
66 code = HTTPStatus.INTERNAL_SERVER_ERROR
67 headers = {}
68 safe = False
70 def __init__(self, message=None, **kwargs):
71 self.kwargs = kwargs
73 if 'code' not in self.kwargs: 73 ↛ 79line 73 didn't jump to line 79 because the condition on line 73 was always true
74 try:
75 self.kwargs['code'] = self.code
76 except AttributeError:
77 pass
79 if not message:
80 try:
81 message = self.msg_fmt % kwargs
82 except Exception:
83 # kwargs doesn't match a variable in msg_fmt
84 # log the issue and the kwargs
85 LOG.exception('Exception in string format operation')
86 for name, value in kwargs.items():
87 LOG.error("%(name)s: %(value)s",
88 {'name': name, 'value': value})
90 if CONF.fatal_exception_format_errors: 90 ↛ 91line 90 didn't jump to line 91 because the condition on line 90 was never true
91 raise
92 else:
93 # at least get the core msg_fmt out if something happened
94 message = self.msg_fmt
96 super(WatcherException, self).__init__(message)
98 def __str__(self):
99 """Encode to utf-8 then wsme api can consume it as well"""
100 return self.args[0]
102 def __unicode__(self):
103 return str(self.args[0])
105 def format_message(self):
106 if self.__class__.__name__.endswith('_Remote'):
107 return self.args[0]
108 else:
109 return str(self)
112class UnsupportedError(WatcherException):
113 msg_fmt = _("Not supported")
116class NotAuthorized(WatcherException):
117 msg_fmt = _("Not authorized")
118 code = HTTPStatus.FORBIDDEN
121class NotAcceptable(WatcherException):
122 msg_fmt = _("Request not acceptable.")
123 code = HTTPStatus.NOT_ACCEPTABLE
126class PolicyNotAuthorized(NotAuthorized):
127 msg_fmt = _("Policy doesn't allow %(action)s to be performed.")
130class OperationNotPermitted(NotAuthorized):
131 msg_fmt = _("Operation not permitted")
134class Invalid(WatcherException, ValueError):
135 msg_fmt = _("Unacceptable parameters")
136 code = HTTPStatus.BAD_REQUEST
139class ObjectNotFound(WatcherException):
140 msg_fmt = _("The %(name)s %(id)s could not be found")
143class Conflict(WatcherException):
144 msg_fmt = _('Conflict')
145 code = HTTPStatus.CONFLICT
148class ResourceNotFound(ObjectNotFound):
149 msg_fmt = _("The %(name)s resource %(id)s could not be found")
150 code = HTTPStatus.NOT_FOUND
153class InvalidParameter(Invalid):
154 msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
157class MissingParameter(Invalid):
158 msg_fmt = _("%(parameter)s is required but missing. Check watcher.conf")
161class InvalidIdentity(Invalid):
162 msg_fmt = _("Expected a uuid or int but received %(identity)s")
165class InvalidOperator(Invalid):
166 msg_fmt = _("Filter operator is not valid: %(operator)s not "
167 "in %(valid_operators)s")
170class InvalidGoal(Invalid):
171 msg_fmt = _("Goal %(goal)s is invalid")
174class InvalidStrategy(Invalid):
175 msg_fmt = _("Strategy %(strategy)s is invalid")
178class InvalidAudit(Invalid):
179 msg_fmt = _("Audit %(audit)s is invalid")
182class EagerlyLoadedAuditRequired(InvalidAudit):
183 msg_fmt = _("Audit %(audit)s was not eagerly loaded")
186class InvalidActionPlan(Invalid):
187 msg_fmt = _("Action plan %(action_plan)s is invalid")
190class EagerlyLoadedActionPlanRequired(InvalidActionPlan):
191 msg_fmt = _("Action plan %(action_plan)s was not eagerly loaded")
194class EagerlyLoadedActionRequired(InvalidActionPlan):
195 msg_fmt = _("Action %(action)s was not eagerly loaded")
198class InvalidUUID(Invalid):
199 msg_fmt = _("Expected a uuid but received %(uuid)s")
202class InvalidName(Invalid):
203 msg_fmt = _("Expected a logical name but received %(name)s")
206class InvalidUuidOrName(Invalid):
207 msg_fmt = _("Expected a logical name or uuid but received %(name)s")
210class InvalidIntervalOrCron(Invalid):
211 msg_fmt = _("Expected an interval or cron syntax but received %(name)s")
214class DataModelTypeNotFound(ResourceNotFound):
215 msg_fmt = _("The %(data_model_type)s data model could not be found")
218class GoalNotFound(ResourceNotFound):
219 msg_fmt = _("Goal %(goal)s could not be found")
222class GoalAlreadyExists(Conflict):
223 msg_fmt = _("A goal with UUID %(uuid)s already exists")
226class StrategyNotFound(ResourceNotFound):
227 msg_fmt = _("Strategy %(strategy)s could not be found")
230class StrategyAlreadyExists(Conflict):
231 msg_fmt = _("A strategy with UUID %(uuid)s already exists")
234class AuditTemplateNotFound(ResourceNotFound):
235 msg_fmt = _("AuditTemplate %(audit_template)s could not be found")
238class AuditTemplateAlreadyExists(Conflict):
239 msg_fmt = _("An audit_template with UUID or name %(audit_template)s "
240 "already exists")
243class AuditTypeNotFound(Invalid):
244 msg_fmt = _("Audit type %(audit_type)s could not be found")
247class AuditTypeNotAllowed(Invalid):
248 msg_fmt = _("Audit type %(audit_type)s is disallowed.")
251class AuditStateNotAllowed(Invalid):
252 msg_fmt = _("Audit state %(state)s is disallowed.")
255class AuditParameterNotAllowed(Invalid):
256 msg_fmt = _("Audit parameter %(parameter)s are not allowed")
259class AuditNotFound(ResourceNotFound):
260 msg_fmt = _("Audit %(audit)s could not be found")
263class AuditAlreadyExists(Conflict):
264 msg_fmt = _("An audit with UUID or name %(audit)s already exists")
267class AuditIntervalNotSpecified(Invalid):
268 msg_fmt = _("Interval of audit must be specified for %(audit_type)s.")
271class AuditIntervalNotAllowed(Invalid):
272 msg_fmt = _("Interval of audit must not be set for %(audit_type)s.")
275class AuditStartEndTimeNotAllowed(Invalid):
276 msg_fmt = _("Start or End time of audit must not be set for "
277 "%(audit_type)s.")
280class AuditReferenced(Invalid):
281 msg_fmt = _("Audit %(audit)s is referenced by one or multiple action "
282 "plans")
285class ActionPlanNotFound(ResourceNotFound):
286 msg_fmt = _("ActionPlan %(action_plan)s could not be found")
289class ActionPlanAlreadyExists(Conflict):
290 msg_fmt = _("An action plan with UUID %(uuid)s already exists")
293class ActionPlanReferenced(Invalid):
294 msg_fmt = _("Action Plan %(action_plan)s is referenced by one or "
295 "multiple actions")
298class ActionPlanCancelled(WatcherException):
299 msg_fmt = _("Action Plan with UUID %(uuid)s is cancelled by user")
302class ActionPlanIsOngoing(Conflict):
303 msg_fmt = _("Action Plan %(action_plan)s is currently running.")
306class ActionNotFound(ResourceNotFound):
307 msg_fmt = _("Action %(action)s could not be found")
310class ActionAlreadyExists(Conflict):
311 msg_fmt = _("An action with UUID %(uuid)s already exists")
314class ActionReferenced(Invalid):
315 msg_fmt = _("Action plan %(action_plan)s is referenced by one or "
316 "multiple goals")
319class ActionFilterCombinationProhibited(Invalid):
320 msg_fmt = _("Filtering actions on both audit and action-plan is "
321 "prohibited")
324class UnsupportedActionType(UnsupportedError):
325 msg_fmt = _("Provided %(action_type)s is not supported yet")
328class EfficacyIndicatorNotFound(ResourceNotFound):
329 msg_fmt = _("Efficacy indicator %(efficacy_indicator)s could not be found")
332class EfficacyIndicatorAlreadyExists(Conflict):
333 msg_fmt = _("An action with UUID %(uuid)s already exists")
336class ScoringEngineAlreadyExists(Conflict):
337 msg_fmt = _("A scoring engine with UUID %(uuid)s already exists")
340class ScoringEngineNotFound(ResourceNotFound):
341 msg_fmt = _("ScoringEngine %(scoring_engine)s could not be found")
344class HTTPNotFound(ResourceNotFound):
345 pass
348class PatchError(Invalid):
349 msg_fmt = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s")
352class DeleteError(Invalid):
353 msg_fmt = _("Couldn't delete when state is '%(state)s'.")
356class StartError(Invalid):
357 msg_fmt = _("Couldn't start when state is '%(state)s'.")
360# decision engine
362class WorkflowExecutionException(WatcherException):
363 msg_fmt = _('Workflow execution error: %(error)s')
366class IllegalArgumentException(WatcherException):
367 msg_fmt = _('Illegal argument')
370class AuthorizationFailure(WatcherException):
371 msg_fmt = _('%(client)s connection failed. Reason: %(reason)s')
374class ClusterStateStale(WatcherException):
375 msg_fmt = _("The cluster state is stale")
378class ClusterDataModelCollectionError(WatcherException):
379 msg_fmt = _("The cluster data model '%(cdm)s' could not be built")
382class ClusterStateNotDefined(WatcherException):
383 msg_fmt = _("The cluster state is not defined")
386class NoAvailableStrategyForGoal(WatcherException):
387 msg_fmt = _("No strategy could be found to achieve the '%(goal)s' goal.")
390class InvalidIndicatorValue(WatcherException):
391 msg_fmt = _("The indicator '%(name)s' with value '%(value)s' "
392 "and spec type '%(spec_type)s' is invalid.")
395class GlobalEfficacyComputationError(WatcherException):
396 msg_fmt = _("Could not compute the global efficacy for the '%(goal)s' "
397 "goal using the '%(strategy)s' strategy.")
400class UnsupportedDataSource(UnsupportedError):
401 msg_fmt = _("Datasource %(datasource)s is not supported "
402 "by strategy %(strategy)s")
405class DataSourceNotAvailable(WatcherException):
406 msg_fmt = _("Datasource %(datasource)s is not available.")
409class MetricNotAvailable(WatcherException):
410 """Indicate that a metric is not configured or does not exists"""
411 msg_fmt = _('Metric: %(metric)s not available')
414class NoDatasourceAvailable(WatcherException):
415 """No datasources have been configured"""
416 msg_fmt = _('No datasources available')
419class NoSuchMetricForHost(WatcherException):
420 msg_fmt = _("No %(metric)s metric for %(host)s found.")
423class ServiceAlreadyExists(Conflict):
424 msg_fmt = _("A service with name %(name)s is already working on %(host)s.")
427class ServiceNotFound(ResourceNotFound):
428 msg_fmt = _("The service %(service)s cannot be found.")
431class WildcardCharacterIsUsed(WatcherException):
432 msg_fmt = _("You shouldn't use any other IDs of %(resource)s if you use "
433 "wildcard character.")
436class CronFormatIsInvalid(WatcherException):
437 msg_fmt = _("Provided cron is invalid: %(message)s")
440class ActionDescriptionAlreadyExists(Conflict):
441 msg_fmt = _("An action description with type %(action_type)s is "
442 "already exist.")
445class ActionDescriptionNotFound(ResourceNotFound):
446 msg_fmt = _("The action description %(action_id)s cannot be found.")
449class ActionExecutionFailure(WatcherException):
450 msg_fmt = _("The action %(action_id)s execution failed.")
453# Model
455class ComputeResourceNotFound(WatcherException):
456 msg_fmt = _("The compute resource '%(name)s' could not be found")
459class InstanceNotFound(ComputeResourceNotFound):
460 msg_fmt = _("The instance '%(name)s' could not be found")
463class InstanceNotMapped(ComputeResourceNotFound):
464 msg_fmt = _("The mapped compute node for instance '%(uuid)s' "
465 "could not be found.")
468class ComputeNodeNotFound(ComputeResourceNotFound):
469 msg_fmt = _("The compute node %(name)s could not be found")
472class StorageResourceNotFound(WatcherException):
473 msg_fmt = _("The storage resource '%(name)s' could not be found")
476class StorageNodeNotFound(StorageResourceNotFound):
477 msg_fmt = _("The storage node %(name)s could not be found")
480class PoolNotFound(StorageResourceNotFound):
481 msg_fmt = _("The pool %(name)s could not be found")
484class VolumeNotFound(StorageResourceNotFound):
485 msg_fmt = _("The volume '%(name)s' could not be found")
488class BaremetalResourceNotFound(WatcherException):
489 msg_fmt = _("The baremetal resource '%(name)s' could not be found")
492class IronicNodeNotFound(BaremetalResourceNotFound):
493 msg_fmt = _("The ironic node %(uuid)s could not be found")
496class LoadingError(WatcherException):
497 msg_fmt = _("Error loading plugin '%(name)s'")
500class ReservedWord(WatcherException):
501 msg_fmt = _("The identifier '%(name)s' is a reserved word")
504class NotSoftDeletedStateError(WatcherException):
505 msg_fmt = _("The %(name)s resource %(id)s is not soft deleted")
508class NegativeLimitError(WatcherException):
509 msg_fmt = _("Limit should be positive")
512class NotificationPayloadError(WatcherException):
513 msg_fmt = _("Payload not populated when trying to send notification "
514 "\"%(class_name)s\"")
517class InvalidPoolAttributeValue(Invalid):
518 msg_fmt = _("The %(name)s pool %(attribute)s is not integer")