1# Copyright (c) 2012-2013 Mitch Garnaat http://garnaat.org/ 2# Copyright 2012-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"). You 5# may not use this file except in compliance with the License. A copy of 6# the License is located at 7# 8# http://aws.amazon.com/apache2.0/ 9# 10# or in the "license" file accompanying this file. This file is 11# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 12# ANY KIND, either express or implied. See the License for the specific 13# language governing permissions and limitations under the License. 14from __future__ import unicode_literals 15from botocore.vendored import requests 16from botocore.vendored.requests.packages import urllib3 17 18 19def _exception_from_packed_args(exception_cls, args=None, kwargs=None): 20 # This is helpful for reducing Exceptions that only accept kwargs as 21 # only positional arguments can be provided for __reduce__ 22 # Ideally, this would also be a class method on the BotoCoreError 23 # but instance methods cannot be pickled. 24 if args is None: 25 args = () 26 if kwargs is None: 27 kwargs = {} 28 return exception_cls(*args, **kwargs) 29 30 31class BotoCoreError(Exception): 32 """ 33 The base exception class for BotoCore exceptions. 34 35 :ivar msg: The descriptive message associated with the error. 36 """ 37 fmt = 'An unspecified error occurred' 38 39 def __init__(self, **kwargs): 40 msg = self.fmt.format(**kwargs) 41 Exception.__init__(self, msg) 42 self.kwargs = kwargs 43 44 def __reduce__(self): 45 return _exception_from_packed_args, (self.__class__, None, self.kwargs) 46 47 48class DataNotFoundError(BotoCoreError): 49 """ 50 The data associated with a particular path could not be loaded. 51 52 :ivar data_path: The data path that the user attempted to load. 53 """ 54 fmt = 'Unable to load data for: {data_path}' 55 56 57class UnknownServiceError(DataNotFoundError): 58 """Raised when trying to load data for an unknown service. 59 60 :ivar service_name: The name of the unknown service. 61 62 """ 63 fmt = ( 64 "Unknown service: '{service_name}'. Valid service names are: " 65 "{known_service_names}") 66 67 68class ApiVersionNotFoundError(BotoCoreError): 69 """ 70 The data associated with either the API version or a compatible one 71 could not be loaded. 72 73 :ivar data_path: The data path that the user attempted to load. 74 :ivar api_version: The API version that the user attempted to load. 75 """ 76 fmt = 'Unable to load data {data_path} for: {api_version}' 77 78 79class HTTPClientError(BotoCoreError): 80 fmt = 'An HTTP Client raised an unhandled exception: {error}' 81 def __init__(self, request=None, response=None, **kwargs): 82 self.request = request 83 self.response = response 84 super(HTTPClientError, self).__init__(**kwargs) 85 86 def __reduce__(self): 87 return _exception_from_packed_args, ( 88 self.__class__, (self.request, self.response), self.kwargs) 89 90 91class ConnectionError(BotoCoreError): 92 fmt = 'An HTTP Client failed to establish a connection: {error}' 93 94 95class EndpointConnectionError(ConnectionError): 96 fmt = 'Could not connect to the endpoint URL: "{endpoint_url}"' 97 98 99class SSLError(ConnectionError, requests.exceptions.SSLError): 100 fmt = 'SSL validation failed for {endpoint_url} {error}' 101 102 103class ConnectionClosedError(HTTPClientError): 104 fmt = ( 105 'Connection was closed before we received a valid response ' 106 'from endpoint URL: "{endpoint_url}".') 107 108 109class ReadTimeoutError(HTTPClientError, requests.exceptions.ReadTimeout, 110 urllib3.exceptions.ReadTimeoutError): 111 fmt = 'Read timeout on endpoint URL: "{endpoint_url}"' 112 113 114class ConnectTimeoutError(ConnectionError, requests.exceptions.ConnectTimeout): 115 fmt = 'Connect timeout on endpoint URL: "{endpoint_url}"' 116 117 118class ProxyConnectionError(ConnectionError, requests.exceptions.ProxyError): 119 fmt = 'Failed to connect to proxy URL: "{proxy_url}"' 120 121 122class NoCredentialsError(BotoCoreError): 123 """ 124 No credentials could be found. 125 """ 126 fmt = 'Unable to locate credentials' 127 128 129class PartialCredentialsError(BotoCoreError): 130 """ 131 Only partial credentials were found. 132 133 :ivar cred_var: The missing credential variable name. 134 135 """ 136 fmt = 'Partial credentials found in {provider}, missing: {cred_var}' 137 138 139class CredentialRetrievalError(BotoCoreError): 140 """ 141 Error attempting to retrieve credentials from a remote source. 142 143 :ivar provider: The name of the credential provider. 144 :ivar error_msg: The msg explaining why credentials could not be 145 retrieved. 146 147 """ 148 fmt = 'Error when retrieving credentials from {provider}: {error_msg}' 149 150 151class UnknownSignatureVersionError(BotoCoreError): 152 """ 153 Requested Signature Version is not known. 154 155 :ivar signature_version: The name of the requested signature version. 156 """ 157 fmt = 'Unknown Signature Version: {signature_version}.' 158 159 160class ServiceNotInRegionError(BotoCoreError): 161 """ 162 The service is not available in requested region. 163 164 :ivar service_name: The name of the service. 165 :ivar region_name: The name of the region. 166 """ 167 fmt = 'Service {service_name} not available in region {region_name}' 168 169 170class BaseEndpointResolverError(BotoCoreError): 171 """Base error for endpoint resolving errors. 172 173 Should never be raised directly, but clients can catch 174 this exception if they want to generically handle any errors 175 during the endpoint resolution process. 176 177 """ 178 179 180class NoRegionError(BaseEndpointResolverError): 181 """No region was specified.""" 182 fmt = 'You must specify a region.' 183 184 185class UnknownEndpointError(BaseEndpointResolverError, ValueError): 186 """ 187 Could not construct an endpoint. 188 189 :ivar service_name: The name of the service. 190 :ivar region_name: The name of the region. 191 """ 192 fmt = ( 193 'Unable to construct an endpoint for ' 194 '{service_name} in region {region_name}') 195 196 197class ProfileNotFound(BotoCoreError): 198 """ 199 The specified configuration profile was not found in the 200 configuration file. 201 202 :ivar profile: The name of the profile the user attempted to load. 203 """ 204 fmt = 'The config profile ({profile}) could not be found' 205 206 207class ConfigParseError(BotoCoreError): 208 """ 209 The configuration file could not be parsed. 210 211 :ivar path: The path to the configuration file. 212 """ 213 fmt = 'Unable to parse config file: {path}' 214 215 216class ConfigNotFound(BotoCoreError): 217 """ 218 The specified configuration file could not be found. 219 220 :ivar path: The path to the configuration file. 221 """ 222 fmt = 'The specified config file ({path}) could not be found.' 223 224 225class MissingParametersError(BotoCoreError): 226 """ 227 One or more required parameters were not supplied. 228 229 :ivar object: The object that has missing parameters. 230 This can be an operation or a parameter (in the 231 case of inner params). The str() of this object 232 will be used so it doesn't need to implement anything 233 other than str(). 234 :ivar missing: The names of the missing parameters. 235 """ 236 fmt = ('The following required parameters are missing for ' 237 '{object_name}: {missing}') 238 239 240class ValidationError(BotoCoreError): 241 """ 242 An exception occurred validating parameters. 243 244 Subclasses must accept a ``value`` and ``param`` 245 argument in their ``__init__``. 246 247 :ivar value: The value that was being validated. 248 :ivar param: The parameter that failed validation. 249 :ivar type_name: The name of the underlying type. 250 """ 251 fmt = ("Invalid value ('{value}') for param {param} " 252 "of type {type_name} ") 253 254 255class ParamValidationError(BotoCoreError): 256 fmt = 'Parameter validation failed:\n{report}' 257 258 259# These exceptions subclass from ValidationError so that code 260# can just 'except ValidationError' to catch any possibly validation 261# error. 262class UnknownKeyError(ValidationError): 263 """ 264 Unknown key in a struct parameter. 265 266 :ivar value: The value that was being checked. 267 :ivar param: The name of the parameter. 268 :ivar choices: The valid choices the value can be. 269 """ 270 fmt = ("Unknown key '{value}' for param '{param}'. Must be one " 271 "of: {choices}") 272 273 274class RangeError(ValidationError): 275 """ 276 A parameter value was out of the valid range. 277 278 :ivar value: The value that was being checked. 279 :ivar param: The parameter that failed validation. 280 :ivar min_value: The specified minimum value. 281 :ivar max_value: The specified maximum value. 282 """ 283 fmt = ('Value out of range for param {param}: ' 284 '{min_value} <= {value} <= {max_value}') 285 286 287class UnknownParameterError(ValidationError): 288 """ 289 Unknown top level parameter. 290 291 :ivar name: The name of the unknown parameter. 292 :ivar operation: The name of the operation. 293 :ivar choices: The valid choices the parameter name can be. 294 """ 295 fmt = ( 296 "Unknown parameter '{name}' for operation {operation}. Must be one " 297 "of: {choices}" 298 ) 299 300 301class AliasConflictParameterError(ValidationError): 302 """ 303 Error when an alias is provided for a parameter as well as the original. 304 305 :ivar original: The name of the original parameter. 306 :ivar alias: The name of the alias 307 :ivar operation: The name of the operation. 308 """ 309 fmt = ( 310 "Parameter '{original}' and its alias '{alias}' were provided " 311 "for operation {operation}. Only one of them may be used." 312 ) 313 314 315class UnknownServiceStyle(BotoCoreError): 316 """ 317 Unknown style of service invocation. 318 319 :ivar service_style: The style requested. 320 """ 321 fmt = 'The service style ({service_style}) is not understood.' 322 323 324class PaginationError(BotoCoreError): 325 fmt = 'Error during pagination: {message}' 326 327 328class OperationNotPageableError(BotoCoreError): 329 fmt = 'Operation cannot be paginated: {operation_name}' 330 331 332class ChecksumError(BotoCoreError): 333 """The expected checksum did not match the calculated checksum. 334 335 """ 336 fmt = ('Checksum {checksum_type} failed, expected checksum ' 337 '{expected_checksum} did not match calculated checksum ' 338 '{actual_checksum}.') 339 340 341class UnseekableStreamError(BotoCoreError): 342 """Need to seek a stream, but stream does not support seeking. 343 344 """ 345 fmt = ('Need to rewind the stream {stream_object}, but stream ' 346 'is not seekable.') 347 348 349class WaiterError(BotoCoreError): 350 """Waiter failed to reach desired state.""" 351 fmt = 'Waiter {name} failed: {reason}' 352 353 def __init__(self, name, reason, last_response): 354 super(WaiterError, self).__init__(name=name, reason=reason) 355 self.last_response = last_response 356 357 358class IncompleteReadError(BotoCoreError): 359 """HTTP response did not return expected number of bytes.""" 360 fmt = ('{actual_bytes} read, but total bytes ' 361 'expected is {expected_bytes}.') 362 363 364class InvalidExpressionError(BotoCoreError): 365 """Expression is either invalid or too complex.""" 366 fmt = 'Invalid expression {expression}: Only dotted lookups are supported.' 367 368 369class UnknownCredentialError(BotoCoreError): 370 """Tried to insert before/after an unregistered credential type.""" 371 fmt = 'Credential named {name} not found.' 372 373 374class WaiterConfigError(BotoCoreError): 375 """Error when processing waiter configuration.""" 376 fmt = 'Error processing waiter config: {error_msg}' 377 378 379class UnknownClientMethodError(BotoCoreError): 380 """Error when trying to access a method on a client that does not exist.""" 381 fmt = 'Client does not have method: {method_name}' 382 383 384class UnsupportedSignatureVersionError(BotoCoreError): 385 """Error when trying to use an unsupported Signature Version.""" 386 fmt = 'Signature version is not supported: {signature_version}' 387 388 389class ClientError(Exception): 390 MSG_TEMPLATE = ( 391 'An error occurred ({error_code}) when calling the {operation_name} ' 392 'operation{retry_info}: {error_message}') 393 394 def __init__(self, error_response, operation_name): 395 retry_info = self._get_retry_info(error_response) 396 error = error_response.get('Error', {}) 397 msg = self.MSG_TEMPLATE.format( 398 error_code=error.get('Code', 'Unknown'), 399 error_message=error.get('Message', 'Unknown'), 400 operation_name=operation_name, 401 retry_info=retry_info, 402 ) 403 super(ClientError, self).__init__(msg) 404 self.response = error_response 405 self.operation_name = operation_name 406 407 def _get_retry_info(self, response): 408 retry_info = '' 409 if 'ResponseMetadata' in response: 410 metadata = response['ResponseMetadata'] 411 if metadata.get('MaxAttemptsReached', False): 412 if 'RetryAttempts' in metadata: 413 retry_info = (' (reached max retries: %s)' % 414 metadata['RetryAttempts']) 415 return retry_info 416 417 def __reduce__(self): 418 # Subclasses of ClientError's are dynamically generated and 419 # cannot be pickled unless they are attributes of a 420 # module. So at the very least return a ClientError back. 421 return ClientError, (self.response, self.operation_name) 422 423 424class EventStreamError(ClientError): 425 pass 426 427 428class UnsupportedTLSVersionWarning(Warning): 429 """Warn when an openssl version that uses TLS 1.2 is required""" 430 pass 431 432 433class ImminentRemovalWarning(Warning): 434 pass 435 436 437class InvalidDNSNameError(BotoCoreError): 438 """Error when virtual host path is forced on a non-DNS compatible bucket""" 439 fmt = ( 440 'Bucket named {bucket_name} is not DNS compatible. Virtual ' 441 'hosted-style addressing cannot be used. The addressing style ' 442 'can be configured by removing the addressing_style value ' 443 'or setting that value to \'path\' or \'auto\' in the AWS Config ' 444 'file or in the botocore.client.Config object.' 445 ) 446 447 448class InvalidS3AddressingStyleError(BotoCoreError): 449 """Error when an invalid path style is specified""" 450 fmt = ( 451 'S3 addressing style {s3_addressing_style} is invalid. Valid options ' 452 'are: \'auto\', \'virtual\', and \'path\'' 453 ) 454 455 456class UnsupportedS3ArnError(BotoCoreError): 457 """Error when S3 ARN provided to Bucket parameter is not supported""" 458 fmt = ( 459 'S3 ARN {arn} provided to "Bucket" parameter is invalid. Only ' 460 'ARNs for S3 access-points are supported.' 461 ) 462 463 464class UnsupportedS3AccesspointConfigurationError(BotoCoreError): 465 """Error when an unsupported configuration is used with access-points""" 466 fmt = ( 467 'Unsupported configuration when using S3 access-points: {msg}' 468 ) 469 470 471class InvalidRetryConfigurationError(BotoCoreError): 472 """Error when invalid retry configuration is specified""" 473 fmt = ( 474 'Cannot provide retry configuration for "{retry_config_option}". ' 475 'Valid retry configuration options are: \'max_attempts\'' 476 ) 477 478 479class InvalidMaxRetryAttemptsError(InvalidRetryConfigurationError): 480 """Error when invalid retry configuration is specified""" 481 fmt = ( 482 'Value provided to "max_attempts": {provided_max_attempts} must ' 483 'be an integer greater than or equal to {min_value}.' 484 ) 485 486 487class InvalidRetryModeError(InvalidRetryConfigurationError): 488 """Error when invalid retry mode configuration is specified""" 489 fmt = ( 490 'Invalid value provided to "mode": "{provided_retry_mode}" must ' 491 'be one of: "legacy", "standard", "adaptive"' 492 ) 493 494 495class InvalidS3UsEast1RegionalEndpointConfigError(BotoCoreError): 496 """Error for invalid s3 us-east-1 regional endpoints configuration""" 497 fmt = ( 498 'S3 us-east-1 regional endpoint option ' 499 '{s3_us_east_1_regional_endpoint_config} is ' 500 'invalid. Valid options are: "legacy", "regional"' 501 ) 502 503 504class InvalidSTSRegionalEndpointsConfigError(BotoCoreError): 505 """Error when invalid sts regional endpoints configuration is specified""" 506 fmt = ( 507 'STS regional endpoints option {sts_regional_endpoints_config} is ' 508 'invalid. Valid options are: "legacy", "regional"' 509 ) 510 511 512class StubResponseError(BotoCoreError): 513 fmt = 'Error getting response stub for operation {operation_name}: {reason}' 514 515 516class StubAssertionError(StubResponseError, AssertionError): 517 pass 518 519 520class UnStubbedResponseError(StubResponseError): 521 pass 522 523 524class InvalidConfigError(BotoCoreError): 525 fmt = '{error_msg}' 526 527 528class InfiniteLoopConfigError(InvalidConfigError): 529 fmt = ( 530 'Infinite loop in credential configuration detected. Attempting to ' 531 'load from profile {source_profile} which has already been visited. ' 532 'Visited profiles: {visited_profiles}' 533 ) 534 535 536class RefreshWithMFAUnsupportedError(BotoCoreError): 537 fmt = 'Cannot refresh credentials: MFA token required.' 538 539 540class MD5UnavailableError(BotoCoreError): 541 fmt = "This system does not support MD5 generation." 542 543 544class MetadataRetrievalError(BotoCoreError): 545 fmt = "Error retrieving metadata: {error_msg}" 546 547 548class UndefinedModelAttributeError(Exception): 549 pass 550 551 552class MissingServiceIdError(UndefinedModelAttributeError): 553 fmt = ( 554 "The model being used for the service {service_name} is missing the " 555 "serviceId metadata property, which is required." 556 ) 557 558 def __init__(self, **kwargs): 559 msg = self.fmt.format(**kwargs) 560 Exception.__init__(self, msg) 561 self.kwargs = kwargs 562 563 564class SSOError(BotoCoreError): 565 fmt = "An unspecified error happened when resolving SSO credentials" 566 567 568class SSOTokenLoadError(SSOError): 569 fmt = "Error loading SSO Token: {error_msg}" 570 571 572class UnauthorizedSSOTokenError(SSOError): 573 fmt = ( 574 "The SSO session associated with this profile has expired or is " 575 "otherwise invalid. To refresh this SSO session run aws sso login " 576 "with the corresponding profile." 577 ) 578 579 580class CapacityNotAvailableError(BotoCoreError): 581 fmt = ( 582 'Insufficient request capacity available.' 583 ) 584