Operation #

Setiap resource dalam konfigurasi Terraform akan mengalami salah satu dari lima operasi: create, read, update, delete, atau replace. Terraform memutuskan operasi mana yang tepat berdasarkan perbandingan antara konfigurasi, state, dan kondisi aktual di cloud. Memahami logika di balik keputusan ini — termasuk mengapa kadang update bisa berubah jadi replace — membantumu menulis konfigurasi yang lebih terprediksi dan menghindari kejutan saat apply.

Lima Operasi Resource #

CREATE (+)
  Kondisi: Resource ada di konfigurasi, tidak ada di state
  Tindakan: Terraform memanggil API provider untuk membuat resource baru
  Simbol di plan: +

READ (<=)
  Kondisi: Data source dibaca
  Tindakan: Terraform query data dari provider, tidak ada perubahan infrastruktur
  Simbol di plan: <=

UPDATE IN-PLACE (~)
  Kondisi: Resource ada di konfigurasi dan state, tapi konfigurasi berbeda
           DAN provider mendukung update in-place untuk atribut yang berubah
  Tindakan: Terraform memanggil API update — resource tetap running
  Simbol di plan: ~

DELETE (-)
  Kondisi: Resource ada di state, tidak ada di konfigurasi
  Tindakan: Terraform memanggil API provider untuk menghapus resource
  Simbol di plan: -

REPLACE (-/+)
  Kondisi: Resource perlu diupdate TAPI perubahan tersebut
           tidak bisa dilakukan in-place (provider tidak mendukung)
  Tindakan: Delete resource lama, create resource baru
  Simbol di plan: -/+ (atau +/- jika create_before_destroy aktif)

Bagaimana Terraform Memilih Operasi #

Keputusan apakah suatu perubahan bisa dilakukan in-place atau harus replace ditentukan oleh provider, bukan Terraform core.

# Setiap argumen resource punya sifat yang didefinisikan provider:
# - "updatable" → perubahan memicu UPDATE in-place
# - "forces new resource" → perubahan memicu REPLACE

resource "aws_instance" "web" {
  ami           = var.ami_id       # forces new resource — tidak bisa diganti in-place
  instance_type = var.type         # updatable — bisa diganti in-place (dengan stop/start)
  
  tags = {
    Name = "web"                   # updatable — bisa diubah tanpa restart instance
  }

  root_block_device {
    volume_size = 30               # forces new resource di beberapa kondisi
  }
}
# Plan output memberitahu kamu atribut mana yang forces replacement:
# -/+ resource "aws_instance" "web" {
#     ~ ami = "ami-OLD" -> "ami-NEW"   # forces replacement
#       id  = "i-0abcdef1234567890"
#     }
#
# Tanda "# forces replacement" atau "forces new resource"
# muncul di samping atribut yang menyebabkan replace

Import: Mengambil Alih Resource yang Sudah Ada #

Salah satu operasi penting yang sering dibutuhkan saat migrasi ke Terraform adalah import — mengambil alih pengelolaan resource yang sudah ada di cloud tanpa harus menghapus dan membuat ulang.

# Format: terraform import <resource_address> <resource_id>

# Import EC2 instance yang sudah ada
terraform import aws_instance.web i-0abcdef1234567890

# Import VPC yang sudah ada
terraform import aws_vpc.main vpc-0abcdef1234567890

# Import S3 bucket
terraform import aws_s3_bucket.assets my-existing-bucket

# Import resource di dalam module
terraform import module.vpc.aws_vpc.main vpc-0abcdef1234567890
# Sebelum import, kamu harus sudah punya blok resource yang kosong
# (atau dengan konfigurasi yang kamu inginkan)

# Langkah 1: Buat blok resource (bisa kosong dulu)
resource "aws_instance" "web" {
  # Isi ini setelah import, berdasarkan output terraform state show
}

# Langkah 2: Import
# terraform import aws_instance.web i-0abcdef1234567890

