Ghosted by ARM? How to Import 'Lost' Azure Resources into Terraform
Provisioning resources through Terraform is generally smooth, but anyone who has worked extensively with any cloud provider knows that issues sometimes arise from unexpected places. When working with Azure, for instance, we can encounter cases where the response is either a “false negative” (the request was recorded as failed but actually succeeded) or where the Terraform provider simply timed out before the control plane (Azure Resource Manager, or ARM) responded.
This can be a significant problem when dealing with resources that take longer to provision. For example, creating a Virtual Hub as part of a Virtual WAN (V-WAN) setup in Azure. Provisioning a Virtual Hub can take considerable time, and if Terraform receives an erroneous “failure” response, it can leave the hub untracked in the Terraform state even though it’s fully operational in Azure. In this article, I’ll walk through how to use Terraform’s import block to efficiently solve this problem.
Let’s say we’re setting up a Virtual WAN using a V-WAN module in Terraform. Here’s the basic configuration for the module:
module "vwan" {
source = "markti/azure-terraformer/azurerm//modules/network/vwan"
version = "1.0.19"
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
name = "vwan-${var.application_name}"
primary_address_prefix = var.address_space
additional_regions = var.additional_regions
}
In this setup, all resources are deployed through the V-WAN module to ensure consistency. However, due to the timing nuances of ARM responses, I encountered an error where the primary virtual hub reported a failure back to Terraform even though it was, in reality, successfully created and fully operational on Azure.
Upon attempting a terraform apply, Terraform threw an error that said:
╷
│ Error: A resource with the ID "/subscriptions/a8dc551f-cbe8-47e9-87c1-d9570ac6d69d/resourceGroups/rg-ena-core-network/providers/Microsoft.Network/virtualHubs/vhub-ena-core-network-primary" already exists - to be managed via Terraform this resource needs to be imported into the State. Please see the resource documentation for "azurerm_virtual_hub" for more information.
│
│ with module.vwan.azurerm_virtual_hub.primary,
│ on .terraform\modules\azure-terraformer\modules\network\vwan\main.tf line 7, in resource "azurerm_virtual_hub" "primary":
│ 7: resource "azurerm_virtual_hub" "primary" {
Terraform rightly recognized that a Virtual Hub with this resource ID existed, yet it was missing from the Terraform state. In cases where the resource is quick to provision, simply deleting it and re-running terraform apply might work. However, since creating and deleting a Virtual Hub can take significant time, a more efficient approach is to use Terraform’s import
block to bring this resource under Terraform’s management without redeploying.
In response to this issue, I added an import block to link the pre-existing Virtual Hub in Azure to my Terraform configuration without triggering any deletion and recreation of the resource:
import {
to = module.vwan.azurerm_virtual_hub.primary
id = "/subscriptions/a8dc551f-cbe8-47e9-87c1-d9570ac6d69d/resourceGroups/rg-ena-core-network/providers/Microsoft.Network/virtualHubs/vhub-ena-core-network-primary"
}
Here’s how the process works:
- Locate the Resource ID: Terraform’s error message provides the resource ID of the existing Virtual Hub. We can use this ID directly in the import block.
- Locate the object reference: Terraform’s error message also provides a fully qualified object reference to wherever the resource is within the Terraform plan’s resource graph.
-
Add the Import Block: By specifying the
to
parameter (which points to the object reference within Terraform) and theid
parameter (the Azure resource ID), the import block effectively tells Terraform to import the existing resource into its state without redeploying it. - Run Apply with Import: With the import block in place, running terraform apply now pulls the Virtual Hub into the state file, allowing Terraform to manage it without additional provisioning. Once Terraform confirms the resource is successfully managed, you can delete the import block.
This approach ensures that we avoid the time-consuming process of deleting and recreating the resource. For longer-running resources like Virtual Hubs, the import command saves time and leverages the existing infrastructure.
Virtual Hubs can take a while so in this case the import command is well worth it.
Conclusion
In cases where Terraform encounters false negatives or time outs from Azure ARM control plane (or the control plane of whatever cloud you’re using), leveraging the import block is an effective strategy. It allows you to bring resources into Terraform’s state management without re-running lengthy provisioning processes–which you might pay for twice (for delete and re-create).
For Virtual Hubs and other resources with longer deployment cycles, using import
can be a real time-saver. So, the next time you’re stuck with an erroneous Terraform failure message, consider using an import
block to get your infrastructure in sync without the hassle.