Terraform - Sayılı iç içe döngüler kullan


19

Terraform iç içe bir döngü kullanmaya çalışıyorum. İki liste değişkenleri var list_of_allowed_accountsve list_of_imagesliste üzerinde yineleme list_of_imagesve sonra liste üzerinde yineleme list_of_allowed_accounts.

İşte benim terraform kodum.

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

Bu, yapmaya çalıştığım şeyin bash eşdeğeri.

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

Yanıtlar:


34

Terraform'un bu tür iç içe yineleme için doğrudan desteği yoktur, ancak bazı aritmetikle taklit edebiliriz.

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

Her hesap ve resim kombinasyonu için bir politika şablonu oluşturmak istediğimizden count, template_fileveri bloğundaki ikisi birlikte çoğaltılır. Daha sonra count.indexher bir listeye ayrı indekslerden geri dönmek için bölme ve modulo işlemlerini kullanabiliriz .

Politika şablonunuzun bir kopyasına sahip olmadığım için yer tutucu bir tane kullandım; bu yapılandırma böylece aşağıdaki planı verdi:

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

Her ilke örneği, tüm kombinasyonları kapsayan farklı bir çift hesap kimliği ve resmi için geçerlidir.


2
Yeni bir hesap veya / ve resim eklemek gibi yapılandırmayı genişletmek istiyorsanız, kaynaklarınız farklı dizinlerle eşleşirse sorun çıkarır, ancak bunları silmek ve yeniden oluşturmak bir sorun değilse bu işe yarar.
balazlar

1
@ justin-grote'nin cevabında bir nokta var: terraform 0.12'de böl işlevini böldüğünüz herhangi bir yerde kullanmanız gerekecek, yoksa kısmi dizinler hakkında bir hata alacaksınız. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

Buradaki cevaplar işe yarıyor (başlangıçta kullandım), ancak Terraform'un setproduct işlevini kullanarak daha iyi bir çözüm bulduğumu düşünüyorum . Ben interwebs çevresinde kullanılan birçok örnek görmedim, ancak setproduct iki set (veya daha da önemlisi, iki liste) alır ve girişlerin her permütasyon ile setlerin bir listesini üretir. Benim durumumda SSM parametreleri oluşturuyorum:

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

Bu, şu şekilde adlandırılan SSM parametrelerini oluşturur:

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

Wimpy küçük beynim bunu diğer cevaplardaki modulo büyüsünden biraz daha kolay ayrıştırabilir!


Çözümünü deneyeceğim. Çok daha iyi göründüğüne katılıyorum. Ama neden saymak ${length(var.list1) * length(var.list2)}yerine kullanıyorsunuz ${length(local.product)}?
chriscatfr

Müşterim v0.12'yi kullanmaya başlayana kadar beklemek zorunda kalacağım :( neden fazla kaynak bulamadığınızı merak
etmeyin

Sebep yok, ${length(local.product)}muhtemelen o zamandan beri daha fazlasını yapar. Ayrıca, setproduct()0.12 öncesi var olduğundan eminim (bağlantılı sayfanın üstündeki mesaj sadece 0.11 dokümanı için genel bir uyarıdır, sanırım?)
Kyle

4

FYI, Google'dan buraya gelirse, terraform 0.12 kullanıyorsanız, böl işlevini bölündüğünüz herhangi bir yerde kullanmanız gerekir, aksi takdirde kısmi dizinler hakkında bir hata alırsınız.

account_id = var.list_of_allowed_accounts [ kat (count.index / uzunluk (var.list_of_images) var)]


Ben matematik yaklaşımı denemeden önce bu gem keşfetmek için SO sayfa aşağı tüm yolu okumak isterdim. Bu şekilde zeminle çalışmayı başardım (count.index / 8). Gönderdiğiniz için teşekkürler.
bytejunkie

0.12 setproduct () ile @kyle 'nin çözümünden daha kolay görünüyor.
chriscatfr

Eğer Terraform 0.12 kullanıyorsanız, o zaman neden yeni eklenen kullanmayın for, for_eachkafa karıştırıcı biraz daha az şey uygulamak ve / veya dinamik iç içe bloklar dil yapıları?
TrinitronX

0

Temelde sorun "template_file" verilerindedir, hesap_kimliği, durumunuzdaki sayım hiçbir zaman artmayan / değiştirilmeyen başka bir değişken olduğundan düşündüğünüz şekilde ayarlanamaz. Sorunuzun tam olarak ne olduğunu görmeyi özlediğimden beri söylüyorum.


0

@ Martin Atkins tarafından verilen yanıta yorum eklemek için yeterli itibar puanım yok , bu yüzden cevabını Terraform 20567 sayısında çalışan hafif bir değişiklikle gönderiyorum.

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]}"
} 
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.