Terraform 我应该尝试合并或展平复杂变量吗?

问题描述 投票:0回答:1

我尝试使用 Terraform 来部署具有可变存储容器的多个存储帐户。但我只想调用结节一次,因此存储帐户变量是对象的映射。存储容器是存储帐户映射内对象的嵌套映射。

看起来像这样:

variables.tf

variable "location" {
  type        = string
  description = "Location for storage account resource."
}

variable "resource_group_name" {
  type        = string
  description = "Resource group that will contain the resource."
}

variable "storage_account" {
  type = map(object({
    name                          = string
    access_tier                   = string
    account_kind                  = string
    account_replication_type      = string
    account_tier                  = string
    public_network_access_enabled = bool

    containers = optional(map(object({
      name = string
      container_access_type = optional(string, "private")
    })))

    network_rules = list(object({
      default_action             = string
      bypass                     = optional(set(string))
      ip_rules                   = optional(set(string))
      virtual_network_subnet_ids = optional(set(string))
    }))

  }))
}

资源模块代码如下所示:

main.tf

resource "azurerm_storage_account" "storage" {
  for_each = var.storage_account

  name                          = each.value.name
  resource_group_name           = var.resource_group_name
  location                      = var.location
  account_tier                  = each.value.account_tier
  account_replication_type      = each.value.account_replication_type
  account_kind                  = each.value.account_kind
  access_tier                   = each.value.access_tier
  public_network_access_enabled = each.value.public_network_access_enabled != null ? each.value.public_network_access_enabled : false

}

locals {
  containers_list = flatten([
    for key, value in var.storage_account : [
      for container in value.containers : {
        name                 = container
        storage_account_name = azurerm_storage_account.storage[key].name
      }
    ]
  ]...)
}

resource "azurerm_storage_container" "storage" {
  #for_each = { for container in local.containers_list : container.name.name => container }
  for_each = tomap({
    for container in local.containers_list : container.name.name => container
  })

  name                 = each.value.container.name
  storage_account_name = each.value.storage_account_name
}

我用这个来调用模块:

main.tf

module "storage_account" {
  source = "./modules/azurerm_storage_account"

  resource_group_name = "rg-temp"
  location            = "uksouth"
  tags                = {}

  storage_account = {
    "storage01" = {
      name                          = "storagerandom0001"
      account_kind                  = "StorageV2"
      account_tier                  = "Standard"
      account_replication_type      = "LRS"
      access_tier                   = "Hot"
      public_network_access_enabled = true
      network_rules                 = []
      containers = {
        "container-aa" = {
          name = "random01"
          container_access_type = "private"
        },
        "container-ab" = {
          name = "random02"
          container_access_type = "private"
        }
      }
    },
    "storage02" = {
      name                          = "storagerandom0002"
      account_kind                  = "StorageV2"
      account_tier                  = "Standard"
      account_replication_type      = "LRS"
      access_tier                   = "Hot"
      public_network_access_enabled = true
      network_rules                 = []
      containers = {
        "container-01" = {
          name = "container01"
          container_access_type = "private"
        },
        "container-02" = {
          name = "container02"
          container_access_type = "private"
        }
      }
    }
  }
}

当我运行此命令时,我收到错误:

│ Error: Too many function arguments
│
│   on modules/azurerm_storage_account/main.tf line 17, in locals:
│   17:   containers_list = flatten([
│   18:     for key, value in var.storage_account : [
│   19:       for container in value.containers : {
│   20:         name                 = container
│   21:         storage_account_name = azurerm_storage_account.storage[key].name
│   22:       }
│   23:     ]
│   24:   ]...)
│     ├────────────────
│     │ while calling flatten(list)
│     │ azurerm_storage_account.storage is object with 2 attributes
│     │ var.storage_account is map of object with 2 elements
│
│ Function "flatten" expects only 1 argument(s).

从这个问题(看起来与我想做的非常相似):

如何在 Terraform 中的 for_each 循环内访问地图中的序列

我想知道我是否需要合并而不是展平?

但是如果我更改为

merge
我会收到此错误:

╷
│ Error: Error in function call
│
│   on modules/azurerm_storage_account/main.tf line 17, in locals:
│   17:   containers_list = merge([
│   18:     for key, value in var.storage_account : [
│   19:       for container in value.containers : {
│   20:         name                 = container
│   21:         storage_account_name = azurerm_storage_account.storage[key].name
│   22:       }
│   23:     ]
│   24:   ]...)
│     ├────────────────
│     │ while calling merge(maps...)
│     │ azurerm_storage_account.storage is object with 2 attributes
│     │ var.storage_account is map of object with 2 elements
│
│ Call to function "merge" failed: arguments must be maps or objects, got "tuple".
╵

这是我第一次必须嵌套循环(或使用合并或展平),所以我做得不太好。

可以帮忙并尝试用简单的语言解释我需要做什么/做错了什么吗?

谢谢。

azure loops terraform terraform-provider-azure
1个回答
0
投票

展平函数需要一个参数,因为错误提示为

while calling flatten(list) [...] Function "flatten" expects only 1 argument(s)
。出现错误的原因是您添加到生成的列表列表中的
...
运算符。只要把它去掉就可以了。

然后您应该将本地值更改为:

  containers_list = flatten([
    for key, value in var.storage_account : [
      for _, container in value.containers : {
        name                 = container
        storage_account_name = azurerm_storage_account.storage[key].name
      }
    ]
  ])

此外,由于容器是可选的,并且可能为空,因此我默认为其提供一个空地图:

variable "storage_account" {
  type = map(object({
    name                          = string
    access_tier                   = string
    account_kind                  = string
    account_replication_type      = string
    account_tier                  = string
    public_network_access_enabled = bool

    containers = optional(map(object({
      name = string
      container_access_type = optional(string, "private")
    })), {})

    network_rules = list(object({
      default_action             = string
      bypass                     = optional(set(string))
      ip_rules                   = optional(set(string))
      virtual_network_subnet_ids = optional(set(string))
    }))

  }))
}
© www.soinside.com 2019 - 2024. All rights reserved.