exceptions.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """
  2. Exception definitions.
  3. """
  4. import json
  5. class CommandError(Exception):
  6. pass
  7. class NoTokenLookupException(Exception):
  8. """This form of authentication does not support looking up
  9. endpoints from an existing token."""
  10. pass
  11. class EndpointNotFound(Exception):
  12. """Could not find Service or Region in Service Catalog."""
  13. pass
  14. class SchemaNotFound(KeyError):
  15. """Could not find schema"""
  16. pass
  17. class ClientException(Exception):
  18. """
  19. The base exception class for all exceptions this library raises.
  20. """
  21. def __init__(self, code, message=None, details=None):
  22. self.code = code
  23. self.message = message or self.__class__.message
  24. self.details = details
  25. def __str__(self):
  26. return "%s (HTTP %s): %s" % (self.message, self.code, self.details)
  27. class BadRequest(ClientException):
  28. """
  29. HTTP 400 - Bad request: you sent some malformed data.
  30. """
  31. http_status = 400
  32. message = "Bad request"
  33. class Unauthorized(ClientException):
  34. """
  35. HTTP 401 - Unauthorized: bad credentials.
  36. """
  37. http_status = 401
  38. message = "Unauthorized"
  39. class Forbidden(ClientException):
  40. """
  41. HTTP 403 - Forbidden: your credentials don't give you access to this
  42. resource.
  43. """
  44. http_status = 403
  45. message = "Forbidden"
  46. class NotFound(ClientException):
  47. """
  48. HTTP 404 - Not found
  49. """
  50. http_status = 404
  51. message = "Not found"
  52. class NotAcceptable(ClientException):
  53. """
  54. HTTP 406 - Not Acceptable
  55. """
  56. http_status = 406
  57. message = "Not acceptable"
  58. class Conflict(ClientException):
  59. """
  60. HTTP 409 - Conflict
  61. """
  62. http_status = 409
  63. message = "Conflict"
  64. class OverLimit(ClientException):
  65. """
  66. HTTP 413 - Over limit: you're over the API limits for this time period.
  67. """
  68. http_status = 413
  69. message = "Over limit"
  70. class HTTPInternalError(ClientException):
  71. """
  72. HTTP 500 - Internal error
  73. """
  74. http_status = 500
  75. message = "Internal error"
  76. # NotImplemented is a python keyword.
  77. class HTTPNotImplemented(ClientException):
  78. """
  79. HTTP 501 - Not Implemented: the server does not support this operation.
  80. """
  81. http_status = 501
  82. message = "Not Implemented"
  83. # In Python 2.4 Exception is old-style and thus doesn't have a __subclasses__()
  84. # so we can do this:
  85. # _code_map = dict((c.http_status, c)
  86. # for c in ClientException.__subclasses__())
  87. #
  88. # Instead, we have to hardcode it:
  89. _code_map = dict((c.http_status, c) for c in [BadRequest, Unauthorized,
  90. Forbidden, NotFound, NotAcceptable, Conflict, OverLimit,
  91. HTTPInternalError, HTTPNotImplemented])
  92. def from_response(response, body):
  93. """
  94. Return an instance of an ClientException or subclass
  95. based on an httplib2 response.
  96. Usage::
  97. resp, body = http.request(...)
  98. if resp.status != 200:
  99. raise exception_from_response(resp, body)
  100. """
  101. from lib import utils
  102. cls = _code_map.get(response.status, ClientException)
  103. body_json = None
  104. if body is not None and len(body) > 0 and body[0] == '{':
  105. body_json = json.loads(body)
  106. if body_json:
  107. if 'code' in body_json and 'details' in body_json:
  108. details = utils.ensure_ascii(body_json['details'])
  109. return cls(code=response.status, details=details)
  110. elif 'error' in body_json and 'code' in body_json['error'] and \
  111. 'message' in body_json['error'] and \
  112. 'title' in body_json['error']:
  113. return cls(code=body_json['error']['code'],
  114. message=body_json['error']['title'],
  115. details=body_json['error']['message'])
  116. if body:
  117. message = "Unable to communicate with API service: %s." % body
  118. details = None
  119. return cls(code=response.status, message=message, details=details)
  120. return cls(code=response.status)