Dependency issue

Hi, im new in HCL. I am creating a simple configuration with the following files main.tf, variables.tf, x.auto.tfvars. When i run apply, it creates the RG in the Azure Portal but throws the error for the vnet. I resolve this by running ‘terraform apply’ again. Why this keeps happening? I dont want to add depends_on and i dont want to have to run apply twice. Please find below the whole code and error. (please ignore the lack of indentations, its not like that in my code)

Error: 
│ Error: creating/updating Virtual Network (Subscription: ""
│ Resource Group Name: "rg-hub-prod-eus-01"
│ Virtual Network Name: "vnet-hub-prod-eus-01"): network.VirtualNetworksClient#CreateOrUpdate: Failure sending request: StatusCode=404 -- Original Error: Code="ResourceGroupNotFound" Message="Resource group 'rg-hub-prod-eus-01' could not be found."
│
│   with azurerm_virtual_network.vnets["hub"],
│   on main.tf line 11, in resource "azurerm_virtual_network" "vnets":
│   11: resource "azurerm_virtual_network" "vnets" {
│

main.tf

resource "azurerm_resource_group" "rgs" {
  for_each = var.rgs
  name     = each.value["name"]
  location = var.location
}

resource "azurerm_virtual_network" "vnets" {
  for_each            = var.vnets
  name                = each.value["name"]
  location            = var.location
  address_space       = each.value["address_space"]
  resource_group_name = each.value["resource_group_name"]
}

variables.tf

variable "location" {
  description = "The desired region for resources"
  type        = string
  default     = "east us"
}

variable "rgs" {
  description = "Map of Resource Group objects"
  type = map(object({
    name     = string
    location = string
    #tags
  }))
}

variable "vnets" {
  description = "Map of Virtual Networks"
  type = map(object({
    name                = string
    location            = string
    address_space       = list(string)
    resource_group_name = string
  }))
}

x.auto.tfvars

rgs = {
  hub = {
    name     = "rg-hub-prod-eus-01"
    location = ""
    #tags
  }
}

vnets = {
  hub = {
    name                = "vnet-hub-prod-eus-01"
    location            = ""
    address_space       = ["10.0.0.0/20"]
    resource_group_name = "rg-hub-prod-eus-01"
  }
}

Hi @mmilan,

In your configuration there is nothing to tell Terraform that the virtual networks depend on the resource groups. Although we as humans can infer that resource_group_name is a unique identifier for a resource group and that azurerm_resource_group is a resource group, Terraform doesn’t have this contextual wisdom and so it relies on references in the configuration to infer the relationships between the resources based on how the data is flowing between them.

One way to achieve that is for the virtual network resource to obtain the resource group name from the azurerm_resource_group resource, rather than directly from the var.vnets element:

resource "azurerm_virtual_network" "vnets" {
  for_each = var.vnets

  name                = each.value["name"]
  location            = var.location
  address_space       = each.value["address_space"]
  resource_group_name = azurerm_resource_group.rgs[each.value["resource_group_name"]].name
}

A resource with for_each appears in expressions as a map of objects whose keys match the keys of the map given to for_each, so therefore each.value["resource_group_name"] can be used to correlate with a specific instance of azurerm_resource_group.rgs and read its name attribute.

In this particular case this may appear redundant because you happen to know that the instance keys of instances azurerm_resource_group.rgs each always exactly match the name argument of the instance, and so the result of this longer expression is the same value as what you had before.

But this way of writing it allows Terraform to infer that azurerm_virtual_network.vnets depends on azurerm_resource_group.rgs and it will therefore deal with creating all of the resource groups before it tries to create any of the virtual networks.

This new approach also implicitly checks that each of the resource group names specified for the var.vnets objects match with one of the resource groups in var.rgs; Terraform will raise an error if not, because it will not find a suitable instance of azurerm_resource_group.rgs to take the name from.

1 Like

I really appreciate you fast reply @apparentlymart , that worked for me!
For anyone that is reading , if you have a resource that is not part of for loop, you can do this to associate the resource group that has for loop:
resource “azurerm_windows_web_app” “app-01” {
name = “app-prod-eus-01”
resource_group_name = azurerm_resource_group.rgs[“rg-app-prod-eus-01”].name