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.