typedpath / terraform2kotlin

a Kotlin DSL for terraform
0 stars 0 forks source link

Terraform2Kotlin

This project offers a Kotlin DSL for Terraform. Kotlin brings the advantages of type safety, IDE autocomplete and the ability to embed code within templates + many other possibilities. This is an experiment in its early stages - there is a mapping of AWS resources only (in com.typedpath.terraform2kotlin.aws) - please provide feedback!

Building

gradle build -x test
cd terraform2kotlin
gradle test

Beware the tests create cloud resources that cost money !
For the tests to work you need to:

Tests

Most of these tests create infrastructure which is destroyed at the end of the test to save money. In order to look at the infrastructure created comment this line: println(runner.destroy()) __EksGettingStarted_test__ takes a long time sometimes (>30 minutes) and is the most expensive so its worth considering "@Ignore ing".

Test Kotlin Template, Generated .tf Test Description
Ec2Basic_test Ec2BasicTemplate.kt Ec2BasicTemplate.tf create terraform template for EC2 instance
SecurityGroupEc2_test SecurityGroupEc2Template.kt SecurityGroupEc2Template.tf create an EC2 instance + security group, install webserver, check a web page is viewable
IamRole_test IamRoleTemplate.kt IamRoleTemplate.tf create an IamRole then check its got an arn
SQSBasic_test SQSBasicTemplate.kt SQSBasicTemplate.tf create an SQS queue, write and read to it
DynamoDbBasic_test DynamoDbBasicTemplate.kt DynamoDbBasicTemplate.tf create a dynamo DB table and CRUD it
SNSBasic_test SNSBasicTemplate.kt SNSBasicTemplate.tf create an SNS topic, subscribe an SQS queue, publish to the topic and read message from the queue
LambdaBasic_test LambdaBasicTemplate.kt LambdaBasicTemplate.tf create an Lambda function, call it and check the parameters and environment received
ApiGatewayBasic_test ApiGatewayBasicTemplate.kt ApiGatewayBasicTemplate.tf create an api gateway, create and link Lambda function (using LambdaBasicTemplate.kt) and call the gateway, check environment received
EksGettingStarted_test EksVpcTemplate.kt EksVpcTemplate.tf EksClusterTemplate.kt EksClusterTemplate.tf EksWorkerNodesTemplate.kt EksWorkerNodesTemplate.tf OutputTemplate.kt OutputTemplate.tf create an EKS cluster return KubeConfig file and configMapAwsAuth - based on https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples/eks-getting-started
S3SimpleModule_test.kt S3CompleteModule_test.kt S3CompleteFeatures.kt S3UtilMainTemplate.kt S3UtilMainTemplate.tf basic s3 S3UtilMainTemplate.tf basic logbucket S3UtilMainTemplate.tf complete s3 S3UtilOutputsTemplate.kt (The generated .tf depends on the main template parameters) re-implements terraform s3 module, there are three tests calling the module in different ways, the original module is here: https://github.com/terraform-aws-modules/terraform-aws-s3-bucket : this kotlin version is much more concise !

Templates

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

class SecurityGroupEc2Template(webgreeting: String) : TerraformTemplate() {...

templates declared in this way will have a terraform resource for every property that extends com.typedpath.terraform.Resource.
In the case of SecurityGroupEc2Template.kt these 2 property declarations map to an ec2 instance, security group and output:

  val myec2 = aws_instance(ami = "ami-0389b2a3c4948b1a0", instance_type = "t2.micro").    apply {
        security_groups = listOf(securityGroupName) . . . . 
   val web_traffic = aws_security_group( . . . .
   val public_ip = Output( ......

Note kotlin forces mandatory fields to be specified in the constructor. Non mandatory fields can be specified in an apply block

Templates are mapped to .tf format with the toTerraform function e.g.:

val template = SecurityGroupEc2Template(webGreeting)
println("template:\r\n ${toTerraform(template)}")

In this example this will give this .tf:

resource "aws_instance" "myec2"   {
    ami =  "ami-0389b2a3c4948b1a0"
. . . .

resource "aws_security_group" "web_traffic"   { 
      egress { 
. . . .

output "public_ip"   {
    value =  "${aws_instance.myec2.public_ip}"
  }

Most of these examples parameterize templates via the Kotlin constructor e.g. :

class ApiGatewayBasicTemplate(function: aws_lambda_function, region: String, accountId: String) : TerraformTemplate() {
}

Please avoid the anti-pattern of declaring resource properties as constructor parameters:

//Warning declaring a resource property as a constructor parameter will cause unexpected results!
class ApiGatewayBasicTemplate(val function: aws_lambda_function, region: String, accountId: String) : TerraformTemplate() {
}

Feature by Feature Comparison

Description Terraform2Kotlin Terraform
Representation of Mandatory / Optional Kotlin Language Feature N / A
Representation of Enumerated Values such as __aws_autoscaling_policy.policy_type__ Kotlin Enum N / A
Rich Scoping / Modularisation Functions and Classes N / A
Terraform Modules Not supported - workaround for terraform global namespace via TerraformTemplate.scope property Native
Terraform Locals Limited supported - Kotlin scoped variables preferred Native
(forward) attribute references via scoped call e.g. gatewayResource.idRef() via global reference e.g. __aws_api_gateway_resource.gatewayResource.id__
resource references via scoped variable e.g. __depends_on = listOf(methodResource, integration)__ via global reference e.g. __depends_on = [ aws_api_gateway_method.methodResource, aws_api_gateway_integration.integration]__
Other languages Required No - backends can be written in Kotlin. Compatibility with alternative frontend languages is easy to support with kotlin plugins. The examples here create infrastructure, deploy code and execute client test code : all 100% kotlin. Yes - terraform only represents infrastructure :-(.