A Clojure library for making AWS CloudFormation easier to use.
Leiningen coordinate:
[com.comoyo/condensation "0.2.2"]
To define templates, require
[com.comoyo.condensation.template :as cft]
.
Then, define resources:
(cft/defresource vpc
{"Type" "AWS::EC2::VPC"
"Properties" {"CidrBlock" "10.10.0.0/16"
"EnableDnsSupport" "true"
"EnableDnsHostnames" "true"}})
(cft/defresource route-table
{"Type" "AWS::EC2::RouteTable"
"Properties" {"VpcId" (cft/ref vpc)}})
We can also create resources that take parameters:
(cft/defresource security-group
[vpc]
{"Type" "AWS::EC2::SecurityGroup"
"Properties" {"VpcId" vpc
"SecurityGroupIngress" [{"IpProtocol" "tcp"
"FromPort" "22"
"ToPort" "22"
"CidrIp" "0.0.0.0/0"}]}})
Logical names are automatically defined based on resource names.
We can now use the ref
function to refer to resources, like with
(cft/ref vpc) => {"Ref" "Vpc"}
above.
The get-att
function can be used to refer to attributes:
(cft/get-att vpc "DefaultSecurityGroup")
=> {"Fn::GetAtt" ["Vpc" "DefaultSecurityGroup"]}
We can now use the resources
macro to access the Resources map:
(cft/resources vpc
route-table
(security-group "vpc-id"))
=> {"RouteTable" {"Properties" {"VpcId" {"Ref" "Vpc"}}
"Type" "AWS::EC2::RouteTable"}
"Vpc" {"Properties" {"CidrBlock" "10.10.0.0/16"
"EnableDnsHostnames" "true"
"EnableDnsSupport" "true"}
"Type" "AWS::EC2::VPC"}
"SecurityGroup" {"Type" "AWS::EC2::SecurityGroup"
"Properties" {"VpcId" "vpc-id"
"SecurityGroupIngress" [{"IpProtocol" "tcp"
"FromPort" "22"
"ToPort" "22"
"CidrIp" "0.0.0.0/0"}]}}}
We can also define outputs using the defoutputs
macro:
(cft/defoutput vpc-id
"The VPC ID"
(cft/ref vpc))
(cft/defoutput security-group-id
"The security group ID"
(cft/ref security-group))
The outputs
function then creates the outputs map:
(cft/outputs vpc-id
security-group-id)
=> {"SecurityGroupId" {"Description" "The security group ID"
"Value" {"Ref" "SecurityGroup"}}
"VpcId" {"Description" "The VPC ID"
"Value" {"Ref" "Vpc"}}}
Finally, the templates
function can be used to create the template
map:
(cft/template :description "A template"
:resources (cft/resources vpc
route-table
(security-group "vpc-id"))
:outputs (cft/outputs vpc-id
security-group-id))
=> {"AWSTemplateFormatVersion" "2010-09-09"
"Description" "A template"
"Outputs" {"SecurityGroupId" {"Description" "The security group ID"
"Value" {"Ref" "SecurityGroup"}}
"VpcId" {"Description" "The VPC ID"
"Value" {"Ref" "Vpc"}}}
"Resources" {"RouteTable" {"Properties" {"VpcId" {"Ref" "Vpc"}}
"Type" "AWS::EC2::RouteTable"}
"Vpc" {"Properties" {"CidrBlock" "10.10.0.0/16"
"EnableDnsHostnames" "true"
"EnableDnsSupport" "true"}
"Type" "AWS::EC2::VPC"}
"SecurityGroup" {"Type" "AWS::EC2::SecurityGroup"
"Properties" {"VpcId" "vpc-id"
"SecurityGroupIngress" [{"IpProtocol" "tcp"
"FromPort" "22"
"ToPort" "22"
"CidrIp" "0.0.0.0/0"}]}}}}
To create a stack, use the create-or-update-stack
function:
(create-or-update-stack :stack-name "dummy" :cloudformation-template-map template)
where template
is created by template/template
as described above.
If the stack already exists it is updated.
Use :wait? false
to return without waiting for the create/update
operation to be done.
To delete a stack, use delete-stack
:
(delete-stack :stack-name "dummy")
You can also use the get-outputs
function to get easy access to
stack outputs:
(:vpc-id
(get-outputs "dummy"))