PageRenderTime 51ms CodeModel.GetById 14ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/boto-2.5.2/boto/exception.py

#
Python | 495 lines | 256 code | 82 blank | 157 comment | 26 complexity | 8ade25cd56d2f436e039eb07769084c4 MD5 | raw file
  1# Copyright (c) 2006-2010 Mitch Garnaat http://garnaat.org/
  2# Copyright (c) 2010, Eucalyptus Systems, Inc.
  3# All rights reserved.
  4#
  5# Permission is hereby granted, free of charge, to any person obtaining a
  6# copy of this software and associated documentation files (the
  7# "Software"), to deal in the Software without restriction, including
  8# without limitation the rights to use, copy, modify, merge, publish, dis-
  9# tribute, sublicense, and/or sell copies of the Software, and to permit
 10# persons to whom the Software is furnished to do so, subject to the fol-
 11# lowing conditions:
 12#
 13# The above copyright notice and this permission notice shall be included
 14# in all copies or substantial portions of the Software.
 15#
 16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 17# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 18# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 19# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 20# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 22# IN THE SOFTWARE.
 23
 24"""
 25Exception classes - Subclassing allows you to check for specific errors
 26"""
 27import base64
 28import xml.sax
 29from boto import handler
 30from boto.resultset import ResultSet
 31
 32
 33class BotoClientError(StandardError):
 34    """
 35    General Boto Client error (error accessing AWS)
 36    """
 37
 38    def __init__(self, reason, *args):
 39        StandardError.__init__(self, reason, *args)
 40        self.reason = reason
 41
 42    def __repr__(self):
 43        return 'BotoClientError: %s' % self.reason
 44
 45    def __str__(self):
 46        return 'BotoClientError: %s' % self.reason
 47
 48class SDBPersistenceError(StandardError):
 49
 50    pass
 51
 52class StoragePermissionsError(BotoClientError):
 53    """
 54    Permissions error when accessing a bucket or key on a storage service.
 55    """
 56    pass
 57
 58class S3PermissionsError(StoragePermissionsError):
 59    """
 60    Permissions error when accessing a bucket or key on S3.
 61    """
 62    pass
 63
 64class GSPermissionsError(StoragePermissionsError):
 65    """
 66    Permissions error when accessing a bucket or key on GS.
 67    """
 68    pass
 69
 70class BotoServerError(StandardError):
 71
 72    def __init__(self, status, reason, body=None, *args):
 73        StandardError.__init__(self, status, reason, body, *args)
 74        self.status = status
 75        self.reason = reason
 76        self.body = body or ''
 77        self.request_id = None
 78        self.error_code = None
 79        self.error_message = None
 80        self.box_usage = None
 81
 82        # Attempt to parse the error response. If body isn't present,
 83        # then just ignore the error response.
 84        if self.body:
 85            try:
 86                h = handler.XmlHandler(self, self)
 87                xml.sax.parseString(self.body, h)
 88            except (TypeError, xml.sax.SAXParseException), pe:
 89                # Remove unparsable message body so we don't include garbage
 90                # in exception. But first, save self.body in self.error_message
 91                # because occasionally we get error messages from Eucalyptus
 92                # that are just text strings that we want to preserve.
 93                self.error_message = self.body
 94                self.body = None
 95
 96    def __getattr__(self, name):
 97        if name == 'message':
 98            return self.error_message
 99        if name == 'code':
