Skip to main content

E2e infrastructure testing in Terraform: How to make scripts reproducible and reliable

Picture of Maciek Gołaszewski, Cloud Engineer

Maciek Gołaszewski

Cloud Engineer
May 23, 2023|13 min read
E2e_infrastructure_testing_in_Terraform_How_to_make_scripts_reproducible_and_reliable_image
1terraform {
2 required_providers {
3 azurerm = {
4 source = "hashicorp/azurerm"
5 version = "=3.50.0"
6 }
7 }
8}
9
10provider "azurerm" {
11 features {}
12}
13
14locals {
15 init_script= <<EOF
16#!/bin/bash
17echo "Hello, World!" > index.html
18nohup busybox httpd -f -p 8080 &
19EOF
20}
21
22variable "prefix" {
23 default = "virtuslab"
24}
25
26resource "azurerm_resource_group" "rg_vm" {
27 name = "${var.prefix}-resources"
28 location = "West Europe"
29}
30
31resource "azurerm_virtual_network" "vn_main" {
32 name = "${var.prefix}-network"
33 address_space = ["10.0.0.0/16"]
34 location = azurerm_resource_group.rg_vm.location
35 resource_group_name = azurerm_resource_group.rg_vm.name
36}
37
38resource "azurerm_subnet" "vns_internal" {
39 name = "internal"
40 resource_group_name = azurerm_resource_group.rg_vm.name
41 virtual_network_name = azurerm_virtual_network.vn_main.name
42 address_prefixes = ["10.0.2.0/24"]
43}
44
45resource "azurerm_public_ip" "pip_vm" {
46 name = "myPublicIP"
47 location = azurerm_resource_group.rg_vm.location
48 resource_group_name = azurerm_resource_group.rg_vm.name
49 allocation_method = "Dynamic"
50}
51
52resource "azurerm_network_interface" "interface_vm" {
53 name = "${var.prefix}-nic"
54 location = azurerm_resource_group.rg_vm.location
55 resource_group_name = azurerm_resource_group.rg_vm.name
56
57 ip_configuration {
58 name = "testconfiguration1"
59 subnet_id = azurerm_subnet.vns_internal.id
60 private_ip_address_allocation = "Dynamic"
61 public_ip_address_id = azurerm_public_ip.pip_vm.id
62 }
63}
64
65resource "azurerm_linux_virtual_machine" "linux_vm" {
66 name = "example-machine"
67 resource_group_name = azurerm_resource_group.rg_vm.name
68 location = azurerm_resource_group.rg_vm.location
69 size = "Standard_DS1_v2"
70 disable_password_authentication = false
71 admin_username = "adminuser"
72 admin_password = "Password1234!" # For tests purposes!
73 network_interface_ids = [ azurerm_network_interface.interface_vm.id ]
74 custom_data = base64encode(local.init_script)
75
76 os_disk {
77 caching = "ReadWrite"
78 storage_account_type = "Standard_LRS"
79 }
80 source_image_reference {
81 publisher = "Canonical"
82 offer = "UbuntuServer"
83 sku = "16.04-LTS"
84 version = "latest"
85 }
86}
87
88output "public_ip" {
89 value = azurerm_linux_virtual_machine.linux_vm.public_ip_address
90}
1package test
2
3import (
4 "fmt"
5 "testing"
6 "time"
7
8 http_helper "github.com/gruntwork-io/terratest/modules/http-helper"
9
10 "github.com/gruntwork-io/terratest/modules/terraform"
11)
12
13func TestTerraformHelloWorldVm(t *testing.T) {
14 t.Parallel()
15
16 // Set up vars
17 vars := map[string]interface{}{
18 "port": 9090,
19 "prefix": "virtuslab",
20 }
21 terraformOptions := &terraform.Options{
22 Vars: vars,
23 }
24
25 // Cleanup after tests.
26 defer terraform.Destroy(t, terraformOptions)
27
28 // Apply infrastructure
29 terraform.InitAndApply(t, terraformOptions)
30
31 // Gather data about infrastructure
32 publicIp := terraform.Output(t, terraformOptions, "public_ip")
33 port := terraform.Output(t, terraformOptions, "port")
34
35 // Check if endpoint is working
36 url := fmt.Sprintf("http://%s:%s", publicIp, port)
37 http_helper.HttpGetWithRetry(t, url, nil, 200, "Hello, World!", 10, 5*time.Second)
38}
1$ go test -v -run TestTerraformHelloWorldVm -timeout 30m
2=== RUN TestTerraformHelloWorldVm
3Running command terraform with args [init]
4Initializing provider plugins...
5[...]
6Terraform has been successfully initialized!
7[...]
8Running command terraform with args [apply -input=false -auto-approve -var port=9090 -var prefix=test -lock=false]
9
10Terraform used the selected providers to generate the following execution
11plan. Resource actions are indicated with the following symbols:
12 + create
13
14Terraform will perform the following actions:
15
16 # azurerm_linux_virtual_machine.linux_vm will be created
17 + resource "azurerm_linux_virtual_machine" "linux_vm" {
18 + admin_password = (sensitive value)
19 + admin_username = "adminuser"
20[...]
21Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
22Outputs:
23port = "9090"
24public_ip = "108.143.19.96"
25[...]
26terraform [output -no-color -json public_ip]
27Running command terraform with args [output -no-color -json public_ip]
28"108.143.19.96"
29terraform [output -no-color -json port]
30Running command terraform with args [output -no-color -json port]
31"9090"
32HTTP GET to URL http://108.143.19.96:9090
33Making an HTTP GET call to URL http://108.143.19.96:9090
34[...]
35Running command terraform with args [destroy -auto-approve -input=false -var port=9090 -var prefix=test -lock=false]
36[...]
37Destroy complete! Resources: 6 destroyed.
38--- PASS: TestTerraformHelloWorldVm (264.28s)
39PASS
40ok github.com/VirtusLab/e2e-example 264.294s
41

Curated by Sebastian Synowiec

Subscribe to our newsletter and never miss an article