Terraform - использовать вложенные циклы с количеством


19

Я пытаюсь использовать вложенный цикл в Terraform. У меня есть две переменные списка list_of_allowed_accountsи list_of_images, и глядя на перебор списка, list_of_imagesа затем перебрать список list_of_allowed_accounts.

Вот мой терраформный код.

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

Это bash эквивалент того, что я пытаюсь сделать.

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

Ответы:


34

Terraform не имеет прямой поддержки для такого рода вложенных итераций, но мы можем подделать это с помощью некоторой арифметики.

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

Поскольку мы хотим создать шаблон политики для каждой комбинации учетной записи и изображения, count на template_fileблоке данных является двумя умноженными вместе. Затем мы можем использовать операции деления и по модулю, чтобы вернуться count.indexк отдельным индексам в каждом списке.

Так как у меня не было копии вашего шаблона политики, я просто использовал заполнитель; таким образом, эта конфигурация дала следующий план:

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

Каждый экземпляр политики применяется к разной паре идентификатора учетной записи и изображения, охватывающих все комбинации.


2
Это создаст проблемы, если вы захотите расширить конфигурацию, например, добавить новую учетную запись или / и изображение, тогда ваши ресурсы будут сопоставлены с другими индексами, однако, если удаление и воссоздание их не является проблемой, это прекрасно работает.
Балаз

1
У @ justin-grote есть ответ на свой вопрос: в terraform 0.12 вам нужно будет использовать функцию floor везде, где вы делите, иначе вы получите ошибку о частичных индексах. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

Ответы здесь работают (я использовал их изначально), но я думаю, что у меня есть лучшее решение, использующее функцию setproduct от Terraform . Я не видел много примеров его использования в паутинах, но setproduct берет два набора (или, что более важно, два списка) и создает список наборов с каждой перестановкой входных данных. В моем случае я создаю параметры 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"] }
}

Это создает параметры SSM с именем:

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

Мой слабый маленький мозг может разобрать это немного легче, чем магия по модулю в других ответах!


Я попробую ваше решение. Я согласен, что это кажется намного лучше. Но почему вы используете ${length(var.list1) * length(var.list2)}вместо ${length(local.product)}для подсчета?
chriscatfr

Мне придется подождать, пока мой клиент не начнет использовать v0.12 :( Не удивительно, почему вы не нашли много источников.
chriscatfr

Нет причин, ${length(local.product)}вероятно, делает больше с тех пор. Кроме того, я вполне уверен, что setproduct()существует до 0.12 (сообщение в верхней части связанной страницы является просто общим предупреждением для всех их документов 0.11, я думаю?)
Кайл

4

К вашему сведению, если кто-нибудь придет сюда из Google, если вы используете terraform 0.12, вам нужно будет использовать функцию floor в любом месте, где вы делите, иначе вы получите ошибку о частичных индексах.

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


Хотелось бы, чтобы я прочитал всю страницу SO, чтобы открыть этот драгоценный камень, прежде чем я попробую математический подход. Вот как я заставил его работать с полом (count.index / 8). Спасибо за публикацию.
bytejunkie

с 0.12 setproduct () из решения @kyle кажется проще.
chriscatfr

Если вы на терраформировать 0.12, то почему бы не использовать вновь добавленные for, for_eachи / или динамические вложенные блоки языковые конструкции , чтобы реализовать что - то чуть меньше толку?
TrinitronX

0

В основном проблема заключается в данных «template_file», account_id не может быть установлен так, как вы думаете, так как count в вашем случае - это просто еще одна переменная, которая никогда не будет увеличена / изменена. Просто говорю, потому что я скучаю, чтобы узнать, что именно ваш вопрос.


0

У меня недостаточно очков репутации, чтобы добавить комментарий к ответу, предоставленному @ Martin Atkins , поэтому я публикую его ответ с небольшим изменением, которое решает проблему 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]}"
} 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.