Example #1
0
 def test_sam_nested_stack_template_path_can_be_resolved_if_root_template_is_not_in_working_dir(
         self, resource_type, location_property_name, child_location,
         child_location_path):
     template_file = "somedir/template.yaml"
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: child_location
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         template_file: template,
         child_location_path: LEAF_TEMPLATE,
     }.get(t)
     stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
         template_file,
         "",
         "",
         parameter_overrides=None,
     )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", template_file, {}, template),
             Stack("", "ChildStack", child_location_path, {},
                   LEAF_TEMPLATE),
         ],
     )
     self.assertFalse(remote_stack_full_paths)
Example #2
0
 def test_sam_nested_stack_should_be_extracted(self, resource_type,
                                               location_property_name,
                                               child_location,
                                               child_location_path):
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: child_location
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
         child_location_path: LEAF_TEMPLATE,
     }.get(t)
     stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
         self.template_file,
         "",
         "",
         parameter_overrides=None,
     )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, {}, template),
             Stack("", "ChildStack", child_location_path, {},
                   LEAF_TEMPLATE),
         ],
     )
     self.assertFalse(remote_stack_full_paths)
    def __enter__(self) -> "BuildContext":

        self._stacks = SamLocalStackProvider.get_stacks(
            self._template_file, parameter_overrides=self._parameter_overrides)

        self._function_provider = SamFunctionProvider(self.stacks)
        self._layer_provider = SamLayerProvider(self.stacks)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(
                pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._cached:
            cache_path = pathlib.Path(self._cache_dir)
            cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS,
                             parents=True,
                             exist_ok=True)
            self._cache_dir = str(cache_path.resolve())

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network,
                skip_pull_image=self._skip_pull_image)

        return self
Example #4
0
 def test_remote_stack_is_skipped(self, resource_type,
                                  location_property_name):
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: "s3://bucket/key"
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
     }.get(t)
     stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
         self.template_file,
         "",
         "",
         parameter_overrides=None,
     )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, {}, template),
         ],
     )
     self.assertEqual(remote_stack_full_paths, ["ChildStack"])
 def test_sam_nested_stack_should_not_be_extracted_when_recursive_is_disabled(
         self, resource_type, location_property_name, child_location,
         child_location_path):
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: child_location
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
         child_location_path: LEAF_TEMPLATE,
     }.get(t)
     with patch.dict(
             os.environ,
         {SamLocalStackProvider.ENV_SAM_CLI_ENABLE_NESTED_STACK: ""}):
         stacks = SamLocalStackProvider.get_stacks(
             self.template_file,
             "",
             "",
             parameter_overrides=None,
         )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, None, template),
         ],
     )
Example #6
0
    def test_global_parameter_overrides_can_be_passed_to_child_stacks(
        self, resource_type, location_property_name, child_location, child_location_path
    ):
        template_file = "somedir/template.yaml"
        template = {
            "Resources": {
                "ChildStack": {
                    "Type": resource_type,
                    "Properties": {location_property_name: child_location},
                }
            }
        }
        self.get_template_data_mock.side_effect = lambda t: {
            template_file: template,
            child_location_path: LEAF_TEMPLATE,
        }.get(t)

        global_parameter_overrides = {"AWS::Region": "custom_region"}

        stacks = SamLocalStackProvider.get_stacks(
            template_file, "", "", parameter_overrides=None, global_parameter_overrides=global_parameter_overrides
        )
        self.assertListEqual(
            stacks,
            [
                Stack("", "", template_file, global_parameter_overrides, template),
                Stack("", "ChildStack", child_location_path, global_parameter_overrides, LEAF_TEMPLATE),
            ],
        )
 def test_remote_stack_is_skipped(self, resource_type,
                                  location_property_name):
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: "s3://bucket/key"
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
     }.get(t)
     with patch.dict(
             os.environ,
         {SamLocalStackProvider.ENV_SAM_CLI_ENABLE_NESTED_STACK: "1"}):
         stacks = SamLocalStackProvider.get_stacks(
             self.template_file,
             "",
             "",
             parameter_overrides=None,
         )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, None, template),
         ],
     )
