web-dev-qa-db-ja.com

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

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

これが私のterraformコードです。

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
22
vikas027

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]}"
}

アカウントと画像のすべての組み合わせに対してポリシーテンプレートを作成する必要があるため、template_fileデータブロックのcountは、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と画像の異なるペアに適用され、すべての組み合わせをカバーします。

37
Martin Atkins

ここでの答えは機能します(私は最初にそれらを使用しました)が、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

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

8
Kyle

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

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

5
Justin Grote

@ 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]}"
} 
0
user9192156

基本的に問題はデータ「template_file」にあります。ケースのカウントは増分または変更されることのない別の変数であるため、account_idは想定どおりに設定できません。ちょうどあなたの質問が何であるかを正確に見逃しているので言っています。

0
IgorC