Использование команд Terraform For_Each и For для фильтрации элементов

У меня есть файл Terraform locals.tf, подобный приведенному ниже фрагменту, который содержит определение моей среды.

locals {
    environments = [
    "dev", 
    "test", 
    "preprod",
    "prod"
   ]
}

Сейчас я хочу создать идентичный ресурс, в данном случае оповещение о метрике монитора Azure, для каждой из перечисленных сред (кроме prod). Я пытаюсь сделать это, используя цикл For_Each в блоке ресурсов моего main.tf файла, фрагмент которого показан ниже:

resource "azurerm_monitor_metric_alert" "main" {
  for_each = {
     [for s in toset(local.environments) : if s != "prod"] 
  }   
  name = "${each.key}-metric-alert"
  resource_group_name = azurerm_resource_group.rg.name
  scopes              = [azurerm_storage_account.to_monitor[each.key].id]
  [..........ADDITIONAL NON-PROD RESOURCE CONFIG...........]

Однако для рабочей среды оповещение монитора требует немного другого набора настроек, чем другие, поэтому я хотел бы отфильтровать эту среду из файла locals.tf, а затем, используя другой блок ресурсов azurerm_monitor_metric_alert, настроить его по строки приведенного ниже фрагмента:

   resource "azurerm_monitor_metric_alert" "main" {
      for_each = {
         [for s in toset(local.environments) : if s == "prod"] 
      } 
      name = "${each.key}-metric-alert"
      resource_group_name = azurerm_resource_group.rg.name
      scopes              = [azurerm_storage_account.to_monitor[each.key].id] 
      [..........ADDITIONAL PROD CONFIG...........]

Я пробовал описанные выше и другие реализации, но, к сожалению, просто не могу заставить это работать. Был бы очень признателен за помощь здесь.

Возможно, есть лучшие способы добиться того, чего вы хотите, в одном блоке ресурсов. Можете ли вы поделиться остальной конфигурацией для рабочей и непроизводственной версии?

Marko E 17.07.2024 13:38
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
Как установить LAMP Stack 1/2 на Azure Linux VM
Как установить LAMP Stack 1/2 на Azure Linux VM
В дополнение к нашему предыдущему сообщению о намерении Azure прекратить поддержку Azure Database для MySQL в качестве единого сервера после 16...
1
1
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы не указали, какую ошибку получаете, но в ваших циклах for отсутствует один аргумент:

[for s in toset(local.environments) : s if s != "prod"]

И:

[for s in toset(local.environments) : s if s == "prod"]

Также я не уверен, нужно ли вам это toset там. Возможно, потребуется поместить весь цикл for внутрь toset, а не local.environments.

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

Со следующим выражением возникает несколько различных проблем:

  for_each = {
     [for s in toset(local.environments) : if s != "prod"] 
  }
  1. В выражении for отсутствует предложение результата после двоеточия. Если вы намерены просто вернуть s напрямую, вы можете просто указать эту переменную между двоеточием и ключевым словом if:

    [for s in toset(local.environments) : s if s != "prod"] 
    
  2. Фигурные скобки {} вокруг этого выражения недействительны. Этот синтаксис предназначен для создания значения объектного типа, но для того, чтобы это работало, вам нужно указать атрибут, которому будет присвоен результат выражения for.

    Поскольку var.environments кажется просто набором строк, я ожидаю, что вы, вероятно, захотите создать набор строк напрямую, без какой-либо карты/объекта-обертки, например:

    for_each = toset([for s in local.environments : s if s != "prod"])
    
  3. Внутренний toset, который вы ранее использовали для local.environments, на самом деле здесь ничего не добавляет, потому что выражение for эффективно обрабатывает набор строк как список этих строк в лексическом порядке. Вы можете безопасно удалить его, как я сделал в своем последнем примере выше, и этого будет достаточно для данного конкретного использования `local.environments.

    Если вы хотите сообщить, что local.environments сам по себе семантически является набором — что может быть полезно будущим сопровождающим вашего модуля, пытающимся понять, что вы задумали, — тогда вы можете вместо этого поместить toset в определение локального значения:

    locals {
      environments = toset([
        "dev", 
        "test", 
        "preprod",
        "prod",
      ])
    }
    

    Однако это не повлияет на выражение for_each, о котором идет речь в этом вопросе, поэтому это будет значимым изменением только в том случае, если local.environments будет использоваться в других местах, которые также должны рассматривать его как набор, и это выходит за рамки этого вопроса.

Это просто гений Мартин Аткинс!! Я реализовал предложенное решение, и оно сработало блестяще => for_each = toset([for s in local.environments : s if s != "prod"]). Меня также привлекло ваше замечание относительно использования toset и local.environments. Хотелось бы увидеть пример того, как можно было бы преобразовать список local.environments с использованием toset и без него.

hitman126 20.07.2024 11:35

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