Terraform 变量循环生成属性

Terraform Variable looping to generate properties

我不得不承认,这是我第一次不得不问一些我自己都不知道如何提出或解释的问题,所以这是我的代码。 值得解释的是,由于特定原因我不能更改输出资源,发送到资源的元数据必须保持原样,否则会导致重新创建,我不希望那样。

目前我有一个 terraform 代码使用 static/fixed 像这样的变量

user1_name="Ed"
user1_Age ="10"
user2_name="Mat"
user2_Age ="20"

然后这些硬类型变量在多个地方使用,但最重要的是它们作为元数据传递给实例,就像这样

resource "google_compute_instance_template" "mytemplate" {
  ...
  metadata = {
    othervalues     = var.other     
    user1_name      = var.user1_name
    user1_Age       = var.user1_Age
    user2_name      = var.user2_name
    user2_Age       = var.user2_Age
  }
  ...
}

我不是 terraform 方面的专家,所以我问,但我知道事实上这是 100% 丑陋和错误的,我需要使用列表或数组或其他任何东西,所以我将我的声明更改为:

users = [
  { "name" : "yo", "age" : "10",  "last" : "other" },
  { "name" : "El", "age" : "20",  "last" : "other" }
]

但是,我该如何为该资源生成相同的结果?生成的资源必须仍然具有与所示相同的元数据。 当然假设用户的顺序将用作值的“索引”,第一个得到 user1_name 等等......

我假设我需要在其中使用 for_each 循环,但无法弄清楚如何绕过资源属性中的循环

不确定我是否清楚这一点,可能没有,但没有找到更好的解释方式。

metadata 不是块,而是 map 类型的常规属性。所以你可以这样做:


# it would be better to use map, not list for users:
variable "users"
  default {
   user1 =  { "name" : "yo", "age" : "10",  "last" : "other" },
   user2 =  { "name" : "El", "age" : "20",  "last" : "other" }
   }
}

resource "google_compute_instance_template" "mytemplate" {
  
  for_each = var.users

  metadata = each.value
  #...
}

从你的例子来看,你的意图似乎是让这些最终都显示为一个单一的地图,其中的键由两部分组成。

你的例子没有说明 user1Ed 之间的关系,但是:你的第一个例子显示“user1's”的名字是 Ed,但是在你的数据例子中您要创建的结构只有一个“名称”,我不清楚该名称是否会替换第一个示例中的“user1”或“Ed”。

相反,我将采用一个略有不同的变量结构,该结构仍然保持像“user1”这样的键 name 属性,如下所示:

variable "users" {
  type = map(object({
    name = string
    age  = number
  })
}

locals {
  # First we'll transform the map of objects into a
  # flat set of key/attribute/value objects, because
  # that's easier to work with when we generate the
  # flattened map below.
  users_flat = flatten([
    for key, user in var.users : [
      for attr, value in user : {
        key   = key
        attr  = attr
        value = value
      }
    ]
  ])
}

resource "google_compute_instance_template" "mytemplate" {
  metadata = merge(
    {
      othervalues = var.other
    },
    {
      for vo in local.users_flat : "${vo.key}_${vo.attr}" => vo.value
    }
  )
}

local.users_flat 这里是一个中间数据结构,它将输入中的键和对象属性的 two-level 层次结构展平。它的形状应该是这样的:

[
  { key = "user1", attr = "name", value = "Ed" },
  { key = "user1", attr = "age", value = 10 },
  { key = "user2", attr = "name", value = "Mat" },
  { key = "user2", attr = "age", value = 20 },
]

metadata 参数中的 merge 调用然后将“其他值”的 directly-configured 映射与从 local.users_flat 派生的生成映射合并,形状如下:

{
  "user1_name" = "Ed"
  "user1_age"  = 10
  "user2_name" = "Mat"
  "user2_age"  = 20
}

从模块调用者的角度来看,users变量应该定义如下值才能得到上面的结果:

  users = {
    user1 = {
      name = "Ed"
      age  = 10
    }
    user2 = {
      name = "Mat"
      age  = 20
    }
  }