179 lines
6.9 KiB
Bash
Executable File
179 lines
6.9 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
echo "========================================="
|
|
echo " NexusGuard SD-WAN: SYSTEM UPDATE "
|
|
echo "========================================="
|
|
|
|
STATE_FILE=".update-state"
|
|
FORCE_REBUILD=false
|
|
BACKUP=false
|
|
NO_MIGRATE=false
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--force)
|
|
FORCE_REBUILD=true
|
|
shift
|
|
;;
|
|
--backup)
|
|
BACKUP=true
|
|
shift
|
|
;;
|
|
--no-migrate)
|
|
NO_MIGRATE=true
|
|
shift
|
|
;;
|
|
*)
|
|
echo "[!] Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# 1. Pastikan file env ada
|
|
if [ ! -f .env ]; then
|
|
echo "[-] ERROR: .env file not found. Please run ./setup.sh first to initialize configuration."
|
|
exit 1
|
|
fi
|
|
|
|
# 2. Update Code dari Git (Main & Submodules)
|
|
echo "[+] Pulling latest source code from repository..."
|
|
GIT_PULL_FAILED=false
|
|
git pull origin main || { GIT_PULL_FAILED=true; echo "[!] Git pull for main repo skipped or failed, continuing..."; }
|
|
|
|
echo "[+] Syncing and updating submodules..."
|
|
SUBMODULE_FAILED=false
|
|
# Only update server-core and dashboard-ui (Docker components)
|
|
# device-agent and device-agent-embedded are built separately
|
|
git submodule update --init --recursive --remote apps/server-core apps/dashboard-ui || { SUBMODULE_FAILED=true; echo "[!] Git submodule update skipped or failed."; }
|
|
|
|
# 2b. Build VitePress docs (non-blocking)
|
|
echo "[+] Building VitePress documentation..."
|
|
DOCS_BUILD_FAILED=false
|
|
if [ -d "apps/docs" ]; then
|
|
(cd apps/docs && npm install && npm run docs:build) || { DOCS_BUILD_FAILED=true; echo "[!] Docs build failed. Documentation may be stale. Continuing deployment..."; }
|
|
else
|
|
echo "[!] apps/docs directory not found. Skipping docs build."
|
|
fi
|
|
|
|
# 3. Hitung state hash (git + .env) untuk deteksi perubahan
|
|
CURRENT_HASH=$(echo "$(git rev-parse HEAD 2>/dev/null)$(git submodule status 2>/dev/null)$(sha256sum .env 2>/dev/null)" | sha256sum | cut -d" " -f1)
|
|
|
|
# 4. Tentukan apakah perlu rebuild
|
|
NEEDS_REBUILD=false
|
|
if [ "$FORCE_REBUILD" = true ]; then
|
|
echo "[+] --force flag detected. Will rebuild."
|
|
NEEDS_REBUILD=true
|
|
elif [ "$GIT_PULL_FAILED" = true ] || [ "$SUBMODULE_FAILED" = true ]; then
|
|
echo "[!] Git operation failed. Rebuilding as safe fallback."
|
|
NEEDS_REBUILD=true
|
|
elif [ ! -f "$STATE_FILE" ]; then
|
|
echo "[+] First run (no state file found). Full cycle required."
|
|
NEEDS_REBUILD=true
|
|
else
|
|
PREVIOUS_HASH=$(cat "$STATE_FILE" 2>/dev/null || echo "")
|
|
if [ "$CURRENT_HASH" != "$PREVIOUS_HASH" ]; then
|
|
echo "[+] State hash changed. Rebuilding."
|
|
NEEDS_REBUILD=true
|
|
else
|
|
echo "[-] No changes detected. Skipping build and restart."
|
|
fi
|
|
fi
|
|
|
|
# 5. Rebuild cycle — hanya jika ada perubahan
|
|
if [ "$NEEDS_REBUILD" = true ]; then
|
|
# Source .env untuk build process
|
|
echo "[+] Sourcing environment variables from root .env..."
|
|
set -a && . .env && set +a
|
|
|
|
# Volume safety check
|
|
echo "[+] Checking PostgreSQL volume safety..."
|
|
if ! docker volume inspect pgdata >/dev/null 2>&1; then
|
|
echo "[!] WARNING: PostgreSQL volume 'pgdata' not found. It will be created on container startup."
|
|
echo "[!] If you expect existing data, check your volume configuration."
|
|
else
|
|
echo "[+] PostgreSQL volume 'pgdata' found."
|
|
fi
|
|
|
|
# Backup option
|
|
if [ "$BACKUP" = true ]; then
|
|
echo "[+] Creating backup of PostgreSQL data..."
|
|
BACKUP_DIR="./backups"
|
|
mkdir -p "$BACKUP_DIR"
|
|
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
|
|
BACKUP_FILE="$BACKUP_DIR/pgdata_backup_$TIMESTAMP.tar"
|
|
|
|
# Backup the volume using a temporary container
|
|
if docker run --rm -v pgdata:/data -v "$(pwd)/$BACKUP_DIR":/backup ubuntu tar czf "/backup/pgdata_backup_$TIMESTAMP.tar.gz" -C /data . 2>/dev/null; then
|
|
echo "[+] Backup created successfully: $BACKUP_FILE.gz"
|
|
else
|
|
echo "[!] Backup failed. Continuing without backup."
|
|
fi
|
|
fi
|
|
|
|
# Password sync if DB_PASSWORD changed
|
|
echo "[+] Checking for PostgreSQL password synchronization..."
|
|
# Get current DB_PASSWORD from .env
|
|
CURRENT_DB_PASSWORD="${DB_PASSWORD:-nexusguard}"
|
|
|
|
# Try to connect to existing postgres container and update password if needed
|
|
POSTGRES_CONTAINER=$(docker compose ps -q postgres 2>/dev/null)
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|
echo "[+] Found running PostgreSQL container. Checking password..."
|
|
# Test if current password works
|
|
if docker exec "$POSTGRES_CONTAINER" pg_isready -U nexusguard -d nexusguard 2>/dev/null; then
|
|
echo "[+] Current password works. No password update needed."
|
|
else
|
|
echo "[!] Current password failed. Attempting to update PostgreSQL password to match .env..."
|
|
# Try to alter user password (requires superuser or same user)
|
|
if docker exec -u postgres "$POSTGRES_CONTAINER" psql -c "ALTER USER nexusguard WITH PASSWORD '$CURRENT_DB_PASSWORD';" 2>/dev/null; then
|
|
echo "[+] PostgreSQL password updated successfully."
|
|
else
|
|
echo "[!] Failed to update password. You may need to manually update it or check permissions."
|
|
echo "[!] Continuing update - authentication may fail if password mismatch."
|
|
fi
|
|
fi
|
|
else
|
|
echo "[i] No running PostgreSQL container found. Password will be set on container initialization (if data directory is empty)."
|
|
fi
|
|
|
|
echo "[+] Stopping existing containers..."
|
|
docker compose down
|
|
|
|
echo "[+] Rebuilding Docker images..."
|
|
docker compose build --build-arg VITE_API_BASE_URL=$VITE_API_BASE_URL
|
|
|
|
echo "[+] Restarting containers..."
|
|
docker compose up -d
|
|
|
|
if [ "$NO_MIGRATE" = false ]; then
|
|
echo "[+] Running automated database migrations..."
|
|
docker exec nexus-guard-suite-server-core-1 ./server-core -migrate-prod || echo "[!] Migration skipped or failed. It might not be needed."
|
|
else
|
|
echo "[+] Skipping database migration (--no-migrate flag used)."
|
|
fi
|
|
|
|
echo "[+] Backfilling interface addresses..."
|
|
docker exec nexus-guard-suite-server-core-1 ./server-core -backfill-interface 2>/dev/null || echo "[!] Backfill skipped or not needed."
|
|
|
|
echo "[+] Cleaning up unused dangling images..."
|
|
docker image prune -f
|
|
|
|
# Simpan state secara atomik (tmp + mv untuk cegah korupsi file)
|
|
echo "$CURRENT_HASH" > "$STATE_FILE.tmp" && mv "$STATE_FILE.tmp" "$STATE_FILE"
|
|
|
|
echo "========================================="
|
|
echo " Update & Deployment complete! "
|
|
echo " Dashboard : http://localhost:${WEB_PORT:-80}"
|
|
echo " API Port : ${API_PORT:-8080}"
|
|
if [ "$BACKUP" = true ]; then
|
|
echo " Backup : Stored in ./backups/ directory"
|
|
fi
|
|
echo "========================================="
|
|
else
|
|
echo "========================================="
|
|
echo " No update needed — system is current. "
|
|
echo "========================================="
|
|
fi |