Terraform - Utilisez des boucles imbriquées avec count

19

J'essaie d'utiliser une boucle imbriquée dans terraform. J'ai deux variables de liste list_of_allowed_accountset list_of_images, et je cherche à parcourir la liste list_of_imagespuis à parcourir la liste list_of_allowed_accounts.

Voici mon code 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}"
}

Ceci est un équivalent bash de ce que j'essaie de faire.

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
la source

Réponses:

34

Terraform ne prend pas directement en charge ce type d'itération imbriquée, mais nous pouvons le simuler avec un peu d'arithmétique.

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

Puisque nous voulons créer un modèle de stratégie pour chaque combinaison de compte et de l' image, le countsur le template_filebloc de données est les deux ensemble multiplié. Nous pouvons ensuite utiliser les opérations de division et de modulo pour revenir des count.indexindex séparés dans chaque liste.

Étant donné que je n'avais pas de copie de votre modèle de stratégie, je viens d'utiliser un espace réservé; cette configuration a donc donné le plan suivant:

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

Chaque instance de stratégie s'applique à une paire différente d'ID et d'image de compte, couvrant toutes les combinaisons.

Martin Atkins
la source
2
Cela vous posera des problèmes si vous souhaitez étendre la configuration, comme ajouter un nouveau compte ou / et une image, que vos ressources mapperont sur différents index, mais si les supprimer et les recréer n'est pas un problème, cela fonctionne bien.
balazs
1
@ justin-grote a un point dans sa réponse: dans terraform 0.12, vous devrez utiliser la fonction floor partout où vous divisez, sinon vous obtiendrez une erreur sur les index partiels. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr
7

Les réponses ici fonctionnent (je les ai utilisées initialement), mais je pense que j'ai une meilleure solution en utilisant la fonction setproduct de Terraform . Je n'en ai pas vu beaucoup d'exemples utilisés autour des interwebs, mais setproduct prend deux ensembles (ou plus important encore, deux listes) et produit une liste d'ensembles avec chaque permutation des entrées. Dans mon cas, je crée des paramètres 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"] }
}

Cela crée des paramètres SSM nommés:

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

Mon petit cerveau wimpy peut analyser cela un peu plus facilement que la magie modulo dans les autres réponses!

Kyle
la source
Je vais essayer ta solution. Je suis d'accord, cela semble beaucoup mieux. Mais pourquoi utilisez-vous ${length(var.list1) * length(var.list2)}au lieu de ${length(local.product)}compter?
chriscatfr
Je vais devoir attendre que mon client commence à utiliser la v0.12 :( pas étonnant que vous n'ayez pas trouvé beaucoup de sources.
chriscatfr
Aucune raison, ${length(local.product)}fait probablement plus depuis. De plus, je suis assez certain qu'il setproduct()existe avant la 0.12, (le message en haut de la page liée n'est qu'un avertissement générique pour tous leurs documents 0.11, je pense?)
Kyle
4

Pour info si quelqu'un vient ici de Google, si vous utilisez terraform 0.12, vous devrez utiliser la fonction de plancher partout où vous divisez, sinon vous obtiendrez une erreur sur les index partiels.

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

Justin Grote
la source
J'aimerais avoir lu tout le long de la page SO pour découvrir ce joyau avant d'essayer l'approche mathématique. C'est ainsi que je l'ai fait fonctionner avec le sol (count.index / 8). Merci d'avoir posté.
bytejunkie
avec 0.12 setproduct () de la solution de @kyle semble plus facile.
chriscatfr
Si vous êtes sur Terraform 0,12, alors pourquoi ne pas utiliser les nouveaux ajoutés for, for_eachet / ou des constructions de langage de blocs imbriqués dynamiques pour mettre en œuvre quelque chose d' un peu moins confus?
TrinitronX
0

Fondamentalement, le problème réside dans les données "template_file", le account_id ne peut pas être défini comme vous le pensez, car le nombre dans votre cas est juste une autre variable qui n'est jamais incrémentée / modifiée. Je dis juste que je manque de voir quelle est votre question exactement.

IgorC
la source
0

Je n'ai pas assez de points de réputation pour ajouter un commentaire à la réponse fournie par @ Martin Atkins , donc je poste sa réponse avec une légère modification, qui contourne le problème 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]}"
} 
user9192156
la source