💭

Terraformでmapにkeyが含まれないときにスキップしたい

2023/07/22に公開

Google CloudではPublic IPを利用した際に割り振られる可能性のあるCIDRの一覧がcloud.jsonでJSON形式で公開されています。

この記事は雑な検証用のTerraformで承認済みネットワークにasia-notheast1のCIDRを全部登録してやろうとしたとき、上記のJSONファイルからscopeがasia-northeast1のprefixes.ipv4Prefixを抜きだそうとしたときにハマったのでその対応方法のメモです

結論

以下のような感じで書いたら対応できました。

contains(keys(hoge), "fuga") # hogeのkeyにhugaを含む場合True

現象

cloud.jsonを見ると分かるとおり、prefixes内のmapはipv4PrefixをKeyとして持つ場合とipv6PrefixをKeyとして持つ場合があります。(それ以外は全て共通)

そのような時に以下のようなTerraformを書くとThis object does not have an attribute named "ipv4Prefix".というエラーを吐いて終了します。

data "http" "google-cloud-public-cidr" {
  url = "https://www.gstatic.com/ipranges/cloud.json"
}
locals {
  cidr_blocks = [
    for prefix in jsondecode(data.http.google-cloud-public-cidr.response_body).prefixes :
    prefix.ipv4Prefix if prefix.scope == "asia-northeast1"
  ]
}

そのためipv4Prefixが存在しない場合(ipv6Prefixが対象の場合)、そのmapオブジェクトをスキップする必要があります。

先行事例

なにか良い方法はないか? と探したところTerraformでmap内の未定義keyを判定するなど未定義Keyを判別する方法は見付けたものの、今回解決したい問題には適応出来ませんでした。

解決方法

Terraformにはcontains(list, string)というliststringが含まれるかを調べる関数と、keys(map)というmapが持つkeyの一覧を取得する関数を組み合わせたら良い感じに実現できました。

data "http" "google-cloud-public-cidr" {
  url = "https://www.gstatic.com/ipranges/cloud.json"
}
locals {
  cidr_blocks = [
    for prefix in jsondecode(data.http.google-cloud-public-cidr.response_body).prefixes :
    prefix.ipv4Prefix if prefix.scope == "asia-northeast1" && contains(keys(prefix), "ipv4Prefix") # この部分 
  ]
}

まとめ

大体公式が何とかしてくれるからこんな素人が書いた資料なんか探してる暇あったら、おとなしく公式ドキュメント読んでください。
貴重な土曜日のn時間を無駄にしてしまった……

GitHubで編集を提案

Discussion