/dhall-aws-cloudformation

Typecheck, template and modularize your AWS CloudFormation with Dhall

Primary LanguageHaskellBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

Dhall AWS CloudFormation

dhall-aws-cloudformation contains Dhall bindings to AWS CloudFormation, so you can generate CloudFormation template from Dhall expressions. This will let you easily typecheck, template and modularize your CloudFormation definitions.

📖 Usage

let Function =
    -- import Lambda Function type definition
      https://raw.githubusercontent.com/jcouyang/dhall-aws-cloudformation/0.5.27/cloudformation/AWS::Lambda::Function.dhall

let Fn =
    -- Intrinsic functions
      https://raw.githubusercontent.com/jcouyang/dhall-aws-cloudformation/0.5.27/Fn.dhall

let s =
    {-
    Each AWS String field can be either a String or a Intrinsic function, we can use `Fn.string "abc"` to create static string

    Or `Fn.fn (Ref (String "abc"))` to create a function that ref to a string
    -}   Fn.string

let fn =
    -- function can be nested `fn (Fn.Ref (Fn.GetAtt (Fn.String "abc.property")))`
      Fn.fn

let example0 =
      { Resources.HelloWorldFunction
        = Function.Resources::{
        , Properties = Function.Properties::{
          , Handler = Some (s "index.handler")
          , Code = Function.Code::{
            , S3Bucket = Some (s "lambda-functions")
            , S3Key = Some (s "amilookup.zip")
            }
          , Runtime = Some (s "nodejs12.x")
          , Role = fn (Fn.Ref (Fn.String "role logical id"))
          , Timeout = Some +25
          , TracingConfig = Some { Mode = Some (s "Active") }
          }
        }
      }

in  example0

to convert to CloudFormation JSON file just

dhall-to-json < ./template.dhall > ./template.json

generates

{
  "Resources": {
    "HelloWorldFunction": {
      "Properties": {
        "Code": {
          "S3Bucket": "lambda-functions",
          "S3Key": "amilookup.zip"
        },
        "Handler": "index.handler",
        "Role": {
          "Ref": "role logical id"
        },
        "Runtime": "nodejs12.x",
        "Timeout": 25,
        "TracingConfig": {
          "Mode": "Active"
        }
      },
      "Type": "AWS::Lambda::Function"
    }
  }
}

Intrinsic Function

The following intrinsic functions are implemented, please refer to let example* for example in Fn.dhall

  • Fn::Base64
  • Fn::Cidr
  • Condition functions
  • Fn::FindInMap
  • Fn::GetAtt
  • Fn::GetAZs
  • Fn::ImportValue
  • Fn::Join
  • Fn::Select
  • Fn::Split
  • Fn::Sub
  • Fn::Transform
  • Ref

☕ Contribute

Build and Test

> nix-shell
$ stack build
$ stack test

Generate Type Definitions

Type definitions are generated from config file ./config.dhall which contains specifications used by AWS CDK as well:

To regenerate types definition files, simply run

$ stack run

Or if you just want to test and don't want to setup haskell dev environment, just

⚠️ Known Issue

The following CloudFormation definitions will raise assertion error due to invalid type definition such as empty type or cyclic import

  • AWS::EMR::Cluster
  • AWS::EMR::InstanceGroupConfig
  • AWS::EMR::InstanceFleetConfig
  • AWS::Macie::FindingsFilter
  • AWS::DataBrew::Recipe
  • AWS::FIS::ExperimentTemplate
  • AWS::SageMaker::ModelBiasJobDefinition
  • AWS::SageMaker::ModelQualityJobDefinition
  • AWS::SageMaker::MonitoringSchedule
  • AWS::SageMaker::DataQualityJobDefinition
  • AWS::SageMaker::ModelExplainabilityJobDefinition
  • AWS::S3::StorageLens
  • AWS::StepFunctions::StateMachine
  • AWS::MWAA::Environment
  • AWS::WAFv2::RuleGroup
  • AWS::WAFv2::WebACL
  • AWS::ServiceDiscovery::PrivateDnsNamespace
  • AWS::ServiceDiscovery::PublicDnsNamespace