Terraform 分配地图时何时需要等号 (=) (TF 0.11)

ipt*_*zer 12 terraform

我无法通过任何其他方法解决这个问题,所以我必须在这里问这个......

在 Terraform 0.11 中将地图分配给值时使用等号 (=) 背后的逻辑是什么?

与 =

resource "pseude_resource" "pseudo_name" {
  value = {
    key1 = value1
    key2 = value2
  }
}
Run Code Online (Sandbox Code Playgroud)

没有 =

resource "pseude_resource" "pseudo_name" {
  value {
    key1 = value1
    key2 = value2
  }
}
Run Code Online (Sandbox Code Playgroud)

使用数组 ([]) 时似乎需要使用 =,但使用映射时则不需要。这背后的原因是什么?到底为什么?可以直接省略吗?

Mar*_*ins 12

在 Terraform 语言中,有两种不同的构造,在常见情况下具有非常相似的语法。

需要映射的参数

Terraform 中的参数是单个名称/值对,其中提供者指示(在资源类型模式中)它期望的值类型您可以以任何您喜欢的方式自由创建该预期类型的​​值,无论是作为文字值还是作为复杂表达式。

一般来说,参数语法是:

  name = value
Run Code Online (Sandbox Code Playgroud)

如果特定参数被定义为映射,那么设置它的一种方法是使用文字值,如下所示:

 tags = {
   Name = "foo bar baz"
 }
Run Code Online (Sandbox Code Playgroud)

...但您也可以使用对与地图类型兼容的其他值的引用:

  # Tags are the same as on some other VPC object
  tags = aws_vpc.example.tags
Run Code Online (Sandbox Code Playgroud)

...或者您可以使用内置 Terraform 函数将地图组合在一起:

  tags = merge(local.default_tags, var.override_tags)
Run Code Online (Sandbox Code Playgroud)

一般来说,您可以使用任何其结果是具有预期元素类型的映射的表达式

在 Terraform 0.11 中,这些非文字示例都需要以模板插值语法来呈现${ ... },但原理是相同的。

嵌套块

虽然参数为其嵌入块的对象设置一些特定的配置设置,但嵌套块语法通常声明与块嵌入的对象相关的另一个对象的存在。有时这实际上是一个单独的物理对象,例如作为与安全组关联的规则,有时它是一个更具概念性的“对象”,例如versioning其中aws_s3_bucket将版本控制功能建模为单独的“对象”,因为它的存在会激活该功能。

嵌套块语法遵循与顶级resourcevariableterraform等块的语法相同的约定:

  block_type "label" {
    nested_argument = value
  }
Run Code Online (Sandbox Code Playgroud)

每个块类型都有其期望的固定数量的标签,在许多情况下根本没有标签。因为每个块代表一个单独对象的声明,所以块结构更加严格,必须始终遵循上面的形状;在这种情况下不可能使用任意表达式,因为 Terraform 希望在静态验证阶段验证每个块内部是否具有正确的参数。

因为块语法和地图文字语法都使用大括号{ },所以它们在配置中具有相似的外观,但它们的含义与 Terraform 完全不同。使用块语法,您可以期望块的内容具有固定结构,其中包含由资源类型架构决定的一组特定参数名称和嵌套块类型。使用地图参数,您可以自由选择您喜欢的地图键(遵守提供者或远程系统可能在 Terraform 模式之外强加的任何验证规则)。

认识到差异

不幸的是,如今提供程序的文档对于每个参数或嵌套块应该如何使用通常含糊其辞,有时甚至省略了参数的预期类型。主要的提供商都是非常庞大的代码库,因此他们的文档质量参差不齐,因为它们是由许多不同的人在几年内编写的,并且对文档的持续改进只能逐步进行。

话虽如此,提供程序文档通常会在描述嵌套块时使用“嵌套块”或“块类型”一词,并且会引用页面上其他位置的某些定义来准确了解参数和嵌套块所属的内容在那个街区里面。如果文档指出特定参数是映射或暗示键是自由格式的,则表明它是需要映射值的参数。另一个线索是块类型名称通常是单数名词(因为每个块描述一个对象),而采用映射和其他集合的参数通常使用复数名词。

如果您发现文档对于特定名称是嵌套块类型还是参数不明确的特定情况,则在提供程序的存储库中为其提出问题以帮助改进文档会很有帮助。Terraform 的文档页面的页脚中有一个“编辑此页面”链接,您可以使用该链接在适当的存储库中提出简单(仅限单页)编辑作为拉取请求。

这些概念的详细解释位于文档部分Arguments and Blocks中。


Nge*_*tor 6

这种混乱来自于 terraform 使用的 hcl 语言的行为。该功能在 terraform 中没有得到很好的记录,但是...在 hcl 中,您可以通过使用重复块来定义列表,这就是aws_route_table等资源定义内联路由的方式,例如

resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.default.id}"

  route {
    cidr_block = "10.0.1.0/24"
    gateway_id = "${aws_internet_gateway.main.id}"
  }

  route {
    ipv6_cidr_block        = "::/0"
    egress_only_gateway_id = "${aws_egress_only_internet_gateway.foo.id}"
  }

  tags = {
    Name = "main"
  }
}
Run Code Online (Sandbox Code Playgroud)

这相当于

resource "aws_route_table" "r" {
  vpc_id = "${aws_vpc.default.id}"

  route = [
    {
      cidr_block = "10.0.1.0/24"
      gateway_id = "${aws_internet_gateway.main.id}"
    },
    {
      ipv6_cidr_block        = "::/0"
      egress_only_gateway_id = "${aws_egress_only_internet_gateway.foo.id}"
    }
  ]

  tags = {
    Name = "main"
  }
}
Run Code Online (Sandbox Code Playgroud)

您需要确保=在为某项赋值时使用的是,并且仅在使用列表时才使用重复块语法。另外,根据我的经验,我建议当单个资源可用时不要使用内联。

一些非常有限的 hcl 文档可以在存储库的自述文件中找到。