Lewati ke konten

Blok identitas peserta

Slug diturunkan dari email, menolak jalan bila bentrok.

Berkas: alat/hari-3/Praktik 11/perbaikan/blok-identitas.sh

Praktik 11/perbaikan/blok-identitas.sh
#!/usr/bin/env bash
# =====================================================================
# Praktik 11 — Blok identitas peserta (pengganti Tahap 2)
#
# Menggantikan blok variabel pada modul Praktik 11 Tahap 2.
#
# Masalah pada versi modul
# ------------------------
# Modul menulis:
#
# PROJECT_ID="geoportal-kelompok-a-xxxxx"
# PARTICIPANT_ID="nama01"
#
# dan hanya memberi catatan "Ganti nilai tersebut dengan kode/nama peserta
# yang diberikan koordinator". Satu project kelompok dipakai EMPAT peserta
# bersama. Peserta yang mengikuti modul tanpa membaca panduan akan
# menyalin "nama01" apa adanya, dan sejak Tahap 4 seluruh nama resource
# menjadi sama:
#
# webgis-nama01 · cb-deployer-nama01 · deploy-nama01
# webgis-ip-nama01 · nextjs-nama01 · github-nama01
#
# Peserta pertama berhasil. Peserta kedua gagal dengan ALREADY_EXISTS di
# pesan yang tidak menyebut penyebabnya.
#
# Cara kerja versi ini
# --------------------
# PARTICIPANT_ID DITURUNKAN dari email peserta, bukan diketik. Empat
# peserta menerima empat email berbeda dari koordinator, sehingga empat
# slug yang dihasilkan pasti berbeda. Tabrakan tidak dicegah dengan
# peringatan, melainkan dengan tidak adanya nilai yang bisa salah diisi.
#
# Blok ini juga menolak jalan bila:
# - slug yang dihasilkan tidak sah sebagai bagian nama resource GCP
# - slug sudah dipakai peserta lain di project yang sama
#
# Cara pakai
# ----------
# Tempel seluruh berkas ini di Cloud Shell, lalu ubah dua baris pertama
# pada bagian "ISI INI" di bawah.
#
# Atau, kalau email peserta sudah menjadi email login Cloud Shell:
#
# curl -sSL <url-berkas-ini> | bash -s -- "$(gcloud config get-value account)"
# =====================================================================
set -euo pipefail
# ---------------------------------------------------------------------
# ISI INI — hanya dua baris ini yang perlu diubah peserta.
# ---------------------------------------------------------------------
PROJECT_ID="${1:-geoportal-kelompok-a-xxxxx}" # dari koordinator
EMAIL_PESERTA="${2:-$(gcloud config get-value account 2>/dev/null || true)}"
# ---------------------------------------------------------------------
# Nilai yang sama untuk semua peserta dalam satu project.
REGION="${REGION:-asia-southeast2}"
ZONE="${ZONE:-asia-southeast2-b}"
REPOSITORY="katalog-images" # milik akun master, JANGAN dibuat peserta
APP_DIR="/opt/webgis/app"
merah() { printf '\033[31m%s\033[0m\n' "$1"; }
hijau() { printf '\033[32m%s\033[0m\n' "$1"; }
kuning() { printf '\033[33m%s\033[0m\n' "$1"; }
if [ -z "$EMAIL_PESERTA" ] || [ "$EMAIL_PESERTA" = "null" ]; then
merah "Email peserta kosong."
echo " Jalankan: bash blok-identitas.sh <PROJECT_ID> <EMAIL_PESERTA>"
echo " Atau pastikan sudah login: gcloud auth list"
exit 1
fi
if [ "$PROJECT_ID" = "geoportal-kelompok-a-xxxxx" ]; then
merah "PROJECT_ID masih bernilai contoh."
echo " Ambil Project ID yang benar dari koordinator."
echo " Untuk melihat project yang boleh diakses: gcloud projects list"
exit 1
fi
# ---------------------------------------------------------------------
# Turunkan slug dari email.
#
# nama01@example.com -> nama01
# asisten01@example.com -> asisten-nama-01
# A01@example.com -> a01
#
# Aturannya sama dengan aturan nama resource GCP: huruf kecil, angka,
# tanda hubung. Titik dan garis bawah diubah menjadi tanda hubung karena
# nama VM dan Service Account GCP tidak menerima keduanya.
# ---------------------------------------------------------------------
# Setiap karakter selain huruf kecil dan angka diubah menjadi SATU tanda
# hubung (bukan dihapus). Menghapus akan membuat dua email berbeda
# menghasilkan slug yang sama:
# asisten02@example.com dan asisten03@example.com -> keduanya "asistennama-01"
# Dengan penggantian, keduanya tetap berbeda:
# asisten-nama-01 dan asistennama-01
PARTICIPANT_ID="$(
printf '%s' "${EMAIL_PESERTA%%@*}" \
| tr '[:upper:]' '[:lower:]' \
| sed -e 's/[^a-z0-9]\{1,\}/-/g' -e 's/^-\{1,\}//' -e 's/-\{1,\}$//'
)"
if [ -z "$PARTICIPANT_ID" ]; then
merah "Tidak bisa menurunkan slug dari email '$EMAIL_PESERTA'."
echo " Minta koordinator memberikan slug secara eksplisit, lalu jalankan:"
echo " PARTICIPANT_ID=\"slug-dari-koordinator\" bash blok-identitas.sh ..."
exit 1
fi
# ---------------------------------------------------------------------
# Penjagaan format. Nama VM, Service Account, dan trigger GCP menolak
# huruf besar, spasi, dan garis bawah — dan pesan errornya menyebut nama
# resource, bukan nama variabel, sehingga sulit dilacak.
# ---------------------------------------------------------------------
if printf '%s' "$PARTICIPANT_ID" | grep -qE '[^a-z0-9-]'; then
merah "Slug '$PARTICIPANT_ID' mengandung karakter yang tidak sah."
echo " Hanya huruf kecil, angka, dan tanda hubung."
exit 1
fi
if [ "${#PARTICIPANT_ID}" -gt 18 ]; then
merah "Slug '$PARTICIPANT_ID' ${#PARTICIPANT_ID} karakter, melebihi batas 18."
echo " Slug dipakai membentuk cb-deployer-<slug> dan webgis-<slug>."
exit 1
fi
# ---------------------------------------------------------------------
# Nama resource yang akan dibentuk. Semuanya mengandung slug, sehingga
# otomatis berbeda antar peserta.
# ---------------------------------------------------------------------
VM_NAME="webgis-${PARTICIPANT_ID}"
STATIC_IP_NAME="webgis-ip-${PARTICIPANT_ID}"
BUILD_SA_NAME="cb-deployer-${PARTICIPANT_ID}"
CONNECTION_NAME="github-${PARTICIPANT_ID}"
LINKED_REPO_NAME="repo-${PARTICIPANT_ID}"
TRIGGER_NAME="deploy-${PARTICIPANT_ID}"
IMAGE_NAME="nextjs-${PARTICIPANT_ID}"
SUBDOMAIN="${PARTICIPANT_ID}.gisbigtrainer.com"
BUILD_SA="${BUILD_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
VM_REGION="${ZONE%-*}"
# Catatan: DNS_ZONE_NAME pada modul sudah tidak dipakai. Panduan
# setup-project bagian 8 menyatakan DNS zone tidak lagi memakai slug
# peserta karena subdomain ditangani penyelenggara.
# ---------------------------------------------------------------------
# Penjagaan tabrakan.
#
# Peserta pertama tidak menemukan apa pun dan lolos. Peserta kedua
# menemukan SA milik peserta pertama, dan diberhentikan SEBELUM membuat
# apa pun. Pesan ini menjelaskan penyebabnya, bukan sekadar
# "ALREADY_EXISTS".
# ---------------------------------------------------------------------
echo "Memeriksa project $PROJECT_ID ..."
if ! gcloud projects describe "$PROJECT_ID" >/dev/null 2>&1; then
merah "Project '$PROJECT_ID' tidak bisa diakses."
echo " Periksa: gcloud projects list"
echo " Kalau project tidak muncul, hubungi koordinator — akses IAM belum terpasang."
exit 1
fi
# Mencari jejak pemilik lebih dahulu supaya pesan galatnya menyebut nama,
# bukan sekadar "sudah ada". created-by pada VM berisi email pembuatnya.
PEMILIK=""
if gcloud compute instances describe "$VM_NAME" --zone="$ZONE" --project="$PROJECT_ID" >/dev/null 2>&1; then
PEMILIK="$(
gcloud compute instances describe "$VM_NAME" --zone="$ZONE" --project="$PROJECT_ID" \
--format='value(metadata.items[?key==`created-by`].value)' 2>/dev/null | head -1 || true
)"
fi
if gcloud iam service-accounts describe "$BUILD_SA" --project="$PROJECT_ID" >/dev/null 2>&1; then
merah "Service Account '$BUILD_SA_NAME' sudah ada di project ini."
echo ""
echo " Artinya slug '$PARTICIPANT_ID' sudah dipakai peserta lain di project yang sama."
[ -n "$PEMILIK" ] && echo " VM '$VM_NAME' dibuat oleh: $PEMILIK"
echo ""
echo " JANGAN melanjutkan. Kalau Anda memakai Service Account milik orang lain,"
echo " Cloud Build Anda akan men-deploy ke VM orang itu, dan sebaliknya."
echo ""
echo " Langkah yang benar:"
echo " 1. Laporkan ke koordinator bahwa slug '$PARTICIPANT_ID' bentrok."
echo " 2. Minta slug pengganti, lalu jalankan blok ini lagi dengan slug itu:"
echo " PARTICIPANT_ID=\"slug-baru\" bash blok-identitas.sh \"$PROJECT_ID\" \"$EMAIL_PESERTA\""
exit 1
fi
if gcloud compute instances describe "$VM_NAME" --zone="$ZONE" --project="$PROJECT_ID" >/dev/null 2>&1; then
merah "VM '$VM_NAME' sudah ada di project ini."
echo " Slug '$PARTICIPANT_ID' sudah dipakai. Lapor ke koordinator."
exit 1
fi
hijau "Lolos. Tidak ada resource dengan nama ini di project $PROJECT_ID."
echo ""
echo "PROJECT_ID = $PROJECT_ID"
echo "EMAIL_PESERTA = $EMAIL_PESERTA"
echo "PARTICIPANT_ID = $PARTICIPANT_ID <- diturunkan dari email, bukan diketik"
echo ""
echo "Nama resource Anda:"
printf ' %-17s %s\n' \
VM_NAME "$VM_NAME" \
STATIC_IP_NAME "$STATIC_IP_NAME" \
BUILD_SA_NAME "$BUILD_SA_NAME" \
BUILD_SA "$BUILD_SA" \
CONNECTION_NAME "$CONNECTION_NAME" \
LINKED_REPO_NAME "$LINKED_REPO_NAME" \
TRIGGER_NAME "$TRIGGER_NAME" \
IMAGE_NAME "$IMAGE_NAME" \
SUBDOMAIN "$SUBDOMAIN"
echo ""
kuning "Resource yang JUSTRU TIDAK boleh Anda buat (milik akun master):"
echo " katalog-images Artifact Registry bersama"
echo " allow-webgis-http Firewall rule port 80 dan 443"
echo " allow-webgis-iap-ssh Firewall rule port 22 lewat IAP"
echo " Kalau salah satu dibuat ulang, hasilnya ALREADY_EXISTS."
echo ""
echo "Kalau resource di atas ternyata BELUM ada, lapor ke koordinator."
echo "Jangan dibuat sendiri: nama yang sama dipakai seluruh peserta project ini."
echo ""
hijau "Lanjutkan ke Tahap 3 modul (periksa API)."
# Ekspor supaya bisa dipakai langsung di sesi yang sama.
export PROJECT_ID REGION ZONE PARTICIPANT_ID REPOSITORY APP_DIR
export VM_NAME STATIC_IP_NAME BUILD_SA_NAME BUILD_SA CONNECTION_NAME
export LINKED_REPO_NAME TRIGGER_NAME IMAGE_NAME SUBDOMAIN VM_REGION