12-June-25

OpenTofu is fork from opensource terraform tool for infrastructure as a code. This tool allow to define infrastructure to human readable file `.tf` so you can manage consistant infrastructure throught lifesycle

12-June-25
Photo by nbtrisna Urban life, seen through reflective layers, where journeys begin and moments linger.

Learn Opentofu

Referensi : https://opentofu.org/docs/ OpenTofu is fork from opensource terraform tool for infrastructure as a code. This tool allow to define infrastructure to human readable file .tf so you can manage consistant infrastructure throught lifesycle.

In first daily quest, we learn to create simple file hello.txt using local provider.

OpenTofu relies on plugins called providers to interact with cloud providers, SaaS providers, and other APIs.

Resources are the most important element in the OpenTofu language. Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records.

Alur init -> plan -> apply diperlukan agar sebelum infrastruktur dijalankan, ops bisa cek.

Hello world

  1. Makesure tofu installed
  2. Create main.tf file
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.0"
    }
  }

  required_version = ">= 1.0"
}

provider "local" {
  # No configuration needed for local provider
  
}

resource "local_file" "hello_world" {
  content  = "Hello, Opentofu!"
  filename = "${path.module}/hello.txt"
  
}
  1. Setup provider & apply
tofu init
tofu plan
tofu apply

Result

Pasted image 20250612085123

Plan Inception

After init, opentofu create plan without apply anything about main.tf. Its crucial for developer to review things you need to create.

Try : skenario we change value content to Hello, Opentofu! V2

  1. Run tofu plan with out for check changes before we edit main.tf
tofu plan -out=plan2.out
---

No changes. Your infrastructure matches the configuration.

OpenTofu has compared your real infrastructure against your configuration and
found no differences, so no changes are needed.

---
# print to text
tofu show plan.out > before.txt
  1. Edit main.tf
# before

resource "local_file" "hello_world" {
  content  = "Hello, Opentofu!"
  filename = "${path.module}/hello.txt"
}

# after

resource "local_file" "hello_world" {
  content  = "Hello, Opentofu! V2"
  filename = "${path.module}/hello.txt"
}
  1. Plan again with different output file
tofu plan -out=plan2.out
---
local_file.hello_world: Refreshing state... [id=38191fd8e74a432bf7ffc42ceee0bb4fb06e658d]

OpenTofu used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement

OpenTofu will perform the following actions:

  # local_file.hello_world must be replaced
-/+ resource "local_file" "hello_world" {
      ~ content              = "Hello, Opentofu!" -> "Hello, Opentofu! V2" # forces replacement
      ~ content_base64sha256 = "lL/QFDa0wcJiPe1okWxphgQ0/2kax3o2shzTdVu8tTs=" -> (known after apply)
      ~ content_base64sha512 = "6JPryukFlv/rFOyC6tMLea+tQ2ZTJZxFsL57CYa3rXC/a28XaB3JmPerpMUSfWS29PyOr9lyCP2nxmIyqTnHpA==" -> (known after apply)
      ~ content_md5          = "4c66612d6cb3994e929b4ed74c1b7290" -> (known after apply)
      ~ content_sha1         = "38191fd8e74a432bf7ffc42ceee0bb4fb06e658d" -> (known after apply)
      ~ content_sha256       = "94bfd01436b4c1c2623ded68916c69860434ff691ac77a36b21cd3755bbcb53b" -> (known after apply)
      ~ content_sha512       = "e893ebcae90596ffeb14ec82ead30b79afad436653259c45b0be7b0986b7ad70bf6b6f17681dc998f7aba4c5127d64b6f4fc8eafd97208fda7c66232a939c7a4" -> (known after apply)
      ~ id                   = "38191fd8e74a432bf7ffc42ceee0bb4fb06e658d" -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Saved the plan to: plan2.out

To perform exactly these actions, run the following command to apply:
    tofu apply "plan2.out"
  1. Check difference between before.txt and after.txt
diff before.txt after.txt

Result

Pasted image 20250612110838

Apply

*After reviewing on plan-stage, next step is apply resources using command tofu apply *

Skenario : Apply plan2.out

In help apply mean Creates or updates infrastructure according to OpenTofu configuration files in the current directory.

By default, OpenTofu will generate a new plan and present it for your approval before taking any action. You can optionally provide a plan file created by a previous call to "tofu plan", in which case OpenTofu will take the actions described in that plan without any confirmation prompt.

  1. Apply plan2.out
tofu apply plan2.out
  1. Result
Pasted image 20250612111149
  1. Destroy for deleting all resources
tofu destroy -auto-approve # !IMPORTANT, dont use in production

Result

Pasted image 20250612111255

Answer

  1. Perbedaan apply plan2.out dengan auto approve adalah ketika menggunakan plan2 adalah kondisi ketika tofu itu sudah di cek dalam stage plan. Sedangakan dengfan auto approve, resource langsung dibuat sesuai dengan file main.tf
  2. Destroy merupakan hal kritikal yang wajib dihindari apalagi dengan -auto-approve yang langsung menghapus resource tanpa adanya konfirmasi. Diwajibkan dengan mengtiadakan -auto-approve

https://github.com

Bos quest

Archon Quest: The Forge of Foundations

  1. Buat main.tf
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.0"
    }
  }

  required_version = ">= 1.0"
}

