Terraform - Verwenden Sie verschachtelte Schleifen mit count


18

Ich versuche, eine verschachtelte Schleife in Terraform zu verwenden. Ich habe zwei Listenvariablen list_of_allowed_accountsund list_of_imagesund suche, über Liste zu iterieren list_of_imagesund dann über Liste zu iterieren list_of_allowed_accounts.

Hier ist mein Terraform-Code.

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

Dies ist ein bash-Äquivalent zu dem, was ich versuche zu tun.

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

Antworten:


34

Terraform hat keine direkte Unterstützung für diese Art von verschachtelter Iteration, aber wir können sie mit ein wenig Arithmetik vortäuschen.

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

Da wir für jede Kombination aus Konto und Bild eine Richtlinienvorlage erstellen möchten, werden die beiden countim template_fileDatenblock miteinander multipliziert. Wir können dann die Divisions- und Modulo-Operationen verwenden, um count.indexzu den einzelnen Indizes in jeder Liste zurückzukehren.

Da ich keine Kopie Ihrer Richtlinienvorlage hatte, habe ich nur eine Platzhaltervorlage verwendet. Diese Konfiguration ergab somit den folgenden Plan:

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

Jede Richtlinieninstanz gilt für ein anderes Paar von Konto-ID und Image und deckt alle Kombinationen ab.


2
Wenn Sie die Konfiguration erweitern möchten, z. B. ein neues Konto oder / und ein Bild hinzufügen, werden Ihre Ressourcen unterschiedlichen Indizes zugeordnet. Wenn das Löschen und Neuerstellen dieser Indizes jedoch kein Problem darstellt, funktioniert dies problemlos.
Balazs

1
@ justin-grote hat einen Punkt in seiner Antwort: In terraform 0.12 müssen Sie die Floor-Funktion überall dort verwenden, wo Sie dividieren. Andernfalls erhalten Sie eine Fehlermeldung zu Teilindizes. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

Die Antworten hier funktionieren (ich habe sie anfangs verwendet), aber ich denke, ich habe eine bessere Lösung, wenn ich die SetProduct- Funktion von Terraform verwende . Ich habe nicht viele Beispiele dafür gesehen, die in den Interwebs verwendet wurden, aber setproduct benötigt zwei Mengen (oder, was noch wichtiger ist, zwei Listen) und erstellt eine Liste von Mengen mit jeder Permutation der Eingaben. In meinem Fall erstelle ich SSM-Parameter:

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

Dadurch werden die folgenden SSM-Parameter erstellt:

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

Mein schwaches kleines Gehirn kann dies ein wenig einfacher analysieren als die Modulo-Magie in den anderen Antworten!


Ich werde deine Lösung versuchen. Ich stimme zu, es scheint weitaus besser zu sein. Aber warum benutzt du ${length(var.list1) * length(var.list2)}statt ${length(local.product)}für die Zählung?
chriscatfr

Ich muss warten, bis mein Kunde v0.12 verwendet :( Kein Wunder, dass Sie nicht viele Quellen gefunden haben.
chriscatfr

Kein Grund, ${length(local.product)}macht wohl mehr da. Ich bin mir auch ziemlich sicher, dass setproduct()es vor 0.12 existiert (die Meldung oben auf der verlinkten Seite ist nur eine allgemeine Warnung für alle 0.11-Dokumente, denke ich?)
Kyle,

4

Zu Ihrer Information, wenn jemand von Google hierher kommt, wenn Sie terraform 0.12 verwenden, müssen Sie die Floor-Funktion überall dort verwenden, wo Sie unterteilen. Andernfalls wird eine Fehlermeldung zu Teilindizes angezeigt.

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


Ich wünschte, ich würde die ganze SO-Seite durchlesen, um dieses Juwel zu entdecken, bevor ich den mathematischen Ansatz ausprobierte. So habe ich es zum Arbeiten mit dem Boden gebracht (count.index / 8). Danke fürs Schreiben.
Bytejunkie

mit 0.12 scheint setproduct () aus @kyles Lösung einfacher.
chriscatfr

Wenn Sie auf Terraforming 0,12 sind, warum dann nicht verwenden , um die neu hinzugekommenen for, for_eachund / oder dynamische verschachtelte Konstrukte Blöcke Sprache etwas weniger zu implementieren verwirrend?
TrinitronX

0

Grundsätzlich liegt das Problem in der Datei "template_file". Die account_id kann nicht so gesetzt werden, wie Sie es sich vorstellen, da die Zählung in Ihrem Fall nur eine andere Variable ist, die niemals inkrementiert / geändert wird. Ich sage nur, da ich vermisse zu sehen, was genau deine Frage ist.


0

Ich habe nicht genug Reputationspunkte, um der Antwort von @ Martin Atkins einen Kommentar hinzuzufügen. Daher veröffentliche ich seine Antwort mit einer geringfügigen Änderung, die das Terraform-Problem 20567 betrifft

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]}"
} 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.