Terraform-カウントでネストされたループを使用する


18

Terraformでネストされたループを使用しようとしています。リスト変数は2つlist_of_allowed_accountsありlist_of_images、リストを反復処理してからリストlist_of_imagesを反復処理しますlist_of_allowed_accounts

これが私のテラフォームのコードです。

variable "list_of_allowed_accounts" {
  type    = "list"
  default = ["111111111", "2222222"]
}

variable "list_of_images" {
  type    = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    count = "${length(var.list_of_allowed_accounts)}"
    account_id = "${element(var.list_of_allowed_accounts, count.index)}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${length(var.list_of_images)}"
  repository = "${element(aws_ecr_repository.images.*.id, count.index)}"
  count = "${length(var.list_of_allowed_accounts)}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.rendered}"
}

これは、私がやろうとしていることに相当するbashです。

for image in alpine java jenkins
do 
  for account_id in 111111111 2222222
  do 
    // call template here using variable 'account_id' and 'image'
  done
done

回答:


34

Terraformはこの種のネストされた反復を直接サポートしていませんが、何らかの算術で偽造することができます。

variable "list_of_allowed_accounts" {
  type = "list"
  default = ["1111", "2222"]
}

variable "list_of_images" {
  type = "list"
  default = ["alpine", "java", "jenkins"]
}

data "template_file" "ecr_policy_allowed_accounts" {
  count = "${length(var.list_of_allowed_accounts) * length(var.list_of_images)}"

  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    account_id = "${var.list_of_allowed_accounts[count.index / length(var.list_of_images)]}"
    image      = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${data.template_file.ecr_policy_allowed_accounts.count}"

  repository = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.*.rendered[count.index]}"
}

アカウントと画像のすべての組み合わせに対してポリシーテンプレートを作成するためcounttemplate_fileデータブロック上の2つは乗算されます。次に、除算およびモジュロ演算を使用して、count.index各リストの個別のインデックスに戻ります。

ポリシーテンプレートのコピーがなかったため、プレースホルダーテンプレートを使用しました。したがって、この構成では次の計画を立てました。

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.0
    policy:     "policy allowing 1111 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.1
    policy:     "policy allowing 1111 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.2
    policy:     "policy allowing 1111 to access jenkins"
    repository: "jenkins"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.3
    policy:     "policy allowing 2222 to access alpine"
    repository: "alpine"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.4
    policy:     "policy allowing 2222 to access java"
    repository: "java"

+ aws_ecr_respository_policy.repo_policy_allowed_accounts.5
    policy:     "policy allowing 2222 to access jenkins"
    repository: "jenkins"

各ポリシーインスタンスは、アカウントIDと画像の異なるペアに適用され、すべての組み合わせをカバーします。


2
新しいアカウントや画像を追加するなど、リソースを別のインデックスにマッピングするよりも構成を拡張したい場合は問題が発生しますが、削除と再作成が問題にならない場合はこれで問題ありません。
バラーズ

1
@ justin-groteの答えは次のとおりです。terraform0.12では、除算を行う場所であればどこでもfloor関数を使用する必要があります。そうしないと、部分インデックスに関するエラーが発生します。account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

ここでの答えは機能します(最初に使用しました)が、Terraformのsetproduct関数を使用する方がより良い解決策があると思います。インターウェブで使用されている例はあまり見ていませんが、setproductは2つのセット(より重要なことには2つのリスト)を取り、入力のすべての順列でセットのリストを生成します。私の場合、SSMパラメーターを作成しています。

variable "list1" {
  type    = "list"
  default = ["outer1", "outer2"]
}

variable "list2" {
  type    = "list"
  default = ["inner1", "inner2", "inner3"]
}

locals {
  product = "${setproduct(var.list1, var.list2)}"
}

resource "aws_ssm_parameter" "params" {
  count     = "${length(var.list1) * length(var.list2)}"
  name      = "/${element(local.product, count.index)[0]}/${element(local.product, count.index)[1]}"
  type      = "String"
  value     = "somevalue"
  overwrite = false
  lifecycle { ignore_changes = ["value"] }
}

これにより、次の名前のSSMパラメーターが作成されます。

/outer1/inner1
/outer1/inner2
/outer1/inner3
/outer2/inner1
/outer2/inner2
/outer2/inner3

私の弱虫の小さな脳は、他の答えのモジュロマジックよりも少し簡単にこれを解析できます!


あなたの解決策を試してみます。はるかに良いようだ。しかし、なぜカウントの${length(var.list1) * length(var.list2)}代わりに使用するの${length(local.product)}ですか?
chriscatfr

お客様がv0.12の使用を開始するまで待つ必要があります:(なぜ多くのソースが見つからなかったのも不思議ではありません。
chriscatfr

理由はありません${length(local.product)}。また、setproduct()0.12より前に存在することはかなり確かです(リンクされたページの上部のメッセージは、0.11のドキュメントすべてに対する一般的な警告であると思いますか?)
Kyle

4

参考までに、Googleから誰かがここに来た場合、terraform 0.12を使用している場合は、分割する場所でfloor関数を使用する必要があります。そうしないと、部分インデックスに関するエラーが発生します。

account_id = var.list_of_allowed_accounts [ floor(count.index / length(var.list_of_images))]


数学のアプローチを試みる前に、SOページを最後まで読んでこのgemを見つけてほしい。これが、floor(count.index / 8)で動作するようになった方法です。投稿していただきありがとうございます。
バイトジャンキー

@kyleのソリューションの0.12 setproduct()を使用すると簡単に思えます。
chriscatfr

Terraform 0.12を使用している場合は、新しく追加されたforfor_eachおよび/または動的なネストされたブロックの言語構造を使用して、少し混乱の少ないものを実装してみませんか?
TrinitronX

0

基本的に、問題はデータ「template_file」にあります。この場合のカウントはインクリメント/変更されない単なる別の変数であるため、account_idを思いどおりに設定することはできません。私はあなたの質問が何であるかを正確に確認するのを逃しているので言っています。


0

@ Martin Atkinsが提供する回答にコメントを追加するのに十分な評判ポイントがないので、Terraformの問題20567を回避するために、少し修正して彼の回答を投稿しています。

variable "list_of_allowed_accounts" {
  type = "list"
  default = ["1111", "2222"]
}

variable "list_of_images" {
  type = "list"
  default = ["alpine", "java", "jenkins"]
}

# workaround for TF issue https://github.com/hashicorp/terraform/issues/20567
locals {
  policy_count = "${length(var.list_of_allowed_accounts) * length(var.list_of_images)}"
}

data "template_file" "ecr_policy_allowed_accounts" {
  count = "${local.policy_count}"

  template = "${file("${path.module}/ecr_policy.tpl")}"

  vars {
    account_id = "${var.list_of_allowed_accounts[count.index / length(var.list_of_images)]}"
    image      = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  }
}

resource "aws_ecr_repository_policy" "repo_policy_allowed_accounts" {
  count = "${local.policy_count}"

  repository = "${var.list_of_images[count.index % length(var.list_of_images)]}"
  policy = "${data.template_file.ecr_policy_allowed_accounts.*.rendered[count.index]}"
} 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.