在 terraform 中创建动态块

Posted

技术标签:

【中文标题】在 terraform 中创建动态块【英文标题】:Create dynamic block in 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
    
  

【问题讨论】:

您当前的代码有什么问题?有什么错误吗? 我已经把它们放在帖子里了 【参考方案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" 与您的变量不匹配。 好的,以其他方式进行,不是最好的但有效,感谢您的回答!

以上是关于在 terraform 中创建动态块的主要内容,如果未能解决你的问题,请参考以下文章

如何在 terraform 中创建允许/拒绝防火墙规则条件?

在同一个 TF 脚本中使用多个 Terraform 提供程序(GCP 和 Kubernetes)创建资源

Terraform EC2(根块设备加密错误未能达到目标状态)

通过 terraform 在 aws 中创建 VPC 问题

如何在 Terraform 中创建存档文件?

如何在 Terraform 中创建 SSH 密钥?