Terraform 1.8で追加されたencode_expr関数を使って、tfe providerでHCP TerraformのVariableを定義してみる

2024.04.30

Terraform 1.8でencode_expr関数が追加されました。

この関数は、TerraformでHCP TerraformのVariablesを書く際に便利です。

Release v1.8.0 · hashicorp/terraform

encode_expr関数とは

HCL形式の値をStringに変換する関数です。

使用用途は限定的で、ドキュメントに以下の記述があるほどです。

provider::terraform::encode_expr is a rarely-needed function

encode_exprから引用

主な使用用途は、HCP TerraformのVariables定義です。(他のユースケースでは使用をお勧めしない旨もドキュメントにありました)

HCP Terraformでは、Workspaceに対してVariablesを渡す機能があります。

tfe_variablevalueはStringである必要があるため、Terraform varialbeでString以外を渡す際に一工夫(後述)必要だったのですが、encode_exprを使えば以下のように書けます。

terraform {
  required_providers {
    terraform = {
      source = "terraform.io/builtin/terraform"
    }
  }
}

locals {
  workspace_vars = {
    example1 = "Hello"
    example2 = ["A", "B"]
    example3 = { key1 = "value1", key2 = "value2" }
  }
}

resource "tfe_variable" "test" {
  for_each = local.workspace_vars

  category     = "terraform"
  workspace_id = tfe_workspace.test.id

  key   = each.key
  value = provider::terraform::encode_expr(each.value)
  hcl   = true
}

やってみた

Terraform CloudのVariables設定を、従来の方法とexprencode関数を使う方法でやってみました。

Variablesには以下の値を設定します。

従来の方法(encode_exprを使わない)

以下は、HCP TerraformのVariable(Terraform変数)を、for_eachを使って定義する例です。

main.tf

provider "tfe" {
  hostname = "app.terraform.io"
}

resource "tfe_workspace" "test" {
  name         = "variables-test"
  organization = "<HCP Terraform Organization名>"
}

locals {
  workspace_vars = {
    example1 = "Hello"
    example2 = ["A", "B"]
    example3 = { key1 = "value1", key2 = "value2" }
  }
}

resource "tfe_variable" "test" {
  for_each = local.workspace_vars

  category     = "terraform"
  workspace_id = tfe_workspace.test.id

  key   = each.key
  value = jsonencode(each.value)
  hcl   = true
}

注目してほしいのは、ハイライト箇所のjsonencode関数です。

tfe_variablevaluestringで有る必要があります。

そのため、listmapを渡す場合は、jsonencode等を使ってStringに変換する必要があります。

本来なら、HCLにエンコードしたいのですが、1.8以前には関数はありませんでした。

また、上記コードは問題ありませんでしたが、この方法は複雑なObject型を扱う際に問題があったようです。

v1.8以降(exprencodeを使う)

HCLにエンコードする関数encode_exprがサポートされたので、以下のように置き換えられます。

用途に適した関数を利用することで、読む側に意図が伝わりやすくなったかと思います。

main.tf

provider "tfe" {
  hostname = "app.terraform.io"
}

resource "tfe_workspace" "test" {
  name         = "variables-test"
  organization = "classmethod-sandbox"
}

+terraform {
+  required_providers {
+    terraform = {
+      source = "terraform.io/builtin/terraform"
+    }
+  }
+}

locals {
  workspace_vars = {
    example1 = "Hello"
    example2 = ["A", "B"]
    example3 = { key1 = "value1", key2 = "value2" }
  }
}

resource "tfe_variable" "test" {
  for_each = local.workspace_vars

  category     = "terraform"
  workspace_id = tfe_workspace.test.id

  key   = each.key
-  value = jsonencode(each.value)
+  value = provider::terraform::encode_expr(each.value)
  hcl   = true
}

encode_exprは組み込み関数ではなく、Provider関数です。

ほとんどのTerraformモジュールでは使われないため、Provider関数にしたようです。

terraform.io/builtin/terraform provider, rather than being language builtins, due to their Terraform-domain-specific nature and the fact that they should not be needed by most Terraform module authors.

provider/terraform: Terraform-specific encoding functions `tfvarsencode`, `tfvarsdecode`, and `exprencode` by apparentlymart · Pull Request #34718 · hashicorp/terraformから引用

[アップデート]TerraformのProviderが関数を定義できるようになりました | DevelopersIO

おわりに

Terraform 1.8で追加されたencode_expr関数についてでした。

使用用途は限定的ですが、Issueを見る限り困っていた人は多くいたみたいです。

tfe providerを使ってHCP TerraformのVariableを定義する際に、encode_expr関数をぜひ使ってみてください。

以上、AWS事業本部の佐藤(@chari7311)でした。