100            return self.error_code
101        raise AttributeError
102
103    def __repr__(self):
104        return '%s: %s %s\n%s' % (self.__class__.__name__,
105                                  self.status, self.reason, self.body)
106
107    def __str__(self):
108        return '%s: %s %s\n%s' % (self.__class__.__name__,
109                                  self.status, self.reason, self.body)
110
111    def startElement(self, name, attrs, connection):
112        pass
113
114    def endElement(self, name, value, connection):
115        if name in ('RequestId', 'RequestID'):
116            self.request_id = value
117        elif name == 'Code':
118            self.error_code = value
119        elif name == 'Message':
120            self.error_message = value
121        elif name == 'BoxUsage':
122            self.box_usage = value
123        return None
124
125    def _cleanupParsedProperties(self):
126        self.request_id = None
127        self.error_code = None
128        self.error_message = None
129        self.box_usage = None
130
131class ConsoleOutput:
132
133    def __init__(self, parent=None):
134        self.parent = parent
135        self.instance_id = None
136        self.timestamp = None
137        self.comment = None
138        self.output = None
139
140    def startElement(self, name, attrs, connection):
141        return None
142
143    def endElement(self, name, value, connection):
144        if name == 'instanceId':
145            self.instance_id = value
146        elif name == 'output':
147            self.output = base64.b64decode(value)
148        else:
149            setattr(self, name, value)
150
151class StorageCreateError(BotoServerError):
152    """
153    Error creating a bucket or key on a storage service.
154    """
155    def __init__(self, status, reason, body=None):
156        self.bucket = None
157        BotoServerError.__init__(self, status, reason, body)
158
159    def endElement(self, name, value, connection):
160        if name == 'BucketName':
161            self.bucket = value
162        else:
163            return BotoServerError.endElement(self, name, value, connection)
164
165class S3CreateError(StorageCreateError):
166    """
167    Error creating a bucket or key on S3.
168    """
169    pass
170
171class GSCreateError(StorageCreateError):
172    """
173    Error creating a bucket or key on GS.
174    """
175    pass
176
177class StorageCopyError(BotoServerError):
178    """
179    Error copying a key on a storage service.
180    """
181    pass
182
183class S3CopyError(StorageCopyError):
184    """
185    Error copying a key on S3.
186    """
187    pass
188
189class GSCopyError(StorageCopyError):
190    """
191    Error copying a key on GS.
192    """
193    pass
194
195class SQSError(BotoServerError):
196    """
197    General Error on Simple Queue Service.
198    """
199    def __init__(self, status, reason, body=None):
200        self.detail = None
201        self.type = None
202        BotoServerError.__init__(self, status, reason, body)
203
204    def startElement(self, name, attrs, connection):
205        return BotoServerError.startElement(self, name, attrs, connection)
206
207    def endElement(self, name, value, connection):
208        if name == 'Detail':
209            self.detail = value
210        elif name == 'Type':
211            self.type = value
212        else:
213            return BotoServerError.endElement(self, name, value, connection)
214
215    def _cleanupParsedProperties(self):
216        BotoServerError._cleanupParsedProperties(self)
217        for p in ('detail', 'type'):
218            setattr(self, p, None)
219
220class SQSDecodeError(BotoClientError):
221    """
222    Error when decoding an SQS message.
223    """
224    def __init__(self, reason, message):
225        BotoClientError.__init__(self, reason, message)
226        self.message = message
227
228    def __repr__(self):
229        return 'SQSDecodeError: %s' % self.reason
230
231    def __str__(self):
232        return 'SQSDecodeError: %s' % self.reason
233
234class StorageResponseError(BotoServerError):
235    """
236    Error in response from a storage service.
237    """
238    def __init__(self, status, reason, body=None):
239        self.resource = None
240        BotoServerError.__init__(self, status, reason, body)
241
242    def startElement(self, name, attrs, connection):
243        return BotoServerError.startElement(self, name, attrs, connection)
244
245    def endElement(self, name, value, connection):
246        if name == 'Resource':
247            self.resource = value
248        else:
249            return BotoServerError.endElement(self, name, value, connection)
250
251    def _cleanupParsedProperties(self):
252        BotoServerError._cleanupParsedProperties(self)
253        for p in ('resource'):
254            setattr(self, p, None)
255
256class S3ResponseError(StorageResponseError):
257    """
258    Error in response from S3.
259    """
260    pass
261
262class GSResponseError(StorageResponseError):
263    """
264    Error in response from GS.
265    """
266    pass
267
268class EC2ResponseError(BotoServerError):
269    """
270    Error in response from EC2.
271    """
272
273    def __init__(self, status, reason, body=None):
274        self.errors = None
275        self._errorResultSet = []
276        BotoServerError.__init__(self, status, reason, body)
277        self.errors = [ (e.error_code, e.error_message) \
278                for e in self._errorResultSet ]
279        if len(self.errors):
280            self.error_code, self.error_message = self.errors[0]
281
282    def startElement(self, name, attrs, connection):
283        if name == 'Errors':
284            self._errorResultSet = ResultSet([('Error', _EC2Error)])
285            return self._errorResultSet
286        else:
287            return None
288
289    def endElement(self, name, value, connection):
290        if name == 'RequestID':
291            self.request_id = value
292        else:
293            return None # don't call subclass here
294
295    def _cleanupParsedProperties(self):
296        BotoServerError._cleanupParsedProperties(self)
297        self._errorResultSet = []
298        for p in ('errors'):
299            setattr(self, p, None)
300
301class DynamoDBResponseError(BotoServerError):
302    """
303    This exception expects the fully parsed and decoded JSON response
304    body to be passed as the body parameter.
305
306    :ivar status: The HTTP status code.
307    :ivar reason: The HTTP reason message.
308    :ivar body: The Python dict that represents the decoded JSON
309        response body.
310    :ivar error_message: The full description of the AWS error encountered.
311    :ivar error_code: A short string that identifies the AWS error
312        (e.g. ConditionalCheckFailedException)
313    """
314
315    def __init__(self, status, reason, body=None, *args):
316        self.status = status
317        self.reason = reason
318        self.body = body
319        if self.body:
320            self.error_message = self.body.get('message', None)
321            self.error_code = self.body.get('__type', None)
322            if self.error_code:
323                self.error_code = self.error_code.split('#')[-1]
324
325
326class SWFResponseError(BotoServerError):
327    """
328    This exception expects the fully parsed and decoded JSON response
329    body to be passed as the body parameter.
330
331    :ivar status: The HTTP status code.
332    :ivar reason: The HTTP reason message.
333    :ivar body: The Python dict that represents the decoded JSON
334        response body.
335    :ivar error_message: The full description of the AWS error encountered.
336    :ivar error_code: A short string that identifies the AWS error
337        (e.g. ConditionalCheckFailedException)
338    """
339
340    def __init__(self, status, reason, body=None, *args):
341        self.status = status
342        self.reason = reason
343        self.body = body
344        if self.body:
345            self.error_message = self.body.get('message', None)
346            self.error_code = self.body.get('__type', None)
347            if self.error_code:
348                self.error_code = self.error_code.split('#')[-1]
349
350
351class EmrResponseError(BotoServerError):
352    """
353    Error in response from EMR
354    """
355    pass
356
357class _EC2Error:
358
359    def __init__(self, connection=None):
360        self.connection = connection
361        self.error_code = None
362        self.error_message = None
363
364    def startElement(self, name, attrs, connection):
365        return None
366
367    def endElement(self, name, value, connection):
368        if name == 'Code':
369            self.error_code = value
370        elif name == 'Message':
371            self.error_message = value
372        else:
373            return None
374
375class SDBResponseError(BotoServerError):
376    """
377    Error in responses from SDB.
378    """
379    pass
380
381class AWSConnectionError(BotoClientError):
382    """
383    General error connecting to Amazon Web Services.
384    """
385    pass
386
387class StorageDataError(BotoClientError):
388    """
389    Error receiving data from a storage service.
390    """
391    pass
392
393class S3DataError(StorageDataError):
394    """
395    Error receiving data from S3.
396    """
397    pass
398
399class GSDataError(StorageDataError):
400    """
401    Error receiving data from GS.
402    """
403    pass
404
405class InvalidUriError(Exception):
406    """Exception raised when URI is invalid."""
407
408    def __init__(self, message):
409        Exception.__init__(self, message)
410        self.message = message
411
412class InvalidAclError(Exception):
413    """Exception raised when ACL XML is invalid."""
414
415    def __init__(self, message):
416        Exception.__init__(self, message)
417        self.message = message
418
419class InvalidCorsError(Exception):
420    """Exception raised when CORS XML is invalid."""
421
422    def __init__(self, message):
423        Exception.__init__(self, message)
424        self.message = message
425
426class NoAuthHandlerFound(Exception):
427    """Is raised when no auth handlers were found ready to authenticate."""
428    pass
429
430class TooManyAuthHandlerReadyToAuthenticate(Exception):
431    """Is raised when there are more than one auth handler ready.
432
433    In normal situation there should only be one auth handler that is ready to
434    authenticate. In case where more than one auth handler is ready to
435    authenticate, we raise this exception, to prevent unpredictable behavior
436    when multiple auth handlers can handle a particular case and the one chosen
437    depends on the order they were checked.
438    """
439    pass
440
441# Enum class for resumable upload failure disposition.
442class ResumableTransferDisposition(object):
443    # START_OVER means an attempt to resume an existing transfer failed,
444    # and a new resumable upload should be attempted (without delay).
445    START_OVER = 'START_OVER'
446
447    # WAIT_BEFORE_RETRY means the resumable transfer failed but that it can
448    # be retried after a time delay within the current process.
449    WAIT_BEFORE_RETRY = 'WAIT_BEFORE_RETRY'
450
451    # ABORT_CUR_PROCESS means the resumable transfer failed and that
452    # delaying/retrying within the current process will not help. If
453    # resumable transfer included a state tracker file the upload can be
454    # retried again later, in another process (e.g., a later run of gsutil).
455    ABORT_CUR_PROCESS = 'ABORT_CUR_PROCESS'
456
457    # ABORT means the resumable transfer failed in a way that it does not
458    # make sense to continue in the current process, and further that the
459    # current tracker ID should not be preserved (in a tracker file if one
460    # was specified at resumable upload start time). If the user tries again
461    # later (e.g., a separate run of gsutil) it will get a new resumable
462    # upload ID.
463    ABORT = 'ABORT'
464
465class ResumableUploadException(Exception):
466    """
467    Exception raised for various resumable upload problems.
468
469    self.disposition is of type ResumableTransferDisposition.
470    """
471
472    def __init__(self, message, disposition):
473        Exception.__init__(self, message, disposition)
474        self.message = message
475        self.disposition = disposition
476
477    def __repr__(self):
478        return 'ResumableUploadException("%s", %s)' % (
479            self.message, self.disposition)
480
481class ResumableDownloadException(Exception):
482    """
483    Exception raised for various resumable download problems.
484
485    self.disposition is of type ResumableTransferDisposition.
486    """
487
488    def __init__(self, message, disposition):
489        Exception.__init__(self, message, disposition)
490        self.message = message
491        self.disposition = disposition
492
493    def __repr__(self):
494        return 'ResumableDownloadException("%s", %s)' % (
495            self.message, self.disposition)