Pkl is a new configuration language created by Apple. It is capable of serializing to other formats like YAML, so it's possible to write a CloudFormation template with pkl.
https://pkl-lang.org/index.html
NOTE Pkl support in Rain is experimental! Breaking changes are possible in minor version upgrades as we gather feedback and improve the design of the generated package.
The following is a basic example of a pkl CloudFormation template.
AWSTemplateFormatVersion: String = "2010-09-09"
Description = "My template"
Parameters {
["Name"] {
["Type"] = "String"
}
}
Resources {
["MyBucket"] {
["Type"] = "AWS::S3::Bucket"
["Properties"] {
["BucketName"] {
["Ref"] = "Name"
}
}
}
}
Running pkl eval -f yaml
on this file results in the following:
AWSTemplateFormatVersion: 2010-09-09
Description: My template
Parameters:
Name:
Type: String
Resources:
MyBucket:
Type: AWS::S3::Bucket
Properties:
BucketName:
Ref: Name
In pkl it's possible to define type-safe configurations, which gives you syntax validation and IDE support. Rain can generate pkl classes based on the CloudFormation registry, and the repository hosts pkl modules that you can import into your own projects.
Here's an example of a file you could write using these modules:
amends "@cfn/template.pkl"
import "@cfn/cloudformation.pkl" as cfn
import "@cfn/aws/s3/bucket.pkl" as bucket
Description = "Create a bucket"
Metadata {
["Foo"] = "bar"
}
Parameters {
["Name"] {
Type = "String"
Default = "baz"
}
}
Resources {
["TypedBucket"] = new bucket.Bucket {
BucketName = cfn.Ref("Name")
}
}
Note that the package alias @cfn
is enabled by creating a PklProject
file that looks like this:
amends "pkl:Project"
dependencies {
["cfn"] {
uri = "package://github.com/aws-cloudformation/rain/releases/download/v1.8.3/[email protected]"
}
}
It's possible to build higher level patterns in Pkl. In the following example, we are building a VPC defined in pkl/patterns/vpc.pkl
.
amends "@cfn/template.pkl"
import "@cfn/cloudformation.pkl" as cfn
import "@cfn/patterns/vpc.pkl"
local pub1 = new vpc.Subnet {
LogicalId = "Pub1"
IsPublic = true
Az = cfn.Select(0, cfn.GetAZs("us-east-1"))
Cidr = "10.0.0.0/18"
}
local pub2 = new vpc.Subnet {
LogicalId = "Pub2"
IsPublic = true
Az = cfn.Select(1, cfn.GetAZs("us-east-1"))
Cidr = "10.0.64.0/18"
}
local priv1 = new vpc.Subnet {
LogicalId = "Priv1"
IsPublic = false
Az = cfn.Select(0, cfn.GetAZs("us-east-1"))
Cidr = "10.0.128.0/18"
PublicNATGateway = pub1.natGateway
}
local priv2 = new vpc.Subnet {
LogicalId = "Priv2"
IsPublic = false
Az = cfn.Select(1, cfn.GetAZs("us-east-1"))
Cidr = "10.0.192.0/18"
PublicNATGateway = pub2.natGateway
}
local myvpc = new vpc {
LogicalId = "MyVPC"
Subnets {
pub1
priv1
pub2
priv2
}
}
Resources {
// Create the VPC
...myvpc.resources
// Create other resources inside the VPC...
}
Outputs {
...myvpc.outputs
}