aws-cli icon indicating copy to clipboard operation
aws-cli copied to clipboard

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

Open ConnorKirk opened this issue 5 years ago • 6 comments

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

ConnorKirk avatar Sep 30 '20 11:09 ConnorKirk

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.

iainelder avatar Jul 04 '21 00:07 iainelder

Any chance this is going to get added soon?

andrewlytle avatar Oct 13 '21 15:10 andrewlytle

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

nandubatchu avatar Nov 30 '22 05:11 nandubatchu

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

iainelder avatar Aug 11 '23 15:08 iainelder

Any change to merge the pull request #5591? SAM CLI does not support packaging stacksets as suggested in some of the comments here/in the PR, and Rain CLI does not look like something I would like to adopt at the moment.

One alternative approach to the suggested script I can think of is to package the file the AWS::CloudFormation::Stackset's TemplateURL property points to, upload it to S3 and change the local path to the upload's URL.

jhonkan avatar Aug 30 '24 11:08 jhonkan

Hi. I hope this feature will come soon.

One real workaround is this:

Transform:
  - AWS::LanguageExtensions
  
...

      TemplateBody:
        Fn::ToJsonString:
             'Fn::Transform':
                Name: 'AWS::Include'
                Parameters:
                  Location:  template-without-shorthand-functions.yaml

By this solution you need to know, that the executions of functions in the template-without-shorthand-functions.yaml will be executed by the ToJsonString. So you have to set the Stack-Set-Parameters with the Stack-Set-Owning-Template-Parameters. So it might be that you have to Nest the StackSet inside a new nested Stack. Complicated, but it works.

gataka avatar Sep 16 '24 10:09 gataka