python-cloudkittyclient/cloudkittyclient/exc.py
Luka Peschke d070f6a68c Rewrite of the client
The client has been completely rewritten in order to use cliff. The code
should be easier to maintain: authentication is now entirely handled by
keystoneauth, CloudKitty's client and CK's OSC plugin use the exact same
classes (no code duplication).

New features for users:

  * Client-side CSV report generation: It is possible for users to generate
    CSV reports with the new client. There is a default format, but reports
    may also be configured through a yaml config file. (see documentation)

  * The documentation has been improved. (A few examples on how to use the
    python library + complete API bindings and CLI reference).

  * It is now possible to use the client without Keystone authentication (this
    requires that CK's API is configured to use the noauth auth strategy).

  * Various features are brought by cliff: completion, command output formatting
    (table, shell, yaml, json...).

New features for developpers:

  * Python 2.7/3.5 compatible 'python-cloudkittyclient' module.

  * Integration tests (for 'openstack rating' and 'cloudkitty') have been
    added. These allow to create gate jobs running against a CK devstack

  * Tests are now ran with stestr instead of testr, which allows a better
    control over execution.

  * The dependency list has been reduced and upper constraints have been set.

Change-Id: I7c6afa46138d499b37b8be3d049b23ab5302a928
Task: 6589
Story: 2001614
2018-06-15 12:08:21 +02:00

130 lines
3.1 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.
import json
import sys
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 InvalidEndpoint(BaseException):
"""The provided endpoint is invalid."""
class ArgumentRequired(BaseException):
"""A required argument was not provided."""
class CommunicationError(BaseException):
"""Unable to communicate with server."""
class InvalidArgumentError(BaseException):
"""Exception raised when a provided argument is invalid"""
class NotUpdatableError(BaseException):
"""This Resource is not updatable."""
def __init__(self, resource):
message = "%s is not updatable" % resource
super(BaseException, self).__init__(message)
class HTTPException(BaseException):
"""Base exception for all HTTP-derived exceptions."""
code = 'N/A'
def __init__(self, details=None):
self.details = details
def __str__(self):
try:
data = json.loads(self.details)
message = data.get("error_message", {}).get("faultstring")
if message:
return "%s (HTTP %s) ERROR %s" % (
self.__class__.__name__, self.code, message)
except (ValueError, TypeError, AttributeError):
pass
return "%s (HTTP %s)" % (self.__class__.__name__, self.code)
class HTTPBadRequest(HTTPException):
code = 400
class HTTPUnauthorized(HTTPException):
code = 401
class HTTPForbidden(HTTPException):
code = 403
class HTTPNotFound(HTTPException):
code = 404
class HTTPMethodNotAllowed(HTTPException):
code = 405
class HTTPConflict(HTTPException):
code = 409
class HTTPOverLimit(HTTPException):
code = 413
class HTTPInternalServerError(HTTPException):
code = 500
class HTTPNotImplemented(HTTPException):
code = 501
class HTTPBadGateway(HTTPException):
code = 502
class HTTPServiceUnavailable(HTTPException):
code = 503
# NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception
# classes
_code_map = {}
for obj_name in dir(sys.modules[__name__]):
if obj_name.startswith('HTTP'):
obj = getattr(sys.modules[__name__], obj_name)
_code_map[obj.code] = obj
def from_response(response, details=None):
"""Return an instance of an HTTPException based on httplib response."""
cls = _code_map.get(response.status, HTTPException)
return cls(details)