Terraform - Gunakan loop bersarang dengan hitungan

18

Saya mencoba menggunakan loop bersarang di terraform. Saya memiliki dua variabel daftar list_of_allowed_accountsdan list_of_images, dan mencari untuk beralih daftar list_of_imagesdan kemudian beralih daftar list_of_allowed_accounts.

Ini kode terraform saya.

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

Ini setara dengan bash dari apa yang saya coba lakukan.

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

Jawaban:

34

Terraform tidak memiliki dukungan langsung untuk iterasi bersarang semacam ini, tetapi kita dapat memalsukannya dengan aritmatika tertentu.

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

Karena kita ingin membuat template kebijakan untuk setiap kombinasi account dan gambar, countpada template_fileblok data adalah dua bersama-sama dikalikan. Kita kemudian dapat menggunakan operasi divisi dan modulo untuk kembali dari count.indexke indeks terpisah ke setiap daftar.

Karena saya tidak memiliki salinan template kebijakan Anda, saya hanya menggunakan placeholder; konfigurasi ini memberikan rencana berikut:

+ 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"

Setiap instance kebijakan berlaku untuk pasangan id dan gambar akun yang berbeda, mencakup semua kombinasi.

Martin Atkins
sumber
2
Akan Membuat Anda kesulitan jika Anda ingin memperpanjang konfigurasi, seperti menambahkan akun baru atau / dan gambar, daripada sumber daya Anda akan memetakan ke indeks yang berbeda, namun jika menghapus dan menciptakan kembali itu bukan masalah ini berfungsi dengan baik.
Balaz
1
@ justin-grote ada benarnya dalam jawabannya: di terraform 0.12 Anda akan perlu menggunakan fungsi lantai di mana saja Anda membagi, atau Anda akan mendapatkan kesalahan tentang indeks parsial. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr
7

Jawaban di sini berfungsi (saya awalnya menggunakannya), tapi saya pikir saya punya solusi yang lebih baik menggunakan fungsi setproduct Terraform . Saya belum melihat banyak contoh yang digunakan di sekitar jalinan, tetapi setproduct membutuhkan dua set (atau lebih penting, dua daftar) dan menghasilkan daftar set dengan setiap permutasi input. Dalam kasus saya, saya membuat parameter 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"] }
}

Ini menciptakan parameter SSM bernama:

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

Otak kecilku yang lemah bisa menguraikan ini sedikit lebih mudah daripada sihir modulo di jawaban lain!

Kyle
sumber
Saya akan mencoba solusi Anda. Saya setuju tampaknya jauh lebih baik. Tetapi mengapa Anda menggunakan ${length(var.list1) * length(var.list2)}bukan ${length(local.product)}untuk menghitung?
chriscatfr
Saya harus menunggu sampai pelanggan saya mulai menggunakan v0.12 :( tidak heran mengapa Anda tidak menemukan banyak sumber.
chriscatfr
Tanpa alasan, ${length(local.product)}mungkin menghasilkan lebih banyak sejak itu. Juga, saya cukup yakin setproduct()ada pra-0,12, (pesan di bagian atas halaman yang ditautkan hanyalah peringatan umum untuk semua dokumen 0,11 mereka, saya kira?)
Kyle
4

FYI jika ada yang datang ke sini dari Google, jika Anda menggunakan terraform 0.12, Anda harus menggunakan fungsi lantai di mana saja Anda membagi, atau Anda akan mendapatkan kesalahan tentang indeks parsial.

account_id = var.list_of_allowed_accounts [ lantai (count.index / panjang (var.list_of_images))]

Justin Grote
sumber
Saya berharap saya telah membaca sampai halaman SO untuk menemukan permata ini sebelum saya mencoba pendekatan matematika. Ini adalah bagaimana saya membuatnya bekerja dengan lantai (count.index / 8). Terima kasih telah memposting.
bytejunkie
dengan 0,12 setproduct () dari solusi @kyle sepertinya lebih mudah.
chriscatfr
Jika Anda menggunakan Terraform 0.12, mengapa tidak menggunakan konstruksi bahasa blok bersarang yang baru ditambahkan for, for_eachdan / atau dinamis untuk mengimplementasikan sesuatu yang sedikit membingungkan?
TrinitronX
0

Pada dasarnya masalahnya ada di data "template_file", account_id tidak dapat mengatur seperti yang Anda pikirkan karena hitungan dalam kasus Anda hanyalah var lain yang tidak pernah bertambah / diubah. Hanya mengatakan karena aku rindu untuk melihat apa pertanyaanmu sebenarnya.

IgorC
sumber
0

Saya tidak memiliki poin reputasi yang cukup untuk menambahkan komentar pada jawaban yang diberikan oleh @ Martin Atkins , jadi saya memposting jawabannya dengan sedikit modifikasi, yang bekerja di sekitar masalah 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]}"
} 
pengguna9192156
sumber