~ubuntu-branches/ubuntu/trusty/python-keystoneclient/trusty-proposed

« back to all changes in this revision

Viewing changes to keystoneclient/apiclient/exceptions.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short, Adam Gandelman, Chuck Short
  • Date: 2013-11-14 10:51:32 UTC
  • mfrom: (1.1.23)
  • Revision ID: package-import@ubuntu.com-20131114105132-p1o428l7fclasv9e
Tags: 1:0.4.1-0ubuntu1
[ Adam Gandelman ]
* debian/patches: Refreshed.
* debian/patches/use-mox-dependency.patch: Use mox instead of mox3
  dependency.

[ Chuck Short ]
* New upstream release.
* debian/control:
  - open icehouse release.
  - Dropped python-d2to1 and python-httplib2 dependency.
* debian/patches/skip-tests-ubuntu.patch: Dropped no longer needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
 
2
 
 
3
# Copyright 2010 Jacob Kaplan-Moss
 
4
# Copyright 2011 Nebula, Inc.
 
5
# Copyright 2013 Alessio Ababilov
 
6
# Copyright 2013 OpenStack Foundation
 
7
# All Rights Reserved.
 
8
#
 
9
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
 
10
#    not use this file except in compliance with the License. You may obtain
 
11
#    a copy of the License at
 
12
#
 
13
#         http://www.apache.org/licenses/LICENSE-2.0
 
14
#
 
15
#    Unless required by applicable law or agreed to in writing, software
 
16
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 
17
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 
18
#    License for the specific language governing permissions and limitations
 
19
#    under the License.
 
20
 
 
21
"""
 
22
Exception definitions.
 
23
"""
 
24
 
 
25
import itertools
 
26
 
 
27
 
 
28
class ClientException(Exception):
 
29
    """The base exception class for all exceptions this library raises.
 
30
    """
 
31
    pass
 
32
 
 
33
 
 
34
class MissingArgs(ClientException):
 
35
    """Supplied arguments are not sufficient for calling a function."""
 
36
    def __init__(self, missing):
 
37
        self.missing = missing
 
38
        msg = "Missing argument(s): %s" % ", ".join(missing)
 
39
        super(MissingArgs, self).__init__(msg)
 
40
 
 
41
 
 
42
class ValidationError(ClientException):
 
43
    """Error in validation on API client side."""
 
44
    pass
 
45
 
 
46
 
 
47
class UnsupportedVersion(ClientException):
 
48
    """User is trying to use an unsupported version of the API."""
 
49
    pass
 
50
 
 
51
 
 
52
class CommandError(ClientException):
 
53
    """Error in CLI tool."""
 
54
    pass
 
55
 
 
56
 
 
57
class AuthorizationFailure(ClientException):
 
58
    """Cannot authorize API client."""
 
59
    pass
 
60
 
 
61
 
 
62
class AuthPluginOptionsMissing(AuthorizationFailure):
 
63
    """Auth plugin misses some options."""
 
64
    def __init__(self, opt_names):
 
65
        super(AuthPluginOptionsMissing, self).__init__(
 
66
            "Authentication failed. Missing options: %s" %
 
67
            ", ".join(opt_names))
 
68
        self.opt_names = opt_names
 
69
 
 
70
 
 
71
class AuthSystemNotFound(AuthorizationFailure):
 
72
    """User has specified a AuthSystem that is not installed."""
 
73
    def __init__(self, auth_system):
 
74
        super(AuthSystemNotFound, self).__init__(
 
75
            "AuthSystemNotFound: %s" % repr(auth_system))
 
76
        self.auth_system = auth_system
 
77
 
 
78
 
 
79
class NoUniqueMatch(ClientException):
 
80
    """Multiple entities found instead of one."""
 
81
    pass
 
82
 
 
83
 
 
84
class EndpointException(ClientException):
 
85
    """Something is rotten in Service Catalog."""
 
86
    pass
 
87
 
 
88
 
 
89
class EndpointNotFound(EndpointException):
 
90
    """Could not find requested endpoint in Service Catalog."""
 
91
    pass
 
92
 
 
93
 
 
94
class EmptyCatalog(EndpointNotFound):
 
