JSON 配置语法

原文


注意:此页面是关于 Packer 的 HCL2 模板的。 HCL2 模板最初作为 Beta 功能被 Packer 1.5 版引入。从 v1.7 开始,HCL2 支持不再处于测试阶段,并且是编写 Packer 配置的首选方式。对于稳定的旧风格配置语言,请参阅模板文档。从 v1.6.2 开始,您可以使用 hcl2_upgrade 命令将遗留的 JSON 模板转换为 HCL2 配置文件。

大多数 Packer 配置都是使用原生 HCL 语法编写的,旨在便于人们阅读和更新。

Packer 还支持与 JSON 兼容的替代语法。当程序生成部分配置时,此语法很有用,因为我们可以使用现有的 JSON 库来生成配置文件。

不要将此语法与 1.5 版之前的“遗留” Packer 模板混淆,后者完全是 JSON 并遵循不同的格式。

JSON 语法是对照原生 HCL 语法定义的。任何可以用原生 HCL 语法表达的东西也可以用 JSON 语法表达,但由于 JSON 语法的限制,一些结构在 JSON 中表示更复杂。

Packer 期望以 .pkr.hcl 后缀命名的文件使用原生 HCL 代码,以 .pkr.json 后缀命名的文件使用 JSON 语法。如果您省略后缀的 .pkr 部分,Packer 将尝试将您的 json 文件作为旧版 Packer 模板读取。

与原生 HCL 语法一样,底层的 JSON 语法是根据 HCL 的规范定义的。无需了解 HCL 语法或其 JSON 对标的所有细节即可使用 Packer,因此本页总结了原生 HCL 语法和 JSON 语法之间最重要的区别。如果您有兴趣,可以在 HCL 规范中找到 HCL 的 JSON 语法的完整定义。

JSON 文件的结构

所有基于 JSON 的 Packer 配置的根都是一个 JSON 对象。该对象的属性对应于 Packer 语言的顶级块类型。例如:

{
  "variables": {
    "example": "value"
  }
}

每个顶级对象属性必须与预期的顶级块类型之一的名称相匹配。表示块类型所需要的标签,例如上面显示的 variable,由每个标签级别对应的一个嵌套对象值表示。source 代码块需要两个标签,因此需要两层嵌套:

{
  "source": {
    "amazon-ebs": {
      "example": {
        "instance_type": "t2.micro",
        "ami_name": "ami-abc123"
      }
    }
  }
}

穿透代表标签的多层嵌套对象之后,最后一个嵌套对象代表块本身的主体。在上面的示例中,指定了 source "amazon-ebs" "example"instance_typeami_name 参数。

综上所述,上述两个配置文件相当于原生语法中的以下块:

variables {
  example = "value"
}

source "amazon-ebs" "example" {
  instance_type = "t2.micro"
  ami_name      = "ami-abc123"
}

在每个顶级块类型中,映射到 JSON 的规则略有不同(请参阅下面特定于块类型的特殊处理),但以下一般规则适用于大多数情况:

  • 表示块主体的 JSON 对象包含对应于参数名称或嵌套块类型名称的属性。
  • 在属性对应于接受本机语法中的任意表达式的参数的情况下,属性值对应到表达式,如下文的表达式映射所述。对于不接受任意表达式的参数,属性值的解释取决于参数,如本页后面给出的特定于块类型的特殊处理中所述。
  • 如果属性名称对应于预期的嵌套块类型名称,则它的值将按照下面的嵌套块映射中的描述进行解释,除非在本页后面给出的特定于块类型的特殊处理中另有说明。

表达式映射

由于 JSON 语法无法表示所有的 Packer 语言表达式语法,因此 JSON 值在对应到表达式时有如下映射关系:

JSON Packer Language Interpretation
Boolean 一个 bool 类型字面值
Number 一个 number 类型字面值
String 作为字符串模板处理,计算过程在下面会有介绍
Object 每一个属性都按照本表格的规则映射,产生一个 object(...) 类型的值,其属性的类型都被解释成和合适的对应类型
Array 每一个元素都按照本表格的规则映射,产生一个 tuple(...) 类型的值,每个元素的类型都被解释成合适的对应类型
Null 一个 null 字面值.

当在应该设置表达式的位置遇到 JSON 字符串时,会首先将其值解析为字符串模板,然后对其求值以产生最终结果。

