Terraform ссылается на вывод из другого модуля с помощью for_each

У меня возникли проблемы со ссылкой на вывод из модуля в другом модуле. Ресурсы в первом модуле были развернуты с помощью for_each. Ресурсы во втором модуле пытаются ссылаться на ресурсы из первого модуля.

Создано 2 модуля

  1. Группа безопасности
  2. ВМ

Цель состоит в том, чтобы назначить группу безопасности для виртуальной машины.

Ниже приведен модуль для группы безопасности.


variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      name              = "Office",
      priority          = "100"
      direction         = "Inbound"
      access            = "Allow"
      protocol          = "TCP"
      source_port_range = "*"
      destination_port_ranges = [
        "22"]
      source_address_prefix = "192.168.1.100"
      destination_address_prefixes = [
        module.configserver_vm[each.key].private_ip
      ]
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

Источник модуля группы безопасности имеет выходной файл, который выводит идентификатор nsg.

output "nsg_id" {
  description = "The ID of the newly created Network Security Group"
  value       = azurerm_network_security_group.nsg.id
}

Как правило, если for_each отсутствует, я мог бы получить доступ к nsg_id следующим образом.

module.configserver_nsg.id

Пока это хорошо, теперь проблема в том, что я не могу получить доступ к nsg_id из другого модуля.

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.key].nsg_id
}

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

nsg_id             = module.configserver_nsg[each.key].nsg_id

это вызывает ошибку

Error: Cycle: module.configserver_nsg (close), module.configserver_vm.var.nsg_id (expand), module.configserver_vm.azurerm_network_interface_security_group_association.this, module.configserver_vm (close), module.configserver_nsg.var.security_rules (expand), module.configserver_nsg.azurerm_network_security_group.nsg, module.configserver_nsg.output.nsg_id (expand)

Есть ли другой способ сослаться на значение?

Привет. Может есть смысл запаковать логику for_each внутрь модуля? Я имею в виду предоставить var.configserver и module.configserver_nsg в качестве входных переменных для модуля и вместо этого использовать for_each для ресурсов внутри модуля "../../../terraform/modules/azure-linux-vm". Или есть проблема с этим подходом?

Fedor Petrov 10.12.2020 16:51

Ошибка подразумевает, что у вас есть циклическая зависимость, которую вам нужно сначала распутать.

Matt Schuchard 10.12.2020 20:35

@FedorPetrov Разве это не означает, что теперь нам нужно создать единый модуль для виртуальной машины и группы безопасности? Дайте мне знать, правильно ли я понимаю это. Мы бы предпочли иметь отдельные модули для виртуальных машин и групп безопасности, чтобы их можно было использовать повторно.

zeroweb 11.12.2020 05:09

@MattSchuchard да, верно, после просмотра файла состояния terraform я вижу некоторую зависимость, и похоже, что вызов зависимости идет как цикл, на который жалуется terraform. Я не совсем уверен, как справиться с этим. Это работает, если я не вызываю модуль в цикле for_each. Все еще смотрю на это

zeroweb 11.12.2020 05:11

Есть ли еще обновления по этому вопросу? Это решает вашу проблему? Если это решит вашу проблему, пожалуйста, примите это.

Charles Xu 24.12.2020 10:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
6 624
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

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

nsg_id             = module.configserver_nsg[each.value.name].nsg_id

И вторая проблема была упомянута @Matt. Это циклическая зависимость между двумя модулями. Вещь, которая создает циклическую зависимость, — это правило NSG, кажется, что для правила NSG требуется частный IP-адрес виртуальной машины. Насколько мне известно, вы не можете решить циклическую зависимость, если не вносите изменения. Поэтому я рекомендую вам внести изменение, отделяющее правило NSG от модуля configserver_nsg, и вместо этого использовать ресурс azurerm_network_security_rule после двух модулей.

И, наконец, это выглядит так:

variable "configserver" {
  type = map(object({
    name              = string
    location          = string
    subnet            = string
    availability_zone = string
    vm_size           = string
    hdd_size          = string
  }))
}


module "configserver_nsg" {
  for_each = var.configserver

  source              = "../../../terraform/modules/azure-network-security-group"
  resource_group_name = var.resource_group_name
  tags                = var.tags
  location = each.value.location
  nsg_name = "${each.value.name}-nsg"

  security_rules = [
    {
      
    },
    

    {
      name                       = "Deny-All-Others"
      priority                   = 4096
      direction                  = "Inbound"
      access                     = "Deny"
      protocol                   = "*"
      source_port_range          = "*"
      destination_port_range     = "*"
      source_address_prefix      = "*"
      destination_address_prefix = "*"
    }

  ]
}

// Value


configserver = {
  config1 = {
    name              = "config1"
    location          = "eastus"
    subnet            = "services"
    availability_zone = 1
    vm_size           = "Standard_F2s_v2"
    hdd_size          = 30
  }
}

module "configserver_vm" {
  for_each = var.configserver

  source         = "../../../terraform/modules/azure-linux-vm"
  resource_group = module.resource_group.name
  ssh_public_key = var.ssh_public_key
  tags           = var.tags
  vm_name            = each.value.name
  location           = each.value.location
  subnet_id          = each.value.subnet
  availability-zones = each.value.availability_zone
  vm_size            = each.value.vm_size
  hdd-size           = each.value.hdd_size
  nsg_id             = module.configserver_nsg[each.value.name].nsg_id
}

resource "azurerm_network_security_rule" "configserver_nsg" {
  for_each = var.configserver
  name              = "Office",
  priority          = "100"
  direction         = "Inbound"
  access            = "Allow"
  protocol          = "TCP"
  source_port_range = "*"
  destination_port_ranges = ["22"]
  source_address_prefix = "192.168.1.100"
  destination_address_prefixes = [
    module.configserver_vm[each.key].private_ip
  ]
  resource_group_name         = var.resource_group_name
  network_security_group_name = "${each.value.name}-nsg"
}

Привет, почему не module.configserver_nsg[each.key].nsg_id, а module.configserver_nsg[each.value.name].nsg_id? Я не понимаю, почему на модуль ссылаются по имени, а не по ключу.

Sam Kah Chiin 19.05.2022 07:24

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