寻找合并资源标签的方法

Finding Ways to Merge Resource Tags

您好 Terraform 专家,

我继承了一些用于将资源部署到 Azure 的旧 Terraform 代码。我在大多数模块中看到的主要组件之一是将资源组标签与单独资源上的附加标签合并。资源组标签作为标签映射输出。例如:

output "resource_group_tags_map" {
  value       = { for r in azurerm_resource_group.this : r.name => r.tags }
  description = "map of rg tags."
}

然后像 vnets 这样的资源将 RG 标签与 vnet 的附加特定标签合并,给定变量中的 RG 名称。

# merge Resource Group tags with Tags for VNET
# this is going to break if we change RGs
locals {
  tags     = merge(var.net_additional_tags, data.azurerm_resource_group.this.tags)

如果我们可以在单个变量中设置资源组,这就很好用了。它假定正在部署的资源将进入一个 RG。但是,情况已不再如此,我们需要以某种方式构建一种方式,以便在部署资源时选择任何 RG。下面的代码显示了原始概念的工作原理。

locals {
  tags                       = merge(var.net_additional_tags, data.azurerm_resource_group.this.tags)
  
# - Virtual Network
# -
resource "azurerm_virtual_network" "this" {
  for_each            = var.virtual_networks
  name                = each.value["name"]
  location            = data.azurerm_resource_group.this.location
  resource_group_name = var.resource_group_name
  address_space       = each.value["address_space"]
  dns_servers         = lookup(each.value, "dns_servers", null)


  tags = local.tags
}

因此寻求帮助以解决此问题。假设我们创建了 100 个 vnet,每个 vnet 都进入不同的 RG,我们无法创建 100 个不同的资源组变量来捕获它,因为它会变得太麻烦。

这是我使用 Key Vault 的示例

resource "azurerm_key_vault" "this" {
  for_each                        = var.key_vaults
  name                            = each.value["name"]
  location                        = each.value["location"]
  resource_group_name             = each.value["resource_group_name"]
  sku_name                        = each.value["sku_name"]
  access_policy                   = var.access_policies
  enabled_for_deployment          = each.value["enabled_for_deployment"]
  enabled_for_disk_encryption     = each.value["enabled_for_disk_encryption"]
  enabled_for_template_deployment = each.value["enabled_for_template_deployment"]
  enable_rbac_authorization       = each.value["enable_rbac_authorization"]
  purge_protection_enabled        = each.value["purge_protection_enabled"]
  soft_delete_retention_days      = each.value["soft_delete_retention_days"]
  tags                            = merge(each.value["tags"], )

在 tags 参数中,我们需要以某种方式将为此 Key Vault 实例输入的标签与用户选择放置 Key Vault 的资源组标签合并。我想到了这样的事情,但显然语法错误。

merge(each.value["tags"], data.azurerm_resource_group[each.key][each.value["resource_group_name"].tags)

感谢您的意见。

更新:

│ Error: Invalid index
│
│   on Modules\keyvault\main.tf line 54, in resource "azurerm_key_vault" "this":
│   54:   tags                            = merge(each.value["tags"], data.azurerm_resource_group.this["${each.value.resource_group_name}"].tags)
│     ├────────────────
│     │ data.azurerm_resource_group.this is object with 1 attribute "keyvault1"
│     │ each.value.resource_group_name is "Terraform1"
│
│ The given key does not identify an element in this collection value.

使用地图和当地人发布的解决方案代码。

解决方案

Variables.tf

variable "key_vaults" {
  description = "Key Vaults and their properties."
  type = map(object({
    name                            = string
    location                        = string
    resource_group_name             = string
    sku_name                        = string
    tenant_id                       = string
    enabled_for_deployment          = bool
    enabled_for_disk_encryption     = bool
    enabled_for_template_deployment = bool
    enable_rbac_authorization       = bool
    purge_protection_enabled        = bool
    soft_delete_retention_days      = number
    tags                            = map(string)
  }))
  default = {}
}
# soft_delete_retention_days numeric value can be between 7 and 90. 90 is default

Main.tf 对于 KeyVault 模块

data "azurerm_resource_group" "this" {
  # read from local variable, index is resource_group_name
  for_each = local.rgs_map
  name     = each.value.name
}

# use data azurerm_client_config to get tenant_id, not from config 
data "azurerm_client_config" "current" {}

# -
# - Setup key vault 
# - transform variables to locals to make sure the correct index will be used: resource group name and key vault name
locals {
  rgs_map = {
    for n in var.key_vaults :
    n.resource_group_name => {
      name = n.resource_group_name
    }
  }
  kvs_map = {
    for n in var.key_vaults :
    n.name => {
      name                            = n.name
      location                        = n.location
      resource_group_name             = n.resource_group_name
      sku_name                        = n.sku_name
      tenant_id                       = data.azurerm_client_config.current.tenant_id # n.tenant_id
      enabled_for_deployment          = n.enabled_for_deployment
      enabled_for_disk_encryption     = n.enabled_for_disk_encryption
      enabled_for_template_deployment = n.enabled_for_template_deployment
      enable_rbac_authorization       = n.enable_rbac_authorization
      purge_protection_enabled        = n.purge_protection_enabled
      soft_delete_retention_days      = n.soft_delete_retention_days
      tags                            = merge(n.tags, data.azurerm_resource_group.this["${n.resource_group_name}"].tags)
    }
  }
}

resource "azurerm_key_vault" "this" {
  for_each                        = local.kvs_map # use local variable, other wise keyvault1 will be used in stead of kv-eastus2-01 as index
  name                            = each.value["name"]
  location                        = each.value["location"]
  resource_group_name             = each.value["resource_group_name"]
  sku_name                        = each.value["sku_name"]
  tenant_id                       = each.value["tenant_id"]
  enabled_for_deployment          = each.value["enabled_for_deployment"]
  enabled_for_disk_encryption     = each.value["enabled_for_disk_encryption"]
  enabled_for_template_deployment = each.value["enabled_for_template_deployment"]
  enable_rbac_authorization       = each.value["enable_rbac_authorization"]
  purge_protection_enabled        = each.value["purge_protection_enabled"]
  soft_delete_retention_days      = each.value["soft_delete_retention_days"]
  tags                            = each.value["tags"]
}