Types de données HCL, interpolation, références, opérateurs, expressions conditionnelles et boucles.


Types primitifs

# string
variable "env" {
  type    = string
  default = "prod"
}
 
# number (entier ou décimal)
variable "count" {
  type    = number
  default = 3
}
 
# bool
variable "enable_https" {
  type    = bool
  default = true
}

Types complexes

# list(TYPE) — liste ordonnée, même type
variable "zones" {
  type    = list(string)
  default = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
}
 
# set(TYPE) — ensemble non ordonné sans doublons
variable "allowed_ips" {
  type    = set(string)
  default = ["10.0.0.1", "10.0.0.2"]
}
 
# map(TYPE) — dictionnaire clé/valeur, même type de valeur
variable "tags" {
  type = map(string)
  default = {
    Project     = "monapp"
    Environment = "prod"
  }
}
 
# tuple([TYPE, TYPE, ...]) — liste ordonnée, types hétérogènes
variable "config" {
  type    = tuple([string, number, bool])
  default = ["t3.micro", 2, true]
}
 
# object({...}) — structure typée
variable "db_config" {
  type = object({
    host     = string
    port     = number
    name     = string
    ssl      = bool
    replicas = optional(number, 1)   # attribut optionnel avec valeur par défaut
  })
}
 
# any — type dynamique (éviter en prod)
variable "misc" {
  type = any
}

Interpolation et références

# Interpolation dans une chaîne
name = "server-${var.env}-${count.index}"
tag  = "arn:aws:s3:::${var.bucket_name}"
 
# Heredoc (chaîne multi-ligne)
user_data = <<-EOF
  #!/bin/bash
  echo "Hello ${var.env}"
  apt-get update
  apt-get install -y nginx
EOF
 
# Références aux autres ressources
subnet_id  = aws_subnet.private.id
vpc_id     = aws_vpc.main.id
depends_on = [aws_internet_gateway.main]
 
# Référence à un module
db_host = module.database.endpoint
 
# Référence à une data source
ami_id = data.aws_ami.ubuntu.id
 
# Référence aux variables et locals
prefix = "${var.project}-${local.env_short}"
 
# Valeur null
value = null

Opérateurs

# Arithmétique
total = var.base_count + var.extra_count
price = var.unit_price * var.quantity
 
# Comparaison
is_prod     = var.env == "prod"
not_dev     = var.env != "dev"
high_count  = var.count > 10
at_least_3  = var.count >= 3
 
# Logiques
enabled = var.enable_feature && var.env == "prod"
either  = var.use_s3 || var.use_gcs
negated = !var.disable_feature
 
# Concaténation de chaînes
full_name = "${var.first}-${var.last}"

Expression conditionnelle (ternaire)

CONDITION ? VALEUR_SI_VRAI : VALEUR_SI_FAUX
# Taille d'instance selon l'environnement
instance_type = var.env == "prod" ? "t3.large" : "t3.micro"
 
# Activer ou non le monitoring
monitoring = var.env == "prod" ? true : false
 
# Valeur par défaut si null
name = var.custom_name != null ? var.custom_name : "default-name"
 
# Equivalent avec coalesce()
name = coalesce(var.custom_name, "default-name")
 
# Multi-niveau (éviter si trop complexe → utiliser locals)
size = var.env == "prod" ? "large" : var.env == "staging" ? "medium" : "small"

Expression for — transformer des collections

# Transformer une liste
[for ITEM in LIST : EXPRESSION]
[for ITEM in LIST : EXPRESSION if CONDITION]
 
# Transformer un map
{for KEY, VALUE in MAP : NEW_KEY => NEW_VALUE}
{for KEY, VALUE in MAP : NEW_KEY => NEW_VALUE if CONDITION}
# Liste → liste transformée
upper_names = [for name in var.names : upper(name)]
# ["alice", "bob"] → ["ALICE", "BOB"]
 
# Liste → liste filtrée
prod_servers = [for s in var.servers : s if s.env == "prod"]
 
# Liste → map (créer un index)
servers_by_id = {for s in var.servers : s.id => s.name}
 
# Map → liste de valeurs
endpoints = [for k, v in var.services : v.endpoint]
 
# Map → map transformé
upper_tags = {for k, v in var.tags : k => upper(v)}
 
# Avec index (count.index équivalent pour for)
indexed = [for i, v in var.names : "${i}: ${v}"]
 
# Cas d'usage : créer des sous-réseaux
subnets = {
  for i, az in var.availability_zones : az => cidrsubnet(var.vpc_cidr, 8, i)
}
# { "eu-west-1a" = "10.0.0.0/24", "eu-west-1b" = "10.0.1.0/24", ... }

Opérateur splat [*]

# Extraire un attribut de chaque élément d'une liste de ressources
all_ids  = aws_instance.web[*].id
all_ips  = aws_instance.web[*].public_ip
 
# Équivalent for mais plus concis
all_ids  = [for instance in aws_instance.web : instance.id]

Accès aux éléments

# Liste
first  = var.zones[0]
last   = var.zones[length(var.zones) - 1]
 
# Map
region = var.config["region"]
region = var.config.region      # notation pointée si clé valide
 
# Objet imbriqué
port = var.db_config.connection.port
 
# Accès sécurisé (évite l'erreur si null)
port = try(var.db_config.connection.port, 5432)

dynamic — générer des blocs répétés

dynamic "NOM_BLOC" {
  for_each = COLLECTION
  content {
    # attributs du bloc, accès via NOM_BLOC.value
  }
}
resource "aws_security_group" "web" {
  name = "web-sg"
 
  dynamic "ingress" {
    for_each = var.allowed_ports
    content {
      from_port   = ingress.value
      to_port     = ingress.value
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }
}
 
# Bloc dynamique avec map
dynamic "tag" {
  for_each = local.common_tags
  content {
    key   = tag.key
    value = tag.value
  }
}

En relation avec