如果给定的模板包含一个插值序列,则直接获取其表达式的结果,而无需先将其转换为字符串。这允许在 JSON 语法中使用非字符串表达式。

嵌套块映射

当 JSON 对象属性的名字等于一个嵌套块类型名时,此属性的值表示该类型的一个或多个块。该属性的值必须是 JSON 对象或 JSON 数组。

最简单的情况是只表示给定类型的单个块,而该类型不需要标签,就像 source 块中使用的 tags 嵌套块一样:

{
  "source": {
    "amazon-ebs": {
      "example": {
        "tags": {
          "key": "value"
        }
      }
    }
  }
}

上述代码等价于下面的 HCL 原生代码:

source "amazon-ebs" "example" {
  tags = {
    key = "value"
  }
}

当嵌套块类型需要一个或多个标签时,或者可以声明多个相同类型的块时,映射会变得稍微复杂一些。例如,build 块中使用的 provisioner 嵌套块类型需要一个标签来提供要使用的配置器类型,并且 provisioner 块的顺序对于决定操作顺序很重要。

以下原生语法示例显示了一个 build 块,包含了许多不同类型的 provisioner

build {
  # (source configuration omitted for brevity)

  provisioner "shell-local" {
    inline = ["echo 'Hello World' >example.txt"]
  }
  provisioner "file" {
    source      = "example.txt"
    destination = "/tmp/example.txt"
  }
  provisioner "shell" {
    inline = [
      "sudo install-something -f /tmp/example.txt",
    ]
  }
}

为了保留这些块的顺序,您必须使用 JSON 数组作为表示此块类型的属性的直接值,如在上面例子的 JSON 版本中:

{
  "build": {
    "//": "(source configuration omitted for brevity)",

    "provisioner": [
      {
        "shell-local": {
          "inline": ["echo 'Hello World' >example.txt"]
        }
      },
      {
        "file": {
          "source": "example.txt",
          "destination": "/tmp/example.txt"
        }
      },
      {
        "shell": {
          "inline": ["sudo install-something -f /tmp/example.txt"]
        }
      }
    ]
  }
}

provisioner 数组的每个元素都是一个具有单个属性的对象,其名称代表每个 provisioner 块的标签。对于需要多个标签的块类型,这种交替数组和对象嵌套的模式可用于每个递进的级别。

如果嵌套块类型需要标签但顺序无关紧要,您可以省略数组并只提供一个对象,其属性名称对应了这些标签。对于简单的场景,这可以作为上述方法的简写,但交替数组和对象方法是最通用的。如果系统地从原生 HCL 语法转换为 JSON,我们建议使用最通用的形式,以确保准确保留配置的含义。

注释属性

尽管我们不建议手动编辑 JSON 语法配置文件 —— 这种格式主要用于由程序生成和使用 —— 但可以使用特殊属性名称对表示一个块的 JSON 对象进行有限形式的注释:

{
  "source": {
    "amazon-ebs": {
      "example": {
        "//": "This instance runs the scheduled tasks for backup",

        "instance_type": "t2.micro",
        "ami_name": "ami-abc123"
      }
    }
  }
}

在任何表示块主体的对象中,名为 "//" 的属性将被 Packer 完全忽略。此例外不适用于被解释为表达式的对象,表达式中的 "//" 将被解释为名为 "//" 的对象类型属性。

这个特殊的属性名称也可以用在基于 JSON 的配置文件的顶层对象中。这对于记录创建文件的程序很有用:

{
  "//": "This file is generated by generate-outputs.py. DO NOT HAND-EDIT!"
}

特定于块类型的特殊处理

特定块类型中的某些参数以特殊方式处理,因此它们到 JSON 语法的映射不遵循上述一般规则。以下小节描述了适用于每个顶级块类型的特殊映射规则。

variable

variable 块中的所有参数到 JSON 的映射都是特殊的:

  • type :包含类型表达式的字符串,如 "string""list(string)"
  • default :可以转换为给定类型的 JSON 字面值。此值内的字符串按字面意思获取,不解释为字符串模板。
  • description :JSON 字面值,不解释为模板。
{
  "variable": {
    "example": {
      "type": "string",
      "default": "hello"
    }
  }
}

results matching ""

    No results matching ""