Terraform 0.12: HCL2 and Provider Improvements

Terraform 0.12 is the biggest update in Terraform’s history, introducing HCL2 (HashiCorp Configuration Language 2). It addresses the major pain points of 0.11: type constraints, complex interpolations, and limited support for loops. This guide demonstrates how to refactor your infrastructure code to leverage the power of HCL2.

First-Class Expressions

Gone are the ‘${…}’ wrappers for everything. HCL2 supports first-class expressions.

# Terraform 0.11 (Old)
resource "aws_security_group" "example" {
  vpc_id = "${var.vpc_id}"
  name   = "sg-${var.environment}"
}

# Terraform 0.12 (New)
resource "aws_security_group" "example" {
  vpc_id = var.vpc_id  # No modification needed
  name   = "sg-${var.environment}"
}

Dynamic Blocks

Creating repeating nested blocks (like ingress rules) was a nightmare in 0.11. dynamic blocks solve this elegantly.

variable "ingress_ports" {
  type    = list(number)
  default = [80, 443, 8080]
}

resource "aws_security_group" "web" {
  name = "web-sg"
  
  dynamic "ingress" {
    for_each = var.ingress_ports
    content {
      from_port   = ingress.value
      to_port     = ingress.value
      protocol    = "tcp"
      cidr_blocks = ["0.0.0.0/0"]
    }
  }
}

For Loops and Map Transformations

HCL2 brings Python-like list comprehensions to Terraform.

output "instance_private_ips" {
  # Return a map of ID => IP
  value = {
    for instance in aws_instance.web :
    instance.id => instance.private_ip
  }
}

# Filtering a list
output "admin_users" {
  value = [
    for u in var.users :
    u.name
    if u.is_admin
  ]
}

Rich Type System

We can now define complex object structures for input variables, enabling strict validation.

variable "node_pools" {
  type = map(object({
    machine_type = string
    min_count    = number
    max_count    = number
    labels       = map(string)
  }))
  
  default = {
    "pool-1" = {
      machine_type = "n1-standard-1"
      min_count    = 1
      max_count    = 3
      labels       = { env = "dev" }
    }
  }
}

Key Takeaways

  • Upgrade Tool: Use `terraform 0.12upgrade` to auto-fix syntax specific to 0.12.
  • Dynamic Blocks: Replace hacky module logic for repeated nested blocks.
  • Strict Typing: Use `object()` and `map()` to enforce configuration contracts.
  • Generalized Splat: `aws_instance.web[*].id` works everywhere now.

Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.