deb-python-senlinclient/senlinclient/common/exc.py
jonnary 4273feb35b Update imoprt order
This patch updates import order.

Co-Authored-By: Qiming Teng (tengqim@cn.ibm.com)
Change-Id: Ie3c33dddb32f70d7a9663e8125a9a073cbd7810c
2017-02-15 01:58:01 -05:00

310 lines
7.2 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.
from keystoneauth1.exceptions import base as kae_base
from keystoneauth1.exceptions import http as kae_http
from openstack import exceptions as sdkexc
from oslo_serialization import jsonutils
from requests import exceptions as reqexc
import six
from senlinclient.common.i18n import _
verbose = False
class BaseException(Exception):
"""An error occurred."""
def __init__(self, message=None):
self.message = message
def __str__(self):
return self.message or self.__class__.__doc__
class CommandError(BaseException):
"""Invalid usage of CLI."""
class FileFormatError(BaseException):
"""Illegal file format detected."""
class HTTPException(BaseException):
"""Base exception for all HTTP-derived exceptions."""
code = 'N/A'
def __init__(self, error=None):
super(HTTPException, self).__init__(error)
try:
self.error = error
if 'error' not in self.error:
raise KeyError(_('Key "error" not exists'))
except KeyError:
# If key 'error' does not exist, self.message becomes
# no sense. In this case, we return doc of current
# exception class instead.
self.error = {'error': {'message': self.__class__.__doc__}}
except Exception:
self.error = {'error':
{'message': self.message or self.__class__.__doc__}}
def __str__(self):
message = self.error['error'].get('message', 'Internal Error')
if verbose:
traceback = self.error['error'].get('traceback', '')
return (_('ERROR: %(message)s\n%(traceback)s') %
{'message': message, 'traceback': traceback})
else:
code = self.error['error'].get('code', 'Unknown')
return _('ERROR(%(code)s): %(message)s') % {'code': code,
'message': message}
class ClientError(HTTPException):
pass
class ServerError(HTTPException):
pass
class HTTPBadRequest(ClientError):
# 400
pass
class HTTPUnauthorized(ClientError):
# 401
pass
class HTTPForbidden(ClientError):
# 403
pass
class HTTPNotFound(ClientError):
# 404
pass
class HTTPMethodNotAllowed(ClientError):
# 405
pass
class HTTPNotAcceptable(ClientError):
# 406
pass
class HTTPProxyAuthenticationRequired(ClientError):
# 407
pass
class HTTPRequestTimeout(ClientError):
# 408
pass
class HTTPConflict(ClientError):
# 409
pass
class HTTPGone(ClientError):
# 410
pass
class HTTPLengthRequired(ClientError):
# 411
pass
class HTTPPreconditionFailed(ClientError):
# 412
pass
class HTTPRequestEntityTooLarge(ClientError):
# 413
pass
class HTTPRequestURITooLong(ClientError):
# 414
pass
class HTTPUnsupportedMediaType(ClientError):
# 415
pass
class HTTPRequestRangeNotSatisfiable(ClientError):
# 416
pass
class HTTPExpectationFailed(ClientError):
# 417
pass
class HTTPInternalServerError(ServerError):
# 500
pass
class HTTPNotImplemented(ServerError):
# 501
pass
class HTTPBadGateway(ServerError):
# 502
pass
class HTTPServiceUnavailable(ServerError):
# 503
pass
class HTTPGatewayTimeout(ServerError):
# 504
pass
class HTTPVersionNotSupported(ServerError):
# 505
pass
class ConnectionRefused(HTTPException):
# 111
pass
_EXCEPTION_MAP = {
111: ConnectionRefused,
400: HTTPBadRequest,
401: HTTPUnauthorized,
403: HTTPForbidden,
404: HTTPNotFound,
405: HTTPMethodNotAllowed,
406: HTTPNotAcceptable,
407: HTTPProxyAuthenticationRequired,
408: HTTPRequestTimeout,
409: HTTPConflict,
410: HTTPGone,
411: HTTPLengthRequired,
412: HTTPPreconditionFailed,
413: HTTPRequestEntityTooLarge,
414: HTTPRequestURITooLong,
415: HTTPUnsupportedMediaType,
416: HTTPRequestRangeNotSatisfiable,
417: HTTPExpectationFailed,
500: HTTPInternalServerError,
501: HTTPNotImplemented,
502: HTTPBadGateway,
503: HTTPServiceUnavailable,
504: HTTPGatewayTimeout,
505: HTTPVersionNotSupported,
}
def parse_exception(exc):
"""Parse exception code and yield useful information.
:param exc: details of the exception.
"""
if isinstance(exc, sdkexc.HttpException):
if exc.details is None:
data = exc.response.json()
code = data.get('code', None)
message = data.get('message', None)
error = data.get('error', None)
if error:
record = {
'error': {
'code': exc.http_status,
'message': message or exc.message
}
}
else:
info = data.values()[0]
record = {
'error': {
'code': info.get('code', code),
'message': info.get('message', message)
}
}
else:
try:
record = jsonutils.loads(exc.details)
except Exception:
# If the exc.details is not in JSON format
record = {
'error': {
'code': exc.http_status,
'message': exc,
}
}
elif isinstance(exc, reqexc.RequestException):
# Exceptions that are not captured by SDK
record = {
'error': {
'code': exc.message[1].errno,
'message': exc.message[0],
}
}
elif isinstance(exc, six.string_types):
record = jsonutils.loads(exc)
# some exception from keystoneauth1 is not shaped by SDK
elif isinstance(exc, kae_http.HttpError):
record = {
'error': {
'code': exc.http_status,
'message': exc.message
}
}
elif isinstance(exc, kae_base.ClientException):
record = {
'error': {
# other exceptions from keystoneauth1 is an internal
# error to senlin, so set status code to 500
'code': 500,
'message': exc.message
}
}
else:
print(_('Unknown exception: %s') % exc)
return
try:
code = record['error']['code']
except KeyError as err:
print(_('Malformed exception record, missing field "%s"') % err)
print(_('Original error record: %s') % record)
return
if code in _EXCEPTION_MAP:
inst = _EXCEPTION_MAP.get(code)
raise inst(record)
else:
raise HTTPException(record)