diff --git a/samcli/commands/deploy/exceptions.py b/samcli/commands/deploy/exceptions.py index 191a353c52..04d155e1bc 100644 --- a/samcli/commands/deploy/exceptions.py +++ b/samcli/commands/deploy/exceptions.py @@ -47,6 +47,15 @@ def __init__(self, stack_name, msg): ) +class DeployBucketInDifferentRegionError(UserException): + def __init__(self, msg): + self.msg = msg + + message_fmt = "{msg} : deployment s3 bucket is in a different region, try sam deploy --guided" + + super(DeployBucketInDifferentRegionError, self).__init__(message=message_fmt.format(msg=self.msg)) + + class DeployBucketRequiredError(UserException): def __init__(self): diff --git a/samcli/lib/deploy/deployer.py b/samcli/lib/deploy/deployer.py index 491ebc3f9f..c05a38697c 100644 --- a/samcli/lib/deploy/deployer.py +++ b/samcli/lib/deploy/deployer.py @@ -25,7 +25,12 @@ import botocore from samcli.lib.deploy.utils import DeployColor -from samcli.commands.deploy.exceptions import DeployFailedError, ChangeSetError, DeployStackOutPutFailedError +from samcli.commands.deploy.exceptions import ( + DeployFailedError, + ChangeSetError, + DeployStackOutPutFailedError, + DeployBucketInDifferentRegionError, +) from samcli.commands._utils.table_print import pprint_column_names, pprint_columns from samcli.commands.deploy import exceptions as deploy_exceptions from samcli.lib.package.artifact_exporter import mktempfile, parse_s3_url @@ -176,6 +181,10 @@ def create_changeset( try: resp = self._client.create_change_set(**kwargs) return resp, changeset_type + except botocore.exceptions.ClientError as ex: + if "The bucket you are attempting to access must be addressed using the specified endpoint" in str(ex): + raise DeployBucketInDifferentRegionError(f"Failed to create/update stack {stack_name}") + except Exception as ex: LOG.debug("Unable to create changeset", exc_info=ex) raise ChangeSetError(stack_name=stack_name, msg=str(ex)) diff --git a/tests/unit/lib/deploy/test_deployer.py b/tests/unit/lib/deploy/test_deployer.py index 69ee317e25..8749f1bb01 100644 --- a/tests/unit/lib/deploy/test_deployer.py +++ b/tests/unit/lib/deploy/test_deployer.py @@ -6,7 +6,12 @@ from botocore.exceptions import ClientError, WaiterError, BotoCoreError -from samcli.commands.deploy.exceptions import DeployFailedError, ChangeSetError, DeployStackOutPutFailedError +from samcli.commands.deploy.exceptions import ( + DeployFailedError, + ChangeSetError, + DeployStackOutPutFailedError, + DeployBucketInDifferentRegionError, +) from samcli.lib.deploy.deployer import Deployer from samcli.lib.package.s3_uploader import S3Uploader from samcli.lib.utils.time import utc_to_timestamp, to_datetime @@ -158,6 +163,36 @@ def test_create_changeset_exception(self): tags={"unit": "true"}, ) + def test_create_changeset_ClientErrorException(self): + error_message = ( + "An error occurred (ValidationError) when calling the CreateChangeSet " + "operation: S3 error: The bucket you are attempting to access must be " + "addressed using the specified endpoint. " + "Please send all future requests to this " + "endpoint.\nFor more information " + "check http://docs.aws.amazon.com/AmazonS3/latest/API/ErrorResponses.html" + ) + self.deployer.has_stack = MagicMock(return_value=False) + self.deployer._client.create_change_set = MagicMock( + side_effect=ClientError( + error_response={"Error": {"Message": error_message}}, operation_name="create_changeset" + ) + ) + with self.assertRaises(DeployBucketInDifferentRegionError): + self.deployer.create_changeset( + stack_name="test", + cfn_template=" ", + parameter_values=[ + {"ParameterKey": "a", "ParameterValue": "b"}, + {"ParameterKey": "c", "UsePreviousValue": True}, + ], + capabilities=["CAPABILITY_IAM"], + role_arn="role-arn", + notification_arns=[], + s3_uploader=S3Uploader(s3_client=self.s3_client, bucket_name="test_bucket"), + tags={"unit": "true"}, + ) + def test_describe_changeset_with_changes(self): response = [ {