TL;DR

Hand crafting an architect and then manually pushing the cloud is not repeatable, you want to be able to come back to it in the future without having to remember commands or figure out what your past self intended to do. Capturing architecture design in Terraform as code is a really effective way to codify a design and integrating that into Maven means that it can be deployed in a single click or as part of a continuous delivery pipeline.

Are you motivated?

The motivation behind wanting to integration Maven and Terraform is so that the generation of infrastructure can be built into the same build pipeline as used for the rest of an application.

Terraform is a great option for codifying your infrastructure. Often the easiest option, at least initially, is not the best. I’ve recently started deep diving into the mechanics of building event based distributed architectures in Microsoft Azure. Initially I found myself either using the tools built into IntelliJ to create Azure resources or using the Azure admin console directly. Thats great for prototyping and learning but very bad for repeatability. To be honest, I know I’ll put this project aside at some point and come back to it in 6 months and have completely forgotten why the infrastructure is configured the way it is, or how to repeat it.

Terraform provides a way for me to capture the learning and design decisions in code rather than in a bespoke implementation of an architecture. Integrating that with the same build tools used for Java gives me a unified and clear way to capture the design and push it to Azure whenever I want to come back to it.

The magic glue - terraform-maven

The project that enables the integration is the Terraform Maven Plugin which can be found over on Github:

https://github.com/deliveredtechnologies/terraform-maven

This provides a set of goals which mirror the commands available on the Terraform CLI.

Plug me in please

<build>
    <plugins>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>azure-functions-maven-plugin</artifactId>
            <version>1.24.0</version>
            <configuration>
                <appName></appName>
                <resourceGroup></resourceGroup>
                <appServicePlanName></appServicePlanName>
                <region></region>
                <pricingTier></pricingTier>
                <disableAppInsights/>

                <runtime>
                    <os>linux</os>
                    <javaVersion>17</javaVersion>
                </runtime>
            </configuration>
        </plugin>

        <plugin>
            <groupId>com.deliveredtechnologies</groupId>
            <artifactId>tf-maven-plugin</artifactId>
            <version>0.13-593</version>

            <executions>
                <execution>
                    <id>terraform-clean</id>
                    <phase>clean</phase>
                    <goals>
                        <goal>init</goal>
                        <goal>destroy</goal>
                        <goal>clean</goal>
                    </goals>
                </execution>
                <execution>
                    <id>terraform-plan</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>init</goal>
                        <goal>plan</goal>
                    </goals>
                </execution>
                <execution>
                    <id>terraform-package</id>
                    <phase>package</phase>
                    <goals>
                        <goal>package</goal>
                    </goals>
                </execution>
                <execution>
                    <id>terraform-install</id>
                    <phase>install</phase>
                    <goals>
                        <goal>deploy</goal>
                    </goals>
                </execution>
                <execution>
                    <id>terraform-deploy</id>
                    <phase>deploy</phase>
                    <goals>
                        <goal>deploy</goal>
                    </goals>
                </execution>
                <execution>
                    <id>terraform-get</id>
                    <phase>validate</phase>
                    <goals>
                        <goal>get</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

You’ll need to fill in the blank which are marked with ❓.

Let’s see some structure

The Terraform code that describes your architecture gets put in the standard Maven directory structure in src/main/tf.

The first step after configuring these is to run tf:init which will generation two things:

  1. src/main/tf/.terraform/providers/.../terraform-provider-azurerm_v2.99.0_x5 - The binary executable for your platform which Terraform uses to integrate with Azure.
  2. src/main/tf/.terraform.lock.hcl - The dependency lock file.

You’ll need to re-run tf:init if the provider needs to be updated.

Plan to succeed

Now you’re ready to run tf:plan and see what changes need to be made to the target platform to put it in the same state as the infrastructure you have defined.