95
    """The service catalog is empty."""
 
96
    pass
 
97
 
 
98
 
 
99
class AmbiguousEndpoints(EndpointException):
 
100
    """Found more than one matching endpoint in Service Catalog."""
 
101
    def __init__(self, endpoints=None):
 
102
        super(AmbiguousEndpoints, self).__init__(
 
103
            "AmbiguousEndpoints: %s" % repr(endpoints))
 
104
        self.endpoints = endpoints
 
105
 
 
106
 
 
107
class HTTPError(ClientException):
 
108
    """The base exception class for all HTTP exceptions.
 
109
    """
 
110
    http_status = 0
 
111
    message = "HTTP Error"
 
112
 
 
113
    def __init__(self, message=None, details=None,
 
114
                 response=None, request_id=None,
 
115
                 url=None, method=None, http_status=None):
 
116
        self.http_status = http_status or self.http_status
 
117
        self.message = message or self.message
 
118
        self.details = details
 
119
        self.request_id = request_id
 
120
        self.response = response
 
121
        self.url = url
 
122
        self.method = method
 
123
        formatted_string = "%(message)s (HTTP %(status)s)" % {
 
124
            "message": self.message, "status": self.http_status}
 
125
        if request_id:
 
126
            formatted_string += " (Request-ID: %s)" % request_id
 
127
        super(HTTPError, self).__init__(formatted_string)
 
128
 
 
129
 
 
130
class HTTPClientError(HTTPError):
 
131
    """Client-side HTTP error.
 
132
 
 
133
    Exception for cases in which the client seems to have erred.
 
134
    """
 
135
    message = "HTTP Client Error"
 
136
 
 
137
 
 
138
class HTTPServerError(HTTPError):
 
139
    """Server-side HTTP error.
 
140
 
 
141
    Exception for cases in which the server is aware that it has
 
142
    erred or is incapable of performing the request.
 
143
    """
 
144
    message = "HTTP Server Error"
 
145
 
 
146
 
 
147
class BadRequest(HTTPClientError):
 
148
    """HTTP 400 - Bad Request.
 
149
 
 
150
    The request cannot be fulfilled due to bad syntax.
 
151
    """
 
152
    http_status = 400
 
153
    message = "Bad Request"
 
154
 
 
155
 
 
156
class Unauthorized(HTTPClientError):
 
157
    """HTTP 401 - Unauthorized.
 
158
 
 
159
    Similar to 403 Forbidden, but specifically for use when authentication
 
160
    is required and has failed or has not yet been provided.
 
161
    """
 
162
    http_status = 401
 
163
    message = "Unauthorized"
 
164
 
 
165
 
 
166
class PaymentRequired(HTTPClientError):
 
167
    """HTTP 402 - Payment Required.
 
168
 
 
169
    Reserved for future use.
 
170
    """
 
171
    http_status = 402
 
172
    message = "Payment Required"
 
173
 
 
174
 
 
175
class Forbidden(HTTPClientError):
 
176
    """HTTP 403 - Forbidden.
 
177
 
 
178
    The request was a valid request, but the server is refusing to respond
 
179
    to it.
 
180
    """
 
181
    http_status = 403
 
182
    message = "Forbidden"
 
183
 
 
184
 
 
185
class NotFound(HTTPClientError):
 
186
    """HTTP 404 - Not Found.
 
187
 
 
188
    The requested resource could not be found but may be available again
 
189
    in the future.
 
190
    """
 
191
    http_status = 404
 
192
    message = "Not Found"
 
193
 
 
194
 
 
195
class MethodNotAllowed(HTTPClientError):
 
196
    """HTTP 405 - Method Not Allowed.
 
197
 
 
198
    A request was made of a resource using a request method not supported
 
199
    by that resource.
 
200
    """
 
201
    http_status = 405
 
202
    message = "Method Not Allowed"
 
203
 
 
204
 
 
205
class NotAcceptable(HTTPClientError):
 
206
    """HTTP 406 - Not Acceptable.
 
207
 
 
208
    The requested resource is only capable of generating content not
 
209
    acceptable according to the Accept headers sent in the request.
 
210
    """
 
