在地形中创建动态块

Create dynamic block in terraform

我想在 terraform 中创建 google_compute_health_check,我正在考虑如何使它们成为最通用的。我的代码 atm 看起来像那样

application.hcl

inputs = {
  health_checks = {
    tcp-health-check = {
      name                = "tcp-health-check"
      desc                = "Health check via tcp"
      port                = 80
      timeout_sec         = 4
      check_interval_sec  = 30
    }
  }

主要terragrunt.hcl

include {
  path = find_in_parent_folders()
}

terraform { source ...}

locals {
  app_vars    = read_terragrunt_config(find_in_parent_folders("application.hcl"))
}

inputs = {
  # and my idea was that every invocation of the module, picks it's own set
  # of health checks that it wants to use
  health_checks = [local.app_vars.inputs.health_checks.tcp-health-check]
}

现在模块 main.tf 看起来像这样

locals {
  checks = { for check in var.health_checks: check.name => check }
}

resource "google_compute_health_check" "main" {
  for_each           = local.checks
  name               = each.value.name

  timeout_sec        = each.value.timeout_sec
  check_interval_sec = each.value.check_interval_sec

  dynamic tcp_health_check {
    #for_each             = each.value.name == "tcp_health_check" ? each.value : []
    #for_each             = lookup(each.value, "tcp_health_check", [])
    for_each             = contains(keys(each.value), "tcp_health_check") != null ? each.value : {}
      content {
        port               = 80
        #        port               = each.value.port
        #        port_name          = each.value.name
      }
  }

我被困在动态块中 - 如何让它工作,以便它只在我通过 tcp health_check 时应用,当我通过时,ssh 它创建动态 ssh 块(我知道代码 atm 中没有 ssh 块,但将来我将通过我需要的任何健康检查来扩展模块)


我得到的错误如下contains

Error: List longer than MaxItems

  on main.tf line 30, in resource "google_compute_health_check" "main":
  30: resource "google_compute_health_check" "main" {

Attribute supports 1 item maximum, config has 7 declared

ERRO[0011] 1 error occurred:
    * exit status 1

lookup

Error: ExactlyOne

  on main.tf line 30, in resource "google_compute_health_check" "main":
  30: resource "google_compute_health_check" "main" {

"ssl_health_check": one of
`grpc_health_check,http2_health_check,http_health_check,https_health_check,ssl_health_check,tcp_health_check`
must be specified

ERRO[0005] 1 error occurred:
    * exit status 1

==比较

Error: Inconsistent conditional result types

  on main.tf line 44, in resource "google_compute_health_check" "main":
  44:     for_each             = each.value.name == "tcp_health_check" ? each.value : []
    |----------------
    | each.value is object with 7 attributes
    | each.value.name is "tcp-health-check"

The true and false result expressions must have consistent types. The given
expressions are object and tuple, respectively.

ERRO[0005] 1 error occurred:
    * exit status 1

好的,用另一种方法解决了它,但感谢 Marcin 的回答

terragrunt.hcl

  inputs = {
    name                = "nat-health-check"
    used_for            = "used for NATs"
    check_interval_sec  = 30
    timeout_sec         = 5
    healthy_threshold   = 1
    unhealthy_threshold = 5
    http_checks         = local.app_vars.inputs.health_checks.nat-http
  }

和模块main.tf

resource "google_compute_health_check" "main" {
  name               = var.name
  timeout_sec        = var.timeout_sec
  check_interval_sec = var.check_interval_sec
  description        = "${var.name} - ${var.used_for}"

  dynamic "http_health_check" {
    for_each = var.http_checks != null ? [1] : []
    content {
      port               = var.http_checks.port
      request_path       = var.http_checks.request_path
      port_specification = var.http_checks.port_specification
    }
  }
}

以下

contains(keys(each.value), "tcp_health_check") != null ? each.value : {}

失败,因为当这是真的时,你的动态块 tcp_health_check 将被执行 一次 ,因为你的 each.value 只是一个值映射.你不能超过一个 tcp_health_check 块。

第二个

for_each             = lookup(each.value, "tcp_health_check", [])

没有失败而且是正确的。但由于它会导致 false,因此不会创建您的 tcp_health_check 块。这失败了,因为您没有提供任何替代块 grpc_health_check,http2_health_check,http_health_check,https_health_check,ssl_health_check,tcp_health_check.

最后一次尝试:

for_each             = each.value.name == "tcp_health_check" ? each.value : []

失败,因为它应该是 for_each = each.value.name == "tcp_health_check" ? each.value : {}。但是,如果您修复此问题,each.value 将再次像以前一样失败。

总而言之,你总是注定要失败,因为当你像第二种情况那样消除你的障碍 tcp_health_check 时,你没有提供任何替代方案。如果您的条件是 trueeach.value 将尝试创建多个区块。

关闭的解决方案是(不考虑错误的情况,您需要提供替代方案):

  dynamic tcp_health_check {
    for_each           = each.value.name == "tcp_health_check" ? [1] : []
    content {
         port          = each.value.port
         port_name     = each.value.name
      }
  }