Skip to content

typedpath/cloudformation2kotlin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

47 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Cloudformation2Kotlin

This project offers a Kotlin DSL for AWS cloudformation. Kotlin brings the advantages of type safety, IDE autocomplete and the ability to embed code within templates. This is a work in progress - please provide feedback!

Building

cd cloudformation2kotlin
gradle publishToMavenLocal

This will take the aws json schema definitions (copied from https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-resource-specification.html) convert them to kotlin and bundle them into a maven artifact along with some helper code. It also includes some classes create manually because I cant find a schema definition for them e.g. IamPolicy and serverless resources such as AWS::Serverless::Function. There are also some properties that are mapped to Any? because I havent mapped the schema manually yet.

Using Code from Gradle

In build.gradle.kts

repositories {
    mavenCentral()
}

dependencies {
    compile("com.typedpath:cloudformation2kotlin:2.0.0")
}

Using Code from Maven

in pom.xml

<dependency>
  <groupId>com.typedpath</groupId>
  <artifactId>cloudformation2kotlin</artifactId>
  <version>2.0.0</version>
</dependency>

Running tests

make sure the default aws user in ~/.aws has admin permissions!

cd cloudformationsamples
gradle clean build -x test
gradle build

This will run the junit tests, creating cloud cloudformation stacks from (kotlin) templates and testing the resources in the created stacks. These are the tests (the xxTemplate.kt files are the source files, the xxxTemplate.yaml files are generated ):

Test Template Test Description
S3Test.kt S3PublicReadableCloudFormationTemplate.kt S3PublicReadableCloudFormationTemplate.yaml write to s3 bucket in stack , read from s3 bucket
LambdaTest.kt LambdaCloudFormationTemplate.kt LambdaCloudFormationTemplate.yaml call lambda in stack
UnzipFunctionTest.kt UnzipS3FunctionTemplate.kt UnzipS3FunctionTemplate.yaml create a stack with an s3 bucket and an unzipping lambda function, upload a zip file and unzip it with the lambda function
PipelineTest.kt PipelineCloudFormationTemplate.kt PipelineCloudFormationTemplate.yaml create stack with 4 stage pipeline + code repository, checkin code and test lambda created by pipeline
LambdaServerlessTest.kt LambdaServerlessTemplate.kt LambdaServerlessTemplate.yaml create a SAM stack containing a lambda and call the lambda
ServerlessBackendApiTest.kt ServerlessBackendApiTemplate.kt ServerlessBackendApiTemplate.yaml, ServerlessBackendApiRefactoredTemplate.kt ( templates functionally equivalent) create a SAM stack implementing a REST api with API gateway, lambda functions and dynamo db. Test with http put, get and d)lete calls
S3ObjectCreatedEventTest.kt S3ObjectCreatedEventTemplate.kt S3ObjectCreatedEventTemplate.yaml create a SAM stack containing an s3 bucket with lambda triggered by object create events. The lambda code is in a seperate kotlin project "lambdas/s3objectcreated" and adds a tag on creation. Write to the s3 bucket and check the tag has been created.
AuroraServerlessTest.kt AuroraServerlessTemplate.kt AuroraServerlessTemplate.yaml create a stack containing an aurora serverless rds cluster. Using rds data client api create a database, table insert a row and read the row back
AuroraBackendApiTest.kt AuroraBackendApiTemplate.kt AuroraBackendApiTemplate.yaml Create a stack containing an aurora serverless rds cluster fronted by a REST api providing a generic typesafe CRUD service over a relational database. More details here

Templates

The examples listed above create templates by extension e.g.:

class S3PublicReadableCloudFormationTemplate(bucketName: String) : CloudFormationTemplate() {...

templates declared in this way will have a cloudformation resource for every property that extends com.typedpath.awscloudformation.Resource. Properties in superclasses will be included. In the case of S3PublicReadableCloudFormationTemplate.kt these 2 property declarations map to an s3 bucket and a s3 bucket policy in the stack:

   val s3Bucket = AWS_S3_Bucket() . . . . 
   val s3BucketPolicy = AWS_S3_BucketPolicy(ref(s3Bucket), policyDocument) 
   val db = AWS_RDS_DBCluster("aurora" /* mandatory fields!*/) {
                // optional fields
                engineMode="serverless"
   . . . .

Templates are mapped to yaml with the toYaml function e.g.:

val strTemplate = toYaml(S3PublicReadableCloudFormationTemplate(bucketName))

In this example this will give:

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  s3Bucket:
    Type: 'AWS::S3::Bucket'
    Properties:
. . . .
s3BucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref s3Bucket
      PolicyDocument:
        Statement:
          - Action:
              - 's3:GetObject'
            Effect: Allow
db:
    Type: 'AWS::RDS::DBCluster'
    Properties:
      EngineMode: 'serverless'            
. . . .

Note the use of helper function ref(s3Bucket)) - this makes it difficult to create an invalid cloudformation reference. Note also that all mandatory fields are in the constructor and optional fields can be specified in the optional init block.

The property definition for policyDocument is:

  val policyDocument = IamPolicy {
    statement {
      effect = IamPolicy.EffectType.Allow
      principal = mapOf(
        Pair(IamPolicy.PrincipalType.AWS, listOf("*"))
      )
      action(S3Action.GetObject)
      resource +=join("", listOf("arn:aws:s3:::", ref(s3Bucket), "/*"))
    }
  }

The constructor for IamPolicy has no arguments because there are no mandatory properties. Non mandatory properties are specified in the init block. Note also that policyDocument does not appear in the top level of the yaml template, it is inlined where it is referenced. This is because it is not a cloud formation resource i.e. not an instance of com.typedpath.awscloudformation.Resource. Class IamPolicy was created manually (unlike Kotlin resource definiton classes) because I couldnt find an amazon supplied schema (json or otherwise) for it.