【问题标题】:how to reference objects in terraform如何在 terraform 中引用对象
【发布时间】:2019-11-13 15:17:01
【问题描述】:

我正在使用 terraform 创建一个 Azure VNet,并在其中创建几个子网。稍后,我想创建一个网络接口,并将其放在已经为 VNet 创建的子网之一中。我不知道如何引用那个子网。

我在下面尝试过,但现在可以正常工作了:

subnet_id = "${azurerm_virtual_network.virtual-network.subnet.ServersSubnet.id}"

resource "azurerm_virtual_network" "virtual-network" {
    name                = "${var.ClientShortName}-az-network"
    address_space       = ["${local.AzureInfraNetwork}"]
    location            = "${var.resource-location}"
    resource_group_name =  "${azurerm_resource_group.test-resource-group.name}"

subnet {
    name           = "ServersSubnet"
    address_prefix = "${local.ServersSubnet}"
}

subnet {
    name           = "GatewaySubnet"
    address_prefix = "${local.GatewaySubnet}"
} 
}

错误:无法索引设定值

  on main.tf line 120, in resource "azurerm_network_interface" "DCNIC":
 120:     subnet_id                     = "${azurerm_virtual_network.virtual-network.subnet.ServersSubnet.id}"

Block type "subnet" is represented by a set of objects, and set elements do
not have addressable keys. To find elements matching specific criteria, use a
"for" expression with an "if" clause.

【问题讨论】:

    标签: azure terraform


    【解决方案1】:

    以下是完整的解决方案。

    如果子网是作为块创建的,您可以引用给定子网的资源 ID,如下所示:

    resource "azurerm_resource_group" "main" {
      name     = "vnet-rg"
      location = "eastus"
    }
    
    resource "azurerm_virtual_network" "main" {
      name                = "my-vnet"
      location            = azurerm_resource_group.main.location
      resource_group_name = azurerm_resource_group.main.name
      address_space       = ["10.0.0.0/16"]
    
      subnet {
        name           = "subnet1"
        address_prefix = "10.0.1.0/24"
      }
    
      subnet {
        name           = "subnet2"
        address_prefix = "10.0.2.0/24"
      }
    
      subnet {
        name           = "subnet3"
        address_prefix = "10.0.3.0/24"
      }
    
    }
    
    output "subnet1_id" {
      value = azurerm_virtual_network.main.subnet.*.id[0]
    }
    
    output "subnet2_id" {
      value = azurerm_virtual_network.main.subnet.*.id[1]
    }
    
    output "subnet3_id" {
      value = azurerm_virtual_network.main.subnet.*.id[2]
    }
    

    【讨论】:

      【解决方案2】:

      将子网创建为块时,您必须使用列表语法来引用它们,例如:

      foo = azurerm_virtual_network.virtual-network.subnet[0].id
      bar = azurerm_virtual_network.virtual-network.subnet[1].id
      

      如果子网形成一个冗余资源池并且您不关心特别引用任何子网,这很有用。

      我不认为这是您的情况,因此您可以考虑将子网创建为单独的资源,例如:

      resource "azurerm_virtual_network" "main" {
          name                = "${var.ClientShortName}-az-network"
          address_space       = [local.AzureInfraNetwork]
          location            = var.resource-location
          resource_group_name = azurerm_resource_group.test-resource-group.name
      }
      
      resource "azurerm_subnet" "server" {
          virtual_network_name  = azurerm_virtual_network.main.name
          name                  = "ServersSubnet"
          address_prefix        = local.ServersSubnet
      }
      
      resource "azurerm_subnet" "gateway" {
          virtual_network_name  = azurerm_virtual_network.main.name
          name                  = "GatewaySubnet"
          address_prefix        = local.ServersSubnet
      }
      

      然后您可以使用常规对象属性语法引用您的子网之一:

      foo = azurerm_subnet.server.id
      

      另外请注意,我使用的是terraform => 0.12 语法,所以当我不需要字符串插值时,我可以写foo.bar 而不是"${foo.bar}"

      【讨论】:

      • 谢谢,所以我的理解是不可能在虚拟网络定义中创建子网,然后在其他地方引用它们(比如我想在创建 NIC 时引用它们的这个场景)?
      • 这是可能的,正如我的回答所写的那样。但是您需要使用语法azurerm_virtual_network.virtual-network.subnet[0].name 来引用您的子网。不过,我认为这不是一个好习惯。
      • 错误:无法在资源“azurerm_network_interface”“DCNIC”中的 main.tf 第 120 行索引设置值:120:subnet_id = azurerm_virtual_network.virtual-network.subnet[0].id 块类型“子网”由一组对象表示,并且集合元素没有可寻址的键。要查找匹配特定条件的元素,请使用带有“if”子句的“for”表达式。
      【解决方案3】:

      您可以将其分解为将虚拟网络和子网创建为单独的资源。这样做的好处是您可以将子网作为映射而不是列表返回,这样以后可以更轻松地按名称检索,如果您需要在以后添加/删除子网,它也可以使其稳定。

      locals {
        subnets = {
          Servers = "10.0.1.0/24",
          Gateway = "10.0.2.0/24"
        }
      }
      
      resource "azurerm_resource_group" "main" {
        name     = "vnet-rg"
        location = "eastus"
      }
      
      resource "azurerm_virtual_network" "main" {
        name                = "my-vnet"
        location            = azurerm_resource_group.main.location
        resource_group_name = azurerm_resource_group.main.name
        address_space       = [ local.AzureInfraNetwork ]    
      }
      
      resource "azurerm_subnet" "main" {
        for_each = var.subnets
      
        name                 = "${each.key}-subnet"
        resource_group_name  = azurerm_resource_group.main.name
        virtual_network_name = azurerm_virtual_network.main.name
        address_prefixes     = [ each.value ]
      }
      
      output "subnets" {
        value = azurerm_subnet.main
      }
      

      【讨论】:

        【解决方案4】:

        如果其他人需要这个问题的答案,请使用:

        "${element(azuread_application.events_backend.app_role[*].id,0)}"
        

        【讨论】:

        • 嗨内森。您可以通过解释其工作原理以及解决问题的方式来改进您的答案。
        • 我已经尝试过这个解决方案,它对我有用,在一辆类似的车上。我使用了类似的东西,它获取第一个元素“0”,让我访问属性element(azuread_application.events_backend.app_role[*].id,0)跨度>
        猜你喜欢
        • 2021-08-13
        • 2021-07-01
        • 2021-08-08
        • 2019-02-06
        • 1970-01-01
        • 2020-11-01
        • 2021-10-04
        • 2020-12-07
        • 1970-01-01
        相关资源
        最近更新 更多