provider "local" {
  # No configuration needed for local provider
  
}

resource "local_file" "hello_world" {
  content  = "Hello, OpenTofu! V2"
  filename = "${path.module}/otf-local/hello.txt"
  
}
  1. Buat .github/workflows/ci.yaml
name: Apply Tofu to create hello.txt
on:
  push:
    branches:
      - main
jobs:
  apply:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Tofu
        uses: opentofu/setup-opentofu@v1

      - name: Apply Tofu
        run: |
          tofu init
          tofu plan
          tofu apply -auto-approve

      - name: Verify otf-local/hello.txt value
        run: |
          if ! grep -q "Hello, OpenTofu! V2" otf-local/hello.txt; then  
            echo "Validation failed!" && exit 1  
          fi  

      - name: Upload hello.txt artifact
        uses: actions/upload-artifact@v4
        with:
          name: hello.txt
          path: otf-local/hello.txt
  1. Pastikan repository sudah di setup + push ke main branch `
git push -u origin main
  1. Result
Pasted image 20250612114614

Repository : https://github.com/ngurah-bagus-trisna/boss-land-of-iac

🌟 Side Quest: Shell Scripting Sprint

Refrensi : https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html

  1. Buat backup.sh
#!/usr/bin/env bash

SRC_DIR="$HOME/my-data"
DEST_DIR="$HOME/backup-$(date +%Y%m%d)"

if [ ! -d "$SRC_DIR" ]; then
    echo "Source directory $SRC_DIR does not exist."
    exit 1
else 
    echo "Backing up $SRC_DIR to $DEST_DIR"
    mkdir -p "$DEST_DIR"
    cp -r "$SRC_DIR/"* "$DEST_DIR/"
    if [ $? -eq 0 ]; then
        echo "Backup completed successfully."
    else
        echo "Backup failed."
        exit 1
    fi
fi
  1. Jadikan executable
chmod +x backup.sh
  1. Coba running
Pasted image 20250612115736

The first workflow | daily-quest

lab : https://vscode.dev/tunnel/nb-ubuntu-desk/home/shezen/learn-gpt/first-workflow

Github action give tools to automation in repository git using github_workflows. It allow to runing task like build, test, deploy and push to production and minimize error/problem.

Skenario : Create new repository, publish on github, add workflows to say "Hello World"

  1. Create new file .github/workflows/first-workflows.yaml
name: Hello CI
on: 
    - push
jobs:
    build:
        runs-on: ubuntu-latest
        steps:
            - name: Checkout code
              uses: actions/checkout@v2
            - name: say hello
              run: echo "Hello from CI/CD!"
  1. Create repository ci-cd-demo on github
Pasted image 20250612231004
  1. Git init, add, commit + push to remote repository
git init
git add .
git commit -m "ci: add testing hello-world on gh_workflows"

git remote add origin https://github.com/ngurah-bagus-trisna/ci-cd-demo.git
git branch -M main
git push -u origin main
Pasted image 20250612231216

4. Result

Pasted image 20250612231216

Answer :

  1. Blok on digunakan untuk penentu trigger sebuah action, jobs adalah sekumpulan action yang akan di running, steps adalah serangkaian langkah yang akan di exec dalam runner
  2. Action checkout digunakan untuk mengambil data dalam repository