aws / aws-cli

Universal Command Line Interface for Amazon Web Services
Other
15.14k stars 4.02k forks source link

Add AWS::CloudFormation::Stackset resource to the cloudformation package command #5590

Open ConnorKirk opened 3 years ago

ConnorKirk commented 3 years ago

Is your feature request related to a problem? Please describe. I would like to be able to use the aws cloudformation package command to package the AWS::CloudFormation::Stackset resource TemplateURL property. Currently it is not supported.

Describe the solution you'd like See above

Describe alternatives you've considered N/A

Additional context I have started a PR for this - https://github.com/aws/aws-cli/pull/5591

iainelder commented 3 years ago

It would be great to see this included.

In the meantime you can use cfn-flip and jq to preprocess and postprocess the result for the package command.

cfn-flip template.yaml \
| jq '
.Resources |= with_entries(
    (.value.Type == "AWS::CloudFormation::StackSet") as $is_stackset
    | .key |= (if $is_stackset then "__STACKSET__" + . else . end)
    | .value.Type |= (if $is_stackset then "AWS::CloudFormation::Stack" else . end)
)' \
| cfn-flip > preprocessed.yaml

aws cloudformation package \
--template-file preprocessed.yaml \
--s3-bucket ... \
--output-template-file packaged.yaml

cfn-flip packaged.yaml \
| jq '
.Resources |= with_entries(
    (.key | startswith("__STACKSET__")) as $is_stackset
    | .key |= (if $is_stackset then split("__STACKSET__")[1] else . end)
    | .value.Type |= (if $is_stackset then "AWS::CloudFormation::StackSet" else . end)
)' \
| cfn-flip > postprocessed.yaml

cfn-flip converts YAML CloudFormation templates to JSON and vice versa.

The first jq program modifies each stack set resource so that the package command will process them. It replaces the StackSet type declaration with a Stack type declaration. It prepends a __STACKSET__ flag to the logical resource name so that the process can be reversed.

The preprocessed.yaml is an invalid CloudFormation template because the StackSet properties don't make sense for the Stack type.

The package command ignores this and does its job. The packaged.yaml is still an invalid CloudFormation template, but it contains the S3 URLs we were hoping for.

The second jq program reverses the changes of the first program.

The postprocessed.yaml is once more a valid CloudFormation template and more or less the result you would hope for. Comments in the original template.yaml are lost, but the resource graph is equivalent.

All the files are written to the same directory as the template.yaml to ensure that relative paths are still correct. After deploying the template you will probably want to delete preprocessed.yaml, packaged.yaml, and postprocessed.yaml to keep your source files clean.

andrewlytle commented 2 years ago

Any chance this is going to get added soon?

nandubatchu commented 1 year ago

Thanks for the PR - I made it work with your dev branch. Hope this gets merged soon!

iainelder commented 11 months ago

Another workaround is to use CloudFormation Rain CLI.

Its !Rain::S3Http is a more powerful version of the package command. that works with any property.

The rain deploy and rain package commands upload a file or directory to S3 and inserts the HTTPS URL into the template as a string.

Resources:
  Example:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: example
      TemplateURL: !Rain::S3Http instance-template.yaml