【小ネタ】Terraformで子リソースに分割されたリソース定義をdynamic blockを使って書き直す例

GitHubで質問もらったやつが例として手頃だったのでブログ書いておきました。

github.com

やりたいこと

Terraform v0.11以前までの親リソース/子リソースに分けて定義していたリソースをv0.12で導入されたdynamic blockに書き直す

v0.11以前

ここではrke_clusterリソースの子リソースとしてdata rke_node_parameterを定義しています。

# locals to allow us to control which nodes get assigned manager roles vs. controlplane and workers
locals {
  mgr_roles    = ["controlplane","etcd"]
  worker_roles = ["worker"]
}

# rke_clusterリソースに対する子リソース(node)の定義
data rke_node_parameter "nodes" {
  count   = "${var.NODE_COUNT}"
  address = "${azurestack_public_ip.vmpip.*.ip_address[count.index]}"
  user    = "myuser"
  role    = "${split(",", count.index < var.nbr_managers ? join(",", local.mgr_roles) : join(",", local.worker_roles))}"
  ssh_key = "${file("path/to/sshkey")}"
}

resource rke_cluster "cluster" {
  depends_on = ["azurestack_public_ip.vmpip", "azurestack_virtual_machine.vm"]

  # 子リソースの定義
  nodes_conf = ["${data.rke_node_parameter.nodes.*.json}"]
}

v0.12のdynamic blockを使って書き直し

子リソースdata rke_node_parameterrke_clusternodesにdynamic blockを使って書き直してます。

# locals to allow us to control which nodes get assigned manager roles vs. controlplane and workers
locals {
  mgr_roles    = ["controlplane","etcd"]
  worker_roles = ["worker"]
}

resource rke_cluster "cluster" {
  depends_on = ["azurestack_public_ip.vmpip", "azurestack_virtual_machine.vm"]

  dynamic nodes {
    for_each = azurestack_public_ip.vmpip.*
    content {
      address = nodes.value.ip_address
      user    = "myuser"
      role    = split(",", nodes.key < var.nbr_managers ? join(",", local.mgr_roles) : join(",", local.worker_roles))
      ssh_key = file("path/to/sshkey")
    }
  }
}

ポイント

まずはこちらのドキュメントには目を通しておきましょう。

www.terraform.io

その上で書き換えのポイントとしては、

  • for_eachにはvariable以外にもresourceやdataも指定できる
  • for_eachにリスト要素を指定した場合、contentブロック内で<element>.keyとすればインデックスを、<element>.valueで値を参照できる

あたりでしょうか。

contentブロック内でイテレート対象の値を参照する際は<element>.valuevalueをつける必要がある点に注意です。(よく間違える)

なお、書き直しするにはプロバイダー側で親リソース内に子リソースの定義を書けるようになっていることが必要です。
(例: azurerm_virtual_machineリソースのstorage_data_diskみたいにブロックでもリソースでも定義できるようになっていること)

終わりに

この類の書き換えはterraform 0.12upgradeで自動置き換えできないので手動で書き換える必要があります。 (書き換える必要があるかは別問題として)

dynamic blockを使えばより簡潔に書ける or 処理が早くなる(反映処理時のロックが不要になったり)などの恩恵を受けられる可能性もありますので使いすぎに注意しつつどんどん使いましょう

以上です。