Условный динамический блок

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

Мой код:

переменные.tf:

variable "notification_channels" {
type = any
}

variable "project_id" {
type = string
}

main.tf:

project      = var.project_id
for_each     = { for k, v in var.notification_channels : k => v }
type         = each.value.type
display_name = each.value.display_name
description  = each.value.description
labels       = each.value.labels
enabled      = each.value.enabled

dynamic "sensitive_labels" {
for_each = each.value.sensitive_labels != {} ?[each.value.sensitive_labels] : []
content {
auth_token = lookup(sensitive_labels.value, "auth_token", null)
}
}
}

dev.tfvars:

notification_channels = [
{
type         = "email"
display_name = "a channel to send emails"
description  = "a nice channel"
labels = {
email_address = "[email protected]"
}
enabled          = true
sensitive_labels = {} // this one doesn't give any errors.
},
{
type         = "email"
display_name = "HeyThere Email"
description  = "a channel to send emails"
labels = {
email_address = "[email protected]"
}
enabled          = true
}
]

Получающий:

Ошибка: неподдерживаемый атрибут

в строке 11 notification_channels.tf в ресурсе "google_monitoring_notification_channel" "каналы": 11: for_each = каждое.значение.чувствительные_метки != {} ? [каждое.значение.чувствительные_метки]: [] │ ├──────────────── каждое.значение - это объект с 5 атрибутами

Этот объект не имеет атрибута с именем «sensive_labels».

Как я могу установить здесь чувствительные метки в качестве необязательного атрибута?

Обновлено: Кажется, это работает, но немного не так:

  project      = var.project_id
  for_each     = { for k, v in var.notification_channels : k => v }
  type         = each.value.type
  display_name = each.value.display_name
  description  = each.value.description
  labels       = each.value.labels
  enabled      = each.value.enabled

  dynamic "sensitive_labels" {
    for_each = lookup(each.value, "sensitive_labels", {})
    content {
      auth_token = lookup(sensitive_labels.value, "auth_token", null)
    }
  }
}

Есть ли лучший способ, который не кажется хакерским?

«Есть ли лучший способ, который не кажется хакерским?» почему вы думаете, что это "хакерский"?

Marcin 30.01.2023 03:37

Это выглядит так, как если бы for_each = lookup(each.value, "sensitive_labels", {}), хотя я устанавливаю чувствительные_метки с auth_token в tfvars, которые я получаю: │ Ошибка: неверная комбинация аргументов │ │ "sensive_labels.0 .auth_token": необходимо указать один из sensitive_labels.0.auth_token,sensitive_labels.0.password,se‌​nsitive_labels.0.ser‌​vice_key

MassHysteria 30.01.2023 10:26

Вы написали: «Кажется, это работает, но немного не так:». Если это работает, почему вы хотите изменить это?

Marcin 30.01.2023 10:32

Эй, Марчин. Я имел в виду, что пропуск меток чувствительных_меток в решении для поиска работает, но теперь я столкнулся с другой проблемой с auth_token = lookup(sensitive_labels.value, "auth_token", null), поскольку он игнорирует его, даже если я устанавливаю для него значение. Извините за недопонимание.

MassHysteria 30.01.2023 10:39

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

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

Ответы 1

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

Хорошее место для начала — правильно определить ограничение типа для вашей входной переменной, чтобы Terraform мог лучше понять, какая структура данных ожидается, и помочь гарантировать, что заданное значение соответствует этой структуре данных.

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

variable "notification_channels" {
  type = map(object({
    type             = string
    display_name     = string
    labels           = map(string)
    enabled          = bool
    sensitive_labels = object({
      auth_token  = string
      password    = string
      service_key = string
    })
  }))
}

Из вашего примера кажется, что вы хотите, чтобы sensitive_labels был необязательным, чтобы вызывающий модуль мог его опустить. В этом случае вы можете использовать модификатор optional при объявлении этого конкретного атрибута, а также трех атрибутов внутри него:

    sensitive_labels = optional(object({
      auth_token  = optional(string)
      password    = optional(string)
      service_key = optional(string)
    }))

Атрибут, помеченный как optional, может быть опущен вызывающей стороной, и в этом случае Terraform автоматически установит для него значение null внутри вашего модуля, чтобы показать, что он не был установлен.

Теперь вы можете использовать эту переменную в другом месте вашего модуля и с уверенностью предположить, что она всегда будет иметь именно тот тип, который определен в блоке variable:

resource "google_monitoring_notification_channel" "channels" {
  for_each     = var.notification_channels

  project      = var.project_id
  type         = each.value.type
  display_name = each.value.display_name
  description  = each.value.description
  labels       = each.value.labels
  enabled      = each.value.enabled

  dynamic "sensitive_labels" {
    for_each = each.value.sensitive_labels[*]
    content {
      auth_token  = sensitive_labels.value.auth_token
      password    = sensitive_labels.value.password
      service_key = sensitive_labels.value.service_key
    }
  }
}

Выражение each.value.sensitive_labels[*] — это выражение с платами, использующее функцию одиночных значений в виде списков, которая кратко преобразует заданное значение либо в список из одного элемента, либо в список из нулевого элемента, в зависимости от того, является ли значение нулевым. Фактически это означает, что будет один блок sensitive_labels, если each.value.sensitive_labels установлен, и ноль блоков этого типа, если этот атрибут не установлен (null).

Атрибуты внутри этих блоков также могут быть просто назначены напрямую без какой-либо специальной логики, потому что Terraform автоматически установит для них значение null, если оно не указано вызывающей стороной, а установка аргумента ресурса на null всегда равнозначна его полному отсутствию.

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

Эй, Мартин. Большое спасибо за подробное объяснение. Определенно имеет смысл.

MassHysteria 31.01.2023 10:11

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