【问题标题】:Create dynamic block in terraform在 terraform 中创建动态块
【发布时间】:2021-12-31 07:35:15
【问题描述】:

我想在 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
      }
  }

我被困在动态块中 - 如何使它工作,以便它仅在我通过 tcphealth_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
    }
  }
}

【问题讨论】:

  • 您当前的代码有什么问题?有什么错误吗?
  • 我已经把它们放在帖子里了

标签: google-cloud-platform terraform hcl terragrunt


【解决方案1】:

以下

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
      }
  }

【讨论】:

  • 它仍然不起作用,抛出错误说它需要一个主要块(ssl/https/http/tcp)看起来像 for_each 中的 if 语句是错误的
  • @CptDolphin 您需要提供替代方案。你不这样做,所以你总是会失败。
  • 我的意思是,我知道如果我不创建 tcp,我将不得不提供替代方案,但我传递(似乎)正确的值,它应该创建它,但它仍然没有通过用它嗯;生病测试一些并输入 - 如果它适合你,它也应该适合我
  • @CptDolphin 您的所有条件都返回false。因此,您必须提供替代方案。如果您想要 true,请更改您的条件或输入变量,因为 each.value.name == "tcp_health_check" 与您的变量不匹配。
  • 好的,以其他方式进行,不是最好的但有效,感谢您的回答!
猜你喜欢
  • 2021-01-06
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 2020-09-08
  • 2022-01-20
  • 1970-01-01
相关资源
最近更新 更多