Terraform - Użyj zagnieżdżonych pętli z liczbą

19

Próbuję użyć zagnieżdżonej pętli w terraformie. Mam dwie zmienne listy list_of_allowed_accountsi list_of_images, i szukam iteracji po liście, list_of_imagesa następnie iteracji po liście list_of_allowed_accounts.

Oto mój kod 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}"
}

To jest odpowiednik tego, co próbuję zrobić.

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
źródło

Odpowiedzi:

34

Terraform nie ma bezpośredniego wsparcia dla tego rodzaju zagnieżdżonej iteracji, ale możemy ją sfałszować za pomocą pewnej arytmetyki.

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

Ponieważ chcemy, aby utworzyć szablon zasad dla każdej kombinacji rozliczeniowej i obrazu, countw template_filebloku danych jest dwa zwielokrotniony razem. Następnie możemy użyć operacji dzielenia i modulo, aby wrócić count.indexdo osobnych indeksów na każdej liście.

Ponieważ nie miałem kopii twojego szablonu polisy, właśnie użyłem zastępczego; ta konfiguracja dała następujący 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"

Każda instancja zasad dotyczy innej pary identyfikatora konta i obrazu, obejmujących wszystkie kombinacje.

Martin Atkins
źródło
2
Sprawi ci kłopoty, jeśli chcesz rozszerzyć konfigurację, na przykład dodać nowe konto lub / i obraz, niż twoje zasoby zostaną zmapowane do różnych indeksów, jednak jeśli ich usunięcie i ponowne utworzenie nie jest problemem, działa to dobrze.
balazs
1
@ justin-grote ma rację w swojej odpowiedzi: w terraformie 0.12 będziesz musiał użyć funkcji floor w dowolnym miejscu, w którym się podzielisz, w przeciwnym razie pojawi się błąd dotyczący indeksów częściowych. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr
7

Odpowiedzi tutaj działają (początkowo ich użyłem), ale myślę, że mam lepsze rozwiązanie, korzystając z funkcji setproduct firmy Terraform . Nie widziałem wielu przykładów tego użytych w interwebach, ale setproduct bierze dwa zestawy (a co ważniejsze, dwie listy) i tworzy listę zestawów przy każdej permutacji danych wejściowych. W moim przypadku tworzę parametry 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"] }
}

To tworzy parametry SSM o nazwie:

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

Mój wątły mózg może przeanalizować to trochę łatwiej niż magia modulo w innych odpowiedziach!

Kyle
źródło
Spróbuję twojego rozwiązania. Zgadzam się, że wydaje się znacznie lepiej. Ale dlaczego używasz ${length(var.list1) * length(var.list2)}zamiast ${length(local.product)}liczyć?
chriscatfr
Będę musiał czekać, aż mój klient zacznie korzystać z wersji 0.12 :( nic dziwnego, że nie znalazłeś wielu źródeł.
chriscatfr,
Bez powodu, ${length(local.product)}prawdopodobnie od tego czasu coś więcej. Poza tym jestem pewien, że setproduct()istnieje przed wersją 0.12 ( myślę , że wiadomość na górze połączonej strony jest tylko ogólnym ostrzeżeniem dla wszystkich dokumentów w wersji 0.11, tak myślę?)
Kyle
4

Do Twojej wiadomości, jeśli ktoś przyjdzie tutaj z Google, jeśli używasz terraformu 0.12, będziesz musiał użyć funkcji floor w dowolnym miejscu, w którym się podzielisz, w przeciwnym razie pojawi się błąd dotyczący indeksów częściowych.

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

Justin Grote
źródło
Chciałbym przeczytać całą stronę SO, aby odkryć ten klejnot, zanim spróbowałem matematyki. W ten sposób mam pracować z podłogą (count.index / 8). Dzięki za wysłanie.
bytejunkie
z 0.12 setproduct () z rozwiązania @kyle wydaje się łatwiejsze.
chriscatfr
Jeśli jesteś na Terraform 0,12, to dlaczego nie skorzystać z nowo dodane for, for_eachi / lub konstrukcje dynamiczne zagnieżdżone bloki językowe zaimplementować coś trochę mniej mylące?
TrinitronX
0

Zasadniczo problem tkwi w danych „file_file”, identyfikator_konta nie może być ustawiony tak, jak myślisz, ponieważ będzie to kolejna zmienna, która nigdy nie zostanie zwiększona / zmieniona. Tylko mówię, skoro tęsknię za tym, aby dokładnie zobaczyć, jakie jest twoje pytanie.

IgorC
źródło
0

Nie mam wystarczającej liczby punktów reputacji, aby dodać komentarz do odpowiedzi udzielonej przez @ Martina Atkinsa , więc zamieszczam jego odpowiedź z niewielką modyfikacją, która działa wokół numeru 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]}"
} 
użytkownik9192156
źródło