diff --git a/samcli/commands/exceptions.py b/samcli/commands/exceptions.py index 3912ab9424..159d05bea4 100644 --- a/samcli/commands/exceptions.py +++ b/samcli/commands/exceptions.py @@ -18,3 +18,9 @@ class CredentialsError(UserException): """ Exception class when credentials that have been passed are invalid. """ + + +class RegionError(UserException): + """ + Exception class when no valid region is passed to a client. + """ diff --git a/samcli/lib/bootstrap/bootstrap.py b/samcli/lib/bootstrap/bootstrap.py index a39489e82f..9620465c38 100644 --- a/samcli/lib/bootstrap/bootstrap.py +++ b/samcli/lib/bootstrap/bootstrap.py @@ -7,11 +7,11 @@ import boto3 from botocore.config import Config -from botocore.exceptions import ClientError +from botocore.exceptions import ClientError, NoRegionError, NoCredentialsError from samcli import __version__ from samcli.cli.global_config import GlobalConfig -from samcli.commands.exceptions import UserException +from samcli.commands.exceptions import UserException, CredentialsError, RegionError LOG = logging.getLogger(__name__) @@ -19,9 +19,17 @@ def manage_stack(profile, region): - session = boto3.Session(profile_name=profile if profile else None) - cloudformation_client = session.client("cloudformation", config=Config(region_name=region if region else None)) - + try: + session = boto3.Session(profile_name=profile if profile else None) + cloudformation_client = session.client("cloudformation", config=Config(region_name=region if region else None)) + except NoCredentialsError: + raise CredentialsError( + "Error Setting Up Managed Stack Client: Unable to resolve credentials for the AWS SDK for Python client. Please see their documentation for options to pass in credentials: https://boto3.amazonaws.com/v1/documentation/api/latest/guide/configuration.html" + ) + except NoRegionError: + raise RegionError( + "Error Setting Up Managed Stack Client: Unable to resolve a region. Please provide a region via the --region parameter or by the AWS_REGION environment variable." + ) return _create_or_get_stack(cloudformation_client) diff --git a/tests/unit/lib/bootstrap/test_bootstrap.py b/tests/unit/lib/bootstrap/test_bootstrap.py index fd548b1b66..ccc073abdf 100644 --- a/tests/unit/lib/bootstrap/test_bootstrap.py +++ b/tests/unit/lib/bootstrap/test_bootstrap.py @@ -1,12 +1,13 @@ from unittest import TestCase +from unittest.mock import patch, Mock import botocore.session -from botocore.exceptions import ClientError +from botocore.exceptions import ClientError, NoCredentialsError, NoRegionError from botocore.stub import Stubber -from samcli.commands.exceptions import UserException -from samcli.lib.bootstrap.bootstrap import _create_or_get_stack, _get_stack_template, SAM_CLI_STACK_NAME +from samcli.commands.exceptions import UserException, CredentialsError, RegionError +from samcli.lib.bootstrap.bootstrap import manage_stack, _create_or_get_stack, _get_stack_template, SAM_CLI_STACK_NAME class TestBootstrapManagedStack(TestCase): @@ -14,6 +15,22 @@ def _stubbed_cf_client(self): cf = botocore.session.get_session().create_client("cloudformation") return [cf, Stubber(cf)] + @patch("boto3.Session") + def test_client_missing_credentials(self, boto_mock): + session_mock = Mock() + session_mock.client.side_effect = NoCredentialsError() + boto_mock.return_value = session_mock + with self.assertRaises(CredentialsError): + manage_stack("testprofile", "fake-region") + + @patch("boto3.Session") + def test_client_missing_region(self, boto_mock): + session_mock = Mock() + session_mock.client.side_effect = NoRegionError() + boto_mock.return_value = session_mock + with self.assertRaises(RegionError): + manage_stack("testprofile", "fake-region") + def test_new_stack(self): stub_cf, stubber = self._stubbed_cf_client() # first describe_stacks call will fail