如何在 terraform 中使用输出 id 作为变量?

How to use output ids in terraform as variable?

我使用 Terraform 在云中构建我的基础设施(我是 Terraform 的新手)。

我还使用 terraform 创建了一些防火墙规则,我需要将其分配给多个服务器。为此,我在我的模型中创建了一个名为 firewall 的字段。

Variables.tf

variable "hosts" {
    type = map(object({
        name                    = string
        serverType              = string
        serverImage             = string
        serverLocation          = string
        serverKeepDisk          = bool
        serverBackup            = bool 
        ip                      = string
        volume                  = bool
        volumeName              = string
        volumeSize              = number
        volumeFormat            = string
        volumeAutomount         = bool
        volumeDeleteProtection  = bool
        floating                = bool
        firewall                = list(string) <--- this thing here!
      }))
    }

Terraform.tfvars

"myServer01"     = {
            name                    = "s01"
            serverType              = "cx11"
            serverImage             = "ubuntu-20.04"
            serverLocation          = "fsn1"
            serverKeepDisk          = false
            serverBackup            = false
            ip                      = "192.168.0.12"
            volume                  = true
            volumeName              = "data"
            volumeSize              = 100
            volumeFormat            = "ext4"
            volumeAutomount         = false
            volumeDeleteProtection  = false
            floating                = false
            firewall                = [hcloud_firewall.basic.id, hcloud_firewall.ssh.id, hcloud_firewall.webserver.id] <-- I define here variables of the firewalls I need to assign to this specific server
        },

main.tf

resource "hcloud_server" "default" {
  for_each      = var.hosts
  name          = each.value.name
  server_type   = each.value.serverType
  image         = each.value.serverImage
  location      = each.value.serverLocation
  user_data     = file("userdata.yml")
  keep_disk     = each.value.serverKeepDisk
  backups       = each.value.serverBackup
  ssh_keys      = [hcloud_ssh_key.default.id]
  firewall_ids  = each.value.firewall

错误:

│ Error: Variables not allowed
│ 
│   on terraform.tfvars line 71:
│   71:             firewall                = [hcloud_firewall.basic.id, hcloud_firewall.ssh.id, hcloud_firewall.webserver.id]
│ 
│ Variables may not be used here.

如何在 Terraform 中通过 ID/ 作为变量定义多个防火墙规则?

您不能创建动态变量。所以不可能做你想做的事。相反,您应该创建一个 local 变量并改用它:

locals {
  firewall = [hcloud_firewall.basic.id, hcloud_firewall.ssh.id, hcloud_firewall.webserver.id]
}

然后在代码中使用 local.firewall 代替 var.firewall

根模块输入变量的定义有效地存在于根模块之外,在同样的意义上,当您将值传递给子模块的变量时,您在 caller[= 的上下文中定义它们28=],因此他们无法直接访问被调用模块中定义的任何内容。

因为根模块之外没有模块可以计算其中的表达式,所以根模块输入变量必须始终具有完全恒定的值。根模块变量定义无法直接引用根模块内声明的对象。

但是,您可以通过添加间接级别获得与此处预期的效果类似的效果:不是让 hosts 变量直接包含防火墙 ID,而是可以包含一些符号名称,这些符号名称具有表示仅在此配置中,每个都指您声明的防火墙之一。

variable "hosts" {
  type = map(object({
    name                    = string
    serverType              = string
    serverImage             = string
    serverLocation          = string
    serverKeepDisk          = bool
    serverBackup            = bool 
    ip                      = string
    volume                  = bool
    volumeName              = string
    volumeSize              = number
    volumeFormat            = string
    volumeAutomount         = bool
    volumeDeleteProtection  = bool
    floating                = bool
    firewall_names          = set(string)
  }))
}

locals {
  firewall_ids = {
    basic     = hcloud_firewall.basic.id
    ssh       = hcloud_firewall.ssh.id
    webserver = hcloud_firewall.webserver.id
  }
}

resource "hcloud_server" "default" {
  for_each = var.hosts

  name          = each.value.name
  server_type   = each.value.serverType
  image         = each.value.serverImage
  location      = each.value.serverLocation
  user_data     = file("userdata.yml")
  keep_disk     = each.value.serverKeepDisk
  backups       = each.value.serverBackup
  ssh_keys      = [hcloud_ssh_key.default.id]
  firewall_ids  = [
    for name in each.value.firewall_names : local.firewall_ids[name]
  ]
}

在您的 terraform.tfvars 文件中,您可以使用符号名称间接指定这些对象,而不是直接引用模块内的对象:

hosts = {
  "myServer01" = {
    name                    = "s01"
    serverType              = "cx11"
    serverImage             = "ubuntu-20.04"
    serverLocation          = "fsn1"
    serverKeepDisk          = false
    serverBackup            = false
    ip                      = "192.168.0.12"
    volume                  = true
    volumeName              = "data"
    volumeSize              = 100
    volumeFormat            = "ext4"
    volumeAutomount         = false
    volumeDeleteProtection  = false
    floating                = false
    firewall_names          = ["basic", "ssh", "webserver"]
  }
}

请注意,惯用的 Terraform 样式是使用全部小写的属性名称,并用下划线分隔单词,例如 server_type 而不是 serverType。 Terraform 当然会同时接受两者,但是使用传统风格可能会使您的模块对具有 Terraform 经验的人来说不那么令人惊讶。