PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/boto-2.5.2/boto/exception.py

#
Python | 495 lines | 256 code | 82 blank | 157 comment | 36 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. Exception classes - Subclassing allows you to check for specific errors
  25. """
  26. import base64
  27. import xml.sax
  28. from boto import handler
  29. from boto.resultset import ResultSet
  30. class BotoClientError(StandardError):
  31. """
  32. General Boto Client error (error accessing AWS)
  33. """
  34. def __init__(self, reason, *args):
  35. StandardError.__init__(self, reason, *args)
  36. self.reason = reason
  37. def __repr__(self):
  38. return 'BotoClientError: %s' % self.reason
  39. def __str__(self):
  40. return 'BotoClientError: %s' % self.reason
  41. class SDBPersistenceError(StandardError):
  42. pass
  43. class StoragePermissionsError(BotoClientError):
  44. """
  45. Permissions error when accessing a bucket or key on a storage service.
  46. """
  47. pass
  48. class S3PermissionsError(StoragePermissionsError):
  49. """
  50. Permissions error when accessing a bucket or key on S3.
  51. """
  52. pass
  53. class GSPermissionsError(StoragePermissionsError):
  54. """
  55. Permissions error when accessing a bucket or key on GS.
  56. """
  57. pass
  58. class BotoServerError(StandardError):
  59. def __init__(self, status, reason, body=None, *args):
  60. StandardError.__init__(self, status, reason, body, *args)
  61. self.status = status
  62. self.reason = reason
  63. self.body = body or ''
  64. self.request_id = None
  65. self.error_code = None
  66. self.error_message = None
  67. self.box_usage = None
  68. # Attempt to parse the error response. If body isn't present,
  69. # then just ignore the error response.
  70. if self.body:
  71. try:
  72. h = handler.XmlHandler(self, self)
  73. xml.sax.parseString(self.body, h)
  74. except (TypeError, xml.sax.SAXParseException), pe:
  75. # Remove unparsable message body so we don't include garbage
  76. # in exception. But first, save self.body in self.error_message
  77. # because occasionally we get error messages from Eucalyptus
  78. # that are just text strings that we want to preserve.
  79. self.error_message = self.body
  80. self.body = None
  81. def __getattr__(self, name):
  82. if name == 'message':
  83. return self.error_message
  84. if name == 'code':
  85. return self.error_code
  86. raise AttributeError
  87. def __repr__(self):
  88. return '%s: %s %s\n%s' % (self.__class__.__name__,
  89. self.status, self.reason, self.body)
  90. def __str__(self):
  91. return '%s: %s %s\n%s' % (self.__class__.__name__,
  92. self.status, self.reason, self.body)
  93. def startElement(self, name, attrs, connection):
  94. pass
  95. def endElement(self, name, value, connection):
  96. if name in ('RequestId', 'RequestID'):
  97. self.request_id = value
  98. elif name == 'Code':
  99. self.error_code = value
  100. elif name == 'Message':
  101. self.error_message = value
  102. elif name == 'BoxUsage':
  103. self.box_usage = value
  104. return None
  105. def _cleanupParsedProperties(self):
  106. self.request_id = None
  107. self.error_code = None
  108. self.error_message = None
  109. self.box_usage = None
  110. class ConsoleOutput:
  111. def __init__(self, parent=None):
  112. self.parent = parent
  113. self.instance_id = None
  114. self.timestamp = None
  115. self.comment = None
  116. self.output = None
  117. def startElement(self, name, attrs, connection):
  118. return None
  119. def endElement(self, name, value, connection):
  120. if name == 'instanceId':
  121. self.instance_id = value
  122. elif name == 'output':
  123. self.output = base64.b64decode(value)
  124. else:
  125. setattr(self, name, value)
  126. class StorageCreateError(BotoServerError):
  127. """
  128. Error creating a bucket or key on a storage service.
  129. """
  130. def __init__(self, status, reason, body=None):
  131. self.bucket = None
  132. BotoServerError.__init__(self, status, reason, body)
  133. def endElement(self, name, value, connection):
  134. if name == 'BucketName':
  135. self.bucket = value
  136. else:
  137. return BotoServerError.endElement(self, name, value, connection)
  138. class S3CreateError(StorageCreateError):
  139. """
  140. Error creating a bucket or key on S3.
  141. """
  142. pass
  143. class GSCreateError(StorageCreateError):
  144. """
  145. Error creating a bucket or key on GS.
  146. """
  147. pass
  148. class StorageCopyError(BotoServerError):
  149. """
  150. Error copying a key on a storage service.
  151. """
  152. pass
  153. class S3CopyError(StorageCopyError):
  154. """
  155. Error copying a key on S3.
  156. """
  157. pass
  158. class GSCopyError(StorageCopyError):
  159. """
  160. Error copying a key on GS.
  161. """
  162. pass
  163. class SQSError(BotoServerError):
  164. """
  165. General Error on Simple Queue Service.
  166. """
  167. def __init__(self, status, reason, body=None):
  168. self.detail = None
  169. self.type = None
  170. BotoServerError.__init__(self, status, reason, body)
  171. def startElement(self, name, attrs, connection):
  172. return BotoServerError.startElement(self, name, attrs, connection)
  173. def endElement(self, name, value, connection):
  174. if name == 'Detail':
  175. self.detail = value
  176. elif name == 'Type':
  177. self.type = value
  178. else:
  179. return BotoServerError.endElement(self, name, value, connection)
  180. def _cleanupParsedProperties(self):
  181. BotoServerError._cleanupParsedProperties(self)
  182. for p in ('detail', 'type'):
  183. setattr(self, p, None)
  184. class SQSDecodeError(BotoClientError):
  185. """
  186. Error when decoding an SQS message.
  187. """
  188. def __init__(self, reason, message):
  189. BotoClientError.__init__(self, reason, message)
  190. self.message = message
  191. def __repr__(self):
  192. return 'SQSDecodeError: %s' % self.reason
  193. def __str__(self):
  194. return 'SQSDecodeError: %s' % self.reason
  195. class StorageResponseError(BotoServerError):
  196. """
  197. Error in response from a storage service.
  198. """
  199. def __init__(self, status, reason, body=None):
  200. self.resource = None
  201. BotoServerError.__init__(self, status, reason, body)
  202. def startElement(self, name, attrs, connection):
  203. return BotoServerError.startElement(self, name, attrs, connection)
  204. def endElement(self, name, value, connection):
  205. if name == 'Resource':
  206. self.resource = value
  207. else:
  208. return BotoServerError.endElement(self, name, value, connection)
  209. def _cleanupParsedProperties(self):
  210. BotoServerError._cleanupParsedProperties(self)
  211. for p in ('resource'):
  212. setattr(self, p, None)
  213. class S3ResponseError(StorageResponseError):
  214. """
  215. Error in response from S3.
  216. """
  217. pass
  218. class GSResponseError(StorageResponseError):
  219. """
  220. Error in response from GS.
  221. """
  222. pass
  223. class EC2ResponseError(BotoServerError):
  224. """
  225. Error in response from EC2.
  226. """
  227. def __init__(self, status, reason, body=None):
  228. self.errors = None
  229. self._errorResultSet = []
  230. BotoServerError.__init__(self, status, reason, body)
  231. self.errors = [ (e.error_code, e.error_message) \
  232. for e in self._errorResultSet ]
  233. if len(self.errors):
  234. self.error_code, self.error_message = self.errors[0]
  235. def startElement(self, name, attrs, connection):
  236. if name == 'Errors':
  237. self._errorResultSet = ResultSet([('Error', _EC2Error)])
  238. return self._errorResultSet
  239. else:
  240. return None
  241. def endElement(self, name, value, connection):
  242. if name == 'RequestID':
  243. self.request_id = value
  244. else:
  245. return None # don't call subclass here
  246. def _cleanupParsedProperties(self):
  247. BotoServerError._cleanupParsedProperties(self)
  248. self._errorResultSet = []
  249. for p in ('errors'):
  250. setattr(self, p, None)
  251. class DynamoDBResponseError(BotoServerError):
  252. """
  253. This exception expects the fully parsed and decoded JSON response
  254. body to be passed as the body parameter.
  255. :ivar status: The HTTP status code.
  256. :ivar reason: The HTTP reason message.
  257. :ivar body: The Python dict that represents the decoded JSON
  258. response body.
  259. :ivar error_message: The full description of the AWS error encountered.
  260. :ivar error_code: A short string that identifies the AWS error
  261. (e.g. ConditionalCheckFailedException)
  262. """
  263. def __init__(self, status, reason, body=None, *args):
  264. self.status = status
  265. self.reason = reason
  266. self.body = body
  267. if self.body:
  268. self.error_message = self.body.get('message', None)
  269. self.error_code = self.body.get('__type', None)
  270. if self.error_code:
  271. self.error_code = self.error_code.split('#')[-1]
  272. class SWFResponseError(BotoServerError):
  273. """
  274. This exception expects the fully parsed and decoded JSON response
  275. body to be passed as the body parameter.
  276. :ivar status: The HTTP status code.
  277. :ivar reason: The HTTP reason message.
  278. :ivar body: The Python dict that represents the decoded JSON
  279. response body.
  280. :ivar error_message: The full description of the AWS error encountered.
  281. :ivar error_code: A short string that identifies the AWS error
  282. (e.g. ConditionalCheckFailedException)
  283. """
  284. def __init__(self, status, reason, body=None, *args):
  285. self.status = status
  286. self.reason = reason
  287. self.body = body
  288. if self.body:
  289. self.error_message = self.body.get('message', None)
  290. self.error_code = self.body.get('__type', None)
  291. if self.error_code:
  292. self.error_code = self.error_code.split('#')[-1]
  293. class EmrResponseError(BotoServerError):
  294. """
  295. Error in response from EMR
  296. """
  297. pass
  298. class _EC2Error:
  299. def __init__(self, connection=None):
  300. self.connection = connection
  301. self.error_code = None
  302. self.error_message = None
  303. def startElement(self, name, attrs, connection):
  304. return None
  305. def endElement(self, name, value, connection):
  306. if name == 'Code':
  307. self.error_code = value
  308. elif name == 'Message':
  309. self.error_message = value
  310. else:
  311. return None
  312. class SDBResponseError(BotoServerError):
  313. """
  314. Error in responses from SDB.
  315. """
  316. pass
  317. class AWSConnectionError(BotoClientError):
  318. """
  319. General error connecting to Amazon Web Services.
  320. """
  321. pass
  322. class StorageDataError(BotoClientError):
  323. """
  324. Error receiving data from a storage service.
  325. """
  326. pass
  327. class S3DataError(StorageDataError):
  328. """
  329. Error receiving data from S3.
  330. """
  331. pass
  332. class GSDataError(StorageDataError):
  333. """
  334. Error receiving data from GS.
  335. """
  336. pass
  337. class InvalidUriError(Exception):
  338. """Exception raised when URI is invalid."""
  339. def __init__(self, message):
  340. Exception.__init__(self, message)
  341. self.message = message
  342. class InvalidAclError(Exception):
  343. """Exception raised when ACL XML is invalid."""
  344. def __init__(self, message):
  345. Exception.__init__(self, message)
  346. self.message = message
  347. class InvalidCorsError(Exception):
  348. """Exception raised when CORS XML is invalid."""
  349. def __init__(self, message):
  350. Exception.__init__(self, message)
  351. self.message = message
  352. class NoAuthHandlerFound(Exception):
  353. """Is raised when no auth handlers were found ready to authenticate."""
  354. pass
  355. class TooManyAuthHandlerReadyToAuthenticate(Exception):
  356. """Is raised when there are more than one auth handler ready.
  357. In normal situation there should only be one auth handler that is ready to
  358. authenticate. In case where more than one auth handler is ready to
  359. authenticate, we raise this exception, to prevent unpredictable behavior
  360. when multiple auth handlers can handle a particular case and the one chosen
  361. depends on the order they were checked.
  362. """
  363. pass
  364. # Enum class for resumable upload failure disposition.
  365. class ResumableTransferDisposition(object):
  366. # START_OVER means an attempt to resume an existing transfer failed,
  367. # and a new resumable upload should be attempted (without delay).
  368. START_OVER = 'START_OVER'
  369. # WAIT_BEFORE_RETRY means the resumable transfer failed but that it can
  370. # be retried after a time delay within the current process.
  371. WAIT_BEFORE_RETRY = 'WAIT_BEFORE_RETRY'
  372. # ABORT_CUR_PROCESS means the resumable transfer failed and that
  373. # delaying/retrying within the current process will not help. If
  374. # resumable transfer included a state tracker file the upload can be
  375. # retried again later, in another process (e.g., a later run of gsutil).
  376. ABORT_CUR_PROCESS = 'ABORT_CUR_PROCESS'
  377. # ABORT means the resumable transfer failed in a way that it does not
  378. # make sense to continue in the current process, and further that the
  379. # current tracker ID should not be preserved (in a tracker file if one
  380. # was specified at resumable upload start time). If the user tries again
  381. # later (e.g., a separate run of gsutil) it will get a new resumable
  382. # upload ID.
  383. ABORT = 'ABORT'
  384. class ResumableUploadException(Exception):
  385. """
  386. Exception raised for various resumable upload problems.
  387. self.disposition is of type ResumableTransferDisposition.
  388. """
  389. def __init__(self, message, disposition):
  390. Exception.__init__(self, message, disposition)
  391. self.message = message
  392. self.disposition = disposition
  393. def __repr__(self):
  394. return 'ResumableUploadException("%s", %s)' % (
  395. self.message, self.disposition)
  396. class ResumableDownloadException(Exception):
  397. """
  398. Exception raised for various resumable download problems.
  399. self.disposition is of type ResumableTransferDisposition.
  400. """
  401. def __init__(self, message, disposition):
  402. Exception.__init__(self, message, disposition)
  403. self.message = message
  404. self.disposition = disposition
  405. def __repr__(self):
  406. return 'ResumableDownloadException("%s", %s)' % (
  407. self.message, self.disposition)