Terraformのplan出力でjsonencode関数が使われる背景
結論
TerraformがヒューリスティックにJSONっぽいと判断したらplanの差分表示に jsonencode() を使う
調査
jsonencode() を使うと < とかもエスケープされるという話を聞く
issue
templatefile() を使えば回避できそうじゃない? とアドバイスするが「templatefile() を使っても jsonencode() が呼ばれる」と聞く
暗黙的な呼び出しっぽいけど、誰が呼んでいるのか気になって調べる
code:input.json.tftpl
{
"name": "${name}"
}
code:input.txt.tftpl
{
"name": "${name}"
}
code:main.tf
terraform {
required_version = "v1.4.5"
}
output "json" {
value = templatefile("./input.json.tftpl", { name = "aereal" })
}
output "txt" {
value = templatefile("./input.txt.tftpl", { name = "aereal" })
}
code:result
Changes to Outputs:
+ json = jsonencode(
{
+ name = "aereal"
}
)
+ txt = jsonencode(
{
+ name = "aereal"
}
)
You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.
input.json.tftpl の場合は .json がついているのでパス名から推測されたのかな?と思ったけど input.txt.tftpl でも起きるということは中身を見ていることはほぼ明らか
かつ output で起きているのでproviderの実装は関係なく、Terraformコアの実装に由来している
terraform plan jsonencodeでググると「差分表示に jsonencode() を使うのは仕様なんだよ」というissueが見つかる
hashicorp/terraformを jsonencode で検索すると internal/command/jsonformat/computed/renderers/primitive.go がひっかかる
renderStringDiffAsJson
https://github.com/hashicorp/terraform/blob/f6737d47e79fdf88c072e765c2ec52202528d2fe/internal/command/jsonformat/computed/renderers/primitive.go#L241
renderStringDiff の中で str.Json != nil だったら呼ばれる
https://github.com/hashicorp/terraform/blob/f6737d47e79fdf88c072e765c2ec52202528d2fe/internal/command/jsonformat/computed/renderers/primitive.go#L86-L92
evaluatePrimitiveString の中で { か [で始まったら str.Jsonにnon-nilな値が入る
https://github.com/hashicorp/terraform/blob/f6737d47e79fdf88c072e765c2ec52202528d2fe/internal/command/jsonformat/computed/renderers/string.go#L32-L40
試しに templatefile()で読み取るファイルの先頭に空白を足して strings.HasPrefix(str, "{") || strings.HasPrefix(str, "[")がfalseになるよう変更してみる
code:plan
+ txt = <<-EOT
{
"name": "aereal"
}
EOT
jsonencode() が呼ばれなくなった!!