Как я могу запустить for_each в terraform для идентификаторов группы ресурсов из нескольких источников? - PullRequest
2 голосов
/ 26 января 2020

Сначала я начал со следующего кода:

resource "azurerm_role_assignment" "pod_sp" {
    for_each = toset(concat(
        [for component in local.components: tostring(azurerm_resource_group.setup[component].id)],
        [tostring(module.component_remote_state.rg_id)]
        ))

    scope              = each.value
    role_definition_id = data.azurerm_role_definition.contributor.id
    principal_id       = azuread_service_principal.pod_sp.id
}

Это дало мне это:

Error: Invalid for_each set argument

  on ..\..\modules\bootstrap\to_inject.tf line 58, in resource "azurerm_role_assignment" "pod_sp":
  58:     for_each = toset(concat(
  59:         [for component in local.components: tostring(azurerm_resource_group.setup[component].id)],
  60:         [tostring(module.component_remote_state.rg_id)]
  61:         ))

The given "for_each" argument value is unsuitable: "for_each" supports maps
and sets of strings, but you have provided a set containing type dynamic.

Затем я нашел https://github.com/hashicorp/terraform/issues/22437 и изменил свой код для:

resource "azurerm_role_assignment" "pod_sp" {
    for_each = {for k in concat(
        [for component in local.components: tostring(azurerm_resource_group.setup[component].id)],
        [tostring(module.component_remote_state.rg_id)]
        ): k => k}

    scope              = each.value
    role_definition_id = data.azurerm_role_definition.contributor.id
    principal_id       = azuread_service_principal.pod_sp.id
}

, который дал мне это:

Error: Invalid for_each argument


  on ..\..\modules\bootstrap\to_inject.tf line 59, in resource "azurerm_role_assignment" "pod_sp":
  59:     for_each = {for k in concat(
  60:         [for component in local.components: tostring(azurerm_resource_group.setup[component].id)],
  61:         [tostring(module.component_remote_state.rg_id)]
  62:         ): k => k}

The "for_each" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the for_each depends on.

Я не понимаю, почему он говорит: «не могу предсказать», когда local.components очень известен:

locals {
    components = toset(["web", "data"])
}

Можно ли заставить его работать без необходимости сначала запускать приложение с целью?

1 Ответ

0 голосов
/ 28 января 2020

Непредсказуемая часть - это значения атрибута id из azurerm_resource_group.setup. Поскольку вы используете их в качестве некоторых ключей на своей карте, в результате получается карта, набор ключей которой не полностью известен, и, следовательно, Terraform не может определить, сколько элементов в конечном итоге будет на этой карте и какие будут все их ключи. be.

Чтобы это работало, я бы предложил вместо этого использовать в качестве ключей строки из local.components, поскольку вы отметили, что они являются константами в вашей конфигурации и, таким образом, гарантированно будут известны при планировании:

  for_each = merge(
    { for component in local.components : component => azurerm_resource_group.setup[component].id },
    { "from_remote_state" = module.component_remote_state.rg_id },
  )

Выше предполагается, что local.components никогда не будет содержать строку from_remote_state, и, таким образом, безопасно использовать в качестве имени специального компонента для работы с этим дополнительным значением, которое не работает так же, как другие , Поскольку вы понимаете требования для этого лучше, чем я, вы могли бы найти другое имя более подходящим там, но общая идея здесь состоит в том, чтобы создать карту, ключи которой всем известны, даже если некоторые значения не являются:

{
  "web": (known after apply),
  "data": (known after apply),
  "from_remote_state": "<your known rg id from the remote state>",
}

Исходя из этого, Terraform может видеть, сколько экземпляров ресурсов вы собираетесь создать и какими должны быть их адреса:

  • azurerm_role_assignment.pod_sp["web"]
  • azurerm_role_assignment.pod_sp["data"]
  • azurerm_role_assignment.pod_sp["from_remote_state"]
...