diff --git a/.env.example b/.env.example index 654f5c7..d807257 100644 --- a/.env.example +++ b/.env.example @@ -21,6 +21,18 @@ COMPILER_WORKER_URL=http://compiler-worker:8080/execute ELEMES_HOST=sinau-c-hostname-kamu TS_AUTHKEY=tskey-auth-xxxx +# ── Velxio Modular Deployment (opsional) ─────── +# Mode operasi Velxio: 'local' (bundled dalam compose) atau 'remote' (terpisah) +VELXIO_MODE=local +# URL compiler Velxio (hanya perlu di-set saat VELXIO_MODE=remote) +# Default local: http://127.0.0.1:80/api/compile/ +# Contoh remote via MagicDNS: http://velxio-dev:80/api/compile/ +#VELXIO_COMPILER_URL= +# Hostname Tailscale untuk standalone Velxio node (dipakai di mesin Velxio & Elemes) +VELXIO_HOST=velxio-dev +# Auth key Tailscale terpisah untuk standalone Velxio node (di mesin Velxio) +VELXIO_TS_AUTHKEY= + # ── Flask (opsional: untuk dev mode lokal) ───── FLASK_DEBUG=false diff --git a/.gitignore b/.gitignore index fc314db..55b1ec0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ velxio-deployer-firmware/build velxio-deployer-firmware/managed_components/ lms-c-precompiled.tar .browser-test/ +config/lms-tail.json diff --git a/config/lms-tail.json b/config/lms-tail.json.template similarity index 93% rename from config/lms-tail.json rename to config/lms-tail.json.template index d050776..2fb1032 100644 --- a/config/lms-tail.json +++ b/config/lms-tail.json.template @@ -20,7 +20,7 @@ "Proxy": "http://127.0.0.1:5000/velxio-compile" }, "/velxio/": { - "Proxy": "http://127.0.0.1:80/" + "Proxy": "__VELXIO_PROXY_TARGET__" }, "/flowchart/": { "Proxy": "http://127.0.0.1:8081/" diff --git a/elemes.sh b/elemes.sh index bf4ed65..f5640b1 100755 --- a/elemes.sh +++ b/elemes.sh @@ -62,6 +62,70 @@ compose_restart() { run_compose_out restart "$@" } +# Helper untuk membaca nilai konfigurasi dari .env tanpa source +env_val() { + grep -m1 "^${1}=" "$PARENT_DIR/.env" 2>/dev/null | cut -d= -f2- +} + +# ── Velxio standalone compose helpers ──────────────────────── +VELXIO_PROJECT="${PROJECT_NAME}-velxio" + +run_velxio_compose() { + cd "$SCRIPT_DIR" || exit + if [ "$VERBOSE" -eq 1 ]; then + podman-compose -p "$VELXIO_PROJECT" -f podman-compose.velxio.yml \ + --env-file "$PARENT_DIR/.env" "$@" + else + podman-compose -p "$VELXIO_PROJECT" -f podman-compose.velxio.yml \ + --env-file "$PARENT_DIR/.env" "$@" \ + 2> >(grep -v -E "$NOISE_RE" >&2) + fi +} + +run_velxio_compose_quiet() { + if [ "$VERBOSE" -eq 1 ]; then + run_velxio_compose "$@" + else + run_velxio_compose "$@" >/dev/null 2>&1 + fi +} + +# Daftar services elemes berdasarkan VELXIO_MODE. +# Return kosong = start all (local mode). +# Return daftar service = start hanya yang terdaftar (remote mode). +elemes_services() { + local mode + mode="$(env_val VELXIO_MODE)" + mode="${mode:-local}" + if [ "$mode" = "remote" ]; then + echo "elemes-ts postgres elemes compiler-worker elemes-frontend flowchart" + fi +} + +# Generate lms-tail.json dari template berdasarkan VELXIO_MODE. +# Dipanggil sebelum container start agar Tailscale Serve config up-to-date. +generate_ts_config() { + local template="$SCRIPT_DIR/config/lms-tail.json.template" + local output="$SCRIPT_DIR/config/lms-tail.json" + + if [ ! -f "$template" ]; then + return + fi + + local mode + mode="$(env_val VELXIO_MODE)" + mode="${mode:-local}" + + if [ "$mode" = "remote" ]; then + local velxio_host + velxio_host="$(env_val VELXIO_HOST)" + velxio_host="${velxio_host:-velxio-dev}" + sed "s|__VELXIO_PROXY_TARGET__|http://${velxio_host}:80/|g" "$template" > "$output" + else + sed 's|__VELXIO_PROXY_TARGET__|http://127.0.0.1:80/|g' "$template" > "$output" + fi +} + # First-run/health DB: tunggu PostgreSQL, migrasi schema (idempotent), lalu # bootstrap akun guru otomatis bila TEACHER_TOKEN di .env tidak kosong. db_init() { @@ -153,6 +217,16 @@ init) echo "🔐 [Buat] Folder state/ (untuk Tailscale credentials & state)" fi + # state/velxio/ (untuk Tailscale credentials & state Velxio standalone) + if [ -d "$PARENT_DIR/state/velxio" ]; then + echo "✅ [Skip] Folder state/velxio/ sudah ada" + else + mkdir -p "$PARENT_DIR/state/velxio" + echo "🔐 [Buat] Folder state/velxio/ (untuk Tailscale Velxio standalone)" + fi + + generate_ts_config + echo "" echo "🎯 Selesai! Langkah selanjutnya yang direkomendasikan:" echo " 👉 1. Edit file ../.env sesuai dengan kebutuhan environment-mu" @@ -181,7 +255,14 @@ runbuild) ;;& runbuild | runclearbuild) echo "🚀 Menjalankan container di background..." - run_compose up --force-recreate -d + generate_ts_config + SERVICES=$(elemes_services) + if [ -n "$SERVICES" ]; then + echo " ℹ️ VELXIO_MODE=remote → Velxio tidak dijalankan secara lokal" + run_compose up --force-recreate -d $SERVICES + else + run_compose up --force-recreate -d + fi echo "✅ Elemes berhasil dijalankan!" db_init ;;& @@ -206,7 +287,14 @@ runbuild | runclearbuild) ;; run) echo "🚀 Menjalankan container..." - run_compose up -d + generate_ts_config + SERVICES=$(elemes_services) + if [ -n "$SERVICES" ]; then + echo " ℹ️ VELXIO_MODE=remote → Velxio tidak dijalankan secara lokal" + run_compose up -d $SERVICES + else + run_compose up -d + fi echo "✅ Elemes berhasil dijalankan!" db_init ;; @@ -470,6 +558,81 @@ docs-validate) compose_exec -w /app -e PYTHONPATH=services \ elemes python scripts/validate_docs.py ;; +velxio-stop | velxio-run | velxio-runbuild) + echo "🛑 Menghentikan Velxio standalone..." + run_velxio_compose_quiet down + ;;& +velxio-stop) + echo "✅ Velxio standalone dihentikan." + ;; +velxio-runbuild) + echo "🏗️ Membangun Velxio standalone image..." + run_velxio_compose build + ;;& +velxio-run) + if ! podman image exists lms-velxio-standalone:latest 2>/dev/null; then + echo "⚠️ Image 'lms-velxio-standalone:latest' belum dibangun." + echo " Jalankan: ./elemes.sh velxio-runbuild" + exit 1 + fi + ;;& +velxio-runbuild | velxio-run) + echo "🚀 Menjalankan Velxio standalone di background..." + run_velxio_compose up -d + echo "✅ Velxio standalone berhasil dijalankan!" + echo "" + VH="$(env_val VELXIO_HOST)" + VH="${VH:-velxio-dev}" + echo "📡 Velxio standalone info:" + echo " Tailscale hostname : $VH" + echo " Port internal : 80 (Nginx → FastAPI :8001)" + echo "" + echo "💡 Untuk menghubungkan Elemes ke Velxio ini, set di .env mesin Elemes:" + echo " VELXIO_MODE=remote" + echo " VELXIO_HOST=$VH" + echo " VELXIO_COMPILER_URL=http://$VH:80/api/compile/" + ;; +velxio-status) + echo "📊 === Status Velxio ===" + MODE="$(env_val VELXIO_MODE)" + MODE="${MODE:-local}" + echo " Mode: $MODE" + + if [ "$MODE" = "local" ]; then + echo " Velxio berjalan dalam compose utama (bundled)" + if podman ps --filter "label=io.podman.compose.project=$PROJECT_NAME" \ + --filter "label=com.docker.compose.service=velxio" \ + --format '{{.Names}} — {{.Status}}' 2>/dev/null | grep -q .; then + echo " ✅ Container:" + podman ps --filter "label=io.podman.compose.project=$PROJECT_NAME" \ + --filter "label=com.docker.compose.service=velxio" \ + --format ' {{.Names}} — {{.Status}}' + else + echo " ⚠️ Container: not running" + fi + else + echo " Velxio berjalan terpisah (remote)" + VURL="$(env_val VELXIO_COMPILER_URL)" + echo " VELXIO_COMPILER_URL: ${VURL:-}" + if podman ps --filter "label=io.podman.compose.project=$VELXIO_PROJECT" \ + --format '{{.Names}}' 2>/dev/null | grep -q .; then + echo " ✅ Standalone container (lokal):" + podman ps --filter "label=io.podman.compose.project=$VELXIO_PROJECT" \ + --format ' {{.Names}} — {{.Status}}' + else + echo " ℹ️ Tidak ada standalone container lokal (Velxio berjalan di mesin remote)" + fi + if [ -n "$VURL" ]; then + HEALTH_URL=$(echo "$VURL" | sed 's|/api/compile.*|/health|') + echo -n " 🔍 Health check ($HEALTH_URL)... " + if curl -sf --max-time 5 "$HEALTH_URL" >/dev/null 2>&1; then + echo "✅ reachable" + else + echo "❌ unreachable" + fi + fi + fi + ;; *) echo "💡 Cara Penggunaan elemes.sh:" echo " ./elemes.sh init # Inisialisasi konfigurasi, folder, & template .env" @@ -493,6 +656,12 @@ docs-validate) echo " ./elemes.sh test-worker # Compiler worker test suite" echo " ./elemes.sh docs-validate # Validasi frontmatter & broken link di docs/*.md" echo " ./elemes.sh loadtest # Menjalankan utilitas simulasi Load Test (Locust)" + echo "" + echo "📡 Velxio Modular:" + echo " ./elemes.sh velxio-run # Jalankan Velxio standalone (reuse image)" + echo " ./elemes.sh velxio-runbuild # Build lalu jalankan Velxio standalone" + echo " ./elemes.sh velxio-stop # Hentikan Velxio standalone" + echo " ./elemes.sh velxio-status # Cek status & health Velxio (local/remote)" ;; esac diff --git a/podman-compose.velxio.yml b/podman-compose.velxio.yml new file mode 100644 index 0000000..cc9a343 --- /dev/null +++ b/podman-compose.velxio.yml @@ -0,0 +1,42 @@ +version: '3.8' + +services: + velxio-ts: + image: docker.io/tailscale/tailscale:latest + hostname: ${VELXIO_HOST:-velxio-dev} + environment: + - TS_AUTHKEY=${VELXIO_TS_AUTHKEY} + - TS_STATE_DIR=/var/lib/tailscale + - TS_USERSPACE=true + volumes: + - ../state/velxio:/var/lib/tailscale + - /dev/net/tun:/dev/net/tun + cap_add: + - net_admin + - sys_module + restart: unless-stopped + + velxio: + image: lms-velxio-standalone:latest + build: + context: ./velxio + dockerfile: Dockerfile.standalone + network_mode: service:velxio-ts + environment: + - SECRET_KEY=${VELXIO_SECRET_KEY:-embed-only-no-auth-needed} + - DATABASE_URL=sqlite+aiosqlite:////app/data/velxio.db + - DATA_DIR=/app/data + restart: unless-stopped + depends_on: + - velxio-ts + volumes: + - velxio-standalone-data:/app/data + - velxio-standalone-arduino-libs:/root/.arduino15 + - velxio-standalone-ccache:/var/cache/ccache + - velxio-standalone-build:/var/lib/velxio-build + +volumes: + velxio-standalone-data: + velxio-standalone-arduino-libs: + velxio-standalone-ccache: + velxio-standalone-build: diff --git a/podman-compose.yml b/podman-compose.yml index aacb4b4..09e3ca1 100644 --- a/podman-compose.yml +++ b/podman-compose.yml @@ -51,7 +51,7 @@ services: environment: - COMPILER_WORKER_URL=http://127.0.0.1:8080/execute - COMPILER_WORKER_BASE_URL=http://127.0.0.1:8080 - - VELXIO_COMPILER_URL=http://127.0.0.1:80/api/compile/ + - VELXIO_COMPILER_URL=${VELXIO_COMPILER_URL:-http://127.0.0.1:80/api/compile/} - DATABASE_URL=${DATABASE_URL} - TOKEN_PEPPER=${TOKEN_PEPPER} - STORAGE_BACKEND=${STORAGE_BACKEND:-postgresql}