Type & Validation #
Variable tanpa type constraint dan validation hanyalah placeholder — siapapun bisa memasukkan nilai apapun, dan error baru muncul ketika apply sudah dijalankan dan provider mencoba membuat resource dengan nilai yang salah. Type constraint dan validation rules memindahkan deteksi error lebih awal: ke saat terraform plan, bahkan sebelum satu pun API call dilakukan. Ini adalah perbedaan antara gagal cepat di lokal dan gagal lambat di production.
Type Constraints Secara Detail #
Type constraint memastikan variable menerima tipe data yang sesuai. Terraform akan error saat plan jika nilai yang diberikan tidak cocok dengan tipe yang dideklarasikan.
# TIPE PRIMITIF dengan constraint ketat
variable "environment" {
type = string
# Menerima: "dev", "production", "staging-01"
# Menolak: 42, true, ["dev"]
}
variable "replica_count" {
type = number
# Menerima: 3, 1.5, 0
# Menolak: "three", true
}
variable "enable_deletion_protection" {
type = bool
# Menerima: true, false
# Juga menerima: "true", "false", "1", "0" (Terraform auto-convert)
}
# TIPE KOLEKSI dengan constraint elemen
variable "allowed_cidrs" {
type = list(string)
description = "CIDR blocks yang diizinkan akses"
# Menerima: ["10.0.0.0/8", "192.168.0.0/16"]
# Menolak: ["10.0.0.0/8", 42] ← elemen bukan string
}
variable "instance_ports" {
type = map(number)
description = "Pemetaan nama layanan ke nomor port"
# Menerima: { http = 80, https = 443, grpc = 9090 }
# Menolak: { http = "eighty" } ← nilai bukan number
}
variable "unique_regions" {
type = set(string)
description = "Set region unik (duplikat otomatis dihapus)"
# Menerima: ["ap-southeast-1", "us-east-1"]
# Duplikat dalam set otomatis di-deduplicate oleh Terraform
}
# OBJECT — type constraint paling detail
variable "rds_config" {
type = object({
engine = string
engine_version = string
instance_class = string
allocated_storage = number
multi_az = bool
backup_retention = optional(number, 7) # Field optional dengan default
})
default = {
engine = "postgres"
engine_version = "15.3"
instance_class = "db.t3.medium"
allocated_storage = 100
multi_az = false
# backup_retention tidak perlu diisi — ada default 7
}
}
Validation Rules #
Validation rules memungkinkan kamu mendefinisikan constraint yang lebih spesifik dari sekadar tipe data — misalnya “string ini harus salah satu dari nilai yang diizinkan” atau “number ini harus lebih besar dari 0”.
variable "environment" {
type = string
description = "Nama environment deployment"
validation {
condition = contains(["dev", "staging", "production"], var.environment)
error_message = "Environment harus salah satu dari: dev, staging, production."
}
}
# Coba set environment = "prod" → error saat plan:
# ╷
# │ Error: Invalid value for variable
# │
# │ on variables.tf line 1:
# │ 1: variable "environment" {
# │
# │ Environment harus salah satu dari: dev, staging, production.
# │
# │ This was checked by the validation rule at variables.tf:6,3-13.
# ╵
variable "replica_count" {
type = number
description = "Jumlah replica untuk deployment"
validation {
condition = var.replica_count >= 1 && var.replica_count <= 20
error_message = "Jumlah replica harus antara 1 dan 20."
}
}
variable "vpc_cidr" {
type = string
description = "CIDR block untuk VPC utama"
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "VPC CIDR harus berupa CIDR block yang valid, contoh: 10.0.0.0/16."
}
}
Multiple Validation Blocks #
Satu variable bisa memiliki lebih dari satu blok validation — masing-masing mengecek kondisi yang berbeda.
variable "instance_type" {
type = string
description = "EC2 instance type"
# Validasi 1: Harus dimulai dengan prefix yang valid
validation {
condition = can(regex("^(t3|t4g|m5|m6i|c5|c6i|r5|r6i)\\.", var.instance_type))
error_message = "Instance type harus menggunakan keluarga yang disetujui (t3, t4g, m5, m6i, c5, c6i, r5, r6i)."
}
# Validasi 2: Tidak boleh menggunakan ukuran nano atau micro di production
validation {
condition = !can(regex("\\.(nano|micro)$", var.instance_type))
error_message = "Instance size nano dan micro tidak diizinkan — gunakan minimal small."
}
}
Validasi dengan Referensi ke Variable Lain #
Validation block bisa mereferensikan variable itu sendiri, tapi tidak bisa mereferensikan variable lain. Untuk cross-variable validation, gunakan locals.
# ANTI-PATTERN: Mencoba referensi variable lain di validation
variable "max_size" {
type = number
validation {
# ✗ Tidak bisa — var.min_size tidak bisa diakses di sini
condition = var.max_size >= var.min_size
error_message = "max_size harus >= min_size."
}
}
# BENAR: Gunakan locals untuk cross-variable validation
variable "min_size" {
type = number
}
variable "max_size" {
type = number
}
locals {
# Validasi cross-variable menggunakan local value dengan kondisi
validate_size_range = (
var.max_size >= var.min_size
? null
: tobool("max_size (${var.max_size}) harus lebih besar atau sama dengan min_size (${var.min_size})")
)
}
Pola Validasi yang Umum di Production #
# Validasi format AWS resource ID
variable "vpc_id" {
type = string
validation {
condition = can(regex("^vpc-[a-f0-9]{8,17}$", var.vpc_id))
error_message = "vpc_id harus berformat 'vpc-' diikuti 8-17 karakter hex."
}
}
# Validasi nama yang aman untuk resource naming
variable "project_name" {
type = string
validation {
condition = can(regex("^[a-z][a-z0-9-]{2,30}[a-z0-9]$", var.project_name))
error_message = "project_name harus lowercase, dimulai huruf, hanya huruf/angka/tanda hubung, panjang 4-32 karakter."
}
}
# Validasi nilai sensitif tidak kosong
variable "db_password" {
type = string
sensitive = true
validation {
condition = length(var.db_password) >= 16
error_message = "Password database harus minimal 16 karakter."
}
}
# Validasi CIDR tidak overlap dengan range yang dilarang
variable "app_cidr" {
type = string
validation {
condition = can(cidrhost(var.app_cidr, 0)) && !startswith(var.app_cidr, "169.254.")
error_message = "app_cidr harus CIDR valid dan bukan link-local (169.254.x.x)."
}
}
Ringkasan #
- Type constraint mendeteksi tipe yang salah saat plan — jauh lebih baik dari error saat apply ketika resource sudah sebagian terbuat.
object()denganoptional()untuk variable yang mengandung banyak sub-field dengan beberapa field yang bisa dikosongkan.- Validation block untuk constraint semantik — nilai yang secara tipe benar tapi tidak valid secara bisnis: environment hanya boleh “dev/staging/production”, CIDR harus valid, panjang minimal, dll.
- Multiple validation blocks untuk memisahkan kondisi yang berbeda — pesan error menjadi lebih spesifik dan membantu.
- Cross-variable validation menggunakan
locals— validation block tidak bisa mengakses variable lain, tapitobool()di locals bisa digunakan untuk membuat error yang informatif.- Investasi di validation rules di awal menghemat waktu debugging di kemudian hari — error yang ditemukan di
planjauh lebih murah dari error yang ditemukan di production.
← Sebelumnya: Apa itu Variable? Berikutnya: File & Environment →