Terraform Testing

For a long time I've been wanting to look at some way of testing terraform. As part of this I've recently looked using terratest and localstack.

While localstack looks promising lots of the things I wanted to test are either in the pro version or not supported so I went back to using live AWS accounts. It would be nice to be able to use localstack in a pipeline, hopefully in the future. I did get a simple pipeline running in GitHub Actions

 1name: localstack-action-example
 2on: push
 3jobs:
 4  example-job:
 5    runs-on: ubuntu-latest
 6    steps:
 7      - name: Checkout
 8        uses: actions/checkout@v3
 9      - name: Start LocalStack
10        env:
11          LOCALSTACK_API_KEY: ${{ secrets.LOCALSTACK_API_KEY }}
12        run: |
13          pip install --upgrade pyopenssl
14          pip install localstack awscli-local[ver1] # install LocalStack cli and awslocal
15          docker pull localstack/localstack         # Make sure to pull the latest version of the image
16          localstack start -d                       # Start LocalStack in the background
17          
18          echo "Waiting for LocalStack startup..."  # Wait 30 seconds for the LocalStack container
19          localstack wait -t 30                     # to become ready before timing out 
20          echo "Startup complete"          
21      - name: Run some Tests against LocalStack
22        run: |
23          awslocal s3 mb s3://test
24          awslocal s3 ls
25          echo "Test Execution complete!"     
26      - name: Terraform
27        run: |
28          pip install terraform-local
29          tflocal init
30          ls -la
31          tflocal apply --auto-approve

Terratest does appear to show some promising results, it has allowed me to wrap some tests around some Terraform examples I've recently put together.

At a basic level it can just a basic init->plan-apply->destroy cycle on a Terraform deployment to check it works

 1
 2package test
 3
 4import (
 5	"testing"
 6	"github.com/gruntwork-io/terratest/modules/terraform"
 7)
 8
 9func TestEksCa(t *testing.T) {
10
11	terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
12		TerraformDir: "../eks-ca",
13	})
14
15	defer terraform.Destroy(t, terraformOptions)
16
17	terraform.InitAndApply(t, terraformOptions)
18
19}

It can also be expanded to query the deployed infrastructure

 1
 2package test
 3
 4import (
 5	"testing"
 6
 7	"github.com/gruntwork-io/terratest/modules/aws"
 8	"github.com/gruntwork-io/terratest/modules/terraform"
 9	"github.com/stretchr/testify/assert"
10)
11
12func TestVpcPeering(t *testing.T) {
13
14	vpcOwnerPrefix := "10.10"
15	vpcAcceptorPrefix := "10.20"
16	awsRegion := "us-east-1"
17	terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
18		TerraformDir: "../vpc_peering",
19		Vars: map[string]interface{}{
20			"cidr_prefix-a": vpcOwnerPrefix,
21			"cidr_prefix-b": vpcAcceptorPrefix,
22		},
23	})
24
25	defer terraform.Destroy(t, terraformOptions)
26
27	terraform.InitAndApply(t, terraformOptions)
28
29	vpcIdOwner := terraform.Output(t, terraformOptions, "vpc-owner-id")
30	vpcIdAccepter := terraform.Output(t, terraformOptions, "vpc-accepter-id")
31
32	vpcOwner := aws.GetVpcById(t, vpcIdOwner, awsRegion)
33	vpcAccepter := aws.GetVpcById(t, vpcIdAccepter, awsRegion)
34
35	assert.NotEmpty(t, vpcOwner.Name)
36	assert.NotEmpty(t, vpcAccepter.Name)
37}

A promising start, it would be nice to pair it with localstack for speed in the future.

comments powered by Disqus