# Langkah 3: Lihat kondisi aktual di state
# terraform state show aws_instance.web

# Langkah 4: Lengkapi konfigurasi berdasarkan kondisi aktual
resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"  # dari state show
  instance_type = "t3.micro"               # dari state show
  subnet_id     = "subnet-0abcdef"         # dari state show
}

# Langkah 5: Jalankan plan — seharusnya "No changes"
# terraform plan

Import dengan Blok import (Terraform 1.5+) #

Sejak Terraform 1.5, ada cara yang lebih deklaratif untuk melakukan import menggunakan blok import dalam konfigurasi.

# Blok import bisa di-commit ke version control
# dan dieksekusi sebagai bagian dari terraform apply

import {
  to = aws_instance.web
  id = "i-0abcdef1234567890"
}

resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.public.id
}

# Terraform 1.5+ juga bisa generate konfigurasi otomatis:
# terraform plan -generate-config-out=generated.tf
# Menghasilkan file .tf dengan konfigurasi berdasarkan kondisi aktual

Moved Block: Rename Resource Tanpa Destroy #

Saat kamu ingin mengganti nama resource di konfigurasi, Terraform secara default akan menghapus yang lama dan membuat yang baru. Blok moved mencegah ini.

# MASALAH: Rename resource menyebabkan destroy + create
# Sebelum:
resource "aws_instance" "web" { ... }

# Sesudah rename:
resource "aws_instance" "web_server" { ... }
# Plan: -aws_instance.web + aws_instance.web_server → DESTROY + CREATE!

# SOLUSI: Gunakan blok moved
moved {
  from = aws_instance.web
  to   = aws_instance.web_server
}

resource "aws_instance" "web_server" {
  ami           = var.ami_id
  instance_type = "t3.micro"
}
# Plan: aws_instance.web moved to aws_instance.web_server
# → TIDAK ada destroy, tidak ada create
# moved juga berguna saat refactoring ke module
moved {
  from = aws_vpc.main
  to   = module.networking.aws_vpc.main
}

Tainted Resource #

Resource yang ditandai “tainted” oleh Terraform berarti resource tersebut dianggap rusak dan perlu di-replace pada apply berikutnya.

# Tandai resource sebagai tainted (akan di-replace saat apply)
terraform taint aws_instance.web

# Hapus taint jika kamu berubah pikiran
terraform untaint aws_instance.web

# Cek resource yang tainted di state
terraform state list  # Resource tainted ditandai dengan (tainted)
# Kasus di mana resource otomatis tainted:
# - Provisioner gagal saat create
# - Resource dibuat tapi berada dalam kondisi error

resource "aws_instance" "web" {
  ami           = var.ami_id
  instance_type = "t3.micro"

  provisioner "remote-exec" {
    inline = ["sudo apt update && sudo apt install -y nginx"]

    connection {
      type = "ssh"
      user = "ubuntu"
      host = self.public_ip
    }
  }
  # Jika provisioner gagal, instance ini otomatis tainted
  # terraform apply berikutnya akan destroy + recreate instance ini
}

Ringkasan #

  • Lima operasi: create +, read <=, update in-place ~, delete -, replace -/+ — Terraform memilih berdasarkan perbandingan konfigurasi, state, dan kondisi aktual.
  • Apakah update atau replace ditentukan oleh provider, bukan Terraform core — cek dokumentasi provider untuk tahu atribut mana yang “forces new resource”.
  • terraform import untuk mengambil alih resource existing tanpa destroy — wajib ada blok resource dulu sebelum import dilakukan.
  • Blok import deklaratif (Terraform 1.5+) lebih clean dari perintah CLI dan bisa di-commit ke version control.
  • Blok moved untuk rename resource atau refactoring ke module tanpa menyebabkan destroy + create.
  • Tainted resource adalah resource yang dianggap rusak dan akan di-replace pada apply berikutnya — bisa ditandai manual atau otomatis saat provisioner gagal.

← Sebelumnya: Dependency   Berikutnya: Local State →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact