{"id":13719029,"url":"https://github.com/cfndsl/cfndsl","last_synced_at":"2025-12-16T17:22:27.462Z","repository":{"id":5918473,"uuid":"7137996","full_name":"cfndsl/cfndsl","owner":"cfndsl","description":"A DSL for generating Amazon Web Services CloudFormation templates.","archived":false,"fork":false,"pushed_at":"2023-01-18T20:45:33.000Z","size":2948,"stargazers_count":422,"open_issues_count":5,"forks_count":136,"subscribers_count":31,"default_branch":"master","last_synced_at":"2024-04-14T01:47:21.309Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cfndsl.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2012-12-12T21:33:23.000Z","updated_at":"2024-01-13T23:51:08.000Z","dependencies_parsed_at":"2023-02-10T18:00:21.733Z","dependency_job_id":null,"html_url":"https://github.com/cfndsl/cfndsl","commit_stats":null,"previous_names":[],"tags_count":138,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cfndsl%2Fcfndsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cfndsl%2Fcfndsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cfndsl%2Fcfndsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cfndsl%2Fcfndsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cfndsl","download_url":"https://codeload.github.com/cfndsl/cfndsl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224592363,"owners_count":17337079,"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-03T01:00:41.250Z","updated_at":"2025-12-16T17:22:27.387Z","avatar_url":"https://github.com/cfndsl.png","language":"Ruby","funding_links":[],"categories":["Ruby","Code Generation"],"sub_categories":["Hooks"],"readme":"cfndsl\n======\n\n[![Spec](https://github.com/cfndsl/cfndsl/actions/workflows/spec.yml/badge.svg)](https://github.com/cfndsl/cfndsl/actions/workflows/spec.yml)\n[![Gem Version](https://badge.fury.io/rb/cfndsl.png)](http://badge.fury.io/rb/cfndsl)\n\n[AWS Cloudformation](http://docs.amazonwebservices.com/AWSCloudFormation/latest/UserGuide/GettingStarted.html) templates are an incredibly powerful way to build\nsets of resources in Amazon's AWS environment.\nUnfortunately, because they are specified in JSON or YAML, they are also difficult to write and maintain:\n\n* JSON does not allow comments, although CloudFormation now supports YAML\n\n* JSON/YAML templates do not allow re-usable logic\n\n* It is easy for a person reading a template to miss the association and dependencies between entries\n\n* References and internal functions have a particularly unpleasant syntax.\n\nThe cnfdsl gem provides a DSL that allows you to write templates using friendly Ruby logic to generate and validate\n  cloudformation templates.\n\n## Getting Started\n\nruby version \u003e 2.7 is required to run cfndsl, you should look at using rbenv example for installing with rbenv\n\n    rbenv exec gem install cfndsl\n\nExample for doing it system wide Ruby\n\n    sudo gem install cfndsl\n\nUpdate the the cloudformation specification to the latest version.\n\n    cfndsl -u\n\nor update to a specific version\n\n    cfndsl -u 7.1.0\n\nNow write a template in the dsl\n\n```ruby\n\nCloudFormation {\n  Description \"Test\"\n\n  Parameter(\"One\") {\n    String\n    Default \"Test\"\n\tMaxLength 15\n  }\n\n  Output(:One,FnBase64( Ref(\"One\")))\n\n  EC2_Instance(:MyInstance) {\n    ImageId \"ami-12345678\"\n  }\n\n}\n```\n\nThen run cfndsl on the file\n\n```\nchris@raspberrypi:~/git/cfndsl$ cfndsl test.rb | json_pp\n{\n   \"Parameters\" : {\n      \"One\" : {\n\t \"Type\" : \"String\",\n\t \"Default\" : \"Test\",\n\t \"MaxLength\" : 15\n      }\n   },\n   \"Resources\" : {\n      \"MyInstance\" : {\n\t \"Type\" : \"AWS::EC2::Instance\",\n\t \"Properties\" : {\n\t    \"ImageId\" : \"ami-12345678\"\n\t }\n      }\n   },\n   \"AWSTemplateFormatVersion\" : \"2010-09-09\",\n   \"Outputs\" : {\n      \"One\" : {\n\t \"Value\" : {\n\t    \"Fn::Base64\" : {\n\t       \"Ref\" : \"One\"\n\t    }\n\t }\n      }\n   },\n   \"Description\" : \"Test\"\n}\n```\n\n*Aside: that is correct - a significant amount of the development for\nthis gem was done on a [Raspberry Pi](http://www.raspberrypi.org).*\n\n## Syntax\n\n`cfndsl` comes with a number of helper methods defined on _each_ resource and/or the stack as a whole.\n\n### Template Metadata\n\nMetadata is a special template section described [here](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/metadata-section-structure.html). The argument supplied must be JSON-able. Some CloudFormation features reference special keys if included in the `Metadata`, check the AWS documentation for specifics.\n\n```ruby\nCloudFormation do\n  Metadata(foo: 'bar')\n\n  EC2_Instance(:myInstance) do\n    ImageId 'ami-12345678'\n    InstanceType 't1.micro'\n  end\nend\n```\n\n### Template Parameters\n\nAt a bare minumum, parameters need a name, and default to having Type `String`. Specify the parameter in the singular, not plural:\n\n```ruby\nCloudFormation do\n  Parameter 'foo'\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Parameters\": {\n    \"foo\": {\n      \"Type\": \"String\"\n    }\n  }\n}\n```\n\nHowever, they can accept all of the following additional keys per the [documentation](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html):\n\n```ruby\nParameter('foo') do\n  Description           'This is a sample parameter definition'\n  Type                  'String'\n  Default               'foo'\n  NoEcho                true\n  AllowedValues         %w(foo bar)\n  AllowedPattern        '/pattern/'\n  MaxLength             5\n  MinLength             3\n  MaxValue              10\n  MinValue              2\n  ConstraintDescription 'The error message printed when a parameter outside the constraints is given'\nend\n```\n\nParameters can be referenced later in your template:\n\n```ruby\nEC2_Instance(:myInstance) do\n  InstanceType 'm3.xlarge'\n  UserData Ref('foo')\nend\n```\n\n### Template Mappings\n\n[Mappings](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html) are a hash-based lookup for your template. They can be specified in the singular or plural.\n\n```ruby\nCloudFormation do\n  Mapping('foo', letters: { a: 'a', b: 'b' }, numbers: { 1: 1, 2: 2 })\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n    \"Mappings\": {\n      \"foo\": {\n\t\"letters\": {\n\t  \"a\": \"a\",\n\t  \"b\": \"b\"\n\t},\n\t\"numbers\": {\n\t  \"one\": 1,\n\t  \"two\": 2\n\t}\n      }\n    }\n  }\n}\n```\n\nYou can then reference them later in your template using the `FnFindInMap` method:\n\n```ruby\nEC2_Instance(:myInstance) do\n  InstanceType 'm3.xlarge'\n  UserData FnFindInMap('foo', :numbers, :one)\nend\n```\n\n### Template Outputs\n\nOutputs are declared one at a time and must be given a name and a value at a minimum, description is optional. Values are most typically obtained from other resources using `Ref` or `FnGetAtt`:\n\n```ruby\nCloudFormation do\n  EC2_Instance(:myInstance) do\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\n\n  Output(:myInstanceId) do\n    Description 'My instance Id'\n    Value Ref(:myInstance)\n  end\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Resources\": {\n    \"myInstance\": {\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      },\n      \"Type\": \"AWS::EC2::Instance\"\n    }\n  },\n  \"Outputs\": {\n    \"myInstanceId\": {\n      \"Description\": \"My instance Id\",\n      \"Value\": {\n\t\"Ref\": \"myInstance\"\n      }\n    }\n  }\n}\n```\n\n### Template Conditions\n\nConditions must be created with statements in three [sections](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html): a variable entry as a `Parameter`, a template-level `Condition` that holds the logic based upon the value of that `Parameter`, and a resource-level `Condition` that references the template-level one by logical id.\n\n```ruby\nCloudFormation do\n  Parameter(:environment) do\n    Default 'development'\n    AllowedValues %w(production development)\n  end\n\n  Condition(:createResource, FnEquals(Ref(:environment), 'production'))\n\n  EC2_Instance(:myInstance) do\n    Condition :createResource\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Parameters\": {\n    \"environment\": {\n      \"Type\": \"String\",\n      \"Default\": \"development\",\n      \"AllowedValues\": [\n\t\"production\",\n\t\"development\"\n      ]\n    }\n  },\n  \"Conditions\": {\n    \"createResource\": {\n      \"Fn::Equals\": [\n\t{\n\t  \"Ref\": \"environment\"\n\t},\n\t\"production\"\n      ]\n    }\n  },\n  \"Resources\": {\n    \"myInstance\": {\n      \"Condition\": \"createResource\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      },\n      \"Type\": \"AWS::EC2::Instance\"\n    }\n  }\n}\n```\n\n### Template Resources\n\nCfndsl creates accessor methods for all of the resources listed [here](https://github.com/cfndsl/cfndsl/blob/master/lib/cfndsl/aws/types.yaml) and [here](https://github.com/cfndsl/cfndsl/blob/master/lib/cfndsl/os/types.yaml). If a resource is missing, or if you prefer to explicitly enter a resource in a template, you can do so. Keep in mind that since you are using the generic `Resource` class, you will also need to explicitly set the `Type` and that you no longer have access to the helper methods defined on that particular class, so you will have to use the `Property` method to set them.\n\n```ruby\nCloudFormation do\n  Resource(:myInstance) do\n    Type 'AWS::EC2::Instance'\n    Property('ImageId', 'ami-12345678')\n    Property('Type', 't1.micro')\n  end\n\n  # Will generate the same json as this\n  #\n  # EC2_Instance(:myInstance) do\n  #   ImageId 'ami-12345678'\n  #   Type 't1.micro'\n  # end\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Resources\": {\n    \"myInstance\": {\n      \"Type\": \"AWS::ApiGateway::Resource\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\",\n\t\"Type\": \"t1.micro\"\n      }\n    }\n  }\n}\n```\n\n### Resource Types\n\nWhen using the generic `Resource` method, rather than the dsl methods, specify the type of resource using `Type` and the properties using `Property`. See [Template Resources](#template-resources) for an example.\n\n### Resource Conditions\n\nResource conditions are specified singularly, referencing a template-level condition by logical id. See [Template Conditions](#template-conditions) for an example.\n\n### Resource DependsOn\n\nResources can depend upon other resources explicitly using `DependsOn`. It accepts one or more logical ids.\n\n```ruby\nCloudFormation do\n  EC2_Instance(:database) do\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\n\n  EC2_Instance(:webserver) do\n    DependsOn :database\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\nend\n```\n\n```json\n{\n  \"AWSTemplateFormatVersion\": \"2010-09-09\",\n  \"Resources\": {\n    \"database\": {\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      },\n      \"Type\": \"AWS::EC2::Instance\"\n    },\n    \"webserver\": {\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      },\n      \"Type\": \"AWS::EC2::Instance\",\n      \"DependsOn\": \"database\"\n    }\n  }\n}\n```\n\n### Resource DeletionPolicy\n\nResources can have [deletion policies](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html) associated with them. Specify them one per resource as an attribute:\n\n```ruby\nCloudFormation do\n  EC2_Instance(:myInstance) do\n    DeletionPolicy 'Retain'\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\nend\n```\n\n### Resource Metadata\n\nYou can attach arbitrary [metadata](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-metadata.html) as an attribute. Arguments provided must be able to be JSON-ified:\n\n```ruby\nCloudFormation do\n  EC2_Instance(:myInstance) do\n    Metadata(foo: 'bar')\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n  end\nend\n```\n\n### Resource CreationPolicy/UpdatePolicy\n\nThese attributes are only usable on particular [resources](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-creationpolicy.html). The name of the attribute is not arbitrary, it must match the policy name you are trying to attach. Different policies have different parameters.\n\n```ruby\nCloudFormation do\n  EC2_Instance(:myInstance) do\n    ImageId 'ami-12345678'\n    Type 't1.micro'\n    CreationPolicy(:ResourceSignal, { Count: 1, Timeout: 'PT1M' })\n  end\nend\n```\n\n## Samples\n\nThere is a more detailed example in the samples directory. The file\n\"autoscale.template\" is one of the standard Amazon sample templates.\n\"autoscale.rb\" generates an equivalent template file.\n\nThere's also a larger set of examples available at [cfndsl_examples](https://github.com/neillturner/cfndsl_examples) thanks to @neillturner.\n\n## Command Line Options\n\nThe cfndsl command line program now accepts some command line options.\n\n```\nUsage: cfndsl [options] FILE\n    -o, --output FILE                Write output to file\n    -y, --yaml FILE                  Import yaml file as local variables\n    -j, --json FILE                  Import json file as local variables\n    -p, --pretty                     Pretty-format output JSON\n    -f, --format FORMAT              Specify the output format (JSON default)\n    -D, --define \"VARIABLE=VALUE\"    Directly set local VARIABLE as VALUE\n    -v, --verbose                    Turn on verbose output\n    -m, --disable-deep-merge         Disable deep merging of yaml\n    -s, --specification-file FILE    Location of Cloudformation Resource Specification file\n    -u [VERSION],                    Update the Resource Specification file to latest, or specific version\n        --update-specification\n    -g RESOURCE_TYPE,RESOURCE_LOGICAL_NAME,\n        --generate                   Add resource type and logical name\n    -l, --list                       List supported resources\n    -h, --help                       Display this screen\n```\n\nBy default, cfndsl will attempt to evaluate FILE as cfndsl template and print\nthe resulting cloudformation json template to stdout. With the -o option, you\ncan instead have it write the resulting json template to a given file. The -v\noption prints out additional information (to stderr) about what is happening\nin the model generation process.\n\nThe -y, -j, -r and -D options can be used to control some things about the\nenvironment that the template code gets evaluate in. For instance, the -D\noption allows you to set a variable at the command line that can then be\nreferred to within the template itself.\n\nThis is best illustrated with a example. Consider the following cfndsl\ntemplate\n\n```ruby\n# cfndsl template sample/t1.rb\nCloudFormation do\n\n  description = external_parameters.fetch(:description, 'default description')\n  machines = external_parameters.fetch(:machines, 1).to_i\n\n  Description description\n\n  (1..machines).each do |i|\n    name = \"machine#{i}\"\n    EC2_Instance(name) do\n      ImageId 'ami-12345678'\n      Type 't1.micro'\n    end\n  end\n\nend\n```\n\nNote the two variables `description` and `machines`. The template\nsets these to some reasonable default values, and if you run cfndsl\non it without changing them in any way you get the following cloudformation\ntemplate:\n\n```json\n{\n  \"Resources\": {\n    \"machine1\": {\n      \"Type\": \"AWS::EC2::Instance\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      }\n    }\n  },\n  \"Description\": \"default description\",\n  \"AWSTemplateFormatVersion\": \"2010-09-09\"\n}\n```\n\nHowever if you run the command\n\n```bash\n$ cfndsl sample/t1.rb -D 'description=3 machine cluster' -D 'machines=3'\n```\n\nyou get the following generated template.\n\n```json\n{\n  \"Resources\": {\n    \"machine3\": {\n      \"Type\": \"AWS::EC2::Instance\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      }\n    },\n    \"machine2\": {\n      \"Type\": \"AWS::EC2::Instance\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      }\n    },\n    \"machine1\": {\n      \"Type\": \"AWS::EC2::Instance\",\n      \"Properties\": {\n\t\"ImageId\": \"ami-12345678\"\n      }\n    }\n  },\n  \"Description\": \"3 machine cluster\",\n  \"AWSTemplateFormatVersion\": \"2010-09-09\"\n}\n```\n\nThe -y and -j options allow you to group several variable definitions\ninto a single file (formated as either yaml or json respectively). If\nyou had a file called 't1.yaml' that contained the following,\n\n```yaml\n# sample/t1.yaml\ndescription: 5 machine cluster\nmachines: 5\n```\n\nthe command\n\n```bash\n$ cfndsl sample/t1.rb -y sample/t1.yaml\n```\n\nwould generate a template with 5 instances declared.\n\nSpecifying multiple -y options will default deep_merge all the yaml in the order specified.\nYou can disable this with -m.\n\n### Rake task\nSimply add the following to your `Rakefile`:\n\n```ruby\nrequire 'cfndsl/rake_task'\n\nnamespace(:cfndsl) do\n  CfnDsl::RakeTask.new do |t|\n    # Use a custom specification file\n    t.specification(file: 'tmp/cloudformation_resources.json')\n\n    desc 'Generate CloudFormation Json'\n    t.json(name: :json, files: FileList.new('sample/*.rb'), pathmap: 'tmp/%f.json')\n    \n    # Generate yaml output, loading an extra file that matches the source file\n    t.yaml(name: :yaml, files: 'sample/t1.rb', pathmap: 'tmp/%f.yaml', extras: '%X.yaml')\n  end\nend\n```\n\nAnd then use rake to generate the cloudformation:\n\n```bash\n$ bin/rake cfndsl:generate\n```\n\n### Embedded Ruby\n```ruby\n\n# Optionally before requiring 'cfndsl' set global options\nrequire `cfndsl/globals`\nCfnDsl.specification_file(file) # Override location of json spec file \nCfnDsl.disable_deep_merge       # Prevent monkey patching of Hash with deep merge capabilities\n\nrequire `cfndsl`\n\n# As a function that takes a block of DSL\ntemplate = CloudFormation do\n  # Some CfnDsl\nend\nputs JSON.pretty_generate(template.validate)\n\n# As a class that is a template\nclass MyTemplate \u003c CfnDsl::CloudFormationTemplate  \n  def initialize \n    super do\n      # Base DSL\n    end  \n  end\n  \n  def instance(logical_id)\n    this = self\n    EC2_Instance(logical_id) do\n      self.class.name # \u003c\u003c 'CfnDsl::ResourceDefinition' not 'MyTemplate' !\n      InstanceType this.instance_type  \n    end \n  end\n   \n  #do not make this private! \n  def instance_type\n    't3.large'      \n  end\nend\n\n# As a builder class\nclass Builder\n  include CfnDsl::CloudFormation\n\n  def model\n    this = self # the DSL blocks are executed via instance_eval\n    ref_param = Ref('param')  # and other Fn::*\n    template = CloudFormation do\n      # Some DSL\n    end\n    template.validate.to_json\n  end\nend\n```\n\n### Generating CloudFormation resources from cfndsl\nBy supplying the -g parameter you are now able to generate cloudformation resources for supported objects, for a list of supported resources run cfndsl -l\n\nExample\n```bash\ncfndsl -g AWS::EC2::EIP,EIP\n```\n```ruby\nrequire 'cfndsl'\nCloudFormation do\n  Description 'auto generated cloudformation cfndsl template'\n\n  EC2_EIP('EIP') do\n        Domain String # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-eip.html#cfn-ec2-eip-domain\n        InstanceId String # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ec2-eip.html#cfn-ec2-eip-instanceid\n  end\nend\n```\nMany thanks to the base code from cfnlego to make this possible!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcfndsl%2Fcfndsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcfndsl%2Fcfndsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcfndsl%2Fcfndsl/lists"}