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
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
- Makesure tofu installed
- Create
main.tffile
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"
}
- Setup provider & apply
tofu init
tofu plan
tofu apply
Result

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
- 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
- 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"
}
- 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"
- Check difference between before.txt and after.txt
diff before.txt after.txt
Result

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.
- Apply
plan2.out
tofu apply plan2.out
- Result

- Destroy for deleting all resources
tofu destroy -auto-approve # !IMPORTANT, dont use in production
Result

Answer
- 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 - Destroy merupakan hal kritikal yang wajib dihindari apalagi dengan
-auto-approveyang langsung menghapus resource tanpa adanya konfirmasi. Diwajibkan dengan mengtiadakan-auto-approve
https://github.com
Bos quest
Archon Quest: The Forge of Foundations
- 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"
}
- 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
- Pastikan repository sudah di setup + push ke main branch `
git push -u origin main
- Result

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
- 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
- Jadikan executable
chmod +x backup.sh
- Coba running

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"
- 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!"
- Create repository
ci-cd-demoon github

- 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

4. Result

Answer :
- 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
- Action checkout digunakan untuk mengambil data dalam repository