python-novaclient/novaclient/exceptions.py
Ziad Sawalha 38bc7ea570 Handle Ambiguous Endpoints Correctly
- Added --service_name argument to allow selecting
  endpoints by service name
- Renamed endpoint_name argument to endpoint_type (this breaks
  compatibility)
- Return AmbiguousEndpoints error if more than one endpoint
  matches filter
- Also addresses bug 924052

Use case:
  $ nova --projectid xxx --version 1.1 --password xxx --username xxx --url https://identity.openstackcloud.com/ image-list
  Found more than one valid endpoint. Use a more restrictive filter
  AmbiguousEndpoints: [
    {'serviceName': 'New Cloud', 'region': 'Test', 'publicURL': 'https://test.openstackcloud.com/v1.1/tttt', 'tenantId': 'tttt'},
    {'serviceName': 'Old Cloud', 'publicURL': 'https://servers.openstackcloud.com/v1.0/tttt', 'tenantId': 'tttt'}]

  $ nova --projectid tttt --version 1.1 --password xxx --username xxx --url https://identity.openstackcloud.com/ --service_name 'New Cloud' image-list
  +--------------------------------------+-----------------------------+--------+--------+
  |                  ID                  |             Name            | Status | Server |
  +--------------------------------------+-----------------------------+--------+--------+
  | 346f4039-a81e-4444-9223-4a3d13592a07 | Debian Squeeze (6.0)        | ACTIVE |        |
  | ac8985ea-c09e-4544-82af-eb459a02a6b2 | Fedora 15                   | ACTIVE |        |
  | ddddc02e-92fa-4f44-b36f-55b39bf66a67 | CentOS 5.6                  | ACTIVE |        |
  +--------------------------------------+-----------------------------+--------+--------+

Change-Id: I9a10b9ad5e5b9cf6e762659013496a93a79774db
2012-01-31 18:37:36 -06:00

136 lines
3.3 KiB
Python

# Copyright 2010 Jacob Kaplan-Moss
"""
Exception definitions.
"""
class UnsupportedVersion(Exception):
"""Indicates that the user is trying to use an unsupported
version of the API"""
pass
class CommandError(Exception):
pass
class AuthorizationFailure(Exception):
pass
class NoTokenLookupException(Exception):
"""This form of authentication does not support looking up
endpoints from an existing token."""
pass
class EndpointNotFound(Exception):
"""Could not find Service or Region in Service Catalog."""
pass
class AmbiguousEndpoints(Exception):
"""Found more than one matching endpoint in Service Catalog."""
def __init__(self, endpoints=None):
self.endpoints = endpoints
def __str__(self):
return "AmbiguousEndpoints: %s" % repr(self.endpoints)
class ClientException(Exception):
"""
The base exception class for all exceptions this library raises.
"""
def __init__(self, code, message=None, details=None):
self.code = code
self.message = message or self.__class__.message
self.details = details
def __str__(self):
return "%s (HTTP %s)" % (self.message, self.code)
class BadRequest(ClientException):
"""
HTTP 400 - Bad request: you sent some malformed data.
"""
http_status = 400
message = "Bad request"
class Unauthorized(ClientException):
"""
HTTP 401 - Unauthorized: bad credentials.
"""
http_status = 401
message = "Unauthorized"
class Forbidden(ClientException):
"""
HTTP 403 - Forbidden: your credentials don't give you access to this
resource.
"""
http_status = 403
message = "Forbidden"
class NotFound(ClientException):
"""
HTTP 404 - Not found
"""
http_status = 404
message = "Not found"
class OverLimit(ClientException):
"""
HTTP 413 - Over limit: you're over the API limits for this time period.
"""
http_status = 413
message = "Over limit"
# NotImplemented is a python keyword.
class HTTPNotImplemented(ClientException):
"""
HTTP 501 - Not Implemented: the server does not support this operation.
"""
http_status = 501
message = "Not Implemented"
# In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
# so we can do this:
# _code_map = dict((c.http_status, c)
# for c in ClientException.__subclasses__())
#
# Instead, we have to hardcode it:
_code_map = dict((c.http_status, c) for c in [BadRequest, Unauthorized,
Forbidden, NotFound, OverLimit, HTTPNotImplemented])
def from_response(response, body):
"""
Return an instance of an ClientException or subclass
based on an httplib2 response.
Usage::
resp, body = http.request(...)
if resp.status != 200:
raise exception_from_response(resp, body)
"""
cls = _code_map.get(response.status, ClientException)
if body:
message = "n/a"
details = "n/a"
if hasattr(body, 'keys'):
error = body[body.keys()[0]]
message = error.get('message', None)
details = error.get('details', None)
return cls(code=response.status, message=message, details=details)
else:
return cls(code=response.status)