Testing a Terraform resource deployment

I like to include smoke tests [ST] in my Terraform [TF] deployments just to make sure I didn’t overlook anything obvious. One such way is to interact with a resource that invokes other resources, such as an HTTP endpoint that is routed through API gateways, application containers and databases.

An easy and portable way to do this with Terraform is declaring a null_resource [NR] with a local-exec provisioner [LE] that invokes a curl [CU] like this:

resource "null_resource" "test-containerapp-helloworld" {
  provisioner "local-exec" {
    command = "curl --insecure --silent --fail $URL"
    interpreter = ["bash", "-c"]
	environment = {
	  URL = "http://my-app.azure.net"
  depends_on = [azurerm_container_app.containerapp-helloworld]

Declaring a null_resource is the way I chose to insert custom logic into the deployment without creating any resources in the target infrastructure. The local-exec provisioner executes a curl command on the client machine which will fetch the target URL and fail if it returns anything other than an 200 code. Variable substitution works here, so a dynamic URL can be constructed by referencing variables and resource outputs. Obviously more complex logic like grepping for a specific output or running test script can be executed here. The depends_on attribute ensures that the test runs only after the resource-under-test has been created (here: a container app).

Update 2023.03.02

Sometimes services can take a while to start even after the deployment is complete, so a liveness probe would initially fail. In that case a simple script that polls over the service until it returns a ready status (or times out) looks like this:

resource "null_resource" "test-containerapp-helloworld" {
  provisioner "local-exec" {
    command = <<EOM
echo Trying "$URL"
timeout 120s bash -c 'until curl --silent --fail  --show-error --retry-connrefused "$URL" > /dev/null; do sleep 5; done' && echo ok || echo not ok
    interpreter = ["bash", "-c"]
	environment = {
	  URL = "${azurerm_api_management.apim-service.gateway_url}/${azurerm_api_management_api.api-helloworld.path}"
  depends_on = [azurerm_container_app.containerapp-helloworld, azurerm_api_management_api.api-helloworld]


[ST] Smoke testing

[TF] Terraform

[NR] null_resource

[LE] local-exec provisioner

[CU] curl man page

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.