211
    http_status = 406
 
212
    message = "Not Acceptable"
 
213
 
 
214
 
 
215
class ProxyAuthenticationRequired(HTTPClientError):
 
216
    """HTTP 407 - Proxy Authentication Required.
 
217
 
 
218
    The client must first authenticate itself with the proxy.
 
219
    """
 
220
    http_status = 407
 
221
    message = "Proxy Authentication Required"
 
222
 
 
223
 
 
224
class RequestTimeout(HTTPClientError):
 
225
    """HTTP 408 - Request Timeout.
 
226
 
 
227
    The server timed out waiting for the request.
 
228
    """
 
229
    http_status = 408
 
230
    message = "Request Timeout"
 
231
 
 
232
 
 
233
class Conflict(HTTPClientError):
 
234
    """HTTP 409 - Conflict.
 
235
 
 
236
    Indicates that the request could not be processed because of conflict
 
237
    in the request, such as an edit conflict.
 
238
    """
 
239
    http_status = 409
 
240
    message = "Conflict"
 
241
 
 
242
 
 
243
class Gone(HTTPClientError):
 
244
    """HTTP 410 - Gone.
 
245
 
 
246
    Indicates that the resource requested is no longer available and will
 
247
    not be available again.
 
248
    """
 
249
    http_status = 410
 
250
    message = "Gone"
 
251
 
 
252
 
 
253
class LengthRequired(HTTPClientError):
 
254
    """HTTP 411 - Length Required.
 
255
 
 
256
    The request did not specify the length of its content, which is
 
257
    required by the requested resource.
 
258
    """
 
259
    http_status = 411
 
260
    message = "Length Required"
 
261
 
 
262
 
 
263
class PreconditionFailed(HTTPClientError):
 
264
    """HTTP 412 - Precondition Failed.
 
265
 
 
266
    The server does not meet one of the preconditions that the requester
 
267
    put on the request.
 
268
    """
 
269
    http_status = 412
 
270
    message = "Precondition Failed"
 
271
 
 
272
 
 
273
class RequestEntityTooLarge(HTTPClientError):
 
274
    """HTTP 413 - Request Entity Too Large.
 
275
 
 
276
    The request is larger than the server is willing or able to process.
 
277
    """
 
278
    http_status = 413
 
279
    message = "Request Entity Too Large"
 
280
 
 
281
    def __init__(self, *args, **kwargs):
 
282
        try:
 
283
            self.retry_after = int(kwargs.pop('retry_after'))
 
284
        except (KeyError, ValueError):
 
285
            self.retry_after = 0
 
286
 
 
287
        super(RequestEntityTooLarge, self).__init__(*args, **kwargs)
 
288
 
 
289
 
 
290
class RequestUriTooLong(HTTPClientError):
 
291
    """HTTP 414 - Request-URI Too Long.
 
292
 
 
293
    The URI provided was too long for the server to process.
 
294
    """
 
295
    http_status = 414
 
296
    message = "Request-URI Too Long"
 
297
 
 
298
 
 
299
class UnsupportedMediaType(HTTPClientError):
 
300
    """HTTP 415 - Unsupported Media Type.
 
301
 
 
302
    The request entity has a media type which the server or resource does
 
303
    not support.
 
304
    """
 
305
    http_status = 415
 
306
    message = "Unsupported Media Type"
 
307
 
 
308
 
 
309
class RequestedRangeNotSatisfiable(HTTPClientError):
 
310
    """HTTP 416 - Requested Range Not Satisfiable.
 
311
 
 
312
    The client has asked for a portion of the file, but the server cannot
 
313
    supply that portion.
 
314
    """
 
315
    http_status = 416
 
316
    message = "Requested Range Not Satisfiable"
 
317
 
 
318
 
 
319
class ExpectationFailed(HTTPClientError):
 
320
    """HTTP 417 - Expectation Failed.
 
321
 
 
322
    The server cannot meet the requirements of the Expect request-header field.
 
323
    """
 
324
    http_status = 417
 
325
    message = "Expectation Failed"
 
326
 
 
327
 
 
328
class UnprocessableEntity(HTTPClientError):
 
