karbor/karbor/exception.py

460 lines
13 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""karbor base exception handling.
Includes decorator for re-raising karbor-type exceptions.
SHOULD include dedicated exception logging.
"""
import sys
from oslo_config import cfg
from oslo_log import log as logging
from oslo_versionedobjects import exception as obj_exc
import six
import webob.exc
from webob.util import status_generic_reasons
from webob.util import status_reasons
from six.moves import http_client
from karbor.i18n import _
LOG = logging.getLogger(__name__)
exc_log_opts = [
cfg.BoolOpt('fatal_exception_format_errors',
default=False,
help='Make exception message format errors fatal.'),
]
CONF = cfg.CONF
CONF.register_opts(exc_log_opts)
class ConvertedException(webob.exc.WSGIHTTPException):
def __init__(self, code=500, title="",
explanation=""):
self.code = code
# There is a strict rule about constructing status line for HTTP:
# '...Status-Line, consisting of the protocol version followed by a
# numeric status code and its associated textual phrase, with each
# element separated by SP characters'
# (http://www.faqs.org/rfcs/rfc2616.html)
# 'code' and 'title' can not be empty because they correspond
# to numeric status code and its associated text
if title:
self.title = title
else:
try:
self.title = status_reasons[self.code]
except KeyError:
generic_code = self.code // 100
self.title = status_generic_reasons[generic_code]
self.explanation = explanation
super(ConvertedException, self).__init__()
class Error(Exception):
pass
class KarborException(Exception):
"""Base karbor Exception
To correctly use this class, inherit from it and define
a 'message' property. That message will get printf'd
with the keyword arguments provided to the constructor.
"""
message = _("An unknown exception occurred.")
code = http_client.INTERNAL_SERVER_ERROR
headers = {}
safe = True
def __init__(self, message=None, **kwargs):
"""Initiate the instance of KarborException
There are two ways to initiate the instance.
1. Specify the value of 'message' and leave the 'kwargs' None.
2. Leave 'message' None, and specify the keyword arguments matched
with the format of KarborException.message. Especially, can't
use the 'message' as the key in the 'kwargs', otherwise, the
first argument('message') will be set.
Note: This class doesn't support to create instance of KarborException
with another instance.
"""
self.kwargs = kwargs
if 'code' not in self.kwargs:
try:
self.kwargs['code'] = self.code
except AttributeError:
pass
if not message:
try:
message = self.message % kwargs
except Exception:
exc_info = sys.exc_info()
# kwargs doesn't match a variable in the message
# log the issue and the kwargs
LOG.exception('Exception in string format operation')
for name, value in kwargs.items():
LOG.error("%(name)s: %(value)s",
{'name': name, 'value': value})
if CONF.fatal_exception_format_errors:
six.reraise(*exc_info)
# at least get the core message out if something happened
message = self.message
elif isinstance(message, Exception):
message = six.text_type(message)
# NOTE(luisg): We put the actual message in 'msg' so that we can access
# it, because if we try to access the message via 'message' it will be
# overshadowed by the class' message attribute
self.msg = message
super(KarborException, self).__init__(message)
def __unicode__(self):
return self.msg
class NotAuthorized(KarborException):
message = _("Not authorized.")
code = http_client.FORBIDDEN
class AdminRequired(NotAuthorized):
message = _("User does not have admin privileges")
class PolicyNotAuthorized(NotAuthorized):
message = _("Policy doesn't allow %(action)s to be performed.")
class AuthorizationFailure(NotAuthorized):
message = _("Authorization for %(obj)s is failed ")
class Invalid(KarborException):
message = _("Unacceptable parameters.")
code = http_client.BAD_REQUEST
class InvalidParameterValue(Invalid):
message = _("%(err)s")
class InvalidInput(Invalid):
message = _("Invalid input received: %(reason)s")
class ScheduledOperationExist(Invalid):
message = _("Scheduled Operation%(op_id)s exists")
class NotFound(KarborException):
message = _("Resource could not be found.")
code = http_client.NOT_FOUND
safe = True
class ConfigNotFound(NotFound):
message = _("Could not find config at %(path)s")
class MalformedRequestBody(KarborException):
message = _("Malformed message body: %(reason)s")
class InvalidContentType(Invalid):
message = _("Invalid content type %(content_type)s.")
class InvalidProtectableInstance(Invalid):
message = _("Invalid protectable instance.")
class PasteAppNotFound(NotFound):
message = _("Could not load paste app '%(name)s' from %(path)s")
class ServiceNotFound(NotFound):
message = _("Service %(service_id)s could not be found.")
class HostBinaryNotFound(NotFound):
message = _("Could not find binary %(binary)s on host %(host)s.")
class TriggerNotFound(NotFound):
message = _("Trigger %(id)s could not be found.")
class ScheduledOperationNotFound(NotFound):
message = _("Scheduled Operation %(id)s could not be found.")
class ScheduledOperationStateNotFound(NotFound):
message = _("Scheduled Operation State %(op_id)s could not be found.")
class ScheduledOperationLogNotFound(NotFound):
message = _("Scheduled Operation Log %(log_id)s could not be found.")
class ListProtectableResourceFailed(KarborException):
message = _("List protectable resources of type %(type)s failed: "
"%(reason)s")
class ProtectableResourceNotFound(NotFound):
message = _("The resource %(id)s of type %(type)s could not be found: "
"%(reason)s")
class ProtectableResourceInvalidStatus(KarborException):
message = _("The resource %(id)s of type %(type)s has a invalid "
"status: %(status)s")
class InvalidOperationObject(Invalid):
message = _("The operation %(operation_id)s is invalid")
class DeleteTriggerNotAllowed(NotAuthorized):
message = _("Can not delete trigger %(trigger_id)s")
class AccessCheckpointNotAllowed(NotAuthorized):
message = _("Access checkpoint %(checkpoint_id)s is not allowed")
class DeleteCheckpointNotAllowed(NotAuthorized):
message = _("Delete checkpoint %(checkpoint_id)s is not allowed")
class ClassNotFound(NotFound):
message = _("Class %(class_name)s could not be found: %(exception)s")
class InvalidOperationDefinition(Invalid):
message = _("Invalid operation definition, reason:%(reason)s")
OrphanedObjectError = obj_exc.OrphanedObjectError
ObjectActionError = obj_exc.ObjectActionError
class PlanNotFound(NotFound):
message = _("Plan %(plan_id)s could not be found.")
class OperationLogFound(NotFound):
message = _("Operation log %(operation_log_id)s could not be found.")
class RestoreNotFound(NotFound):
message = _("Restore %(restore_id)s could not be found.")
class VerificationNotFound(NotFound):
message = _("Verification %(verification_id)s could not be found.")
class OperationLogNotFound(NotFound):
message = _("OperationLog %(restore_id)s could not be found.")
class InvalidPlan(Invalid):
message = _("Invalid plan: %(reason)s")
class ProtectableTypeNotFound(NotFound):
message = _("ProtectableType %(protectable_type)s could"
" not be found.")
class ProtectionPluginNotFound(NotFound):
message = _("Protection Plugin for %(type)s could"
" not be found.")
class ProviderNotFound(NotFound):
message = _("Provider %(provider_id)s could"
" not be found.")
class CheckpointRecordNotFound(NotFound):
message = _("CheckpointRecord %(id)s could not be found.")
class CreateResourceFailed(KarborException):
message = _("Create %(name)s failed: %(reason)s, id=%(resource_id)s,"
" type=%(resource_type)s")
class DeleteResourceFailed(KarborException):
message = _("Delete %(name)s failed: %(reason)s, id=%(resource_id)s,"
" type=%(resource_type)s")
class RestoreResourceFailed(KarborException):
message = _("Restore %(name)s failed: %(reason)s, id=%(resource_id)s,"
" type=%(resource_type)s")
class VerifyResourceFailed(KarborException):
message = _("Verify %(name)s failed: %(reason)s, id=%(resource_id)s,"
" type=%(resource_type)s")
class FlowError(KarborException):
message = _("Flow: %(flow)s, Error: %(error)s")
class CheckpointNotFound(NotFound):
message = _("Checkpoint %(checkpoint_id)s could"
" not be found.")
class BankCreateObjectFailed(KarborException):
message = _("Create Object in Bank Failed: %(reason)s")
class BankUpdateObjectFailed(KarborException):
message = _("Update Object %(key)s in Bank Failed: %(reason)s")
class BankDeleteObjectFailed(KarborException):
message = _("Delete Object %(key)s in Bank Failed: %(reason)s")
class BankGetObjectFailed(KarborException):
message = _("Get Object %(key)s in Bank Failed: %(reason)s")
class BankListObjectsFailed(KarborException):
message = _("Get Object in Bank Failed: %(reason)s")
class BankReadonlyViolation(KarborException):
message = _("Bank read-only violation")
class AcquireLeaseFailed(KarborException):
message = _("Acquire Lease in Failed: %(reason)s")
class CreateContainerFailed(KarborException):
message = _("Create Container in Bank Failed: %(reason)s")
class CreateBucketFailed(KarborException):
message = _("Create Bucket in Bank Failed: %(reason)s")
class TriggerIsInvalid(Invalid):
message = _("Trigger%(trigger_id)s is invalid.")
class InvalidTaskFlowObject(Invalid):
message = _("The task flow is invalid: %(reason)s")
class InvalidOriginalId(Invalid):
message = _("The original_id: %(original_id)s is invalid.")
class CheckpointNotAvailable(KarborException):
message = _("The checkpoint %(checkpoint_id)s is not available")
class CheckpointNotBeDeleted(KarborException):
message = _("The checkpoint %(checkpoint_id)s can not be deleted.")
class CheckpointNotBeReset(KarborException):
message = _("The checkpoint %(checkpoint_id)s can not be reset.")
class GetProtectionNetworkSubResourceFailed(KarborException):
message = _("Get protection network sub-resources of type %(type)s failed:"
" %(reason)s")
class QuotaNotFound(NotFound):
message = _("Quota could not be found")
class QuotaResourceUnknown(QuotaNotFound):
message = _("Unknown quota resources %(unknown)s.")
class ProjectQuotaNotFound(QuotaNotFound):
message = _("Quota for project %(project_id)s could not be found.")
class QuotaClassNotFound(QuotaNotFound):
message = _("Quota class %(class_name)s could not be found.")
class QuotaUsageNotFound(QuotaNotFound):
message = _("Quota usage for project %(project_id)s could not be found.")
class ReservationNotFound(QuotaNotFound):
message = _("Quota reservation %(uuid)s could not be found.")
class OverQuota(KarborException):
message = _("Quota exceeded for resources: %(overs)s")
class InvalidReservationExpiration(Invalid):
message = _("Invalid reservation expiration %(expire)s.")
class InvalidQuotaValue(Invalid):
message = _("Change would make usage less than 0 for the following "
"resources: %(unders)s.")
class QuotaError(KarborException):
message = _("Quota exceeded: code=%(code)s")
code = 413
headers = {'Retry-After': '0'}
safe = True
class PlanLimitExceeded(QuotaError):
message = _("Maximum number of plans allowed (%(allowed)d) exceeded")
class UnexpectedOverQuota(QuotaError):
message = _("Unexpected over quota on %(name)s.")
class InvalidName(Invalid):
message = _("An invalid 'name' value was provided. %(reason)s")
class ValidationError(Invalid):
message = "%(detail)s"