Terraform on Azure – I am trying to call the results of a for_each block in one resource in another resource

huangapple go评论59阅读模式
英文:

Terraform on Azure - I am trying to call the results of a for_each block in one resource in another resource

问题

这是您提供的代码片段,我将保留代码不进行翻译,只提供注释和描述:

# 创建2个资源组,每个资源组在2个地区中各创建一个
resource "azurerm_resource_group" "rg" {
  for_each = {
    for k, v in local.multi_region_rg : v.rg_name => v
  }
  name     = each.key
  location = each.value.region_name
}
# 创建2个虚拟网络,在2个地区中各创建一个
resource "azurerm_virtual_network" "vnet" {
  for_each = {
    for k, v in local.multi_region_vnet : v.vnet_name => v
  }
  name                = each.key
  location            = each.value.region_name
  address_space       = each.value.virtual_network_address_space
  resource_group_name = azurerm_resource_group.rg[each.key]  # 尝试从上面的资源组块中调用结果
}

这两个资源块的目的是创建Azure资源组和虚拟网络。在第二个资源块中,您尝试使用azurerm_resource_group.rg[each.key]来引用第一个资源块中已创建的资源组。

然而,根据报错信息,看起来有一个问题。您可能需要确保在第二个资源块中,azurerm_resource_group.rg返回的索引是有效的,以便能够正确引用资源组。检查一下是否在azurerm_resource_group.rg中包含了与local.multi_region_vnet中的each.key相对应的资源组名称。如果资源组名称与local.multi_region_vnet中的each.key不匹配,就会导致"Invalid index"错误。

您可以确保azurerm_resource_group.rg中的索引与local.multi_region_vnet中的资源组名称匹配,以解决这个问题。如果需要更多帮助,请提供更多上下文。

英文:

Terraform on Azure - I am trying to call the results of a for_each block in one resource in another resource.

I have gone through the following & cant seem to be able to wrap my head around the logic.

>https://stackoverflow.com/questions/71646136/terraform-reference-a-for-each-resource-from-another-for-each-resource

>https://stackoverflow.com/questions/68571073/for-each-loop-in-resource-block-terraform

I have 2 resource blocks [I have added the locals file ]

# Local Variables
#
locals {
  # Create a flattened list for resource groups in multiple regions
  multi_region_rg = flatten([
    for rg_key, rg in var.multiple_resource_groups : [
      for region_key, region in var.regions : {
        rg_name     = var.environment != "" ? format("%s-rg-%s-%s-%s", var.tenant, rg_key, var.environment, region.code) : format("%s-rg-%s-%s", var.tenant, rg_key, region.code)
        region_name = region.name
      }
    ]
  ])
}

# Local Variables
#
locals {
  # Create a flattened list for resource groups in multiple regions
  multi_region_vnet = flatten([
    for vnet_key, vnet in var.multiple_vnets : [
      for region_key, region in var.regions : {
        vnet_name                     = var.environment != "" ? format("%s-rg-%s-%s-%s", var.tenant, vnet_key, var.environment, region.code) : format("%s-rg-%s-%s", var.tenant, vnet_key, region.code)
        region_name                   = region.name
        virtual_network_address_space = vnet.address_space
      }
    ]
  ])
}

TFVARS file

# Global tags
global_tags = { "ManagedBy" = "Terraform" }
# Map of regions for deployment of resource groups
regions = {
  region1 = { name = "australiaeast", code = "ae" },
  region2 = { name = "australiasoutheast", code = "ase" }
}
# Tenant
tenant = "cubem_"


# Map of resource groups
# NOTE: Use short names or aliases for resource groups as the code will generate the resource group name as per the following format:
#       <tenant>-rg-<resource_group_alias>-<environment>-<region_code>

multiple_resource_groups = {
  connectivity = {

    tags = {
      
      CostCenter = "NETWORKS",
      Department = "Network Services"
    }

  }
}

###################################### Vnet Values #######################

# Map of resource groups
# NOTE: Use short names or aliases for resource groups as the code will generate the resource group name as per the following format:
#       <tenant>-rg-<resource_group_alias>-<environment>-<region_code>

multiple_vnets = {
  vnetx = { address_space = ["10.1.0.0/24"] },
 
}

