Наследование значений из output.tf с условными ресурсами с использованием TF 0.12+

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

Вот мой модуль

resource "google_service_account" "service_account" {
  count        = var.enabled ? 1 : 0
  account_id   = var.account_id
  display_name = var.display_name
}

resource "google_project_iam_member" "service_account_roles" {
  count  = var.enabled ? length(var.roles) : 0
  role   = "roles/${element(var.roles, count.index)}"
  member = "serviceAccount:${google_service_account.service_account[0].email}"
}

resource "google_service_account_key" "service_account_key" {
  count              = var.enabled ? 1 : 0
  service_account_id = google_service_account.service_account[0].name
}

'output.tf' содержит следующее

output "private_decoded_key" {
  value = base64decode(
    element(
      concat(
        google_service_account_key.service_account_key.*.private_key,
        [""],
      ),
      0,
    ),
  )
  description = "The base 64 decoded version of the credentials"
}

Поскольку есть условие, что ни один из этих ресурсов не создается без флага enabled, мне пришлось обрабатывать это в TF 0.11.14 таким образом, и инструмент автообновления tf0.12 не внес здесь больших изменений.

Как я могу упростить это в Terraform 0.12.24, я попытался изменить вывод просто

value = base64decode(google_service_account_key.service_account_key[0].private_key)

Но проблема в том, что если соответствующий кластер kubernetes будет удален во время удаления, и возникнут ошибки на полпути из-за terraform, я не смогу очистить состояние terraform остальных ресурсов с помощью `terraform destroy'

Попытки преобразовать count в for_each, как показано ниже, привели к следующим ошибкам.

resource "google_service_account" "service_account" {
  # count        = var.enabled ? 1 : 0
  for_each     = var.enabled ? 1 : 0
  account_id   = var.account_id
  display_name = var.display_name
}

resource "google_project_iam_member" "service_account_roles" {
  # count  = var.enabled ? length(var.roles) : 0
  for_each = var.enabled ? toset(var.roles) : 0
  # role   = "roles/${element(var.roles, count.index)}"
  role     = "roles/${each.value}" 
  member   = "serviceAccount:${google_service_account.service_account[0].email}"
}
for_each = var.enabled ? toset(var.roles) : 0

The true and false result expressions must have consistent types. The given
expressions are set of dynamic and number, respectively.

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


comment
Я не уверен, что полностью понимаю вашу проблему. Но, насколько я понимаю, вы говорите о состоянии на выходе. Если да, то вы можете использовать depends_on с выходными значениями.   -  person m0hit    schedule 25.04.2020


Ответы (1)


В упомянутой вами версии terraform (0.12.24) вы должны иметь возможность использовать try() в вашем outputs.tf:

value = try(base64decode(google_service_account_key.service_account_key[0].private_key), "")

По умолчанию это будет "", если google_service_account_key.service_account_key[0].private_key не разрешимо по какой-либо причине; вы также можете по умолчанию использовать null, конечно.

Изменить/обновить. Чтобы ответить на вторую (отредактированную) часть вопроса:

Чтобы избавиться от ошибки, что обе стороны должны иметь одинаковый тип, нужно использовать [] как пустой набор вместо 0 при преобразовании в for_each:

for_each = var.enabled ? toset(var.roles) : []

Пожалуйста, обратите внимание на существующую инфраструктуру, так как вам нужно манипулировать файлом состояния при преобразовании из count в for_each, иначе terraform попытается уничтожить и создать ресурсы.

(Более подробно я расскажу об этом в третьей части серии статей о том, как писать модули терраформирования, над которыми я сейчас работаю. Вы можете найти часть 1 на носителе и часть 2 будут выпущены на следующей неделе. )

person mariux    schedule 25.04.2020
comment
Знаете ли вы, как решить задачу от подсчета до for_each, описанную выше? - person Shoaib Ahmed Nasir; 25.04.2020
comment
@ShoaibAhmedNasir обновил ответ, объясняя, как решить вашу проблему. - person mariux; 25.04.2020
comment
Можно ли использовать for_each для условных ресурсов? for_each = var.enabled ? 1 : 0, выдает ошибку. Заданное значение аргумента for_each не подходит: аргумент for_each должен быть картой или набором строк, а вы предоставили значение типа number. - person Shoaib Ahmed Nasir; 25.04.2020
comment
@ShoaibAhmedNasir сегодня вы найдете три типа ресурсов в терраформе (как описано в моей связанной статье): отдельные ресурсы, массовые ресурсы с count и массовые ресурсы с for_each .. нет смысла заменять все count на for_each только для ради использования for_each.. так что имеет смысл посмотреть, как ресурс будет расширяться/использоваться в будущем.. для отдельных ресурсов я бы оставил его с count, чтобы включить/отключить их. если вы знаете, что это скоро будет использоваться как массовый ресурс, попробуйте сделать его for_each, если только ключи не зависят от вычисляемых значений. - person mariux; 26.04.2020