Selective Terraform Testing: Targeting New Resources While Preserving Existing Ones

Take into account the tfvars file provided. Presently, during the execution of “terraform test,” all resources undergo provisioning and deprovisioning for testing. However, if the intention is to exclusively test the “New_Resource” while maintaining the “Existing_Resource” untouched, or to skip the provisioning and deprovisioning steps for the existing resource, is there a method within Terraform tests to accomplish this?
variable resource_group_variables = {
“resource_group_1” = {
resource_group_name = “Existing_Resource”
resource_group_location = “eastus2”
resource_group_managed_by = “blabla” #(optional) The ID of the resource or application that manages this Resource Group.
resource_group_tags = {
Created_By = “testuser”,
Department = “IT”
}
},
“resource_group_2” = {
resource_group_name = “New_Resource” #(Required) Name of the Resouce Group with which it should be created.
resource_group_location = “westus”
resource_group_managed_by = “blabla”
resource_group_tags = {
Created_By = “testuser”,
Department = “IT”
}
}
}

Hi @anoop.pc, hopefully I’m understanding your question. You can specify the -target argument within Terraform Test run blocks as a way to selectively test specific resources:

run "test" {
  plan_options {
    target = [
      resource_type.resource_name,
      resource_type.other_name[0],
    ]
  }
}

The above code snippet would only update the targeted resources, and any resources needed by the targeted resources in the dependency graph.

Thanks for a your response.

I’m seeking a solution that allows me to utilize “terraform test” for existing resources that have already been provisioned. Whenever there’s a modification to any attributes or dependencies of a provisioned resource, the “terraform test” command, which operates in memory, always attempts to provision new resources and raises errors, stating that the “resource already exists.”

Hi @anoop.pc, what you’re describing isn’t possible with the terraform test command. The test command should be executed in a separate environment from your live infrastructure. This ensures that running the test command won’t modify or break anything you have running in production.

Note that running a normal terraform plan or terraform apply command would achieve what you are describing - in which the new infrastructure is provisioned as described in your configuration.

In addition, you can use Custom Conditions within your regular Terraform configuration. These operate in the same way as assertions within test files, and would allow you to run a terraform plan command and validate the new infrastructure that will be created, in much the same way the terraform test command would, without starting from an empty state file.

Official Terraform 1.8.5 Repo via JARaaS Hybrid RAG - Documentation - code current 6/17/2024

Note: Sources at the end of the response

To achieve selective Terraform testing where only the new resources are tested, while existing resources remain untouched, you can employ the use of targeting with the -target option in the terraform plan and terraform apply commands.

Here’s how you can approach this:

  1. Identify the Resource Addresses: Determine the resource addresses for both the “New_Resource” and the “Existing_Resource”. For example:

    • resource_group_1 has the address azurerm_resource_group.resource_group_1
    • resource_group_2 has the address azurerm_resource_group.resource_group_2
  2. Use Target Option in Terraform Plan: Use the -target option to specify the resource you want to include in the plan. For instance, to include only resource_group_2 (New_Resource), execute:

    terraform plan -target=azurerm_resource_group.resource_group_2
    
  3. Apply Target Option in Terraform Apply: Similarly, apply the target option to exclusively apply changes to the new resource:

    terraform apply -target=azurerm_resource_group.resource_group_2
    

For selective testing within Terraform, you can also integrate Terraform’s null_resource and triggers to simulate testing without impacting real resource provisioning. Here’s a brief section of how you can implement null_resource:

resource "azurerm_resource_group" "existing" {
  name     = var.resource_group_variables["resource_group_1"].resource_group_name
  location = var.resource_group_variables["resource_group_1"].resource_group_location
  tags     = var.resource_group_variables["resource_group_1"].resource_group_tags
}

resource "azurerm_resource_group" "new" {
  name     = var.resource_group_variables["resource_group_2"].resource_group_name
  location = var.resource_group_variables["resource_group_2"].resource_group_location
  tags     = var.resource_group_variables["resource_group_2"].resource_group_tags
}

resource "null_resource" "test" {
  triggers = {
    new_resource_name = azurerm_resource_group.new.name
  }

  provisioner "local-exec" {
    command = "echo Testing new resource: ${self.triggers.new_resource_name}"
  }
}

By using the above approach, you can ensure only the new resource group undergoes testing, while the existing resource group remains unchanged.

Sources:

  • Main Terraform Specification: main.tf (internal document)
  • Shared Variable Definitions: variables.tf (internal document)