/dhall-aws-cloudformation/gh-pages/README.md.dhall.html

Copy path to clipboard

Source

<!DOCTYPE HTML><html><head><title>/README.md.dhall</title><link rel="stylesheet" type="text/css" href="index.css"><link rel="stylesheet" type="text/css" href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500;600;700&amp;family=Lato:ital,wght@0,400;0,700;1,400&amp;display=swap"><script type="text/javascript" src="index.js"></script><meta charset="UTF-8"></head><body><div class="nav-bar"><img class="dhall-icon" src="dhall-icon.svg"><p class="package-title">dhall-aws-cloudformation</p><div class="nav-bar-content-divider"></div><a id="switch-light-dark-mode" class="nav-option">Switch Light/Dark Mode</a></div><div class="main-container"><h2 class="doc-title"><span class="crumb-divider">/</span><a href="index.html">dhall-aws-cloudformation</a><span class="crumb-divider">/</span><span class="title-crumb" href="index.html">README.md.dhall</span></h2><a class="copy-to-clipboard" data-path="https://raw.githubusercontent.com/jcouyang/dhall-aws-cloudformation/0.9.81/README.md.dhall"><i><small>Copy path to clipboard</small></i></a><br><div class="doc-contents"></div><h3>Source</h3><div class="source-code"><pre>let <span id="var1-5" class="name-decl" data-name="var1-5">version</span> = <a href="./version.dhall.html">./version.dhall</a><br><br>let <span id="var3-5" class="name-decl" data-name="var3-5">config</span> = <a href="./config.dhall.html">./config.dhall</a><br><br>let <span id="var5-5" class="name-decl" data-name="var5-5">fold</span> =<br> <a href="https://github.com/dhall-lang/dhall-lang/raw/v20.0.0/Prelude/List/fold.dhall" target="_blank">https://github.com/dhall-lang/dhall-lang/raw/v20.0.0/Prelude/List/fold.dhall</a><br><br>let <span id="var8-5" class="name-decl" data-name="var8-5">exampleText</span> = <a href="./examples/readme.gen.dhall.html">./examples/readme.gen.dhall as Text</a><br><br>let <span id="var10-5" class="name-decl" data-name="var10-5">exampleResult</span> = <a href="./examples/readme.gen.json.html">./examples/readme.gen.json as Text</a><br><br>in &#39;&#39;<br># Dhall AWS CloudFormation<br><br>`dhall-aws-cloudformation` contains [Dhall](https://github.com/dhall-lang/dhall-lang) 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.<br><br>## :mag: [References](https://gh.1punch.dev/dhall-aws-cloudformation/package.dhall.html)<br>## :bulb: [Examples](https://gh.1punch.dev/dhall-aws-cloudformation/examples/index.html)<br><br>## :book: Usage<br><br>### Use resource schema<br>AWS Cloudformation has massive amount of specifications, to load all<br>dhall remotely will be very slow and impractical.<br><br>One simply way to make import faster is by only importing just each resource you need<br>#### Remote import resource<br>```dhall<br>${<a href="#var8-5" class="name-use" data-name="var8-5">exampleText</a>}<br>```<br><br>to convert to CloudFormation JSON file just<br><br>```<br>dhall-to-json &lt; ./template.dhall &gt; ./template.json<br>```<br><br>which generates<br><br>```json<br>${<a href="#var10-5" class="name-use" data-name="var10-5">exampleResult</a>}<br>```<br><br>Other way around is build the binary of subset of the resources using nix<br><br>#### Build and load package.dhall binary to local cache<br><br>Have something like `./examples/example0.nix`, and the dhall file you want to compile `./examples/example0.dhall`<br><br>```nix<br>${<a href="./examples/example0.dhall.html">./examples/example0.dhall as Text</a>}<br>```<br>Add all the resources you need to `cf-preset`, run nix-build, if the subset is not too large it will be very quick, and you will see something like:<br>```<br> ⚠ ─ If error occured, you may need to update the sha256 in your dhall file e.g.<br> │ let aws = missing sha256:a04e4db67b092e40987639cca5cd845f452b3984ee7ec77172f815a31e830325<br>```<br><br>Actually the first time it will fail since you can&#39;t guess the correct sha of the subset binary, now if you update example0.dhall with the correct sha,<br>it should then be able to compile to `./result/example0.yaml`<br>```dhall<br>let aws =<br>missing<br>sha256:a04e4db67b092e40987639cca5cd845f452b3984ee7ec77172f815a31e830325<br><br>let Function = aws.Cloudformation.`AWS::Lambda::Function`<br>```<br><br>### Intrinsic Function<br><br>The following intrinsic functions are implemented, you can find examples of using intrinsic function in [Fn.dhall document](https://oyanglul.us/dhall-aws-cloudformation/Fn.dhall.html)<br>- [x] Fn::Base64<br>- [x] Fn::Cidr<br>- [x] Condition functions<br>- [x] Fn::FindInMap<br>- [x] Fn::GetAtt<br>- [x] Fn::GetAZs<br>- [x] Fn::ImportValue<br>- [x] Fn::Join<br>- [x] Fn::Select<br>- [x] Fn::Split<br>- [x] Fn::Sub<br>- [x] Fn::Transform<br>- [x] Ref<br><br>### Type Safe `Fn::GetAttr`<br>Instead of manually looking for AWS documents to make sure the resource has what attributes, we can just use `&lt;Resource&gt;.GetAttr.&lt;attribute name&gt;`:<br><br>```dhall<br>render (Role.GetAttr.Arn &quot;HelloWorldFunctionRole&quot;)<br>```<br><br>So the compiler can just help you find the correct attributes available.<br><br>### Sam Policy Templates<br>Cloudformation&#39;s Policy document is loosy type as just JSON, it is hard to get the policy right and too many boilerplates to create a Dhall JSON data<br>thanks to [AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html) there are some common policy documents we can laverage<br><br>these templates are translated into Dhall functions, so you don&#39;t need to use SAM to be able to use these policy documents.<br><br>```dhall<br>let Policy = https://github.com/jcouyang/dhall-aws-cloudformation/raw/${<a href="#var1-5" class="name-use" data-name="var1-5">version</a>}/cloudformation/AWS::IAM::Role/Policy.dhall<br>let Sam/Policy = https://github.com/jcouyang/dhall-aws-cloudformation/raw/${<a href="#var1-5" class="name-use" data-name="var1-5">version</a>}/sam/policy-template/package.dhall<br>...<br> Policies = Some [Policy::{<br> , PolicyDocument = Sam/Policy.DynamoDBReadPolicy (Fn.String &quot;DBName&quot;)<br> , PolicyName = s &quot;dynamo read only&quot;<br> }]<br>...<br>```<br>will generates<br>```json<br>{<br> &quot;Policies&quot;: [<br> {<br> &quot;PolicyDocument&quot;: {<br> &quot;Statement&quot;: [<br> {<br> &quot;Action&quot;: [<br> &quot;dynamodb:GetItem&quot;,<br> &quot;dynamodb:Scan&quot;,<br> &quot;dynamodb:Query&quot;,<br> &quot;dynamodb:BatchGetItem&quot;,<br> &quot;dynamodb:DescribeTable&quot;<br> ],<br> &quot;Effect&quot;: &quot;Allow&quot;,<br> &quot;Resource&quot;: [<br> {<br> &quot;Fn::Sub&quot;: [<br> &quot;arn:&#39;&#39;${AWS::Partition}:dynamodb:&#39;&#39;${AWS::Region}:&#39;&#39;${AWS::AccountId}:table/&#39;&#39;${tableName}&quot;,<br> {<br> &quot;tableName&quot;: &quot;DBName&quot;<br> }<br> ]<br> },<br> {<br> &quot;Fn::Sub&quot;: [<br> &quot;arn:&#39;&#39;${AWS::Partition}:dynamodb:&#39;&#39;${AWS::Region}:&#39;&#39;${AWS::AccountId}:table/&#39;&#39;${tableName}/index/*&quot;,<br> {<br> &quot;tableName&quot;: &quot;DBName&quot;<br> }<br> ]<br> }<br> ]<br> }<br> ]<br> },<br> &quot;PolicyName&quot;: &quot;dynamo read only&quot;<br> }<br> ]<br>}<br>```<br>## :coffee: Contribute<br>### Build and Test<br><br>```<br>&gt; nix-shell<br>$ cabal build<br>$ cabal test<br>```<br>### Generate Type Definitions<br>e definitions are generated from config file `./config.dhall` which contains specifications used by [AWS CDK](https://github.com/aws/aws-cdk/blob/master/packages/%40aws-cdk/cfnspec/build-tools/update.sh) as well:<br>${<a href="#var5-5" class="name-use" data-name="var5-5">fold</a><br> { mapKey : Text, mapValue : Text }<br> <a href="#var3-5" class="name-use" data-name="var3-5">config</a>.specifications<br>Text<br> ( λ(<span id="var167-9" class="name-decl" data-name="var167-9">x</span> : { <span id="var167-15" class="name-decl" data-name="var167-15">mapKey</span> : Text, <span id="var167-30" class="name-decl" data-name="var167-30">mapValue</span> : Text }) →<br> λ(<span id="var168-9" class="name-decl" data-name="var168-9">y</span> : Text) →<br> &#39;&#39;<br> - [${<a href="#var167-9" class="name-use" data-name="var167-9">x</a>.<a href="#var167-15" class="name-use" data-name="var167-15">mapKey</a>}](${<a href="#var167-9" class="name-use" data-name="var167-9">x</a>.<a href="#var167-30" class="name-use" data-name="var167-30">mapValue</a>})<br> ${<a href="#var168-9" class="name-use" data-name="var168-9">y</a>}&#39;&#39;<br> )<br> &quot;&quot;}<br>regenerate types definition files, simply run<br>```<br>$ cabal run<br>```<br>if you just want to regenerate dhall files without setting up haskell dev environment, just<br>```sh<br>docker run --rm -v $(pwd):/data -w /data ghcr.io/jcouyang/dhall-aws-cloudformation<br>```<br>## :warning: Known Issue<br>The following CloudFormation definitions will raise assertion error due to invalid type definition such as empty type or cyclic import<br>${<a href="#var5-5" class="name-use" data-name="var5-5">fold</a><br> Text<br> <a href="#var3-5" class="name-use" data-name="var3-5">config</a>.excludes<br> Text<br> ( λ(<span id="var188-9" class="name-decl" data-name="var188-9">x</span> : Text) →<br> λ(<span id="var189-9" class="name-decl" data-name="var189-9">y</span> : Text) →<br> &#39;&#39;<br> - `${<a href="#var188-9" class="name-use" data-name="var188-9">x</a>}`<br> ${<a href="#var189-9" class="name-use" data-name="var189-9">y</a>}&#39;&#39;<br> )<br> &quot;&quot;}<br>&#39;&#39;<br></pre></div></div></body></html>