Example #8
0
 def test_sam_nested_stack_template_path_can_be_resolved_if_root_template_is_not_in_working_dir(
         self, resource_type, location_property_name, child_location,
         child_location_path):
     template_file = "somedir/template.yaml"
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": resource_type,
                 "Properties": {
                     location_property_name: child_location
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         template_file: template,
         child_location_path: LEAF_TEMPLATE,
     }.get(t)
     with patch.dict(
             os.environ,
         {SamLocalStackProvider.ENV_SAM_CLI_ENABLE_NESTED_STACK: "1"}):
         stacks = SamLocalStackProvider.get_stacks(
             template_file,
             "",
             "",
             parameter_overrides=None,
         )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", template_file, None, template),
             Stack("", "ChildStack", child_location_path, None,
                   LEAF_TEMPLATE),
         ],
     )
Example #9
0
 def _get_stacks(self):
     try:
         return SamLocalStackProvider.get_stacks(
             self._template_file,
             parameter_overrides=self.parameter_overrides)
     except (TemplateNotFoundException,
             TemplateFailedParsingException) as ex:
         raise InvokeContextException(str(ex)) from ex
Example #10
0
 def _get_stacks(self) -> List[Stack]:
     try:
         stacks, _ = SamLocalStackProvider.get_stacks(
             self._template_file,
             parameter_overrides=self._parameter_overrides,
             global_parameter_overrides=self._global_parameter_overrides,
         )
         return stacks
     except (TemplateNotFoundException,
             TemplateFailedParsingException) as ex:
         raise InvokeContextException(str(ex)) from ex
Example #11
0
 def test_sam_deep_nested_stack(self):
     child_template_file = "./child.yaml"
     grand_child_template_file = "./grand-child.yaml"
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": AWS_SERVERLESS_APPLICATION,
                 "Properties": {
                     "Location": child_template_file
                 },
             }
         }
     }
     child_template = {
         "Resources": {
             "GrandChildStack": {
                 "Type": AWS_SERVERLESS_APPLICATION,
                 "Properties": {
                     "Location": grand_child_template_file
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
         child_template_file: child_template,
         grand_child_template_file: LEAF_TEMPLATE,
     }.get(t)
     with patch.dict(
             os.environ,
         {SamLocalStackProvider.ENV_SAM_CLI_ENABLE_NESTED_STACK: "1"}):
         stacks = SamLocalStackProvider.get_stacks(
             self.template_file,
             "",
             "",
             parameter_overrides=None,
         )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, None, template),
             Stack("", "ChildStack", child_template_file, None,
                   child_template),
             Stack("ChildStack", "GrandChildStack",
                   grand_child_template_file, None, LEAF_TEMPLATE),
         ],
     )
Example #12
0
 def test_sam_deep_nested_stack(self):
     child_template_file = "child.yaml"
     grand_child_template_file = "grand-child.yaml"
     template = {
         "Resources": {
             "ChildStack": {
                 "Type": AWS_SERVERLESS_APPLICATION,
                 "Properties": {
                     "Location": child_template_file
                 },
             }
         }
     }
     child_template = {
         "Resources": {
             "GrandChildStack": {
                 "Type": AWS_SERVERLESS_APPLICATION,
                 "Properties": {
                     "Location": grand_child_template_file
                 },
             }
         }
     }
     self.get_template_data_mock.side_effect = lambda t: {
         self.template_file: template,
         child_template_file: child_template,
         grand_child_template_file: LEAF_TEMPLATE,
     }.get(t)
     stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
         self.template_file,
         "",
         "",
         parameter_overrides=None,
     )
     self.assertListEqual(
         stacks,
         [
             Stack("", "", self.template_file, {}, template),
             Stack("", "ChildStack", child_template_file, {},
                   child_template),
             Stack("ChildStack", "GrandChildStack",
                   grand_child_template_file, {}, LEAF_TEMPLATE),
         ],
     )
     self.assertFalse(remote_stack_full_paths)
