aws / aws-sam-cli

CLI tool to build, test, debug, and deploy Serverless applications using AWS SAM
https://aws.amazon.com/serverless/sam/
Apache License 2.0
6.52k stars 1.17k forks source link

Bug: `sam build`and `sam package` commands are not building resources recursively for stacksets #4653

Open baxterjo opened 1 year ago

baxterjo commented 1 year ago

Description:

Unsure if this is a bug report or a feature request, but I have successfully deployed nested applications with sam I would expect the build a package steps for stacksets to look similar, so I think it is a bug.

The sam build and sam package steps for templates containing AWS::CloudFormation::StackSet resources are not generating the necessary artifacts for deploying the stackset resource with sam and I think this is because they are not looking into the templates recursively for these steps.

Steps to reproduce:

Filestructure:

.
+-- src
|   +-- traffic_forwarder_pkg
|       +-- traffic_forwarder.py
|       +-- traffic_forwarder_lib
|           +-- lib_file.py
|       +-- requirements.txt
+-- template.yaml
+-- traffic_forwarder_template.yaml

I have an AWS::CloudFormation::StackSet resource in template.yaml that looks similar to the following:

TrafficForwarderStackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: !Sub ${AWS::StackName}-TrafficForwarderStackSet
      PermissionModel: SELF_MANAGED
      ManagedExecution:
        Active: true
      Capabilities:
        - CAPABILITY_AUTO_EXPAND
        - CAPABILITY_IAM
      TemplateURL: ./traffic_forwarder_template.yaml
      StackInstancesGroup:
        - DeploymentTargets:
            Accounts: [target_accounts]
          Regions:
            - !Ref AWS::Region

The local template for the stackset contains a serverless function that uses a local file path and looks like the following:

TrafficForwarder:
    Type: AWS::Serverless::Function
    Properties:
      Runtime: python3.8
      CodeUri: ./src/traffic_forwarder_pkg
      Handler: traffic_forwarder.lambda_handler

Observed result:

When sam build is run, the following build directory is produced in the .aws-sam directory:

build
+-- lambda_build_1/
+-- lambda_build_2/
+-- lambda_build_3/
+-- template.yaml

With no traffic_forwarder_template.yaml file or TrafficForwarder directory to be found.

This problem cascades into the package and deploy step since there are no resources to be found in the build directory.

Expected result:

I would expect Lambda deployment packages for the lambda located in the stackset template to be in the build directory after build is run. Then package should upload those packages to S3 and replace code uri in all appropriate locations with the S3 URI.

Additional environment details (Ex: Windows, Mac, Amazon Linux etc)

# Paste the output of `sam --info` here
{
  "version": "1.71.0",
  "system": {
    "python": "3.8.13",
    "os": "macOS-13.1-arm64-arm-64bit"
  },
  "additional_dependencies": {
    "docker_engine": "Not available",
    "aws_cdk": "Not available",
    "terraform": "1.3.7"
  }
}
baxterjo commented 1 year ago

Temporary Workaround

My deployment process is fairly lockstep with my CI, so I have made a workaround that relies pretty heavily on the CI to get sam to do what I want. Basically what has to happen is the CI needs to build and package the stackset template in a separate step, then save the packaged template to a hard coded file path that is also hard coded in template.yaml. So this is the sequence of commands:

# Build lambda functions in local directory *including requirements file*

sam build \
--template-file traffic_forwarder_template.yaml

# Send the built lambda functions for the stackset to S3, 
# replaces the codeuri with the appropriate s3 uri, 
# and outputs to packages_stackset.yaml
sam package \
--output-template-file packaged_stackset_template.yaml

# Build the template that holds the stackset resource

sam build

# Deploy the template that holds the stackset resource

sam deploy

and the stackset resource in my template.yaml looks like this

TrafficForwarderStackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: !Sub ${AWS::StackName}-TrafficForwarderStackSet
      PermissionModel: SELF_MANAGED
      ManagedExecution:
        Active: true
      Capabilities:
        - CAPABILITY_AUTO_EXPAND
        - CAPABILITY_IAM
      TemplateURL: ./packaged_stackset_template.yaml
      StackInstancesGroup:
        - DeploymentTargets:
            Accounts: [target_accounts]
          Regions:
            - !Ref AWS::Region

Notice that the output file for sam package and the TemplateURL parameter in the stackset are the same.

This cannot be passed in as a parameter override because the package step that is run implicitly with sam deploy replaces the TemplateURL parameter with an appropriate S3 url after uploading the packaged_stackset_template.yaml

mildaniel commented 1 year ago

Hey @baxterjo, thanks for creating this issue. We don't currently support nested stack sets which is why this isn't working but nested stacks do. I'll mark this as a feature request and bring it up to the team for prioritization.