将多行文件拆分为 Terraform 变量以通过键访问值
Split a multiline file into Terraform variable to access the values by their keys
我有一个包含很多行的第三方维护文件,看起来像:
# a comment lines
aaa.bbb.cc 423
ddd.ee.fff 452
...
tons.like.them 111
是否有任何方法可以将文件加载到本地地图并使用类似语法在 Terraform 中访问其密钥?:
"${lookup(var.locals.mylist, 'ddd.ee.fff', 0)}"
文件名为myfile.txt
,内容为:
# a comment line
aaa.bbb.cc 423
ddd.ee.fff 452
...
tons.like.them 111
数据查询应如下所示:
data "external" "myfile" {
program = [
"bash",
"${path.module}/template/parser.sh",
"${path.module}/template/myfile.txt",
"ddd.ee.fff"
]
}
并且 template/parser.sh
包含:
#!/usr/bin/env bash
set -eo pipefail
CONFIG=$(cat |grep -v '#' | sed 's/ /=/g' | jq -R -n -c '.data = ([inputs|split("=")|{(.[0]):.[1]}] |add)')
OUTPUT=$(echo $CONFIG | jq -r '.data["''"]')
jq -n --arg output "$OUTPUT" '{"output":$output}'
这个棘手的脚本将 return:
{"output": 452}
并且可以使用插值得到结果值:
${data.external.myfile.result.output}
不幸的是,我没有找到如何将完整的行列表加载到 Terraform 并使用 "variable of variable" 或 lookup() 访问它们。如果 bash 脚本 return 第一个 jq
调用的结果,Terraform 抛出异常:
command "bash" produced invalid JSON: json: cannot unmarshal object into Go value of type string
Update2: 要访问结果值,您需要在脚本的实际“.output”键之前使用一个附加键“.result”。
像这样使用以通用编程语言编写的单独程序预处理文件通常更好,因为 Terraform 的 DSL 不太适合这种特殊的解析逻辑。
Terraform v0.11 及更早版本缺少在语言本身内实现此类解析所需的原语。 v0.12.0 版本(在撰写本文时为 in beta)引入了一些原语,do 允许实现这种解析,但我通常仍然更喜欢如果可能的话,在 Terraform 之外作为预处理步骤进行。
话虽如此,下面是一个使用 Terraform v0.12 功能将文件(如您的示例)解析为地图的示例:
locals {
raw_lines = [
for line in split("\n", file("${path.module}/input.txt")) :
split(" ", trimspace(line))
]
lines = [
for line in local.raw_lines :
line if length(line[0]) > 0 && substr(line[0], 0, 1) != "#"
]
records = { for line in local.lines : line[0] => line[1] }
}
output "result" {
value = local.records
}
给定以下输入文件:
# a comment line
aaa.bbb.cc 423
ddd.ee.fff 452
tons.like.them 111
# another comment
another.record abc
这会使用 Terraform v0.12.0-beta1 产生以下结果:
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
result = {
"aaa.bbb.cc" = "423"
"another.record" = "abc"
"ddd.ee.fff" = "452"
"tons.like.them" = "111"
}
我有一个包含很多行的第三方维护文件,看起来像:
# a comment lines
aaa.bbb.cc 423
ddd.ee.fff 452
...
tons.like.them 111
是否有任何方法可以将文件加载到本地地图并使用类似语法在 Terraform 中访问其密钥?:
"${lookup(var.locals.mylist, 'ddd.ee.fff', 0)}"
文件名为myfile.txt
,内容为:
# a comment line
aaa.bbb.cc 423
ddd.ee.fff 452
...
tons.like.them 111
数据查询应如下所示:
data "external" "myfile" {
program = [
"bash",
"${path.module}/template/parser.sh",
"${path.module}/template/myfile.txt",
"ddd.ee.fff"
]
}
并且 template/parser.sh
包含:
#!/usr/bin/env bash
set -eo pipefail
CONFIG=$(cat |grep -v '#' | sed 's/ /=/g' | jq -R -n -c '.data = ([inputs|split("=")|{(.[0]):.[1]}] |add)')
OUTPUT=$(echo $CONFIG | jq -r '.data["''"]')
jq -n --arg output "$OUTPUT" '{"output":$output}'
这个棘手的脚本将 return:
{"output": 452}
并且可以使用插值得到结果值:
${data.external.myfile.result.output}
不幸的是,我没有找到如何将完整的行列表加载到 Terraform 并使用 "variable of variable" 或 lookup() 访问它们。如果 bash 脚本 return 第一个 jq
调用的结果,Terraform 抛出异常:
command "bash" produced invalid JSON: json: cannot unmarshal object into Go value of type string
Update2: 要访问结果值,您需要在脚本的实际“.output”键之前使用一个附加键“.result”。
像这样使用以通用编程语言编写的单独程序预处理文件通常更好,因为 Terraform 的 DSL 不太适合这种特殊的解析逻辑。
Terraform v0.11 及更早版本缺少在语言本身内实现此类解析所需的原语。 v0.12.0 版本(在撰写本文时为 in beta)引入了一些原语,do 允许实现这种解析,但我通常仍然更喜欢如果可能的话,在 Terraform 之外作为预处理步骤进行。
话虽如此,下面是一个使用 Terraform v0.12 功能将文件(如您的示例)解析为地图的示例:
locals {
raw_lines = [
for line in split("\n", file("${path.module}/input.txt")) :
split(" ", trimspace(line))
]
lines = [
for line in local.raw_lines :
line if length(line[0]) > 0 && substr(line[0], 0, 1) != "#"
]
records = { for line in local.lines : line[0] => line[1] }
}
output "result" {
value = local.records
}
给定以下输入文件:
# a comment line
aaa.bbb.cc 423
ddd.ee.fff 452
tons.like.them 111
# another comment
another.record abc
这会使用 Terraform v0.12.0-beta1 产生以下结果:
$ terraform apply
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
result = {
"aaa.bbb.cc" = "423"
"another.record" = "abc"
"ddd.ee.fff" = "452"
"tons.like.them" = "111"
}