Tipar fuertemente una variable.
→Primitivos: `string`, `number`, `bool`. Colecciones: `list(<type>)`, `set(<type>)`, `map(<type>)`. Estructurales: `object({...})`, `tuple([...])`. Usar `any` solo cuando sea verdaderamente polimórfico.
Referencia↗
Restringir `environment` a dev/staging/prod.
→`variable "environment" { validation { condition = contains(["dev","staging","prod"], var.environment); error_message = "..." } }`. Se permiten múltiples bloques `validation`; todos deben pasar.
Referencia↗
Generar una contraseña de base de datos sin que aparezca en `terraform output`.
→`output "db_password" { value = ...; sensitive = true }`. La CLI muestra `(sensitive value)`. Todavía se puede leer a través de `terraform output db_password` o `-json` (intencionadamente, para scripts).
Referencia↗
Calcular un valor una vez y reutilizarlo en muchos recursos.
→`locals { common_tags = merge(var.tags, { Project = var.project }) }`. Referenciar como `local.common_tags`. No se puede anular desde fuera del módulo.
Referencia↗
Buscar una AMI existente sin gestionarla.
→`data "aws_ami" "ubuntu" { most_recent = true; filter { ... } }`. Solo lectura. Referenciar atributos como `data.aws_ami.ubuntu.id`.
Referencia↗
Crear N recursos similares — elegir `count` o `for_each`.
→`for_each` (con mapa o conjunto) cuando los elementos tienen identidad estable (nombres de región, claves de entorno). `count` para "Necesito N copias, el orden no importa, la identidad es solo un índice". Añadir/eliminar en medio de `count` causa destruir/recrear; `for_each` preserva la identidad.
Referencia↗
Crear un recurso por cada elemento en una lista de strings.
→`for_each = toset(["a", "b", "c"])`. `each.key` y `each.value` dan la cadena. Para mapas: `for_each = var.users` — `each.key` = clave del mapa, `each.value` = valor del mapa.
Referencia↗
Generar un número variable de bloques anidados (ej. reglas de entrada).
→`dynamic "ingress" { for_each = var.rules; content { from_port = ingress.value.from; ... } }`. El argumento `iterator` puede renombrar el iterador si es necesario.
Referencia↗
Obtener una lista de atributos de todas las instancias de un recurso `count`.
→`aws_instance.web[*].id` devuelve una lista de IDs. Funciona con `count` y `for_each` (pero `for_each` produce un mapa desordenado, por lo que `values(aws_instance.web)[*].id`).
Referencia↗
Establecer un valor basándose en una condición.
→Ternario: `var.is_prod ? 5 : 1`. Ambas ramas deben producir el mismo tipo.
Referencia↗
Combinar dos mapas; los valores del segundo ganan en caso de colisión de claves.
→`merge(local.defaults, local.overrides)`. Gana el mapa más a la derecha. Útil para la composición de etiquetas.
Referencia↗
Leer un valor de mapa con un valor predeterminado si falta la clave.
→`lookup(var.config, "region", "us-east-1")`. Devuelve el valor predeterminado cuando la clave no está presente. Para estructuras profundamente opcionales, preferir la función `try()` opcional.
Referencia↗
Colapsar listas anidadas en una lista plana.
→`flatten([["a","b"], ["c"], [["d","e"]]])` → `["a","b","c","d","e"]`. Aplana listas recursivamente; preserva el orden.
Referencia↗
Insertar un mapa de Terraform en un documento de política de IAM.
→`jsonencode({Version = "2012-10-17", Statement = [...]})`. Produce una cadena JSON. Inverso: `jsondecode()`.
Referencia↗
Renderizar un script de datos de usuario con plantilla utilizando valores de variables.
→`templatefile("init.sh.tpl", { region = var.region, env = var.env })`. La plantilla usa la sintaxis `${region}`. Alternativa más nueva para renderizado estático: `file()` + `format()`.
Referencia↗
Dividir CIDRs de subred de un rango de VPC.
→`cidrsubnet("10.0.0.0/16", 8, 0)` → `10.0.0.0/24`. Primer argumento = padre, segundo = bits a extender, tercero = número de subred.
Referencia↗
Leer un valor que podría no existir; recurrir a un valor predeterminado.
→`try(yamldecode(file("config.yaml")), { defaults = true })`. Evalúa de izquierda a derecha; devuelve la primera expresión sin error.
Referencia↗
Iterar sobre archivos que coinciden con un patrón glob.
→`fileset(path.module, "configs/*.json")` devuelve un conjunto de rutas. Combinar con `for_each` para gestionar un recurso por archivo.
Referencia↗
El mismo proveedor en dos regiones (ej. AWS us-east-1 + us-west-2).
→Dos bloques `provider "aws" { alias = "..." }`. Los recursos optan por `provider = aws.us_west`. Los módulos aceptan alias a través de `configuration_aliases`.
Referencia↗
Ejecutar un comando de shell en una VM recién creada.
→Provisioner `remote-exec` dentro de un recurso. Herramienta de último recurso: preferir cloud-init, datos de usuario o gestión de configuración. Los provisioners no se rastrean en el estado y no se vuelven a ejecutar en caso de desviación.
Referencia↗
Ejecutar un comando que no corresponde a un recurso en la nube (ej. invocación de CLI).
→`resource "null_resource" "trigger" { triggers = { sha = sha1(file(".")) }; provisioner "local-exec" { command = "..." } }`. Se vuelve a ejecutar cuando cambian los `triggers`.
Referencia↗
Verificar continuamente un invariante en tiempo de ejecución (ej. el endpoint de salud devuelve 200) sin bloquear la aplicación.
→`check "endpoint" { data "http" "h" { url = "..." }; assert { condition = data.http.h.status_code == 200; error_message = "..." } }`. Se ejecuta en plan/apply; la falla es una advertencia, no un error grave.
Por qué: `check` permite fuentes de datos con alcance utilizables solo dentro del chequeo. `precondition`/`postcondition` son errores graves en plan/apply.
Referencia↗
Hacer que el plan falle si una AMI es demasiado antigua.
→`lifecycle { precondition { condition = data.aws_ami.x.creation_date > "2024-01-01"; error_message = "..." } }`. Falla grave, evaluada antes/después según corresponda.
Referencia↗
Variable con un valor posicional de forma fija.
→`type = tuple([string, number, bool])` requiere exactamente tres elementos en ese orden. Diferente de una lista (homogénea, longitud variable).
Referencia↗
Tipar fuertemente una entrada estructurada (ej. `database = { instance_class = string, allocated_storage = number }`).
→`type = object({ instance_class = string, allocated_storage = number, multi_az = optional(bool, false) })`. `optional(<type>, <default>)` hace que los atributos sean opcionales.
Referencia↗
¿Cómo se cargan los archivos `*.tfvars`?
→`terraform.tfvars` y `*.auto.tfvars` se cargan automáticamente (orden lexicográfico para `auto`). Otros nombres requieren `-var-file=path.tfvars`.
Referencia↗
Escribir pruebas automatizadas para un módulo de Terraform.
→Archivos `.tftest.hcl` con `run "name" { command = plan|apply, assert { condition = ..., error_message = ... } }`. `command = plan` no tiene efectos secundarios; `command = apply` realmente crea recursos.
Referencia↗
Pasar variables a las ejecuciones de prueba.
→El bloque `variables { ... }` a nivel de archivo se aplica a todas las ejecuciones. El bloque `variables { ... }` por ejecución anula para esa ejecución solamente.
Referencia↗