# Create 2 resource groups in 2 regions [1 in each region]
#
resource "azurerm_resource_group" "rg" {
  for_each = {
    for k, v in local.multi_region_rg : v.rg_name => v
  }
  name     = each.key
  location = each.value.region_name
  
}
# Create 2 vnets   in 2 regions [1 in each region]
#

resource "azurerm_virtual_network" "vnet" {
  for_each = {
    for k, v in local.multi_region_vnet : v.vnet_name => v
  }
  name                = each.key
  location            = each.value.region_name
  address_space       = each.value.virtual_network_address_space
  resource_group_name = azurerm_resource_group.rg[each.key]  #Im trying to call the results of the resource group block above 

}

These blocks work well when they are run independently but I want to have the ability to run them concurrently so that the vnets gets deployed into the resource groups that are created.

If I use this line resource_group_name = azurerm_resource_group.rg[each.key] its throwing this error


PS C:\PycharmProjects\terraform-projects\my_azure_connectivity_ref_repo\hub-and-spoke\modules\vnet> terraform plan  
╷
│ Error: Invalid index
│ 
│   on main.tf line 69, in resource "azurerm_virtual_network" "vnet":
│   69:   resource_group_name = azurerm_resource_group.rg[each.key]
│     ├────────────────
│     │ azurerm_resource_group.rg is object with 2 attributes
│     │ each.key is "rg-vnetx-ae"
│ 
│ The given key does not identify an element in this collection value.
╵
╷
│ Error: Invalid index
│
│   on main.tf line 69, in resource "azurerm_virtual_network" "vnet":
│   69:   resource_group_name = azurerm_resource_group.rg[each.key]
│     ├────────────────
│     │ azurerm_resource_group.rg is object with 2 attributes
│     │ each.key is "rg-vnetx-ase"
│
│ The given key does not identify an element in this collection value.
╵
PS C:\PycharmProjects\terraform-projects\my_azure_connectivity_ref_repo\hub-and-spoke\modules\vnet> 

答案1

得分: 2

以下是翻译好的部分:

  1. azurerm_virtual_network 定义中的 resource_group_name 属性存在两个问题。

    • azurerm_resource_group.rg[each.key] 表达式中的 [each.key] 不存在。这里的 [each.key] 实际上来自于 for_each = { for k, v in local.multi_region_vnet : v.vnet_name => v },而这个值在 azurerm_resource_group.rg 资源中不可用。

    • 另一个问题也存在于 vnet 资源的 resource_group_name 属性中。尽管 azurerm_resource_group.rg[$(expression)] 应该是 azurerm_resource_group.rg[$(expression)].name

  2. 因此,您需要调整资源中的一个,以使用一个标准的键,该键对于资源组和虚拟网络都是通用的。我在资源组中使用了位置/区域作为这两个资源都需要的标准键。

以下是修复了上述两个问题的正确代码:

## azurerm_resource_group 的 key 现在是 region_name ##

resource "azurerm_resource_group" "rg" {
  for_each = {
    for k, v in local.multi_region_rg : v.region_name => v
  }
  name     = each.value.rg_name
  location = each.key
}

resource "azurerm_virtual_network" "vnet" {
  for_each = {
    for k, v in local.multi_region_vnet : v.vnet_name => v
  }
  name                = each.key
  location            = each.value.region_name
  address_space       = each.value.virtual_network_address_space
  resource_group_name = azurerm_resource_group.rg[each.value.region_name].name
}

希望这对您有所帮助。

英文:

There are two issues in your resource "azurerm_virtual_network" "vnet" definition in the resource_group_name attribute.

  • [each.key] in azurerm_resource_group.rg[each.key] expression does not exists. here [each.key] is the vnet name actually coming from for_each = { for k, v in local.multi_region_vnet : v.vnet_name => v} which is not available in the resource azurerm_resource_group.rg
> { for k, v in local.multi_region_vnet : v.vnet_name => v }
{
  "test-rg-vnet_key-dev-ae" = {
    "region_name" = "australiaeast"
    "virtual_network_address_space" = [
      "10.1.0.0/24",
    ]
    "vnet_name" = "test-rg-vnet_key-dev-ae"
  }
  "test-rg-vnet_key-dev-ase" = {
    "region_name" = "australiasoutheast"
    "virtual_network_address_space" = [
      "10.1.0.0/24",
    ]
    "vnet_name" = "test-rg-vnet_key-dev-ase"
  }
}
  • The other issue also lies in the resource_group_name attribute of vnet resource with the reference. in spite of azurerm_resource_group.rg[$(expression)] should be azurerm_resource_group.rg[$(expression)].name

