"Fossies" - the Fresh Open Source Software Archive

Member "masakari-10.0.3/masakari/exception.py" (19 Aug 2021, 11524 Bytes) of package /linux/misc/openstack/masakari-10.0.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "exception.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 10.0.2_vs_10.0.3.

    1 # Copyright 2016 NTT DATA
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    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, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 
   16 """Masakari base exception handling.
   17 
   18 Includes decorator for re-raising Masakari-type exceptions.
   19 
   20 SHOULD include dedicated exception logging.
   21 
   22 """
   23 
   24 import functools
   25 from http import client as http
   26 import inspect
   27 import sys
   28 
   29 from oslo_log import log as logging
   30 from oslo_utils import excutils
   31 import webob.exc
   32 from webob import util as woutil
   33 
   34 import masakari.conf
   35 from masakari.i18n import _
   36 from masakari import safe_utils
   37 from masakari import utils
   38 
   39 LOG = logging.getLogger(__name__)
   40 
   41 
   42 CONF = masakari.conf.CONF
   43 
   44 
   45 class ConvertedException(webob.exc.WSGIHTTPException):
   46     def __init__(self, code, title="", explanation=""):
   47         self.code = int(code)
   48         # There is a strict rule about constructing status line for HTTP:
   49         # '...Status-Line, consisting of the protocol version followed by a
   50         # numeric status code and its associated textual phrase, with each
   51         # element separated by SP characters'
   52         # (http://www.faqs.org/rfcs/rfc2616.html)
   53         # 'code' and 'title' can not be empty because they correspond
   54         # to numeric status code and its associated text
   55         if title:
   56             self.title = title
   57         else:
   58             try:
   59                 self.title = woutil.status_reasons[self.code]
   60             except KeyError:
   61                 msg = "Improper or unknown HTTP status code used: %d"
   62                 LOG.error(msg, code)
   63                 self.title = woutil.status_generic_reasons[self.code // 100]
   64         self.explanation = explanation
   65         super(ConvertedException, self).__init__()
   66 
   67 
   68 def _cleanse_dict(original):
   69     """Strip all admin_password, new_pass, rescue_pass keys from a dict."""
   70     return {k: v for k, v in original.items() if "_pass" not in k}
   71 
   72 
   73 def wrap_exception(notifier=None, get_notifier=None):
   74     """This decorator wraps a method to catch any exceptions that may
   75     get thrown. It also optionally sends the exception to the notification
   76     system.
   77     """
   78     def inner(f):
   79         def wrapped(self, context, *args, **kw):
   80             # Don't store self or context in the payload, it now seems to
   81             # contain confidential information.
   82             try:
   83                 return f(self, context, *args, **kw)
   84             except Exception as e:
   85                 with excutils.save_and_reraise_exception():
   86                     if notifier or get_notifier:
   87                         payload = dict(exception=e)
   88                         wrapped_func = safe_utils.get_wrapped_function(f)
   89                         call_dict = inspect.getcallargs(wrapped_func, self,
   90                                                         context, *args, **kw)
   91                         # self can't be serialized and shouldn't be in the
   92                         # payload
   93                         call_dict.pop('self', None)
   94                         cleansed = _cleanse_dict(call_dict)
   95                         payload.update({'args': cleansed})
   96 
   97                         # If f has multiple decorators, they must use
   98                         # functools.wraps to ensure the name is
   99                         # propagated.
  100                         event_type = f.__name__
  101 
  102                         (notifier or get_notifier()).error(context,
  103                                                            event_type,
  104                                                            payload)
  105 
  106         return functools.wraps(f)(wrapped)
  107     return inner
  108 
  109 
  110 class MasakariException(Exception):
  111     """Base Masakari Exception
  112 
  113     To correctly use this class, inherit from it and define
  114     a 'msg_fmt' property. That msg_fmt will get printf'd
  115     with the keyword arguments provided to the constructor.
  116 
  117     """
  118     msg_fmt = _("An unknown exception occurred.")
  119     code = http.INTERNAL_SERVER_ERROR
  120     headers = {}
  121     safe = False
  122 
  123     def __init__(self, message=None, **kwargs):
  124         self.kwargs = kwargs
  125 
  126         if 'code' not in self.kwargs:
  127             try:
  128                 self.kwargs['code'] = self.code
  129             except AttributeError:
  130                 pass
  131 
  132         if not message:
  133             try:
  134                 message = self.msg_fmt % kwargs
  135 
  136             except Exception:
  137                 exc_info = sys.exc_info()
  138                 # kwargs doesn't match a variable in the message
  139                 # log the issue and the kwargs
  140                 LOG.exception('Exception in string format operation')
  141                 for name, value in kwargs.items():
  142                     LOG.error("%s: %s" % (name, value))    # noqa
  143 
  144                 if CONF.fatal_exception_format_errors:
  145                     utils.reraise(*exc_info)
  146                 else:
  147                     # at least get the core message out if something happened
  148                     message = self.msg_fmt
  149 
  150         self.message = message
  151         super(MasakariException, self).__init__(message)
  152 
  153     def format_message(self):
  154         # NOTE: use the first argument to the python Exception object
  155         # which should be our full MasakariException message, (see __init__)
  156         return self.args[0]
  157 
  158 
  159 class APIException(MasakariException):
  160     msg_fmt = _("Error while requesting %(service)s API.")
  161 
  162     def __init__(self, message=None, **kwargs):
  163         if 'service' not in kwargs:
  164             kwargs['service'] = 'unknown'
  165         super(APIException, self).__init__(message, **kwargs)
  166 
  167 
  168 class APITimeout(APIException):
  169     msg_fmt = _("Timeout while requesting %(service)s API.")
  170 
  171 
  172 class Conflict(MasakariException):
  173     msg_fmt = _("Conflict")
  174     code = http.CONFLICT
  175 
  176 
  177 class Invalid(MasakariException):
  178     msg_fmt = _("Bad Request - Invalid Parameters")
  179     code = http.BAD_REQUEST
  180 
  181 
  182 class InvalidName(Invalid):
  183     msg_fmt = _("An invalid 'name' value was provided. "
  184                 "The name must be: %(reason)s")
  185 
  186 
  187 class InvalidInput(Invalid):
  188     msg_fmt = _("Invalid input received: %(reason)s")
  189 
  190 
  191 class InvalidAPIVersionString(Invalid):
  192     msg_fmt = _("API Version String %(version)s is of invalid format. Must "
  193                 "be of format MajorNum.MinorNum.")
  194 
  195 
  196 class MalformedRequestBody(MasakariException):
  197     msg_fmt = _("Malformed message body: %(reason)s")
  198 
  199 
  200 # NOTE: NotFound should only be used when a 404 error is
  201 # appropriate to be returned
  202 class NotFound(MasakariException):
  203     msg_fmt = _("Resource could not be found.")
  204     code = http.NOT_FOUND
  205 
  206 
  207 class ConfigNotFound(NotFound):
  208     msg_fmt = _("Could not find config at %(path)s")
  209 
  210 
  211 class Forbidden(MasakariException):
  212     msg_fmt = _("Forbidden")
  213     code = http.FORBIDDEN
  214 
  215 
  216 class AdminRequired(Forbidden):
  217     msg_fmt = _("User does not have admin privileges")
  218 
  219 
  220 class PolicyNotAuthorized(Forbidden):
  221     msg_fmt = _("Policy doesn't allow %(action)s to be performed.")
  222 
  223 
  224 class PasteAppNotFound(MasakariException):
  225     msg_fmt = _("Could not load paste app '%(name)s' from %(path)s")
  226 
  227 
  228 class InvalidContentType(Invalid):
  229     msg_fmt = _("Invalid content type %(content_type)s.")
  230 
  231 
  232 class VersionNotFoundForAPIMethod(Invalid):
  233     msg_fmt = _("API version %(version)s is not supported on this method.")
  234 
  235 
  236 class InvalidGlobalAPIVersion(Invalid):
  237     msg_fmt = _("Version %(req_ver)s is not supported by the API. Minimum "
  238                 "is %(min_ver)s and maximum is %(max_ver)s.")
  239 
  240 
  241 class ApiVersionsIntersect(Invalid):
  242     msg_fmt = _("Version of %(name) %(min_ver) %(max_ver) intersects "
  243                 "with another versions.")
  244 
  245 
  246 class ValidationError(Invalid):
  247     msg_fmt = "%(detail)s"
  248 
  249 
  250 class InvalidSortKey(Invalid):
  251     msg_fmt = _("Sort key supplied was not valid.")
  252 
  253 
  254 class MarkerNotFound(NotFound):
  255     msg_fmt = _("Marker %(marker)s could not be found.")
  256 
  257 
  258 class FailoverSegmentNotFound(NotFound):
  259     msg_fmt = _("No failover segment with id %(id)s.")
  260 
  261 
  262 class HostNotFound(NotFound):
  263     msg_fmt = _("No host with id %(id)s.")
  264 
  265 
  266 class NotificationNotFound(NotFound):
  267     msg_fmt = _("No notification with id %(id)s.")
  268 
  269 
  270 class FailoverSegmentNotFoundByName(FailoverSegmentNotFound):
  271     msg_fmt = _("Failover segment with name %(segment_name)s could not "
  272                 "be found.")
  273 
  274 
  275 class HostNotFoundByName(HostNotFound):
  276     msg_fmt = _("Host with name %(host_name)s could not be found.")
  277 
  278 
  279 class ComputeNotFoundByName(NotFound):
  280     msg_fmt = _("Compute service with name %(compute_name)s could not "
  281                 "be found.")
  282 
  283 
  284 class FailoverSegmentExists(MasakariException):
  285     msg_fmt = _("Failover segment with name %(name)s already exists.")
  286 
  287 
  288 class HostExists(MasakariException):
  289     msg_fmt = _("Host with name %(name)s already exists.")
  290 
  291 
  292 class Unauthorized(MasakariException):
  293     msg_fmt = _("Not authorized.")
  294     code = http.UNAUTHORIZED
  295 
  296 
  297 class ObjectActionError(MasakariException):
  298     msg_fmt = _('Object action %(action)s failed because: %(reason)s')
  299 
  300 
  301 class OrphanedObjectError(MasakariException):
  302     msg_fmt = _('Cannot call %(method)s on orphaned %(objtype)s object')
  303 
  304 
  305 class DuplicateNotification(Invalid):
  306     msg_fmt = _('Duplicate notification received for type: %(type)s')
  307     code = http.CONFLICT
  308 
  309 
  310 class HostOnMaintenanceError(Invalid):
  311     msg_fmt = _('Host %(host_name)s is already under maintenance.')
  312     code = http.CONFLICT
  313 
  314 
  315 class HostRecoveryFailureException(MasakariException):
  316     msg_fmt = _('Failed to execute host recovery.')
  317 
  318 
  319 class InstanceRecoveryFailureException(MasakariException):
  320     msg_fmt = _('Failed to execute instance recovery workflow.')
  321 
  322 
  323 class SkipInstanceRecoveryException(MasakariException):
  324     msg_fmt = _('Skipping execution of instance recovery workflow.')
  325 
  326 
  327 class SkipProcessRecoveryException(MasakariException):
  328     msg_fmt = _('Skipping execution of process recovery workflow.')
  329 
  330 
  331 class SkipHostRecoveryException(MasakariException):
  332     msg_fmt = _('Skipping execution of host recovery workflow.')
  333 
  334 
  335 class ProcessRecoveryFailureException(MasakariException):
  336     msg_fmt = _('Failed to execute process recovery workflow.')
  337 
  338 
  339 class DBNotAllowed(MasakariException):
  340     msg_fmt = _('%(binary)s attempted direct database access which is '
  341                 'not allowed by policy')
  342 
  343 
  344 class FailoverSegmentInUse(Conflict):
  345     msg_fmt = _("Failover segment %(uuid)s can't be updated as it is in-use "
  346                 "to process notifications.")
  347 
  348 
  349 class HostInUse(Conflict):
  350     msg_fmt = _("Host %(uuid)s can't be updated as it is in-use to process "
  351                 "notifications.")
  352 
  353 
  354 class ReservedHostsUnavailable(MasakariException):
  355     msg_fmt = _('No reserved_hosts available for evacuation.')
  356 
  357 
  358 class LockAlreadyAcquired(MasakariException):
  359     msg_fmt = _('Lock is already acquired on %(resource)s.')
  360 
  361 
  362 class IgnoreInstanceRecoveryException(MasakariException):
  363     msg_fmt = _('Instance recovery is ignored.')
  364 
  365 
  366 class HostNotFoundUnderFailoverSegment(HostNotFound):
  367     msg_fmt = _("Host '%(host_uuid)s' under failover_segment "
  368                 "'%(segment_uuid)s' could not be found.")
  369 
  370 
  371 class InstanceEvacuateFailed(MasakariException):
  372     msg_fmt = _("Failed to evacuate instance %(instance_uuid)s")