プログラマ行進曲第二章

主にソフトウェア関連の技術をネタにした記事を執筆するためのブログ

Terraformでdynamic blockを使って特定のblockを一つだけ生成するかしないかを制御するやり方

前回の記事で書いていないけれど、割と遭遇しがちなTerraformの書き方の記録を残します。

takuan-osho.hatenablog.com

前回、例えばsecuriy group id関係の変数の値に長さが0より大きいリストが与えられたときにblockを作るかどうかといった書き方で以下の様な書き方を紹介しました。

resource "aws_eks_node_group" "varanus" {
  for_each = var.node_groups
  # 省略
  dynamic "remote_access" {
    for_each = length(each.value.config.security_group_ids) > 0 ? [each.value.config] : []

今回はその亜種を紹介します。

例えばaws_launch_templateリソースにはtag_specificationsというargumentがありますが、これはblockを取ります。

resource "aws_launch_template" "foo" {
  name = "foo"
  # 省略
  tag_specifications {
    resource_type = "instance"

    tags = {
      Name = "test"
    }
  }
# 省略

こんな感じでtag_specificationsというblockの中に更にネストするような感じで付与したいタグをmapの形で指定します。

こういったとき、既にaws_launch_templateを作っていて、その既存のリソースにはtag_specificationsをつけていないけれど、tag_specificationsをまず開発環境で動作確認してから順次他の環境にも付けていきたい、となった場合、ある特定の環境だけtag_specificationsのblockをつけ、それ以外はつけないように制御したくなります。

こういった場合、ワークアラウンド的な書き方になりますが、最初の例と同じく三項演算子と条件に取る変数を上手く使って以下の様に書けます。

variable "tags" {
  description = "tags"
  type = object({
    Environment = string
    Owner       = string
  })
  default = null
}

変数をこんな感じで宣言するなら、以下の様に書きます。

resource "aws_launch_template" "bar" {
  name                   = "bar"
  # 省略
  dynamic "tag_specifications" {
    for_each = var.tags != null ? ["We only have to contain a list whose length is one."] : []
    content {
      resource_type = "volume"
      tags          = var.tags
    }
  }
}

変数var.tagsはdefaultがnullなので、変数を宣言していない場合はtag_specifications blockを作らず、宣言している場合は条件に書いてあるリストの長さが1のため、一回だけtag_specifications blockが挿入される形になる。

だいたいの場合は最初の例のように、変数の要素数でblockを生成する必要があるからeach.valueなりを使う必要が出てくるが、このaws_launch_templateのtag_specifications blockの例のように、一つだけ生成すれば良いか不必要になるかといった場合は、こんなダミーのリストを入れて、each.valueなどは中では使わないというやり方で一応書けます。