Let's connect
Let's connect

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

Picture of Maciek Gołaszewski, Cloud Engineer

Maciek Gołaszewski

Cloud Engineer

13 minutes read

java

terraform {
 required_providers {
   azurerm = {
     source  = "hashicorp/azurerm"
     version = "=3.50.0"
   }
 }
}

provider "azurerm" {
 features {}
}

locals {
 init_script= <<EOF
#!/bin/bash
echo "Hello, World!" > index.html
nohup busybox httpd -f -p 8080 &
EOF
}

variable "prefix" {
 default = "virtuslab"
}

resource "azurerm_resource_group" "rg_vm" {
 name     = "${var.prefix}-resources"
 location = "West Europe"
}

resource "azurerm_virtual_network" "vn_main" {
 name                = "${var.prefix}-network"
 address_space       = ["10.0.0.0/16"]
 location            = azurerm_resource_group.rg_vm.location
 resource_group_name = azurerm_resource_group.rg_vm.name
}

resource "azurerm_subnet" "vns_internal" {
 name                 = "internal"
 resource_group_name  = azurerm_resource_group.rg_vm.name
 virtual_network_name = azurerm_virtual_network.vn_main.name
 address_prefixes     = ["10.0.2.0/24"]
}

resource "azurerm_public_ip" "pip_vm" {
 name                = "myPublicIP"
 location            = azurerm_resource_group.rg_vm.location
 resource_group_name = azurerm_resource_group.rg_vm.name
 allocation_method   = "Dynamic"
}

resource "azurerm_network_interface" "interface_vm" {
 name                = "${var.prefix}-nic"
 location            = azurerm_resource_group.rg_vm.location
 resource_group_name = azurerm_resource_group.rg_vm.name

 ip_configuration {
   name                          = "testconfiguration1"
   subnet_id                     = azurerm_subnet.vns_internal.id
   private_ip_address_allocation = "Dynamic"
   public_ip_address_id          = azurerm_public_ip.pip_vm.id
 }
}

resource "azurerm_linux_virtual_machine" "linux_vm" {
 name                = "example-machine"
 resource_group_name = azurerm_resource_group.rg_vm.name
 location            = azurerm_resource_group.rg_vm.location
 size                = "Standard_DS1_v2"
 disable_password_authentication = false
 admin_username      = "adminuser"
 admin_password      = "Password1234!" # For tests purposes!
 network_interface_ids = [ azurerm_network_interface.interface_vm.id ]
 custom_data = base64encode(local.init_script)

 os_disk {
   caching              = "ReadWrite"
   storage_account_type = "Standard_LRS"
 }
 source_image_reference {
   publisher = "Canonical"
   offer     = "UbuntuServer"
   sku       = "16.04-LTS"
   version   = "latest"
 }
}

output "public_ip" {
 value = azurerm_linux_virtual_machine.linux_vm.public_ip_address
}

java

package test

import (
   "fmt"
   "testing"
   "time"

   http_helper "github.com/gruntwork-io/terratest/modules/http-helper"

   "github.com/gruntwork-io/terratest/modules/terraform"
)

func TestTerraformHelloWorldVm(t *testing.T) {
   t.Parallel()

   // Set up vars
   vars := map[string]interface{}{
      "port":   9090,
      "prefix": "virtuslab",
   }
   terraformOptions := &terraform.Options{
      Vars: vars,
   }

   // Cleanup after tests.
   defer terraform.Destroy(t, terraformOptions)

   // Apply infrastructure
   terraform.InitAndApply(t, terraformOptions)

   // Gather data about infrastructure
   publicIp := terraform.Output(t, terraformOptions, "public_ip")
   port := terraform.Output(t, terraformOptions, "port")

   // Check if endpoint is working
   url := fmt.Sprintf("http://%s:%s", publicIp, port)
   http_helper.HttpGetWithRetry(t, url, nil, 200, "Hello, World!", 10, 5*time.Second)
}

bash

$ go test -v -run TestTerraformHelloWorldVm -timeout 30m
=== RUN   TestTerraformHelloWorldVm
Running command terraform with args [init]
Initializing provider plugins...
[...]
Terraform has been successfully initialized!
[...]
Running command terraform with args [apply -input=false -auto-approve -var port=9090 -var prefix=test -lock=false]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # azurerm_linux_virtual_machine.linux_vm will be created
  + resource "azurerm_linux_virtual_machine" "linux_vm" {
  	+ admin_password              	= (sensitive value)
  	+ admin_username              	= "adminuser"
[...]
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
Outputs:
port = "9090"
public_ip = "108.143.19.96"
[...]
terraform [output -no-color -json public_ip]
Running command terraform with args [output -no-color -json public_ip]
"108.143.19.96"
terraform [output -no-color -json port]
Running command terraform with args [output -no-color -json port]
"9090"
HTTP GET to URL http://108.143.19.96:9090
Making an HTTP GET call to URL http://108.143.19.96:9090
[...]
Running command terraform with args [destroy -auto-approve -input=false -var port=9090 -var prefix=test -lock=false]
[...]
Destroy complete! Resources: 6 destroyed.
--- PASS: TestTerraformHelloWorldVm (264.28s)
PASS
ok  	github.com/VirtusLab/e2e-example    	264.294s

Curated by

Sebastian Synowiec

Liked the article?

Share it with others!

explore more on

Take the first step to a sustained competitive edge for your business

Get your free consultation

VirtusLab's work has met the mark several times over, and their latest project is no exception. The team is efficient, hard-working, and trustworthy. Customers can expect a proactive team that drives results.

Stephen Rooke
Stephen RookeDirector of Software Development @ Extreme Reach

VirtusLab's engineers are truly Strapi extensions experts. Their knowledge and expertise in the area of Strapi plugins gave us the opportunity to lift our multi-brand CMS implementation to a different level.

facile logo
Leonardo PoddaEngineering Manager @ Facile.it

VirtusLab has been an incredible partner since the early development of Scala 3, essential to a mature and stable Scala 3 ecosystem.

Martin_Odersky
Martin OderskyHead of Programming Research Group @ EPFL

The VirtusLab team's in-depth knowledge, understanding, and experience of technology have been invaluable to us in developing our product. The team is professional and delivers on time – we greatly appreciated this efficiency when working with them.

Michael_Grant
Michael GrantDirector of Development @ Cyber Sec Company