合并 terraform 中的对象列表

Dar*_*Var 6 terraform

有没有办法合并以下对象列表

variable "common_variables" {
  type = list(object({ var_name = string, var_value = string, workspace_name = string }))
  default = [
    {
      "var_name"       = "location"
      "var_value"      = "West US"
      "workspace_name" = "env-1"
    }
  ]
}

variable "custom_variables" {
  type = list(object({ var_name = string, var_value = string, workspace_name = string }))
  default = [
    {
      "var_name"       = "location"
      "var_value"      = "West Europe"
      "workspace_name" = "env-1"
    }
  ]
}


locals {

  # custom_variables should replace common_variables
  merged_variables = concat(var.common_variables, var.custom_variables)

}

output "merged_variables" {
  value = local.merged_variables
}
Run Code Online (Sandbox Code Playgroud)

Anycustom_variables应该替换&common_variables上的匹配。workspace_namevar_name

所以我想要的输出是:

merged_variables = [
  {
    "var_name" = "location"
    "var_value" = "West Europe"
    "workspace_name" = "env-1"
  }
]
Run Code Online (Sandbox Code Playgroud)

Die*_*lez 11

使用setunion https://www.terraform.io/docs/language/functions/setunion.html

用法:

locals {
    all_users = setunion(var.restricted_users, var.admin_users)
}
Run Code Online (Sandbox Code Playgroud)

本例使用的变量类型

variable "restricted_users" {
  type = set(object({
    email = string
    name  = string
    roles = set(string)
  }))

  default = []
}

variable "admin_users" {
  type = set(object({
    email = string
    name  = string
    roles = set(string)
  }))

  default = []
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*ins 3

进行合并和替换的最简单方法是使用地图而不是列表,所以我想我首先将两个列表投影到地图中,其中键通过您想要使用的值唯一地标识它们使用for表达式决定要覆盖的内容:

locals {
  common_variables_map = { for v in var.common_variables : "${v.workspace_name}/${v.var_name}" => v }
  custom_variables_map = { for v in var.custom_variables : "${v.workspace_name}/${v.var_name}" => v }
}
Run Code Online (Sandbox Code Playgroud)

然后,我们可以使用映射来merge获取您想要的覆盖行为,然后values在必要时转换回列表:

locals {
  merged_variables_map = merge(
    local.common_variables_map,
    local.custom_variables_map,
  )
  merged_variables = toset(values(merged_variables_map))
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是,转换为这样的地图将丢失给定列表的原始顺序,因为地图没有排序。var.common_variables因此,合并后的项目的顺序可能与或中的项目的顺序不同var.custom_variables,因此我通过使用 转换 local.merged_variables 的结果来明确这一点toset。如果您认为没关系,因为无论如何输入都被认为是有序的,那么您也可以通过使用变量的集合类型而不是列表类型来使模块的调用者更加明确:

variable "common_variables" {
  type = set(object({ var_name = string, var_value = string, workspace_name = string }))
  default = [
    {
      "var_name"       = "location"
      "var_value"      = "West US"
      "workspace_name" = "env-1"
    }
  ]
}

variable "custom_variables" {
  type = set(object({ var_name = string, var_value = string, workspace_name = string }))
  default = [
    {
      "var_name"       = "location"
      "var_value"      = "West Europe"
      "workspace_name" = "env-1"
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

集合也没有排序,因此将变量标记为具有集合类型可以让调用者知道对象的顺序并不重要。Terraform 可以自动从列表转换为集合(通过丢弃排序),因此这不会改变使用该模块的语法。