Hence, You have to adjust either of your resources with a standard key which is common for both resource_group and vnet. I have done it in the resource group with location/region as it is required in both of the resources.

Hence the correct code addressing both the above issues would be.

## key is now region_name in azurerm_resource_group  ##

resource "azurerm_resource_group" "rg" {
  for_each = {
    for k, v in local.multi_region_rg : v.region_name => v
  }
  name     = each.value.rg_name
  location = each.key

}

resource "azurerm_virtual_network" "vnet" {
  for_each = {
    for k, v in local.multi_region_vnet : v.vnet_name => v
  }
  name                = each.key
  location            = each.value.region_name
  address_space       = each.value.virtual_network_address_space
  resource_group_name = azurerm_resource_group.rg[(each.value.region_name)].name
}

Code In Action


➜  random_local_tests git:(main) ✗ terraform apply -auto-approve 

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_resource_group.rg["australiaeast"] will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "australiaeast"
      + name     = "test-rg-vnet_key-dev-ae"
    }

  # azurerm_resource_group.rg["australiasoutheast"] will be created
  + resource "azurerm_resource_group" "rg" {
      + id       = (known after apply)
      + location = "australiasoutheast"
      + name     = "test-rg-vnet_key-dev-ase"
    }

  # azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ae"] will be created
  + resource "azurerm_virtual_network" "vnet" {
      + address_space       = [
          + "10.1.0.0/24",
        ]
      + dns_servers         = (known after apply)
      + guid                = (known after apply)
      + id                  = (known after apply)
      + location            = "australiaeast"
      + name                = "test-rg-vnet_key-dev-ae"
      + resource_group_name = "test-rg-vnet_key-dev-ae"
      + subnet              = (known after apply)
    }

  # azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ase"] will be created
  + resource "azurerm_virtual_network" "vnet" {
      + address_space       = [
          + "10.1.0.0/24",
        ]
      + dns_servers         = (known after apply)
      + guid                = (known after apply)
      + id                  = (known after apply)
      + location            = "australiasoutheast"
      + name                = "test-rg-vnet_key-dev-ase"
      + resource_group_name = "test-rg-vnet_key-dev-ase"
      + subnet              = (known after apply)
    }

Plan: 4 to add, 0 to change, 0 to destroy.
azurerm_resource_group.rg["australiaeast"]: Creating...
azurerm_resource_group.rg["australiasoutheast"]: Creating...
azurerm_resource_group.rg["australiaeast"]: Creation complete after 5s [id=/subscriptions/xxxxxxxxxxxx/resourceGroups/test-rg-vnet_key-dev-ae]
azurerm_resource_group.rg["australiasoutheast"]: Creation complete after 6s [id=/subscriptions/xxxxxxxxxxxx/resourceGroups/test-rg-vnet_key-dev-ase]
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ae"]: Creating...
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ase"]: Creating...
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ase"]: Still creating... [10s elapsed]
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ae"]: Still creating... [10s elapsed]
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ae"]: Creation complete after 18s [id=/subscriptions/xxxxxxxxxxxx/resourceGroups/test-rg-vnet_key-dev-ae/providers/Microsoft.Network/virtualNetworks/test-rg-vnet_key-dev-ae]
azurerm_virtual_network.vnet["test-rg-vnet_key-dev-ase"]: Creation complete after 19s [id=/subscriptions/xxxxxxxxxxxx/resourceGroups/test-rg-vnet_key-dev-ase/providers/Microsoft.Network/virtualNetworks/test-rg-vnet_key-dev-ase]

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

Hope it helps.

And additional info which is not relevant here too much I have used static values instead of some variables.

rg_name = var.environment != "" ? format("%s-rg-%s-%s-%s", "test", "vnet_key", var.environment, region.code) : format("%s-rg-%s-%s", "test", "vnet_key", region.code)

vnet_name = var.environment != "" ? format("%s-rg-%s-%s-%s", "test", "vnet_key", var.environment, region.code) : format("%s-rg-%s-%s", "test", "vnet_key", region.code)

huangapple
  • 本文由 发表于 2023年2月16日 06:18:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75465952.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定