Terraform - Використовуйте вкладені петлі з підрахунком


19

Я намагаюся використовувати вкладену петлю в тераформі. У мене є два список змінних 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}"
}

Це баш-еквівалент того, що я намагаюся зробити.

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 є відповідь: у тераформі 0,12 вам потрібно буде використовувати функцію підлоги в будь-якому місці поділу, інакше ви отримаєте помилку щодо часткових індексів. account_id = var.list_of_allowed_accounts[floor(count.index / length(var.list_of_images))]
chriscatfr

7

Відповіді тут діють (я їх використовував спочатку), але я думаю, що в мене є краще рішення за допомогою функції setform продукту 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

FYI, якщо хтось приходить сюди з Google, якщо ви використовуєте Terraform 0,12, вам потрібно буде використовувати функцію підлоги в будь-якому місці, де ви ділитеся, інакше ви отримаєте помилку щодо часткових індексів.

account_id = var.list_of_allowed_accounts [ пол (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 не може бути встановлений так, як ви думаєте, так як це вважається, оскільки підрахунок у вашому випадку є лише іншим var, який ніколи не збільшується / змінюється. Щойно кажу, оскільки я сумую, щоб точно зрозуміти, у чому полягає ваше питання.


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.