Terraform: ссылки на локальные значения внутри блока создания

Можно ли ссылаться на другое значение locals внутри создания значения locals?

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

variable "size" {
  default     = 3
}

variable "infrastructure_version" {
  default = 1
}

locals {
  values = {
    for n in range(var.size) : n => {
      name = "instance_${n + 1}"
      full_name = "test_${name}_v${var.infrastructure_version}"
    }
  }
}

При попытке доступа к название в цикле for внутри блока locals я получаю следующую ошибку:

│ Error: Invalid reference
│ 
│   on instances.tf line 13, in locals:
│   13:       full_name = "test_${name}_v${var.infrastructure_version}"
│ 
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.

Другие попытки: (Это были отчаянные попытки без реальных шансов на успех)

  • local.values[n].name что дает Error: Self-referencing local value
  • n.name что дает Error: Unsupported attribute
  • self.name что дает Error: Invalid "self" reference

Кто-нибудь знает, возможно ли это? Или я застрял, повторяя создание название и внутри ФИО?

full_name = "test_instance_${n + 1}_v${var.infrastructure_version}"

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
37
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваша последняя попытка верна. Вы не можете сделать это по-другому, и это работает:

 full_name = "test_instance_${n + 1}_v${var.infrastructure_version}"

Итак, вы говорите, что это невозможно. Последний пример не корректен, это всё-таки дублирование кода. Это выполняет цель в этом примере, который сильно упрощен.

kiabso 12.05.2022 13:25

@kiabso, последний пример правильный, и это единственный способ. Если вам не нравится дублирование кода, то, возможно, terraform не для вас, и вам следует поискать другой инструмент для инфраструктуры в качестве кода.

Marcin 12.05.2022 23:37

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

victor m 13.05.2022 04:29

@Marcin Я знаю, что это работает, хотя и не очень удобно. Но я прошу альтернативы. Например, функции, которые я обнаружил, не реализованы (пока?). Это была бы хорошая альтернатива

kiabso 13.05.2022 08:58

@victorm Я думаю, причина, по которой это не работает, заключается в том, что значение принадлежит карте, которая еще не построена. Но вы можете сделать locals { a = "foo", b = "${local.foo}_bar" }, поэтому не будет слишком надуманным, если что-то похожее на то, что я пытался сделать в своем исходном посте, сработает.

kiabso 13.05.2022 09:03

@kiabso Альтернативы нет. Я не уверен, что вы хотите сделать. Любой другой способ будет длиннее, если вы хотите ввести некоторые локальные списки.

Marcin 13.05.2022 09:17
Ответ принят как подходящий

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

Короткий пример ниже, он лучше подходит для более сложных и крупных приложений из-за больших накладных расходов.

main.tf: Из основного модуля я импортирую локальный модуль, который будет выполнять функции

module "instance_conf" {
  source = "./modules"
  count  = var.size

  index = count.index
  infra = var.infrastructure_version
}

locals {
  values = {for idx, val in module.instance_conf: idx => val}  
}

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

модули/func.tf:

variable "index" {
  type = number
}

variable "infra" {
  type = number
}

locals {
  name = "instance_${var.index + 1}"
}

output "name" {
  value = local.name
}
output "full_name" {
  value = "test_${local.name}_v${var.infra}"
}

Чтобы получить желаемый вывод в основной модуль, вычислите значения либо в блоке локальных переменных, либо непосредственно в блоке вывода. При импорте этого модуля значения будут доступны в виде списка карт для каждого count.index в основном модуле. count = var.size

Список может выглядеть так:

[
  {
    name: "instance_1",
    full_name: "test_instance_1_v1"
  },
  {
    name: "instance_2",
    full_name: "test_instance_2_v1"
  },
  ...
]

Итак, чтобы использовать вывод модуля, как и в предыдущем случае, с for_each, я преобразовал список объектов карты в карту с индексом каждого объекта карты в качестве ключа для этого объекта.

locals {
  values = {for idx, val in module.instance_conf: idx => val}  
}

И теперь при использовании local.values ​​это будет выглядеть так:

{
  "1": {
    name: "instance_1",
    full_name: "test_instance_1_v1"
  },
  "2": {
    name: "instance_2",
    full_name: "test_instance_2_v1"
  },
  ...
}

Теперь структура проекта выглядит так:

.
├── main.tf
├── modules
│   └── values_function.tf

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

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