Brooklyn Terraform integration

In this article, we’ll take a look at Apache Brooklyn’s integration with Hashicorp Terraform, a tool for building, changing, and versioning infrastructure safely and efficiently.

Brief Overview of Terraform

The key component of a Terraform system is the configuration file. Configuration files describe to Terraform the components needed to run anything from a single application to an entire datacenter.

Terraform generates an execution plan describing what it will do to reach the desired end state. Upon application of the configuration, Terraform builds all of the infrastructure that is specified in the configuration. Once infrastructure has been created, the user may modify the configuration freely. Terraform is able to determine what has changed in the configuration and create incremental execution plans that can be applied to change the existing infrastructure.

Terraform can manage low-level components such as compute instances, storage, and networking, as well as high-level components such as DNS entries, SaaS features, etc.

Brooklyn + Terraform Integration

The io.cloudsoft.terraform.TerraformConfiguration Brooklyn entity adds deployment and lifecycle management of Terraform configurations to Brooklyn.

Users can now author YAML Brooklyn blueprints which specify the location on which the Terraform CLI is to be installed, and provide a Terraform configuration file to be applied.

The Terraform entity includes sensors which provide the status of the configuration (whether it has been applied), the current execution plan, and the state of the created infrastructure. It also includes effectors which can apply or destroy the configuration.

Support for more advanced monitoring and management of the actual infrastructure created by Terraform (as opposed to just managing the configuration via automated Terraform CLI calls) is on the roadmap.

Getting Set Up

The easiest way to get Brooklyn + Terraform up and running is by following those simple steps:

  • install Java 7+
  • install latest Apache Brooklyn (0.10.0+) from here 
  • copy the latest jar available at here into $BROOKLYN_HOME/lib/dropins/
  • $BROOKLYN_HOME/bin/brooklyn launch

At this point, Brooklyn is ready to deploy and manage Terraform configurations.

Applying an Example Configuration

Now that Brooklyn is running, open http://localhost:8081 in your browser to view the Brooklyn GUI. When the GUI first loads, you will be immediately prompted to create an application.

Select the YAML Composer tab to add your own blueprint.

The following Brooklyn blueprint will install the Terraform CLI on your local machine (localhost) where Brooklyn is running and use the CLI to both provision a VM on Amazon EC2 and assign it an elastic IP.

location: localhost
name: Brooklyn Terraform Example
services:
- type: io.cloudsoft.terraform.TerraformConfiguration
  name: Amazon EC2 VM with Elastic IP
  brooklyn.config:
    tf.configuration.contents: |        
        provider "aws" {
            access_key = "YOUR_ACCESS_KEY"
            secret_key = "YOUR_SECRET_KEY"
            region = "us-east-1"
        }

        resource "aws_instance" "example" {
            ami = "ami-408c7f28"
            instance_type = "t1.micro"
            tags {
                Name = "brooklyn-terraform-example"
            }
        }

        resource "aws_eip" "ip" {
            instance = "${aws_instance.example.id}"
        }

        output "myVmId" {
            value = "${aws_instance.example.id}"
        }

Edit the above YAML by adding your AWS credentials and paste it into the Brooklyn YAML Composer window and click “Finish” to apply the configuration!

Provisioning will last for a few minutes — while you wait for its completion, have a look at your AWS console to see your VM starting up, as well as the Brooklyn “Applications” tab for detail on all your deployments, across all your infrastructure.

Once the configuration has been fully applied and provisioning is complete, all of the Terraform-specific sensors (beginning with tf.*) should look similar to this:

Notice, because the Terraform plan defines `output` like:

output "myVmId" {
  value = "${aws_instance.example.id}"
}

and additional sensor will be exposed on the entity named tf.output.myVmId.

Using these sensors, you can see exactly which resources have been created, the state of those resources, and of course whether the application of the configuration was successful overall.

Integrating with other tools is simple thanks to Brooklyn’s REST API. The creation was and the sensor data can be retrieved with

POST /v1/applications
GET /v1/applications/:appId/entities/:entityId/sensors/tf.state

Mixed blueprint

It is also possible to have a mixed blueprint which uses Terraform plan in conjunction with Apache Brooklyn blueprint, similarly to the following:

location: localhost
name: TF + Brooklyn Deployment
services:

- type: server 
  location: 
    jclouds:aws-ec2:us-west-2:
      osFamily: centos
      templateOptions:
        subnetId: $brooklyn:component("tf").attributeWhenReady("tf.output.subnetId")
        securityGroupIds: 
        - $brooklyn:component("tf").attributeWhenReady("tf.output.serverSecurityGroupId")

  launch.latch: $brooklyn:component("tf").attributeWhenReady("service.isUp")  

- type: io.cloudsoft.terraform.TerraformConfiguration
  name: Terraform Configuration
  id: tf
  brooklyn.config:

    tf.configuration.contents: |

        provider "aws" {
            access_key = "YOUR_ACCESS_KEY"
            secret_key = "YOUR_SECRET_KEY"
            region = "us-west-2"
        }        
        
        # Create a VPC to launch our instances into
        resource "aws_vpc" "default" {
            cidr_block = "10.0.0.0/16"
        }

        # Create an internet gateway to give our subnet access to the outside world
        resource "aws_internet_gateway" "default" {
            vpc_id = "${aws_vpc.default.id}"
        }

        # Grant the VPC internet access on its main route table
        resource "aws_route" "internet_access" {
            route_table_id         = "${aws_vpc.default.main_route_table_id}"
            destination_cidr_block = "0.0.0.0/0"
            gateway_id             = "${aws_internet_gateway.default.id}"
        }

        # Create a subnet to launch our instances into
        resource "aws_subnet" "default" {
            vpc_id                  = "${aws_vpc.default.id}"
            cidr_block              = "10.0.1.0/24"
            map_public_ip_on_launch = true
        }

        #######  Security Group  ###########
        
        resource "aws_security_group" "server" {
            name = "server"
            description = "Allow communication with the server"
            vpc_id =  "${aws_vpc.default.id}"
        }
        
        resource "aws_security_group_rule" "ssh" {
            type = "ingress"
            from_port = 22
            to_port = 22
            protocol = "tcp"
            security_group_id = "${aws_security_group.server.id}"
            cidr_blocks = ["0.0.0.0/0"]
        }

        output "subnetId" {
          value = "${aws_subnet.default.id}"
        }

        output "serverSecurityGroupId" {
          value = "${aws_security_group.server.id}"
        }       
This is a demonstration of Cloudsoft Engineer Andrea Turli showing Apache Brooklyn's integration with Hashicorp Terraform, a tool for building, changing, and versioning infrastructure safely and efficiently.

Give it a try and let us know your thoughts!