首页 > 解决方案 > 对象和类型的组合 any - Terraform

问题描述

我正在寻找一种解决方案,允许我在我的 locals.tf 中结合topic_subscriptiondefault_subscription我们的代码中,我们创建了一个类型any如下的变量;

variable "topic_subscription" {
  type        = any
  default     = {}
}

这将允许向我们的 SNS 主题添加多种订阅类型。

topic_subscription = {
  departmenta = {
    endpoint = "a@b.com",
    protocol = "email"
  },
  departmentc = {
    endpoint = "c@d.com",
    protocol = "email" 
  }
}

并在设置中使用它for.each

resource "aws_sns_topic_subscription" "this" {
  for_each = var.topic_subscription

  endpoint  = each.value["endpoint"]  
  protocol  = each.value["protocol"]  
  topic_arn = aws_sns_topic.this.arn
}

在 locals.tf 中是否有将 topic_subscription 与 default_subscription 映射/对象相结合的解决方案?

locals {
  default_subscription = {
    endpoint = "x@y.com",
    protocol = "email"
  }

  combined_subscription = ???? var.topic_subscription + local.default_subscription ????
}

非常感谢任何帮助,谢谢

== 更新组合的定义 ==

如果它是按照以下方式创建的(硬编码),它可以工作,所以“组合”变量和本地看起来如下。

combined_subscription = {
  departmenta = {
    endpoint = "a@b.com",
    protocol = "email"
  },
  departmentc = {
    endpoint = "c@d.com",
    protocol = "email"
  }
  default_subscription = {
    endpoint = "x@y.com",
    protocol = "email"
  }
}

标签: amazon-web-servicesterraform

解决方案


首先,我认为需要注意的重要一点是anyTerraform 中并没有真正的“类型值”。相反,变量 withtype = any表示类型是unconstrained,也就是说 Terraform 将根据调用者传入的内容动态决定类型是什么。

话虽如此,您的示例值是一个对象类型。如果我们将它写成显式类型约束,不使用any通配符,它​​看起来像这样:

  type = object({
    departmenta = object({
      endpoint = string
      protocol = string
    })
    departmentc = object({
      endpoint = string
      protocol = string
    })
  })

实际上,any在评估变量值时,Terraform 会动态地将您替换为上述值,因此在您的模块中,您可以将此值用于任何对这种类型的值有意义的操作。

merge函数,当给定对象类型的值时,会产生一个对象类型的新值,该值通过它们唯一的属性名称将两个对象类型合并在一起。在您的情况下,您似乎想要构造一个新值,其对象类型包含一个附加default_subscription属性,其值匹配local.default_subscription

这是实现这一目标的一种方法,使用merge

variable "topic_subscription" {
  type    = any
  default = {}
}

locals {
  default_subscription = {
    endpoint = "x@y.com",
    protocol = "email"
  }

  combined_subscription = merge(
    { default_subscription = local.default_subscription },
    var.topic_subscription,
  )
}

使用merge我上面写的参数排序,调用者可以提供自己的default_subscription属性,该属性将覆盖模块内给定的属性。如果您不希望这是真的,那么您可以反转两个参数(使模块定义default_subscription优先),或者您可以编写一个验证规则来禁止调用者default_subscription完全设置:

variable "topic_subscription" {
  type    = any
  default = {}

  validation {
    condition     = !can(var.topic_subscription.default_subscription)
    error_message = "The topic subscription key \"default_subscription\" is reserved for this module's own use."
  }
}

推荐阅读