Terraform 0.12 вложенные циклы for

Я пытаюсь реализовать вложенные циклы for, используя новые функции Terraform 0.12, чтобы зацикливаться на пользователях AWS IAM, к каждому из которых может быть прикреплена одна или несколько политик. Переменная, используемая для представления этого списка, имеет тип map(list(string)) и выглядит примерно так:

{
  "user 1" = [ "policy1", "policy2" ],
  "user 2" = [ "policy1" ]
}

Получить список пользователей для создания достаточно просто с помощью keys(), но поскольку в настоящее время в Terraform нет механизма вложения зацикленных ресурсов, вложения политики должны выполняться как отдельный цикл, независимый от каждого пользователя. Итак, я пытаюсь создать список ассоциаций пользователя: политика из ввода карты, который будет выглядеть примерно так, основываясь на приведенном выше примере:

[
  [ "user1", "policy1" ],
  [ "user1", "policy2" ],
  [ "user2", "policy1" ]
]

Я пытаюсь создать этот список и сохранить его в локальной переменной, например, где var.iam-user-policy-map — входная карта:

locals {
  ...
  association-list = [
    for user in keys(var.iam-user-policy-map):
    [
      for policy in var.iam-user-policy-map[user]:
      [user, policy]
    ]
  ]
  ...
}

Однако я получаю ошибки при попытке доступа к значениям в этом вложенном списке. Я пытаюсь получить доступ к пользовательской части ассоциации со ссылкой local.association-list[count.index][0] и к политике со ссылкой local.association-list[count.index][1], но при запуске terraform plan возникает ошибка:

Error: Incorrect attribute value type

  on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
  27:   user = local.association-list[count.index][0]

Inappropriate value for attribute "user": string required.


Error: Incorrect attribute value type

  on main.tf line 27, in resource "aws_iam_user_policy_attachment" "test-attach":
  27:   user = local.association-list[count.index][0]

Inappropriate value for attribute "user": string required.


Error: Invalid index

  on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
  28:   policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
    |----------------
    | count.index is 0
    | local.association-list is tuple with 2 elements

The given key does not identify an element in this collection value.


Error: Invalid template interpolation value

  on main.tf line 28, in resource "aws_iam_user_policy_attachment" "test-attach":
  28:   policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index][1]}"
    |----------------
    | count.index is 1
    | local.association-list is tuple with 2 elements

Cannot include the given value in a string template: string required.

Что я делаю неправильно?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
24
0
37 243
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Выражение for в вашем локальном значении association-list создает список из списков списков строк, но ваши ссылки на него обрабатывают его как список списков строк.

Чтобы получить желаемое плоское представление, вы можете использовать функцию flatten, но, поскольку в противном случае она сгруппирует все в плоский список Один, я бы рекомендовал вместо этого сделать самое внутреннее значение объектом. (Это также сделает ссылки на него более понятными.)

locals {
  association-list = flatten([
    for user in keys(var.iam-user-policy-map) : [
      for policy in var.iam-user-policy-map[user] : {
        user   = user
        policy = policy
      }
    ]
  ])
}

Результат этого выражения будет иметь следующий вид:

[
  { user = "user1", policy = "policy1" },
  { user = "user1", policy = "policy2" },
  { user = "user2", policy = "policy2" },
]

Тогда ваши ссылки на него могут быть в следующей форме:

user = local.association-list[count.index].user
policy_arn = "arn:aws-us-gov:iam::aws:policy/${local.association-list[count.index].policy}"

Я думаю, что это лучший дизайн, чем я изначально предполагал, спасибо.

ViggyNash 09.05.2019 22:15

здесь есть еще одна проблема, заключающаяся в том, что на числовые элементы влияют изменения элементов в списке. Если у вас есть несколько вложений политики, и вы изменили одно из них, terraform покажет изменения в других вложениях политики, которые вы не изменили, поскольку он переупорядочил список. Использование for_each в модуле приведет к ключевым элементам, на которые ссылаются, например. module.iam-policy-attachments.aws_iam_role_policy_attachment‌​.role_policy["policy‌​_name"] вместо module.iam-policy-attachments.aws_iam_role_policy_attachment‌​.role_policy[1], поэтому одно изменение политики не повлияет на другие

nick fox 26.02.2020 17:35

здесь есть хорошее объяснение blog.gruntwork.io/…

nick fox 26.02.2020 17:41

В официальных документах есть очень полезный пример, который объясняет, как использовать это, а затем создать из него карту, которую вы можете использовать с for_each: terraform.io/docs/language/functions/…

Matt Browne 13.04.2021 21:17

Если вам нужна карта для 'for_each', 'merge' удобен.

variable "iam-user-policy-map" {
  default = {
    "user 1" = ["policy1", "policy2"],
    "user 2" = ["policy1"]
  }
}

locals {
  association-map = merge([
    for user, policies in var.iam-user-policy-map : {
      for policy in policies :
        "${user}-${policy}" => {
          "user"   = user
          "policy" = policy
        }
    }
  ]...)
}

output "association-map" {
  value = local.association-map
}

Выходы:

association-map = {
  "user 1-policy1" = {
    "policy" = "policy1"
    "user" = "user 1"
  }
  "user 1-policy2" = {
    "policy" = "policy2"
    "user" = "user 1"
  }
  "user 2-policy1" = {
    "policy" = "policy1"
    "user" = "user 2"
  }
}

Пример использования for_each:

resource "null_resource" "echo" {
  for_each = local.association-map
  provisioner "local-exec" {
    command = "echo 'policy - ${each.value.policy}, user - ${each.value.user}'"
  }
}

https://github.com/hashicorp/terraform/issues/22263#issuecomment-969549347

Другие вопросы по теме