azure - 数据源的列表和字符串转换问题

标签 azure terraform terraform-provider-azure

我在这个问题上陷入了一个循环。需要向 azure_windows_virtual_machine 提供网络接口(interface) ID 列表。网络接口(interface)是使用单独的资源 block 创建的。在 Windows 虚拟机的变量定义中,我为所述网络接口(interface)的名称提供了一个参数,以便我们可以正确地将我们想要的网卡与每个虚拟机关联起来。如果我们有 100 个网卡和 90 个虚拟机,则某些虚拟机可能会获得两个网卡,因此我们希望确保提供网卡名称和虚拟机名称之间的某些链接。

因此,网络接口(interface)名称是一个列表(字符串)。

我一直在尝试使用值函数来获取 NIC ID 列表(给定名称),但遇到了失败:“每个对象只能在“模块”或“资源” block 中使用,并且仅当设置了“for_each”参数时。”

如果我在资源 block 中使用数据源(这看起来最合乎逻辑),它也会失败,因为我为 network_interface_names 参数指定了一个列表(字符串),但数据源无法接受它。它当然需要一个字符串。但它永远不会是单个字符串,它始终是一个列表(因为每个虚拟机可以有多个 NIC)。

我认为正确的答案可能是预先创建 ID 列表 - 技巧是对于每个定义的虚拟机来说,它几乎需要是动态的 - 因为每个虚拟机都有不同的网络接口(interface)名称列表。因此,我们需要为每个虚拟机动态生成新列表。

变量

variable "resource_groups" {
  description = "Resource groups"
  type = map(object({
    location = string
  }))
}

variable "virtual_networks" {
  description = "virtual networks and properties"
  type = map(object({
    resource_group_name = string
    address_space       = list(string)
  }))
}

variable "subnets" {
  description = "subnet and their properties"
  type = map(object({
    resource_group_name  = string
    virtual_network_name = string
    address_prefixes     = list(string)
  }))
}

variable "nic" {
  description = "network interfaces"
  type = map(object({
    subnet_name         = string
    resource_group_name = string
  }))
}

variable "admin_password" {
  type      = string
  sensitive = true
}

variable "admin_user" {
  type      = string
  sensitive = true
}

variable "windows_vm" {
  description = "Windows virtual machine"
  type = map(object({
    network_interface_names = list(string)
    resource_group_name     = string
    size                    = string
    timezone                = string
  }))
}

输入

resource_groups = {
  rg-eastus-dev1 = {
    location = "eastus"
  }
}

virtual_networks = {
  vnet-dev1 = {
    resource_group_name = "rg-eastus-dev1"
    address_space       = ["10.0.0.0/16"]
  }
}

subnets = {
  snet-01 = {
    resource_group_name  = "rg-eastus-dev1"
    virtual_network_name = "vnet-dev1"
    address_prefixes     = ["10.0.1.0/24"]
  }
}

nic = {
  nic1 = {
    subnet_name         = "snet-01"
    resource_group_name = "rg-eastus-dev1"
  }
}

admin_password = "s}8cpH96qa.1BQ"
admin_user     = "padmin"

windows_vm = {
  winvm1 = {
    network_interface_names = ["nic1"]
    resource_group_name     = "rg-eastus-dev1"
    size                    = "Standard_B2s"
    timezone                = "Eastern Standard Time"
  }
}

主要

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

data "azurerm_resource_group" "rgs" {
  for_each = var.resource_groups
  name     = each.key
  depends_on = [
    azurerm_resource_group.rgs
  ]
}

resource "azurerm_virtual_network" "vnet" {
  for_each            = var.virtual_networks
  name                = each.key
  resource_group_name = each.value["resource_group_name"]
  address_space       = each.value["address_space"]
  location            = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
}

resource "azurerm_subnet" "subnet" {
  for_each             = var.subnets
  name                 = each.key
  resource_group_name  = each.value["resource_group_name"]
  virtual_network_name = each.value["virtual_network_name"]
  address_prefixes     = each.value["address_prefixes"]
  depends_on = [
    azurerm_virtual_network.vnet
  ]
}

