kb.erickguedes.com
Terraform: Infraestrutura como Código

Provisioners e Meta-arguments

Aula 4 de 7

Meta-arguments

Meta-arguments modificam o comportamento de qualquer resource block.

depends_on

# Garantir ordem de criação (quando implicit dependencies não bastam)
resource "aws_s3_bucket" "logs" {
  bucket = "app-logs"
}

resource "aws_iam_role_policy" "s3_access" {
  role   = aws_iam_role.app.name
  policy = data.aws_iam_policy_document.s3.json

  depends_on = [aws_s3_bucket.logs]
}

count

# Criar N instâncias idênticas
variable "subnet_ids" {
  type = list(string)
}

resource "aws_instance" "web" {
  count = length(var.subnet_ids)

  ami           = "ami-xxx"
  instance_type = "t3.micro"
  subnet_id     = var.subnet_ids[count.index]

  tags = {
    Name = "web-${count.index + 1}"
  }
}

for_each

# Criar recursos baseados em map/set (mais flexível que count)

variable "users" {
  type = map(object({
    role    = string
    groups  = list(string)
  }))
  default = {
    alice = { role = "developer", groups = ["dev", "ops"] }
    bob   = { role = "admin", groups = ["admin"] }
  }
}

resource "aws_iam_user" "this" {
  for_each = var.users

  name = each.key
  tags = {
    Role = each.value.role
  }
}

resource "aws_iam_user_group_membership" "this" {
  for_each = var.users

  user   = aws_iam_user.this[each.key].name
  groups = each.value.groups
}

lifecycle

resource "aws_instance" "web" {
  # ...

  lifecycle {
    create_before_destroy = true    # cria nova antes de destruir antiga
    prevent_destroy       = true    # impede destruição acidental
    ignore_changes = [
      ami,                          # AMI pode ser atualizada fora do TF
      user_data,
    ]
  }
}

Provisioners

Provisioners executam scripts local ou remotamente. Use como último recurso — prefira user_data, imagens pré-buildadas ou ferramentas de config management.

# file provisioner — copia arquivos
resource "aws_instance" "web" {
  # ...

  provisioner "file" {
    source      = "app.conf"
    destination = "/tmp/app.conf"

    connection {
      type        = "ssh"
      user        = "ubuntu"
      private_key = file("~/.ssh/id_rsa")
      host        = self.public_ip
    }
  }
}

# remote-exec — executa comandos
resource "aws_instance" "web" {
  provisioner "remote-exec" {
    inline = [
      "sudo apt update",
      "sudo apt install -y nginx",
      "sudo systemctl enable nginx",
    ]

    connection {
      type = "ssh"
      user = "ubuntu"
      host = self.public_ip
    }
  }
}

# local-exec — executa no próprio computador
resource "null_resource" "kubectl" {
  provisioner "local-exec" {
    command = "kubectl apply -f deployment.yaml"
  }
}

Provisioners com triggers

# null_resource — executa algo sem recurso cloud real
resource "null_resource" "ansible" {
  triggers = {
    instance_id = aws_instance.web.id
    config_hash = filesha256("playbook.yml")
  }

  provisioner "local-exec" {
    command = "ansible-playbook -i '${self.triggers.instance_id},' playbook.yml"
  }
}

Destroy Provisioners

resource "aws_instance" "web" {
  # Executa ANTES de destruir o recurso
  provisioner "local-exec" {
    when    = destroy
    command = "curl -X POST https://api.example.com/cleanup/${self.id}"
  }
}

Meta-arguments são sua principal ferramenta de flexibilidade. Provisioners são o "break glass" — use apenas quando não há alternativa nativa. Prefira user_data e imagens customizadas.