Error de terraform con bloque dinámico en for_each

Sep 09 2020

Estoy intentando crear una instancia de un mapa celeste storage_share utilizando el recurso azuremrm storage_share . Por diseño, necesito poder instanciar más de un recurso compartido de almacenamiento con el mismo bloque; cada una de esas acciones puede tener o no una sección "acl".

Estaba pensando en resolver este problema usando un for_each junto con un bloque dinámico, como en la pregunta SE relacionada:

Main.tf

resource "azurerm_storage_share" "storage_share" {
  for_each             = var.storage_share_map
  name                 = each.key
  storage_account_name = azurerm_storage_account.sa.name
  quota                = each.value.quota

  dynamic "acl" {
    for_each = each.value.acl
    content {
      id = acl.value.id

      access_policy {
        permissions = acl.value.access_policy.permissions
        start       = acl.value.access_policy.start
        expiry      = acl.value.access_policy.expiry
      }
    }
  }

La variable se definiría como:

variable "storage_share_map" {
  type = map(object({
    quota = number,
    acl = object({
      id = string,
      access_policy = object({
        expiry      = string,
        permissions = string,
        start       = string
      })
    }),
  }))
  default     = {}
}

y luego parametrizado en mis pruebas como:

storage_share_map = { 
  my-share-2 = {
    quota = 123,
    acl = {
      id = "a-id",
      access_policy = {
        expiry      = "ISO8061 UTC TIME"
        permissions = "rwdl"
        start       = "ISO8601 UTC TIME"
      },
    },
  }

Sin embargo, al realizar pruebas, terraform devuelve el siguiente resultado:

Error: Unsupported attribute

  on .terraform\modules\sa\main.tf line 83, in resource "azurerm_storage_share" "storage_share":
  83:       id = acl.value.id
    |----------------
    | acl.value is object with 3 attributes

This object does not have an attribute named "id".


Error: Unsupported attribute

  on .terraform\modules\sa\main.tf line 83, in resource "azurerm_storage_share" "storage_share":
  83:       id = acl.value.id
    |----------------
    | acl.value is "a-id"

This value does not have any attributes.


Error: Unsupported attribute

  on .terraform\modules\sa\main.tf line 86, in resource "azurerm_storage_share" "storage_share":
  86:         permissions = acl.value.access_policy.permissions
    |----------------
    | acl.value is object with 3 attributes

This object does not have an attribute named "access_policy".


Error: Unsupported attribute

  on .terraform\modules\sa\main.tf line 86, in resource "azurerm_storage_share" "storage_share":
  86:         permissions = acl.value.access_policy.permissions
    |----------------
    | acl.value is "a-id"

This value does not have any attributes.

Según tengo entendido, el problema aquí es que for_each dentro del bloque dinámico está mal formado o se comporta mal: acl.value parece estar valorado como la cadena "a-id" y llevar tres atributos (?).

Terraform versión 0.12.26 Azurerm versión 2.26.0

Cualquier idea sería apreciada.

Pregunta relacionada: Bloque dinámico con for_each dentro de un recurso creado con for_each

Respuestas

3 MattSchuchard Sep 09 2020 at 23:33

Al iterar en el bloque dinámico con for_each = each.value.acl, está iterando sobre los valores del objecttipo. Parece que realmente desea iterar sobre aclellos mismos. Debería ajustar su tipo a:

variable "storage_share_map" {
  type = map(object({
    quota = number,
    acl = list(object({
      ...
    }))
  })),
}

Puede saber por los mensajes de error que actualmente está iterando idy luego access_policy, y no encuentra los dos atributos solicitados para cada uno, por lo que tiene 2 * 2 = 4 errores.

Puede ajustar su entrada correspondientemente a:

storage_share_map = { 
  my-share-2 = {
    quota = 123,
    acl = [{
      id = "a-id",
      access_policy = {
        expiry      = "ISO8061 UTC TIME"
        permissions = "rwdl"
        start       = "ISO8601 UTC TIME"
      },
    }],
  }

y esto logrará el comportamiento que desea.

Tenga en cuenta que Terraform 0.12 tiene problemas a veces con las especificaciones de tipo de objeto anidado, por lo que omitir el aclcon []puede provocar fallas en determinadas circunstancias.

3 adp Sep 09 2020 at 21:39

Utilice corchetes para each.value.acl.

El bloque de recursos compartidos de Azure Storage debería verse así:

resource "azurerm_storage_share" "storage_share" {
  for_each             = var.storage_share_map
  name                 = each.key
  storage_account_name = azurerm_storage_account.sa.name
  quota                = each.value.quota

  dynamic "acl" {
    for_each = [each.value.acl]
    content {
      id = acl.value.id

      access_policy {
        permissions = acl.value.access_policy.permissions
        start       = acl.value.access_policy.start
        expiry      = acl.value.access_policy.expiry
      }
    }
  }
}