Example #13
0
    def __enter__(self) -> "BuildContext":

        self._stacks, remote_stack_full_paths = SamLocalStackProvider.get_stacks(
            self._template_file, parameter_overrides=self._parameter_overrides)

        if remote_stack_full_paths:
            LOG.warning(
                "Below nested stacks(s) specify non-local URL(s), which are unsupported:\n%s\n"
                "Skipping building resources inside these nested stacks.",
                "\n".join([
                    f"- {full_path}" for full_path in remote_stack_full_paths
                ]),
            )

        # Note(xinhol): self._use_raw_codeuri is added temporarily to fix issue #2717
        # when base_dir is provided, codeuri should not be resolved based on template file path.
        # we will refactor to make all path resolution inside providers intead of in multiple places
        self._function_provider = SamFunctionProvider(self.stacks,
                                                      self._use_raw_codeuri)
        self._layer_provider = SamLayerProvider(self.stacks,
                                                self._use_raw_codeuri)

        if not self._base_dir:
            # Base directory, if not provided, is the directory containing the template
            self._base_dir = str(
                pathlib.Path(self._template_file).resolve().parent)

        self._build_dir = self._setup_build_dir(self._build_dir, self._clean)

        if self._cached:
            cache_path = pathlib.Path(self._cache_dir)
            cache_path.mkdir(mode=self._BUILD_DIR_PERMISSIONS,
                             parents=True,
                             exist_ok=True)
            self._cache_dir = str(cache_path.resolve())

        if self._use_container:
            self._container_manager = ContainerManager(
                docker_network_id=self._docker_network,
                skip_pull_image=self._skip_pull_image)

        return self
    def guided_prompts(self, parameter_override_keys):
        default_stack_name = self.stack_name or "sam-app"
        default_region = self.region or get_session().get_config_variable(
            "region") or "us-east-1"
        default_capabilities = self.capabilities[0] or ("CAPABILITY_IAM", )
        default_config_env = self.config_env or DEFAULT_ENV
        default_config_file = self.config_file or DEFAULT_CONFIG_FILE_NAME
        input_capabilities = None
        config_env = None
        config_file = None

        click.echo(
            self.color.yellow(
                "\n\tSetting default arguments for 'sam deploy'\n\t========================================="
            ))

        stack_name = prompt(f"\t{self.start_bold}Stack Name{self.end_bold}",
                            default=default_stack_name,
                            type=click.STRING)
        region = prompt(f"\t{self.start_bold}AWS Region{self.end_bold}",
                        default=default_region,
                        type=click.STRING)
        input_parameter_overrides = self.prompt_parameters(
            parameter_override_keys, self.parameter_overrides_from_cmdline,
            self.start_bold, self.end_bold)
        stacks = SamLocalStackProvider.get_stacks(
            self.template_file,
            parameter_overrides=sanitize_parameter_overrides(
                input_parameter_overrides))
        image_repositories = self.prompt_image_repository(stacks)

        click.secho(
            "\t#Shows you resources changes to be deployed and require a 'Y' to initiate deploy"
        )
        confirm_changeset = confirm(
            f"\t{self.start_bold}Confirm changes before deploy{self.end_bold}",
            default=self.confirm_changeset)
        click.secho(
            "\t#SAM needs permission to be able to create roles to connect to the resources in your template"
        )
        capabilities_confirm = confirm(
            f"\t{self.start_bold}Allow SAM CLI IAM role creation{self.end_bold}",
            default=True)

        if not capabilities_confirm:
            input_capabilities = prompt(
                f"\t{self.start_bold}Capabilities{self.end_bold}",
                default=list(default_capabilities),
                type=FuncParamType(func=_space_separated_list_func_type),
            )

        self.prompt_authorization(stacks)
        self.prompt_code_signing_settings(stacks)

        save_to_config = confirm(
            f"\t{self.start_bold}Save arguments to configuration file{self.end_bold}",
            default=True)
        if save_to_config:
            config_file = prompt(
                f"\t{self.start_bold}SAM configuration file{self.end_bold}",
                default=default_config_file,
                type=click.STRING,
            )
            config_env = prompt(
                f"\t{self.start_bold}SAM configuration environment{self.end_bold}",
                default=default_config_env,
                type=click.STRING,
            )

        s3_bucket = manage_stack(profile=self.profile, region=region)
        click.echo(f"\n\t\tManaged S3 bucket: {s3_bucket}")
        click.echo(
            "\t\tA different default S3 bucket can be set in samconfig.toml")

        self.guided_stack_name = stack_name
        self.guided_s3_bucket = s3_bucket
        self.guided_image_repositories = image_repositories
        self.guided_s3_prefix = stack_name
        self.guided_region = region
        self.guided_profile = self.profile
        self._capabilities = input_capabilities if input_capabilities else default_capabilities
        self._parameter_overrides = (input_parameter_overrides
                                     if input_parameter_overrides else
                                     self.parameter_overrides_from_cmdline)
        self.save_to_config = save_to_config
        self.config_env = config_env if config_env else default_config_env
        self.config_file = config_file if config_file else default_config_file
        self.confirm_changeset = confirm_changeset
