-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve error message for sigv4 and PermanentRedirect errors
The error message now includes a note on specifying the correct region: $ aws s3api list-objects --bucket wrong.region.bucket A client error (PermanentRedirect) occurred when calling the ListObjects operation: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint: wrong.region.bucket.s3-ap-southeast-2.amazonaws.com You can fix this issue by explicity providing the correct region location using the --region argument, the AWS_DEFAULT_REGION environment variable, or the region variable in the AWS CLI configuration file. You can get the bucket's location by running "aws s3api get-bucket-location --bucket BUCKET". Same thing when you try to access a bucket in eu-central-1.
- Loading branch information
Showing
3 changed files
with
130 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"). You | ||
# may not use this file except in compliance with the License. A copy of | ||
# the License is located at | ||
# | ||
# http://aws.amazon.com/apache2.0/ | ||
# | ||
# or in the "license" file accompanying this file. This file is | ||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | ||
# ANY KIND, either express or implied. See the License for the specific | ||
# language governing permissions and limitations under the License. | ||
"""Give better S3 error messages. | ||
""" | ||
from awscli.customizations import utils | ||
|
||
|
||
REGION_ERROR_MSG = ( | ||
'You can fix this issue by explicity providing the correct region ' | ||
'location using the --region argument, the AWS_DEFAULT_REGION ' | ||
'environment variable, or the region variable in the AWS CLI ' | ||
"configuration file. You can get the bucket's location by " | ||
'running "aws s3api get-bucket-location --bucket BUCKET".' | ||
) | ||
|
||
|
||
def register_s3_error_msg(event_handlers): | ||
event_handlers.register('after-call.s3', enhance_error_msg) | ||
|
||
|
||
def enhance_error_msg(parsed, **kwargs): | ||
if parsed is None or 'Error' not in parsed: | ||
# There's no error message to enhance so we can continue. | ||
return | ||
if _is_sigv4_error_message(parsed): | ||
message = ( | ||
'You are attempting to operate on a bucket in a region ' | ||
'that requires Signature Version 4. ' | ||
) | ||
message += REGION_ERROR_MSG | ||
parsed['Error']['Message'] = message | ||
elif _is_permanent_redirect_message(parsed): | ||
endpoint = parsed['Error']['Endpoint'] | ||
message = parsed['Error']['Message'] | ||
new_message = message[:-1] + ': %s\n' % endpoint | ||
new_message += REGION_ERROR_MSG | ||
parsed['Error']['Message'] = new_message | ||
|
||
|
||
def _is_sigv4_error_message(parsed): | ||
return ('Please use AWS4-HMAC-SHA256' in | ||
parsed.get('Error', {}).get('Message', '')) | ||
|
||
|
||
def _is_permanent_redirect_message(parsed): | ||
return parsed.get('Error', {}).get('Code', '') == 'PermanentRedirect' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"). You | ||
# may not use this file except in compliance with the License. A copy of | ||
# the License is located at | ||
# | ||
# http://aws.amazon.com/apache2.0e | ||
# | ||
# or in the "license" file accompanying this file. This file is | ||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF | ||
# ANY KIND, either express or implied. See the License for the specific | ||
# language governing permissions and limitations under the License. | ||
import copy | ||
|
||
from awscli.testutils import unittest | ||
from awscli.customizations import s3errormsg | ||
|
||
|
||
class TestGetRegionFromEndpoint(unittest.TestCase): | ||
|
||
def test_sigv4_error_message(self): | ||
parsed = { | ||
'Error': { | ||
'Message': 'Please use AWS4-HMAC-SHA256' | ||
} | ||
} | ||
s3errormsg.enhance_error_msg(parsed) | ||
# We should say how to fix the issue. | ||
self.assertIn('You can fix this issue', | ||
parsed['Error']['Message']) | ||
# We should mention the --region argument. | ||
self.assertIn('--region', parsed['Error']['Message']) | ||
# We should mention get-bucket-location | ||
self.assertIn('get-bucket-location', parsed['Error']['Message']) | ||
|
||
def test_301_error_message(self): | ||
parsed = { | ||
'Error': { | ||
'Code': 'PermanentRedirect', | ||
'Message': "Please use the correct endpoint.", | ||
'Endpoint': "myendpoint", | ||
} | ||
} | ||
s3errormsg.enhance_error_msg(parsed) | ||
# We should include the endpoint in the error message. | ||
error_message = parsed['Error']['Message'] | ||
self.assertIn('myendpoint', error_message) | ||
|
||
def test_error_message_not_enhanced(self): | ||
parsed = { | ||
'Error': { | ||
'Message': 'This is a different error message.', | ||
'Code': 'Other Message' | ||
} | ||
} | ||
expected = copy.deepcopy(parsed) | ||
s3errormsg.enhance_error_msg(parsed) | ||
# Nothing should have changed | ||
self.assertEqual(parsed, expected) | ||
|
||
def test_not_an_error_message(self): | ||
parsed = { | ||
'Success': 'response', | ||
'ResponseMetadata': {} | ||
} | ||
expected = copy.deepcopy(parsed) | ||
s3errormsg.enhance_error_msg(parsed) | ||
# Nothing should have changed | ||
self.assertEqual(parsed, expected) |