data "azurerm_subnet" "subnet" {
  for_each             = var.subnets
  name                 = each.key
  virtual_network_name = each.value["virtual_network_name"]
  resource_group_name  = each.value["resource_group_name"]
  depends_on = [
    azurerm_resource_group.rgs
  ]
}

resource "azurerm_network_interface" "nics" {
  for_each = var.nic
  ip_configuration {
    name                          = each.key
    subnet_id                     = data.azurerm_subnet.subnet[each.value["subnet_name"]].id
    private_ip_address_allocation = "Dynamic"
  }
  location            = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
  name                = each.key
  resource_group_name = each.value["resource_group_name"]
  depends_on = [
    azurerm_resource_group.rgs,
    azurerm_subnet.subnet
  ]
}

data "azurerm_network_interface" "nics" {
  for_each            = var.nic
  name                = each.key
  resource_group_name = each.value["resource_group_name"]
  depends_on = [
    azurerm_resource_group.rgs
  ]
}

resource "azurerm_windows_virtual_machine" "windows_vm" {
  for_each              = var.windows_vm
  admin_password        = var.admin_password
  admin_username        = var.admin_user
  location              = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
  name                  = each.key
  network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
  resource_group_name = each.value["resource_group_name"]
  size                = each.value["size"]
  timezone            = each.value["timezone"]
  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2019-Datacenter"
    version   = "latest"
  }
}

当前计划错误

╷
│ Error: Invalid index
│ 
│   on main.tf line 75, in resource "azurerm_windows_virtual_machine" "windows_vm":
│   75:   network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
│     ├────────────────
│     │ data.azurerm_network_interface.nics is object with 1 attribute "nic1"
│     │ each.value["network_interface_names"] is list of string with 1 element
│ 
│ The given key does not identify an element in this collection value: string required.

可能的解决方案 - 但不起作用 提供 NIC ID 的映射(不包含 VM 名称)。然后,在 windows_vm 资源中,获取该映射并尝试获取 NIC ID 值的列表。

locals {
  nic_ids {
    [for k, v in var.windows_vm : k => v {data.azurerm_network_interface.nics[v.network_interface_names]}.id]
  }
}


resource "azurerm_windows_virtual_machine" "windows_vm" {
  for_each       = var.windows_vm
  admin_password = var.admin_password
  admin_username = var.admin_user
  location       = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
  name           = each.key
  network_interface_ids = values(local.nic_ids[each.key])
  os_disk {
    caching              = "ReadWrite"
    storage_account_type = "Standard_LRS"
  }
  resource_group_name = each.value["resource_group_name"]
  size                = each.value["size"]
  timezone            = each.value["timezone"]
  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2019-Datacenter"
    version   = "latest"
  }
}

最佳答案

首先,您不需要在创建每个资源后调用data资源本身将包含您需要的所有信息。因此,您应该消除代码中的所有数据源并直接使用资源

但回到您提供的错误。动态生成列表的一种方法是:

  network_interface_ids = [for ni_name in each.value["network_interface_names"]: azurerm_network_interface.nics[ni_name].id]

关于azure - 数据源的列表和字符串转换问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75122034/

相关文章:

azure - Terraform 源错误 - 错误 : Failed to query available provider packages

c# - 将文件从 Azure 存储 blob 移动到 Ftp 服务器

Azure 函数在几个小时后停止工作

amazon-web-services - 如何使用与 terraform 中的最新/非限定 lambda 函数相同的事件源映射设置 lambda 别名

azure - 使用本地值定义 Azure Databricks 用户 block

azure - terraform 显示返回 4 个 json 对象

azure - 如何检测 Azure DevOps 代理上安装了哪个版本的 Az PowerShell 模块集合?

Azure API 管理 POST 请求 - 需要所有正文参数

azure - 用于检查条件的 Terraform 脚本

azure - Terraform CLI 出现错误 : ID was missing the `slots` element