ZMB Webui: Complete Project – Rebrand & Initial Clean Commit
ARCHITECTURE ============ Backend: FastAPI + uvicorn (port 8000) - JWT authentication with PAM system users - ZFS CLI wrapper with caching (30-60s TTL) - WebSocket pool status broadcaster (30s interval) - Services: auth, zfs_runner, file_manager, shares, identities, system_info - Routers: pools, datasets, snapshots, shares, identities, navigator, system Frontend: Next.js 15 + TypeScript (static export) - Incremental Static Regeneration (ISR) for weak hardware - Type-safe API client (lib/api.ts) - Dark mode + custom Tailwind theme - Pages: Dashboard, Login, Snapshots, Datasets, Shares, etc. DEPLOYMENT ========== Test Target: 192.168.1.179:8090 (Debian LXC) Production: 10.66.120.3:9090 (Raspberry Pi 4GB ARM64) Updater: Automated Gitea-based deployment (update-test.sh, update-pi.sh) FEATURES COMPLETED ================== Phase 3a: Dashboard Quick Stats (System, CPU, Memory, Storage) - Real-time stats with color-coded progress bars - Responsive grid layout (mobile: 1, tablet: 2, desktop: 4 columns) - ISR-optimized for fast loads on weak hardware REBRANDING ========== Renamed throughout: - Project: 'ZFS Manager' → 'ZMB Webui' - Services: 'zfs-manager' → 'zmb-webui' - Systemd units: zfs-manager-backend → zmb-webui-backend - Configuration files and documentation Co-Authored-By: Patrick <patrick@perlbach24.de>
This commit is contained in:
Executable
+197
@@ -0,0 +1,197 @@
|
||||
#!/bin/bash
|
||||
# ZMB Webui Updater – Lädt vom Gitea, baut neu und deployt
|
||||
# Unterstützt: update-179 (Test) und update-pi (Produktion)
|
||||
|
||||
set -e
|
||||
|
||||
GITEA_URL="https://gitea.perlbach24.de/scripte/zmb-webui.git"
|
||||
BRANCH="${1:-master}"
|
||||
TARGET="${2:-179}" # 179 oder pi
|
||||
|
||||
# Farben für Output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() { echo -e "${GREEN}✓${NC} $1"; }
|
||||
log_warn() { echo -e "${YELLOW}⚠${NC} $1"; }
|
||||
log_error() { echo -e "${RED}✗${NC} $1"; }
|
||||
|
||||
# Target validieren
|
||||
if [[ ! "$TARGET" =~ ^(179|pi)$ ]]; then
|
||||
log_error "Invalid target. Use: 179 (test) or pi (production)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Deploy-Parameter basierend auf Target
|
||||
if [ "$TARGET" = "179" ]; then
|
||||
REMOTE_HOST="192.168.1.179"
|
||||
BACKEND_PORT="8000"
|
||||
FRONTEND_PORT="8090"
|
||||
BACKEND_PATH="/opt/zmb-webui/backend"
|
||||
FRONTEND_PATH="/opt/zmb-webui/frontend"
|
||||
else
|
||||
REMOTE_HOST="10.66.120.3"
|
||||
BACKEND_PORT="8000"
|
||||
FRONTEND_PORT="9090"
|
||||
BACKEND_PATH="/opt/zmb-webui/backend"
|
||||
FRONTEND_PATH="/opt/zmb-webui/frontend"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo " ZMB Webui Updater – Target: $TARGET ($REMOTE_HOST)"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# 1. Gitea Pull
|
||||
echo "📥 Pulling from Gitea ($BRANCH)..."
|
||||
git fetch origin "$BRANCH" || {
|
||||
log_error "Git fetch failed. Token valid?"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/$BRANCH)" ]; then
|
||||
git pull origin "$BRANCH" || {
|
||||
log_error "Git pull failed"
|
||||
exit 1
|
||||
}
|
||||
log_info "Repository updated"
|
||||
else
|
||||
log_warn "Already up to date"
|
||||
fi
|
||||
|
||||
# 2. Frontend Build
|
||||
echo ""
|
||||
echo "🔨 Building frontend..."
|
||||
cd frontend
|
||||
rm -rf .next out 2>/dev/null || true
|
||||
|
||||
if ! npm run build > /tmp/npm-build.log 2>&1; then
|
||||
log_error "Frontend build failed"
|
||||
cat /tmp/npm-build.log | tail -20
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# next.config.js has output: 'export', so build creates ./out automatically
|
||||
if [ ! -d "out" ]; then
|
||||
log_error "Frontend export failed (out/ directory not created)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Frontend built and exported to ./out"
|
||||
cd ..
|
||||
|
||||
# 3. Backend Files
|
||||
echo ""
|
||||
echo "📦 Preparing backend files..."
|
||||
BACKEND_FILES=(
|
||||
"main.py"
|
||||
"requirements.txt"
|
||||
"services/auth.py"
|
||||
"services/zfs_runner.py"
|
||||
"services/file_manager.py"
|
||||
"services/identities.py"
|
||||
"services/shares.py"
|
||||
"services/system_info.py"
|
||||
"services/system_users.py"
|
||||
"routers/auth.py"
|
||||
"routers/pools.py"
|
||||
"routers/datasets.py"
|
||||
"routers/snapshots.py"
|
||||
"routers/shares.py"
|
||||
"routers/identities.py"
|
||||
"routers/navigator.py"
|
||||
"routers/system.py"
|
||||
"models/auth.py"
|
||||
"models/pool.py"
|
||||
"models/dataset.py"
|
||||
"models/snapshot.py"
|
||||
)
|
||||
|
||||
# 4. Sync zu Remote
|
||||
echo ""
|
||||
echo "🚀 Deploying to $REMOTE_HOST..."
|
||||
|
||||
# SSH Connection test
|
||||
if ! ssh -o ConnectTimeout=5 root@"$REMOTE_HOST" "echo 'SSH OK'" > /dev/null 2>&1; then
|
||||
log_error "Cannot connect to $REMOTE_HOST via SSH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Backend sync
|
||||
log_info "Syncing backend files..."
|
||||
for file in "${BACKEND_FILES[@]}"; do
|
||||
src="backend/$file"
|
||||
dst_dir="${BACKEND_PATH}/${file%/*}"
|
||||
|
||||
# Only sync if file exists
|
||||
if [ -f "$src" ]; then
|
||||
ssh root@"$REMOTE_HOST" "mkdir -p $dst_dir" 2>/dev/null || true
|
||||
scp -q "$src" "root@$REMOTE_HOST:$dst_dir/" 2>/dev/null || {
|
||||
log_warn "Could not sync $file"
|
||||
}
|
||||
fi
|
||||
done
|
||||
|
||||
# Frontend sync
|
||||
log_info "Syncing frontend..."
|
||||
rsync -q -r --delete frontend/out/ "root@$REMOTE_HOST:$FRONTEND_PATH/" || {
|
||||
log_error "Frontend rsync failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 5. Services Restart
|
||||
echo ""
|
||||
echo "🔄 Restarting services..."
|
||||
|
||||
ssh root@"$REMOTE_HOST" "systemctl restart zmb-webui-backend 2>/dev/null || true; sleep 2; systemctl restart nginx 2>/dev/null || true; sleep 1" || {
|
||||
log_error "Service restart failed"
|
||||
exit 1
|
||||
}
|
||||
|
||||
log_info "Backend restarted"
|
||||
log_info "Nginx restarted"
|
||||
|
||||
# 6. Health Check
|
||||
echo ""
|
||||
echo "🏥 Health check..."
|
||||
|
||||
BACKEND_UP=false
|
||||
FRONTEND_UP=false
|
||||
|
||||
# Backend check (max 10 Sekunden)
|
||||
for i in {1..10}; do
|
||||
if ssh root@"$REMOTE_HOST" "curl -s http://localhost:$BACKEND_PORT/health >/dev/null 2>&1" 2>/dev/null; then
|
||||
BACKEND_UP=true
|
||||
log_info "Backend responding"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Frontend check
|
||||
if ssh root@"$REMOTE_HOST" "curl -s http://localhost:$FRONTEND_PORT/ | grep -q '<html'" 2>/dev/null; then
|
||||
FRONTEND_UP=true
|
||||
log_info "Frontend responding"
|
||||
else
|
||||
log_warn "Frontend health check incomplete (may still be syncing)"
|
||||
fi
|
||||
|
||||
# 7. Summary
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
if [ "$BACKEND_UP" = true ]; then
|
||||
echo -e "${GREEN}✅ Update complete!${NC}"
|
||||
echo ""
|
||||
echo " Backend: http://$REMOTE_HOST:$BACKEND_PORT"
|
||||
echo " Frontend: http://$REMOTE_HOST:$FRONTEND_PORT"
|
||||
echo " Branch: $BRANCH"
|
||||
echo ""
|
||||
else
|
||||
echo -e "${YELLOW}⚠ Update deployed but backend not responding yet${NC}"
|
||||
echo " Check: ssh root@$REMOTE_HOST journalctl -u zmb-webui-backend -f"
|
||||
fi
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user