{"id":13598385,"url":"https://github.com/aws-cloudformation/rain","last_synced_at":"2025-05-14T10:12:23.536Z","repository":{"id":35930800,"uuid":"185874127","full_name":"aws-cloudformation/rain","owner":"aws-cloudformation","description":"A development workflow tool for working with AWS CloudFormation.","archived":false,"fork":false,"pushed_at":"2024-12-17T22:21:39.000Z","size":61091,"stargazers_count":825,"open_issues_count":71,"forks_count":75,"subscribers_count":14,"default_branch":"main","last_synced_at":"2024-12-18T19:03:43.301Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aws-cloudformation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-05-09T21:28:16.000Z","updated_at":"2024-12-18T11:09:35.000Z","dependencies_parsed_at":"2023-11-15T17:31:59.321Z","dependency_job_id":"30178a1f-011a-47fd-97de-9bc52639f220","html_url":"https://github.com/aws-cloudformation/rain","commit_stats":{"total_commits":1111,"total_committers":37,"mean_commits":"30.027027027027028","dds":0.6084608460846085,"last_synced_commit":"e303a7be83cd7bfa27705ca2f76e377aab4f1266"},"previous_names":[],"tags_count":70,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-cloudformation%2Frain","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-cloudformation%2Frain/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-cloudformation%2Frain/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aws-cloudformation%2Frain/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aws-cloudformation","download_url":"https://codeload.github.com/aws-cloudformation/rain/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248650414,"owners_count":21139671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T17:00:52.184Z","updated_at":"2025-05-14T10:12:23.529Z","avatar_url":"https://github.com/aws-cloudformation.png","language":"Go","funding_links":[],"categories":["others","Go","Further Reading","CLI Tools"],"sub_categories":["Updating Existing Components","Hooks"],"readme":"[![Unit tests](https://github.com/aws-cloudformation/rain/actions/workflows/test.yml/badge.svg)](https://github.com/aws-cloudformation/rain/actions/workflows/test.yml)\n[![Mentioned in Awesome CloudFormation](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/aws-cloudformation/awesome-cloudformation)\n\n# Rain\n\n* Documentation: \u003chttps://aws-cloudformation.github.io/rain/\u003e\n\n\u003e Rain is what happens when you have a lot of CloudFormation\n\nRain is also a command line tool for working with [AWS CloudFormation](https://aws.amazon.com/cloudformation/) templates and stacks.\n\n[![Make it Rain](./docs/rain.svg)](https://asciinema.org/a/vtbAXkriC0zg0T2UzP0t63G4S?autoplay=1)\n\n## Discord\n\nJoin us on Discord to discuss rain and all things CloudFormation! Connect and interact with CloudFormation developers and\nexperts, find channels to discuss rain, the CloudFormation registry, StackSets,\ncfn-lint, Guard and more:\n\n[![Join our Discord](https://discordapp.com/api/guilds/981586120448020580/widget.png?style=banner3)](https://discord.gg/9zpd7TTRwq)\n\n## Key features\n\n* **Interactive deployments**: With `rain deploy`, rain packages your CloudFormation templates, prompts you for any parameters that have not yet been defined, shows you a summary of the changes that will be made, and then displays real-time updates as your stack is being deployed. Once finished, you get a summary of the outcome along with any error messages collected along the way - including errors messages for stacks that have been rolled back and no longer exist.\n\n* **Consistent formatting of CloudFormation templates**: Using `rain fmt`, you can format your CloudFormation templates to a consistent standard or reformat a template from JSON to YAML (or YAML to JSON if you prefer). Rain preserves your comments when using YAML and switches use of [intrinsic functions](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html) to use the short syntax where possible.\n\n* **Combined logs for nested stacks with sensible filtering**: When you run `rain log`, you will see a combined stream of logs from the stack you specified along with any nested stack associated with it. Rain also filters out uninteresting log messages by default so you just see the errors that require attention. You can also use `rain log --chart` to see a Gantt chart that shows you how long each operation took for a given stack.\n\n* **Build new CloudFormation templates**: `rain build` generates new CloudFormation templates containing skeleton resources that you specify. This saves you having to look up which properties are available and which are required vs. optional. Build skeleton templates by specifying a resource name like `AWS::S3::Bucket`, or enable the Bedrock Claude model in your account to use generative AI with a command like `rain build --prompt \"A VPC with 2 subnets\"`. (Note that Bedrock is not free, and requires some [setup](https://docs.aws.amazon.com/bedrock/latest/userguide/model-access.html)). **NEW** Use the `rain build --recommend` command to pick from a list of functional templates that will pass typical compliance checks by default. These templates are great starting points for infrastructure projects.\n\n* **Build policy validation files**: The `rain build` command can now send prompts to the Bedrock Cloude3 Haiku and Sonnet models, which can write Open Policy Agent (OPA) Rego files or CloudFormation Guard files, to verify the compliance of your templates\n\n* **Manipulate CloudFormation stack sets**: `rain stackset deploy` creates a new stackset, updates an existing one or adds a stack instance(s) to an existing stack set. You can list stack sets using `rain stackset ls`, review stack set details with `rain stackset ls \u003cstack set name\u003e` and delete stack set and\\or its instances with `rain stackset rm \u003cstack set name\u003e`\n\n* **Predict deployment failures** (EXPERIMENTAL): `rain forecast` analyzes a template and the target deployment account to predict things that might go wrong when you attempt to create, update, or delete a stack. This command speeds up development by giving you advanced notice for issues like missing permissions, resources that already exist, and a variety of other common resource-specific deployment blockers.\n\n* **Modules** (EXPERIMENTAL): `rain pkg` supports client-side module development. Rain modules are partial templates that are inserted into the parent template, with some extra functionality added to enable extending existing resource types. This feature integrates with CodeArtifact to enable package publish and install.\n\n* **Content Deployment** (EXPERIMENTAL): `rain deploy` and `rain rm` support metadata commands that can upload static assets to a bucket and then delete those assets when the bucket is deleted. Rain can also run build scripts before and after stack deployment to prepare content like web sites and lambda functions before uploading to S3.\n\n_Note that in order to use experimental commands, you have to add `--experimental` or `-x` as an argument._\n\n## Getting started\n\nIf you have [homebrew](https://brew.sh/) installed, `brew install rain`\n\nOr you can download the appropriate binary for your system from [the releases page](https://github.com/aws-cloudformation/rain/releases).\n\nOr if you're a [Gopher](https://blog.golang.org/gopher), you can `go install github.com/aws-cloudformation/rain/cmd/rain@latest`\n\n```\nUsage:\n  rain [command]\n\nStack commands:\n  cat         Get the CloudFormation template from a running stack\n  cc          Interact with templates using Cloud Control API instead of CloudFormation\n  deploy      Deploy a CloudFormation stack or changeset from a local template\n  logs        Show the event log for the named stack\n  ls          List running CloudFormation stacks or changesets\n  rm          Delete a CloudFormation stack or changeset\n  stackset    This command manipulates stack sets.\n  watch       Display an updating view of a CloudFormation stack\n\nTemplate commands:\n  bootstrap   Creates the artifacts bucket\n  build       Create CloudFormation templates\n  diff        Compare CloudFormation templates\n  fmt         Format CloudFormation templates\n  forecast    Predict deployment failures\n  merge       Merge two or more CloudFormation templates\n  module      Interact with Rain modules in CodeArtifact\n  pkg         Package local artifacts into a template\n  tree        Find dependencies of Resources and Outputs in a local template\n\nOther Commands:\n  console     Login to the AWS console\n  help        Help about any command\n  info        Show your current configuration\n```\n\nYou can find shell completion scripts in [docs/bash_completion.sh](./docs/bash_completion.sh) and [docs/zsh_completion.sh](./docs/zsh_completion.sh).\n\n## Contributing\n\nRain is written in [Go](https://golang.org/) and uses the [AWS SDK for Go v2](https://github.com/aws/aws-sdk-go-v2).\n\nTo contribute a change to Rain, [fork this repository](https://github.com/aws-cloudformation/rain/fork), make your changes, and submit a Pull Request.\n\n### Go Generate\n\nThe `README.md`, documentation in `docs/`, the auto completion scripts and a copy of the cloudformation specification in `cft/spec/cfn.go` are generated through `go generate`.\n\n## License\n\nRain is licensed under the Apache 2.0 License. \n\n## Example Usage\n\n### Packaging\n\nThe `rain pkg` command can be used as a replacement for the `aws cloudformation\npackage` CLI command.  When packaging a template, `rain` looks for specific\ndirectives to appear in resources.\n\n#### Embed\n\nThe `!Rain::Embed` directive simply inserts the contents of a file into the template as a string.\n\nThe template:\n\n```yaml\nResources:\n  Test:\n    Type: AWS::CloudFormation::WaitConditionHandle\n    Metadata:\n      Comment: !Rain::Embed embed.txt\n```\nThe contents of `embed.txt`, which is in the same directory as the template:\n\n```txt\nThis is a test\n```\n\nThe resulting packaged template:\n\n```yaml\nResources:\n  Test:\n    Type: AWS::CloudFormation::WaitConditionHandle\n    Metadata:\n      Comment: This is a test\n```\n\n#### Include\n\nThe `!Rain::Include` directive parses a YAML or JSON file and inserts the object into the template.\n\nThe template:\n\n```yaml\nResources:\n  Test:\n    !Rain::Include include-file.yaml\n```\n\nThe file to be included:\n\n```yaml\nType: AWS::S3::Bucket\nProperties:\n  BucketName: test\n```\n\nThe resulting packaged template:\n\n```yaml\nResources:\n  Test:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: test\n```\n\n#### Env\n\nThe `!Rain::Env` directive reads environment variables and inserts them into the template as strings.\n\nThe template:\n\n```yaml\nResources:\n  Test:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Rain::Env BUCKET_NAME\n```\n\nThe resulting packaged template, if you have exported an environment variable named `BUCKET_NAME` with value `abc`:\n\n```yaml\nResources:\n  Test:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: abc\n```\n\n#### S3Http\n\nThe `!Rain::S3Http` directive uploads a file or directory to S3 and inserts the\nHTTPS URL into the template as a string.\n\nThe template:\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URL: !Rain::S3Http s3http.txt\n```\n\nIf you have a file called `s3http.txt` in the same directory as the template,\nrain will use your current default profile to upload the file to the artifact\nbucket that rain creates as a part of bootstrapping. If the path provided is a \ndirectory and not a file, the directory will be zipped first.\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URL: https://rain-artifacts-012345678912-us-east-1.s3.us-east-1.amazonaws.com/a84b588aa54068ed4b027b6e06e5e0bb283f83cf0d5a6720002d36af2225dfc3\n```\n\n#### S3 \n\nThe `!Rain::S3` directive is basically the same as `S3Http`, but it inserts the S3 URI instead of an HTTPS URL.\n\nThe template:\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URI: !Rain::S3 s3.txt\n```\n\nIf you have a file called `s3.txt` in the same directory as the template,\nrain will use your current default profile to upload the file to the artifact\nbucket that rain creates as a part of bootstrapping. If the path provided is a \ndirectory and not a file, the directory will be zipped first.\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URI: s3://rain-artifacts-755952356119-us-east-1/a84b588aa54068ed4b027b6e06e5e0bb283f83cf0d5a6720002d36af2225dfc3 \n```\n\nIf instead of providing a path to a file, you supply an object with properties, you can exercise more control over how the object is uploaded to S3. The following example is a common pattern for uploading Lambda function code. The optional `Run` property is a local script that you want Rain to run before uploading the content at `Path`.\n\n```yaml\nResources:\n  MyFunction:\n    Type: AWS::Lambda::Function\n    Properties:\n      Code: !Rain::S3 \n        Path: lambda-dist\n        Zip: true\n        BucketProperty: S3Bucket\n        KeyProperty: S3Key\n        Run: buildscript.sh\n```\n\nThe packaged template:\n\n```yaml\nResources:\n  MyFunction:\n    Type: AWS::Lambda::Function\n    Properties:\n      Code:\n        S3Bucket: rain-artifacts-012345678912-us-east-1\n        S3Key: 1b4844dacc843f09941c11c94f80981d3be8ae7578952c71e875ef7add37b1a7\n```\n\nSometimes you require that objects uploaded to S3 have a specific extension, use the `Extension` property to ensure the artifact in S3 ends .\u003cExtension\u003e.\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URI: !Rain::S3\n        Path: test\n        Extension: sh\n```\n\nThe packaged template:\n\n```yaml\nResources:\n  Test:\n    Type: A::B::C\n    Properties:\n      TheS3URI: s3://rain-artifacts-012345678912-us-east-1/a84b588aa54068ed4b027b6e06e5e0bb283f83cf0d5a6720002d36af2225dfc3.sh\n```\n\n#### Metadata commands\n\nYou can add a metadata section to an `AWS::S3::Bucket` resource to take additional actions during deployment, such as running pre and post build scripts, uploading content to the bucket after stack deployment completes, and emptying the contents of the bucket when the stack is deleted.\n\n```yaml\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Metadata:\n      Rain:\n        EmptyOnDelete: true\n        Content: site/dist\n        Version: 2\n        DistributionLogicalId: SiteDistribution\n        RunBefore: \n          Command: buildsite.sh\n          Args:\n          - ALiteralArgument\n        RunAfter:\n          Command: buildsite.sh\n          Args:\n            - Rain::OutputValue AStackOutputKey\n```\n\n`EmptyOnDelete`: If true, the bucket's contents, including all versions, will be deleted so that the bucket itself can be deleted. This can be useful for development environments, but be careful about using it in production!\n\n`Version`: Rain doesn't do anything with this, but incrementing the number can force the stack to deploy if there have been no infrastructure changes to the stack.\n\n`RunBefore`: Rain will run this command before the stack deploys. Useful to run your website build script before bothering to deploy, to make sure it builds successfully.\n\n`RunAfter`: Rain will run this command after deployment, and it is capable of doing stack output lookups to provide arguments to the script. This is useful if you deployed a resource like an API Gateway and need to know the stage URL to plug in to your website configuration. Use `Rain::OutputValue OutputKey` to pass one of the arguments to the script.\n\n`DistributionLogicalId`: Supply the logical id of a CloudFront distribution to invalidate all files in it after the content upload completes.\n\nSee `test/webapp/README.md` for a complete example of using these commands with Rain modules.\n\n#### Modules\n\nYou can use Rain to package templates with client-side modules, which gives\nCloudFormation multi-file support. This feature is compatible with (upcoming)\nfunctionality in the AWS CLI `cloudformation package` command. This feature is\nstill considered experimental, so you need to use the `--experimental` flag to\nuse it. The UX is fairly stable at this point, but we still reserve the right\nto change the behavior in a minor version release.\n\nThe `rain pkg` command does not actually deploy any resources if the template\ndoes not upload any objects to S3, so you always have a chance to review the\npackaged template. It's recommended to run linters and scanners on the packaged\ntemplate, rather than a pre-processed template that makes use of these advanced\ndirectives. (We are working on native support for modules in cfn-lint and in\nIDE plugins)\n\nA prior version of modules in Rain made use of the `Rain::Module` resource type\ndirective, which is still available for backwards compatibility.\n\nModules are imported into the parent template or parent module via a new\n`Modules` section. This is a departure from registry modules and from the prior\nversion of Rain modules, which are configured as resources. \n\n```\nModules:\n  Content:\n    Source: ./module.yaml\n```\n\nModules are very similar to CloudFormation templates. They support\n`Parameters`, `Resources`, `Conditions`, and `Outputs`. `Parameters` are\nconfigured with the `Properties` attribute in the parent, and act much like\nnormal parameters, except it is possible to pass in objects and lists to a\nmodule. Any valid CloudFormation template can be used as a module.\n\n\u003cimg src=\"./docs/module.png\" /\u003e\n\nA sample module:\n\n```\nParameters:\n  Name:\n    Type: Scalar\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Metadata:\n      OverrideMe: abc\n    Properties:\n      BucketName: !Ref Name\nOutputs:\n   BucketArn: \n    Value: !GetAtt Bucket.Arn\n```\n\nThe `Outputs` of a module are reference-able in the parent by using `GetAtt` or `Sub` for scalars and `Ref` for objects.\n\nAn example of using the module above:\n\n```\nModules:\n  Content:\n    Source: ./module.yaml\n    Properties:\n      Name: foo\n    Overrides:\n      Bucket:\n        Metadata:\n          OverrideMe: def\nOutputs:\n  TheArn:\n    Value: !GetAtt Content.BucketArn\n```\n\nThe `Overrides` attribute is a new feature that distinguishes local modules\nfrom registry modules. This allows the consumer to override content from the\nmodule that is included in the parent template, if they know the internal\nstructure of the module. Instead of forcing a module author to anticipate every\npossible use case with numerous parameters, the author can focus on basic use\ncases and allow the consumer to get creative if they want to change certain\nelements of the output. Using `Overrides` carries a risk of breaking changes\nwhen a module author changes things, so it will generally be safer to rely on\n`Parameters` and `References`, but the overrides provide a flexible and\neasy-to-use escape hatch that can solve some tricky design challenges\nassociated with a declarative language like YAML.\n\nThe packaged output of the above template:\n\n```\nResources:\n  ContentBucket:\n    Type: AWS::S3::Bucket\n    Metadata:\n      OverrideMe: def\n    Properties:\n      BucketName: foo\n```\n\nYou can also define constant values in modules. The `Constants` section is a\nsimple key-value list of strings or objects that are referred to later with\n`Fn::Sub` or `Ref`. When referencing an object, only the entire object can be\nreferenced, not any sub-elements of the object.\n\n```\nConstants:\n  S3Arn: \"arn:${AWS::Partition}:s3:::\"\n  BucketName: \"${Name}-${AWS::Region}-${AWS::AccountId}\"\n  BucketArn: \"${Const::S3Arn}${Const::BucketName}\"\n  AnObject:\n    Foo: bar\n```\n\nBefore any processing of the template happens, all instances of constants in\n`!Sub` strings are replaced, including in subsequent constant declarations.\nConstant references are prefixed by `Const::`. Constants are supported not\njust in modules, but in the parent template as well. For constants that are\nobjects, they are referenced with `!Ref Const::name`. \n\nAfter constants are processed, the `Modules` section is processed. Module\nsource files are specified using a path that is relative to the parent template\nor module. The path is not relative to where the `package` command is being\nrun. So, if a module is in the same directory as the parent, it is simply\nreferred to as `module.yaml` or `./module.yaml`. Modules can also reference an\nHTTPS URL as the source location.\n\nModules can contain other modules, with no enforced maximum limit on nesting.\nModules are not allowed to refer to themselves directly or in cycles. Module A\ncan’t import Module A, and it can’t import Module B if that module imports\nModule A.\n\nModules support a basic form of looping/foreach by either using the familiar\n`Fn::ForEach` syntax, or with a shorthand by adding a `ForEach` attribute to\nthe module configuration. Special variables `$Identifier` and `$Index` can be\nused to refer to the value and list index. With the shorthand, or if you don't\nput the Identifier in the logical id, logical ids are auto-incremented by\nadding an integer starting at zero. Since this is a client-side-only feature,\nlist values must be fully resolved scalars, not values that must be resolved at\ndeploy time. \n\n```\nParameters:\n  List:\n    Type: CommaDelimitedList\n    Default: A,B,C\n\nModules:\n  Content:\n    Source: ./map-module.yaml\n    ForEach: !Ref List\n    Properties:\n      Name: !Sub my-bucket-$MapValue\n```\n\nAssuming the module itself simply creates a bucket, the output would be:\n\n```\nParameters:\n  List: \n    Type: CommaDelimitedList  \n    Default: A,B,C\nResources:  \n  Content0Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-A\n  Content1Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-B\n  Content2Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: my-bucket-C\n```\n\nIt’s also possible to refer to elements within a `Map` using something like\n`!GetAtt Content[0].Arn` for a single element, or `!GetAtt Content[].Arn`,\nwhich resolves to a list of all of the `Arn` outputs from that module.\n\nWhen a module is processed, the first thing that happens is parsing of the\nConditions within the module. Any Resources, Modules, or Outputs marked with a\nfalse condition are removed, and any property nodes with conditions are\nprocessed. Any values of !Ref AWS::NoValue are removed. Any unresolved\nconditions (for example, a condition that references a paramter in the parent\ntemplate, or something like AWS::Region) are emitted into the parent template,\nprefixed with the module name.\n\nMuch of the value of module output is in the smart handling of `Ref`,\n`Fn::GetAtt`, and `Fn::Sub`. For the most part, we want these to “just work” in\nthe way that an author would expect them to. Since the logical IDs in the\nmodule result in a concatenation of the module name and the ID specified inside\nthe module, we have to modify self-references within the module. And we have to\nfix up any references to parameter values, so that in the final rendered\noutput, they match up with actual IDs and property names.\n\nFrom the parent, the author has two options for referring to module properties.\nIf they know the structure of the module, they can use the predicted final name\nfor resources, in which case we leave the strings alone. For example, in a\nmodule that creates a bucket, if the logical id within the module is `Bucket`\nand the name of the module in the parent is `Content`, the author could write\n`!Ref ContentBucket` or `!GetAtt ContentBucket.BucketName`. The second, safer\nway would be for the module author to specify an output reference called `Name`\nthat refs the bucket name, so the parent author could write `!GetAtt\nContent.Name`. Module authors are encouraged to provide `Outputs` that provide\naccess to all needed values, but there will be cases when they cannot predict\neverything a consumer needs. For `Sub` strings, if we can fully resolve the\nvalue, we get rid of the `Fn::Sub` and simply write the string to the output.\nThe parent can also refer directly to the `Properties` defined for a module\nimport in the `Modules` section.\n\nComplex objects are merged when an override is specified, so it’s possible to\ndo things like add statements to a policy without actually overwriting the\nentire thing. This is usually what the author wants, but the tradeoff is that\nthere is no way to delete an element from a list in the module.\n\n#### Intrinsics\n\nAs a part of this design, we are adding support for intrinsic functions that do\nnot exist for normal CloudFormation templates, and can only be processed by the\n`package` command. We also augment the behavior of some intrinsics. These\nfunctions are fully resolved locally and won’t need server-side support.\n\n`Fn::Merge` merges the contents of multiple objects. This is useful for things\nlike tagging, where each module might want to add a set of tags, in addition to\nany tags defined by the parent module. \n\n`Fn::Select` is collapsed if we can fully resolve the return value as a string.\nWe do the same for `Fn::Join`.\n\n`Fn::InsertFile` inserts the contents of a local file directly into the\ntemplate as a string.\n\n`Fn::Invoke` allows modules to be treated sort of like functions. A module can\nbe created with only `Parameters` and `Outputs`, and by using `Invoke` later,\nyou can get different outputs. An example use case is a module that creates\nstandard resource names, accepting things like `Env` and `App` and `Name` as\nparameters, and returning a concatenated string. \n\n#### Metadata\n\nWhen processing modules, the package command adds metadata to the template for\nmetrics gathering.\n\n```\nMetadata:\n  AWSToolsMetrics:\n    Rain: '{\"Version\":\"v1.21.0\",\"Experimental\":true,\"HasModules\":true,\"HasRainSection\":false}'\n```\n\nEach rendered resource has an added Metadata property to indicate where it\noriginated. This can be useful for tooling such as IDE integration, and for\ntroubleshooting in the console.\n\n```\nResources:\n  ContentBucket:\n    Metadata:\n      SourceMap: \"./modules/bucket.yaml:Bucket:35\"\n```\n\n### Packaging\n\nIn order to reference a collection of modules, you can add a `Packages` section\nto the template. Packages are zip files containing modules.\n\n```\nPackages:\n  abc:\n    Source: ./package.zip\n  def:\n    Source: https://example.com/packages/package.zip\n```\n\nPackages are referenced by using an alias to the package name that starts with `$`.\n\n```\nModules:\n  Foo:\n    Source: $abc/foo.yaml\n  Bar:\n    Source: $def/a/b/bar.yaml\n```\n\n### Publish modules to CodeArtifact \n\nRain integrates with AWS CodeArtifact to enable an experience similar to npm\npublish and install. A directory that includes Rain module YAML files can be\npackaged up with `rain module publish`, and then the directory can be installed\nby developers with `rain module install`.\n\n\nA module package is published and released from this repository separately from\nthe Rain binary release. This allows the package to be referenced by version\nnumbers using tags, such as `m0.1.0` as shown in the example above. The major\nversion number will be incremented if any breaking changes are introduced to\nthe modules. The available modules in the release package are listed below.\nTreat these modules as samples to be used as a proof-of-concept for building\nyour own module packages.\n\n#### simple-vpc.yaml\n\nA VPC with just two availability zones. This module is useful for POCs and simple projects.\n\n#### encrypted-bucket.yaml\n\nA simple bucket with encryption enabled and public access blocked\n\n#### compliant-bucket.yaml\n\nA bucket, plus extra buckets for access logs and replication and a bucket policy that should pass most typical compliance checks.\n\n#### bucket-policy.yaml\n\nA bucket policy that denies requests not made with TLS.\n\n#### load-balancer.yaml\n\nAn ELBv2 load balancer\n\n#### static-site.yaml\n\nAn S3 bucket and a CloudFront distribution to host content for a web site\n\n#### cognito.yaml\n\nA Cognito User Pool and associated resources\n\n#### rest-api.yaml\n\nAn API Gateway REST API\n\n#### api-resource.yaml\n\nA Lambda function and associated API Gateway resources\n\n### IfParam and IfNotParam\n\nInside a module, you can add a Metadata attribute to show or hide resources,\ndepending on whether the parent template sets a parameter value. This is\nsimilar to the Conditional section in a template, but somewhat simpler, and it\nonly works in modules. Modules also support normal Conditions. `IfParam` is\nbasically just a shorthand for writing the complete Condition.\n\n```yaml\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Metadata:\n      Rain:\n        IfParam: Foo\n```\n\nIf the parent template does not set a value for the `Foo` property, the module will \nomit the resource. The opposite is true for `IfNotParam`. \n\n`IfParam` can be useful to make flexible modules that can optionally do things like \nconfigure permissions for related resources, like allowing access to a bucket or table.\n\n`IfNotParam` is useful if you have pre-created a resource and you don't want the module \nto create it for you.\n\n### Gantt Chart\n\nOutput a chart to an HTML file that you can view with a browser to look at how long stack operations take for each resource.\n\n`rain log --chart CDKToolkit \u003e ~/Desktop/chart.html`\n\n\u003cimg src=\"./docs/chart.png\" /\u003e\n\n### Pkl\n\nYou can now write CloudFormation templates in Apple's new configuration\nlanguage, Pkl. Rain commands that accept input as JSON or YAML now also accept\nfiles with the `.pkl` extension. We host a Pkl package in a [separate\nrepo](https://github.com/aws-cloudformation/cloudformation-pkl) that is\ngenerated based on the CloudFormation registry. This package has classes that\ncan be imported for each registry resource type, in addition to higher level\npatterns. This allows you to write a type-safe template and create your own\nclient-side modules, in a way that is similar to CDK, but with declarative\ncode.\n\nExample Pkl template:\n\n```pkl\namends \"package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.1/cloudformation@0.1.1#/template.pkl\"\nimport \"package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.1/cloudformation@0.1.1#/cloudformation.pkl\" as cfn\nimport \"package://github.com/aws-cloudformation/cloudformation-pkl/releases/download/cloudformation@0.1.1/cloudformation@0.1.1#/aws/s3/bucket.pkl\" as bucket\n\nDescription = \"Create a bucket\"\n\nParameters {\n    [\"Name\"] {\n        Type = \"String\"\n        Default = \"baz\"\n    }\n}\n\nResources {\n    [\"MyBucket\"] = new bucket.Bucket {\n        BucketName = cfn.Ref(\"Name\")\n    }\n}\n```\n\n## Constants\n\nYou can put constants into the `Rain` section in the template and then refer to\nthose constants later in the template. Constants can be strings or entire\nobjects (but only strings can be used later in Sub functions). Use the\n`!Rain::Constant` directive to refer to a constant in the template. For\nstrings, you can add constants to `!Sub` strings with the\n`${Rain::ConstantName}` pseudo-parameter. Constants can contain previosuly\ndeclared constants in Sub strings using the same format. The `Rain` section\ngets removed during packaging.\n\n```yaml\nParameters:\n  Prefix:\n    Type: String\n\nRain:\n  Constants:\n    Test1: ezbeard-rain-test-constants\n    Test2: !Sub ${Prefix}-${Rain::Test1}-SubTest\n\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Rain::Constant Test1\n\n  Bucket2:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Rain::Constant Test2\n\n  Bucket3:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Sub \"pre-${Prefix}-${Rain::Test1}-suffix\" \n```\n\nRun `rain pkg` on that template to produce the following output:\n\n```yaml\nParameters:\n  Prefix:\n    Type: String\n\nResources:\n  Bucket:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: ezbeard-rain-test-constants\n\n  Bucket2:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Sub ${Prefix}-ezbeard-rain-test-constants-SubTest\n\n  Bucket3:\n    Type: AWS::S3::Bucket\n    Properties:\n      BucketName: !Sub pre-${Prefix}-ezbeard-rain-test-constants-suffix\n```\n\n\n## Other CloudFormation tools\n\n* [cfn-lint](https://github.com/aws-cloudformation/cfn-python-lint)\n\n    Validate CloudFormation yaml/json templates against the CloudFormation spec and additional checks. Includes checking valid values for resource properties and best practices.\n\n* [cfn-guard](https://docs.aws.amazon.com/cfn-guard/latest/ug/what-is-guard.html)\n\n    Guard is a policy evaluation tool that allows you to build your own rules with a custom DSL. You can also pull rules from the \n    [guard registry](https://github.com/aws-cloudformation/aws-guard-rules-registry) to scan your templates for resources that don't comply with common best practices.\n\n* [taskcat](https://github.com/aws-quickstart/taskcat)\n\n    taskcat is a tool that tests AWS CloudFormation templates. It deploys your AWS CloudFormation template in multiple AWS Regions and generates a report with a pass/fail grade for each region. You can specify the regions and number of Availability Zones you want to include in the test, and pass in parameter values from your AWS CloudFormation template. taskcat is implemented as a Python class that you import, instantiate, and run.\n\nAre we missing an excellent tool? Let us know via a GitHub issue.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faws-cloudformation%2Frain","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faws-cloudformation%2Frain","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faws-cloudformation%2Frain/lists"}