使用具有 for_each 集的模块的输出值

Posted

技术标签:

【中文标题】使用具有 for_each 集的模块的输出值【英文标题】:Use output value from module that has a for_each set 【发布时间】:2021-04-18 15:09:57 【问题描述】:

我的代码设置为在创建 VM 时导出动态私有 IP 地址。我通过输出值做到了这一点。从那时起,我已经更新到 tf 0.13 并且我在模块中使用了一个 for_each 但是当我现在引用这个值时,我得到了以下错误。我不确定如何导出 NIC 的动态私有地址属性,现在 for_each 已设置为在 source_address_prefixes 中使用。我明白错误在说什么,但不确定将值导出到对象映射的正确方式?

Error: Unsupported attribute

  on main.tf line 66, in resource "azurerm_network_security_rule" "fico-app-sr-80":
  66:   source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]
    |----------------
    | module.fico_web_vm is object with 1 attribute "web-1"

This object does not have an attribute named "linux_vm_ips".

outputs.tf 文件:

output "linux_vm_names" 
  value = [azurerm_linux_virtual_machine.virtual_machine.*.name]


output "linux_vm_ips" 
  value = [azurerm_network_interface.network_interface.*.private_ip_address]


output "linux_vm_nsg" 
  value = azurerm_network_security_group.network_security_group.name

错误引用的安全规则,位于main.tf中:

resource "azurerm_network_security_rule" "fico-app-sr-80" 
  name                        = "nsr-$var.environment-$var.directorate-$var.business_unit-$var.vm_identifier$var.instance_number-http80"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "80"
  source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]
  destination_address_prefix  = "VirtualNetwork"
  resource_group_name         = azurerm_resource_group.rg_dwp_fico_app.name
  network_security_group_name = "module.fico_app_vm.linux_vm_nsg"

根模块中的网卡:

resource "azurerm_network_interface" "network_interface" 
  name                          = "nic-$var.environment-$var.directorate-$var.business_unit-$var.vm_identifier-$var.vm_name"
  resource_group_name           = var.resource_group
  location                      = var.location
  enable_ip_forwarding          = "false"
  enable_accelerated_networking = "false"

  ip_configuration 
    name                          = "ipconfig1"
    subnet_id                     = data.azurerm_subnet.dwp_subnet.id
    private_ip_address_allocation = "Dynamic"
    primary                       = "true"
  

main.tf 中构建 web_vm 的模块:

module "fico_web_vm" 
  for_each                     = var.web_servers
  source                       = "../modules/compute/linux_vm"
  source_image_id              = var.web_image_id
  location                     = var.location
  vm_name                      = each.key
  vm_identifier                = "$var.vm_identifier$var.instance_number"
  vm                           = each.value
  disks                        = each.value["disks"]
  resource_group               = azurerm_resource_group.rg_dwp_fico_web.name
  directorate                  = var.directorate
  business_unit                = var.business_unit
  environment                  = var.environment
  network_rg_identifier        = var.network_rg_identifier
  subnet_name                  = "sub-dwp-$var.environment-$var.directorate-$var.business_unit-fe01"
  diag_storage_account_name    = var.diag_storage_account_name
  ansible_storage_account_name = var.ansible_storage_account_name
  ansible_storage_account_key  = var.ansible_storage_account_key
  log_analytics_workspace_name = var.log_analytics_workspace_name
  backup_policy_name           = var.backup_policy_name

main.tf 中应用的变量:

# Web VM Variables
variable "web_servers" 
  description = "Variable for defining each instance"
  type = map(object(
      size           = string
      admin_username = string
      public_key      = string
      disks          = list(number)
      zone_vm        = string
      zone_disk      = list(string)
  ))

variables.tf 转换到的 tfvars 文件以及 for_each 循环的文件:

web_servers =
  web-1 = 
    size           = "Standard_B2s"
    admin_username = xxxx
    public_key     = xxxx
    disks          = [32, 32]
    zone_vm        = "1"
    zone_disk      = ["1"]
  

【问题讨论】:

关于这个问题的任何更新?它能解决你的问题吗? 【参考方案1】:

如我所见,您的代码中有两个错误。

第一:

network_security_group_name = "module.fico_app_vm.linux_vm_nsg"

需要改成:

network_security_group_name = module.fico_app_vm.linux_vm_nsg

双引号通常用于设置字符串,当你只使用它们时,不使用其他资源。

第二:

source_address_prefixes     = module.fico_web_vm.linux_vm_ips[0]

需要改成:

source_address_prefixes     = module.fico_web_vm.linux_vm_ips

输出也应该变成:

output "linux_vm_ips" 
  value = azurerm_network_interface.network_interface.*.private_ip_address

我看到您只创建了一个没有countfor_each 的网卡,但是当您使用azurerm_network_interface.network_interface.*.private_ip_address 设置值时,它也会返回一个列表。而source_address_prefixes 选项需要一个列表,因此您只需提供输出即可。

也许最好像这样更改输出:

output "linux_vm_ip" 
  value = azurerm_network_interface.network_interface.private_ip_address

然后你可以像这样设置source_address_prefixes

source_address_prefixes     = [ module.fico_web_vm.linux_vm_ip ]

【讨论】:

这行得通,但我必须像以前一样将安全规则中引用的 NSG 输出更改为字符串,因为它会引发类型错误

以上是关于使用具有 for_each 集的模块的输出值的主要内容,如果未能解决你的问题,请参考以下文章

将 aws 资源导入具有 for_each 的 terraform 模块

使用 for_each 创建不同数量的具有唯一 NIC 的 VM

Terraform For_Each:如何引用创建的资源 ID

Terraform for_each - each.key 在哪里定义?

如何导入具有由 for_each 创建的特殊字符的资源

Terraform : for_each 一个一个