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
+243
@@ -0,0 +1,243 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ZMB Webui Deployment Script
|
||||
# Unterstützt Frontend, Backend und Full-Deployment auf Remote-Host
|
||||
# Usage: ./deploy.sh [--target HOST] [--backend-only|--frontend-only]
|
||||
|
||||
set -e
|
||||
|
||||
# Default values
|
||||
TARGET="192.168.1.179"
|
||||
DEPLOY_BACKEND=true
|
||||
DEPLOY_FRONTEND=true
|
||||
BACKEND_SERVICE="zmb-webui-backend"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--target)
|
||||
TARGET="$2"
|
||||
shift 2
|
||||
;;
|
||||
--backend-only)
|
||||
DEPLOY_FRONTEND=false
|
||||
shift
|
||||
;;
|
||||
--frontend-only)
|
||||
DEPLOY_BACKEND=false
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown option: $1${NC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
check_prerequisites() {
|
||||
log_info "Checking prerequisites..."
|
||||
|
||||
if ! command -v scp &> /dev/null; then
|
||||
log_error "scp not found. Please install openssh-client"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v ssh &> /dev/null; then
|
||||
log_error "ssh not found. Please install openssh-client"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v curl &> /dev/null; then
|
||||
log_error "curl not found. Please install curl"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_FRONTEND" = true ] && ! command -v npm &> /dev/null; then
|
||||
log_error "npm not found. Please install Node.js/npm"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "All prerequisites met"
|
||||
}
|
||||
|
||||
check_ssh_connection() {
|
||||
log_info "Testing SSH connection to $TARGET..."
|
||||
|
||||
if ! ssh -o ConnectTimeout=5 root@$TARGET "echo 'Connection OK'" > /dev/null 2>&1; then
|
||||
log_error "Cannot connect to $TARGET via SSH"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "SSH connection successful"
|
||||
}
|
||||
|
||||
deploy_frontend() {
|
||||
log_info "Building frontend..."
|
||||
|
||||
if [ ! -d "frontend" ]; then
|
||||
log_error "frontend directory not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd frontend
|
||||
|
||||
if [ ! -f "package.json" ]; then
|
||||
log_error "package.json not found in frontend directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
npm run build
|
||||
|
||||
if [ ! -d "out" ]; then
|
||||
log_error "Frontend build failed - 'out' directory not created"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Frontend build successful"
|
||||
cd ..
|
||||
|
||||
log_info "Uploading frontend to $TARGET..."
|
||||
|
||||
if ! scp -r frontend/out/* root@$TARGET:/opt/zmb-webui/backend/static/ 2>/dev/null; then
|
||||
log_error "Failed to upload frontend files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Frontend deployed successfully"
|
||||
}
|
||||
|
||||
deploy_backend() {
|
||||
log_info "Deploying backend services..."
|
||||
|
||||
if [ ! -d "backend/services" ]; then
|
||||
log_error "backend/services directory not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "backend/main.py" ]; then
|
||||
log_error "backend/main.py not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Uploading backend services to $TARGET..."
|
||||
|
||||
if ! scp backend/services/*.py root@$TARGET:/opt/zmb-webui/backend/services/ 2>/dev/null; then
|
||||
log_error "Failed to upload backend services"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Uploading main.py to $TARGET..."
|
||||
|
||||
if ! scp backend/main.py root@$TARGET:/opt/zmb-webui/backend/ 2>/dev/null; then
|
||||
log_error "Failed to upload main.py"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Backend files uploaded successfully"
|
||||
}
|
||||
|
||||
restart_backend() {
|
||||
log_info "Restarting backend service on $TARGET..."
|
||||
|
||||
if ! ssh root@$TARGET "systemctl restart $BACKEND_SERVICE" 2>/dev/null; then
|
||||
log_error "Failed to restart backend service"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Backend service restarted"
|
||||
|
||||
# Wait a moment for service to start
|
||||
sleep 2
|
||||
}
|
||||
|
||||
reload_nginx() {
|
||||
log_info "Testing Nginx configuration on $TARGET..."
|
||||
|
||||
if ! ssh root@$TARGET "nginx -t" 2>/dev/null; then
|
||||
log_error "Nginx configuration test failed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Reloading Nginx..."
|
||||
|
||||
if ! ssh root@$TARGET "systemctl reload nginx" 2>/dev/null; then
|
||||
log_error "Failed to reload Nginx"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Nginx reloaded successfully"
|
||||
}
|
||||
|
||||
health_check() {
|
||||
log_info "Running health check..."
|
||||
|
||||
local max_retries=5
|
||||
local retry_count=0
|
||||
local http_code
|
||||
|
||||
while [ $retry_count -lt $max_retries ]; do
|
||||
http_code=$(curl -s -o /dev/null -w "%{http_code}" "http://$TARGET/api/status" || echo "000")
|
||||
|
||||
if [ "$http_code" = "200" ]; then
|
||||
log_info "Health check passed (HTTP $http_code)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
if [ $retry_count -lt $max_retries ]; then
|
||||
log_warn "Health check returned HTTP $http_code, retrying... ($retry_count/$max_retries)"
|
||||
sleep 2
|
||||
fi
|
||||
done
|
||||
|
||||
log_error "Health check failed after $max_retries attempts (last HTTP code: $http_code)"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
log_info "Starting deployment to $TARGET"
|
||||
log_info "Frontend: $DEPLOY_FRONTEND | Backend: $DEPLOY_BACKEND"
|
||||
|
||||
check_prerequisites
|
||||
check_ssh_connection
|
||||
|
||||
if [ "$DEPLOY_FRONTEND" = true ]; then
|
||||
deploy_frontend
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_BACKEND" = true ]; then
|
||||
deploy_backend
|
||||
restart_backend
|
||||
fi
|
||||
|
||||
if [ "$DEPLOY_BACKEND" = true ] || [ "$DEPLOY_FRONTEND" = true ]; then
|
||||
reload_nginx
|
||||
fi
|
||||
|
||||
health_check
|
||||
|
||||
log_info "Deployment completed successfully!"
|
||||
exit 0
|
||||
}
|
||||
|
||||
main
|
||||
Reference in New Issue
Block a user