Example #15
0
    def deploy(
        self,
        stack_name,
        template_str,
        parameters,
        capabilities,
        no_execute_changeset,
        role_arn,
        notification_arns,
        s3_uploader,
        tags,
        region,
        fail_on_empty_changeset=True,
        confirm_changeset=False,
    ):
        """
        Deploy the stack to cloudformation.
        - if changeset needs confirmation, it will prompt for customers to confirm.
        - if no_execute_changeset is True, the changeset won't be executed.

        Parameters
        ----------
        stack_name : str
            name of the stack
        template_str : str
            the string content of the template
        parameters : List[Dict]
            List of parameters
        capabilities : List[str]
            List of capabilities
        no_execute_changeset : bool
            A bool indicating whether to execute changeset
        role_arn : str
            the Arn of the role to create changeset
        notification_arns : List[str]
            Arns for sending notifications
        s3_uploader : S3Uploader
            S3Uploader object to upload files to S3 buckets
        tags : List[str]
            List of tags passed to CloudFormation
        region : str
            AWS region to deploy the stack to
        fail_on_empty_changeset : bool
            Should fail when changeset is empty
        confirm_changeset : bool
            Should wait for customer's confirm before executing the changeset
        """
        stacks, _ = SamLocalStackProvider.get_stacks(
            self.template_file,
            parameter_overrides=sanitize_parameter_overrides(
                self.parameter_overrides))
        auth_required_per_resource = auth_per_resource(stacks)

        for resource, authorization_required in auth_required_per_resource:
            if not authorization_required:
                click.secho(f"{resource} may not have authorization defined.",
                            fg="yellow")

        try:
            result, changeset_type = self.deployer.create_and_wait_for_changeset(
                stack_name=stack_name,
                cfn_template=template_str,
                parameter_values=parameters,
                capabilities=capabilities,
                role_arn=role_arn,
                notification_arns=notification_arns,
                s3_uploader=s3_uploader,
                tags=tags,
            )
            click.echo(
                self.MSG_SHOWCASE_CHANGESET.format(changeset_id=result["Id"]))

            if no_execute_changeset:
                return

            if confirm_changeset:
                click.secho(self.MSG_CONFIRM_CHANGESET_HEADER, fg="yellow")
                click.secho("=" * len(self.MSG_CONFIRM_CHANGESET_HEADER),
                            fg="yellow")
                if not click.confirm(f"{self.MSG_CONFIRM_CHANGESET}",
                                     default=False):
                    return

            self.deployer.execute_changeset(result["Id"], stack_name)
            self.deployer.wait_for_execute(stack_name, changeset_type)
            click.echo(
                self.MSG_EXECUTE_SUCCESS.format(stack_name=stack_name,
                                                region=region))

        except deploy_exceptions.ChangeEmptyError as ex:
            if fail_on_empty_changeset:
                raise
            click.echo(str(ex))