En el archivo config.meta almaceno los accesos a los conjuntos de datos de google bigquery. El objeto accesses es una lista de diccionarios, donde cada diccionario contiene el rol como el primer elemento y el segundo elemento (por ejemplo, special_group o group_by_email) que se está variando entre la lista.

Mi objetivo es aplicar los accesos dinámicamente. El enfoque es bastante fácil cuando cada diccionario en la lista accesses tiene el mismo segundo elemento (por ejemplo, special_group solamente). ¿Pero cómo aplicarlos dinámicamente depende del nombre / valor del segundo elemento?

# config.meta file
{
    "accesses": [
        {
            "role": "OWNER",
            "special_group": "projectOwners"
        },
        {
            "role": "READER",
            "group_by_email": "myemail@myemail.com"
        },
       ...
    ]
    ...
}

Archivo terraform:

resource "google_bigquery_dataset" "dataset" {
    dataset_id    = "${var.dataset}"
    location      = "${var.bq_region}"
    friendly_name = "${var.dataset}"

    dynamic "access" {
        # get accesses (list of dictionaries) from a file
        for_each = [for a in jsondecode(file("$config.meta"))["access"]: {
            role = a.role
            special_group = a.special_group
            # how to get special_group/group_by name conditionally?
            # like: if dictionary has the key 'special_group' create that variable
            # othervise create 'group_by_name'
        }]

        content {
            role = access.value.role
            special_group = access.value.special_group
            # how to get special_group/group_by name conditionally?
            # like: if the 'special_group' had been declared add 'special_group' to the access block
            # othervise add 'group_by_name'.
        }
    }

}

¿Cómo agrego condicionalmente un atributo a una etiqueta dinámica?

0
Tomasz Kubat 29 abr. 2020 a las 16:22

2 respuestas

La mejor respuesta
locals {
  items = fileexists("$config.meta") ? jsondecode(file("$config.meta")).accesses : []
  special_groups = [for v in local.items: v if lookup(v, "special_group", "") != ""]
  group_by_emails = [for v in local.items: v if lookup(v, "group_by_email", "") != ""]
}

Puede usar varias definiciones de bloque dynamic

resource "google_bigquery_dataset" "dataset" {

  ...

  dynamic "access" {
    for_each = [for a in local.special_groups: {
      role = lookup(a, "role", "")
      special_group = lookup(a, "special_group", "")
    }]

    content {
      role          = access.value.role
      special_group = access.value.special_group
    }
  }

  dynamic "access" {

    for_each = [for a in local.group_by_emails: {
      role = lookup(a, "role", "")
      group_by_email = lookup(a, "group_by_email", "")
    }]

    content {
      role           = access.value.role
      group_by_email = access.value.group_by_email
    }
  }

}
0
dmkvl 29 abr. 2020 a las 16:44

Dentro de un bloque de configuración en Terraform, omitir un argumento opcional y establecer ese argumento en null son equivalentes. Debido a que access es un bloque anidado, podemos explotarlo para escribir expresiones que establezcan condicionalmente el argumento.

  dynamic "access" {
    # get accesses (list of dictionaries) from a file
    for_each = [for a in jsondecode(file("$config.meta"))["access"]: {
      role           = a.role
      special_group  = try(a.special_group, null)
      group_by_email = try(a.group_by_email, null)
    }]

    content {
      role           = access.value.role
      special_group  = access.value.special_group
      group_by_email = access.value.group_by_email
    }
  }

Este primero utiliza la función try para que falte El atributo dará como resultado una caída en un valor null en lugar de un error. Esto significa que los objetos resultantes se verán así:

[
  {
    "role": "OWNER",
    "special_group": "projectOwners",
    "group_by_name": null,
  },
  {
    "role": "READER",
    "special_group": null,
    "group_by_email": "myemail@myemail.com",
  },
]

Dentro del bloque content, simplemente asignamos todo esto directamente. Terraform tratará los que son null como si no estuvieran configurados, debido al comportamiento que describí anteriormente. (Tenga en cuenta que el comportamiento de tratar null como no establecido no se aplica al construir valores de objeto: es un comportamiento especial solo para argumentos directos dentro de un bloque).

Esto debería tener el mismo efecto que si hubiera escrito los siguientes dos bloques access directamente:

access {
  role          = "OWNER"
  special_group = "projectOwners"
}

access {
  role           = "READER"
  group_by_email = "myemail@myemail.com"
}
1
Martin Atkins 30 abr. 2020 a las 17:40