329
    """HTTP 422 - Unprocessable Entity.
 
330
 
 
331
    The request was well-formed but was unable to be followed due to semantic
 
332
    errors.
 
333
    """
 
334
    http_status = 422
 
335
    message = "Unprocessable Entity"
 
336
 
 
337
 
 
338
class InternalServerError(HTTPServerError):
 
339
    """HTTP 500 - Internal Server Error.
 
340
 
 
341
    A generic error message, given when no more specific message is suitable.
 
342
    """
 
343
    http_status = 500
 
344
    message = "Internal Server Error"
 
345
 
 
346
 
 
347
# NotImplemented is a python keyword.
 
348
class HTTPNotImplemented(HTTPServerError):
 
349
    """HTTP 501 - Not Implemented.
 
350
 
 
351
    The server either does not recognize the request method, or it lacks
 
352
    the ability to fulfill the request.
 
353
    """
 
354
    http_status = 501
 
355
    message = "Not Implemented"
 
356
 
 
357
 
 
358
class BadGateway(HTTPServerError):
 
359
    """HTTP 502 - Bad Gateway.
 
360
 
 
361
    The server was acting as a gateway or proxy and received an invalid
 
362
    response from the upstream server.
 
363
    """
 
364
    http_status = 502
 
365
    message = "Bad Gateway"
 
366
 
 
367
 
 
368
class ServiceUnavailable(HTTPServerError):
 
369
    """HTTP 503 - Service Unavailable.
 
370
 
 
371
    The server is currently unavailable.
 
372
    """
 
373
    http_status = 503
 
374
    message = "Service Unavailable"
 
375
 
 
376
 
 
377
class GatewayTimeout(HTTPServerError):
 
378
    """HTTP 504 - Gateway Timeout.
 
379
 
 
380
    The server was acting as a gateway or proxy and did not receive a timely
 
381
    response from the upstream server.
 
382
    """
 
383
    http_status = 504
 
384
    message = "Gateway Timeout"
 
385
 
 
386
 
 
387
class HTTPVersionNotSupported(HTTPServerError):
 
388
    """HTTP 505 - HTTPVersion Not Supported.
 
389
 
 
390
    The server does not support the HTTP protocol version used in the request.
 
391
    """
 
392
    http_status = 505
 
393
    message = "HTTP Version Not Supported"
 
394
 
 
395
 
 
396
_code_map = dict(
 
397
    (cls.http_status, cls)
 
398
    for cls in itertools.chain(HTTPClientError.__subclasses__(),
 
399
                               HTTPServerError.__subclasses__()))
 
400
 
 
401
 
 
402
def from_response(response, method, url):
 
403
    """Returns an instance of :class:`HTTPError` or subclass based on response.
 
404
 
 
405
    :param response: instance of `requests.Response` class
 
406
    :param method: HTTP method used for request
 
407
    :param url: URL used for request
 
408
    """
 
409
    kwargs = {
 
410
        "http_status": response.status_code,
 
411
        "response": response,
 
412
        "method": method,
 
413
        "url": url,
 
414
        "request_id": response.headers.get("x-compute-request-id"),
 
415
    }
 
416
    if "retry-after" in response.headers:
 
417
        kwargs["retry_after"] = response.headers["retry-after"]
 
418
 
 
419
    content_type = response.headers.get("Content-Type", "")
 
420
    if content_type.startswith("application/json"):
 
421
        try:
 
422
            body = response.json()
 
423
        except ValueError:
 
424
            pass
 
425
        else:
 
426
            if hasattr(body, "keys"):
 
427
                error = body[body.keys()[0]]
 
428
                kwargs["message"] = error.get("message")
 
429
                kwargs["details"] = error.get("details")
 
430
    elif content_type.startswith("text/"):
 
431
        kwargs["details"] = response.text
 
432
 
 
433
    try:
 
434
        cls = _code_map[response.status_code]
 
435
    except KeyError:
 
436
        if 500 <= response.status_code < 600:
 
437
            cls = HTTPServerError
 
438
        elif 400 <= response.status_code < 500:
 
439
            cls = HTTPClientError
 
440
        else:
 
441
            cls = HTTPError
 
442
    return cls(**kwargs)