合并terraform中的对象列表

合并terraform中的对象列表,terraform,Terraform,是否有方法合并以下对象列表 variable "common_variables" { type = list(object({ var_name = string, var_value = string, workspace_name = string })) default = [ { "var_name" = "location" "var_value"

是否有方法合并以下对象列表

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
}
任何
自定义_变量
都应替换在
工作区_名称
变量名称
上匹配的
通用_变量

所以我想要的输出是:

merged_variables = [
  {
    "var_name" = "location"
    "var_value" = "West Europe"
    "workspace_name" = "env-1"
  }
]

进行合并和替换的最简单方法是使用映射,而不是列表,因此我想首先将这两个列表投影到映射中,其中键通过要用于确定覆盖内容的值唯一标识它们,使用:

然后,我们可以使用带有的映射来获得所需的覆盖行为,然后在必要时使用转换回列表:

locals {
  merged_variables_map = merge(
    local.common_variables_map,
    local.custom_variables_map,
  )
  merged_variables = toset(values(merged_variables_map))
}
需要注意的是,转换为这样的映射将丢失给定列表的原始顺序,因为映射没有顺序。因此,合并后的项目可能与
var.common\u variables
var.custom\u variables
中的项目顺序不同,因此我通过使用转换local.merged\u变量的结果来明确这一点。如果你认为这是好的,因为输入无论如何都被认为是有序的,那么你可以通过使用集合类型而不是变量的列表类型,使你的模块的调用方更加明确:

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

合并列表 这里有一个保持秩序的解决方案(基本技巧大胆地从马丁的答案中窃取)

重组变量 作为一种选择,您可能需要考虑重构变量,并通过输入文件提供变量。如果你像这样为地形提供参数

terraform apply -var-file="common.tfvars" -var-file="custom.tfvars"
然后,两个文件中声明的变量将取自最后列出的文件。 为了使其发挥作用,您当然需要将单个列表分解为各个参数。此外,您可能希望在不同的情况下使用不同的文件,例如,根据工作区的不同使用不同的文件(可以选择使用批处理或shell脚本或make文件包装对terraform的调用,以使其更方便)

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 }
  common_keys          = [ for v in var.common_variables : "${v.workspace_name}/${v.var_name}" ]
  custom_keys          = [ for v in var.common_variables : "${v.workspace_name}/${v.var_name}" ]
  all_keys             = distinct(concat(common_keys, custom_keys))
  
  merged = [
    for k in local.all_keys:
      contains(common_variables_map, k) ? common_variables_map[k] : custom_variables_map[k]
  ]
}
terraform apply -var-file="common.tfvars" -var-file="custom.tfvars"