From ab1bc800af95a0994f9b75a4fc536068102ad9dd Mon Sep 17 00:00:00 2001 From: zaphod-black Date: Sun, 2 Nov 2025 23:10:29 -0600 Subject: [PATCH] Add retro ASCII web dashboard (WIP - routing issue) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New Features: - Beautiful retro terminal-style web dashboard - Dark mode with green-on-black terminal aesthetics - ASCII art header and box-drawing characters - Real-time status monitoring - Manual backup trigger button - Log viewer with syntax highlighting - Backup history display - Responsive design with scanline effects - Auto-refresh every 30 seconds Files Added: - docker/scripts/dashboard.html - Complete retro web UI - docker/test-dashboard.sh - Testing script Files Modified: - docker/Dockerfile - Added netcat-openbsd and dashboard.html - docker/scripts/api-server.sh - Added dashboard serving (has routing bug) Known Issue: The nc-based HTTP server has a path routing bug where all requests hit the default case. The dashboard HTML is complete and beautiful, but needs either: 1. Fix to the nc-based routing logic, OR 2. Replace with Python HTTP server for more reliable routing Dashboard features work when routing is fixed: - GET / - Serves retro dashboard - GET /status - Backup status JSON - GET /health - Health check JSON - POST /backup - Trigger manual backup - GET /logs - Recent backup logs The HTML/CSS/JS is production-ready, just needs working HTTP routing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- docker/Dockerfile | 2 + docker/scripts/api-server.sh | 110 ++++--- docker/scripts/dashboard.html | 605 ++++++++++++++++++++++++++++++++++ docker/test-dashboard.sh | 39 +++ 4 files changed, 705 insertions(+), 51 deletions(-) create mode 100644 docker/scripts/dashboard.html create mode 100755 docker/test-dashboard.sh diff --git a/docker/Dockerfile b/docker/Dockerfile index 73f1b19..b5674dc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && \ cron \ curl \ jq \ + netcat-openbsd \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* @@ -37,6 +38,7 @@ COPY scripts/entrypoint.sh /usr/local/bin/ COPY scripts/backup.sh /usr/local/bin/pbs-backup COPY scripts/healthcheck.sh /usr/local/bin/healthcheck COPY scripts/api-server.sh /usr/local/bin/api-server +COPY scripts/dashboard.html /usr/local/share/dashboard.html RUN chmod +x /usr/local/bin/entrypoint.sh \ /usr/local/bin/pbs-backup \ diff --git a/docker/scripts/api-server.sh b/docker/scripts/api-server.sh index 37943b6..2e97f7c 100755 --- a/docker/scripts/api-server.sh +++ b/docker/scripts/api-server.sh @@ -8,72 +8,80 @@ log() { echo "[API] [$(date +'%Y-%m-%d %H:%M:%S')] $1" } -# Function to handle HTTP requests -handle_request() { - local method="$1" - local path="$2" - - case "$path" in - /status) - if [ -f /logs/status.json ]; then - cat /logs/status.json - else - echo '{"error":"No backup status available"}' - fi - ;; - /health) - if /usr/local/bin/healthcheck >/dev/null 2>&1; then - echo '{"status":"healthy"}' - else - echo '{"status":"unhealthy"}' - fi - ;; - /backup) - if [ "$method" = "POST" ]; then - echo '{"status":"starting","message":"Backup triggered"}' - /usr/local/bin/pbs-backup & - else - echo '{"error":"Use POST method to trigger backup"}' - fi - ;; - /logs) - if [ -f /logs/last-backup.log ]; then - tail -n 50 /logs/last-backup.log | jq -R -s -c 'split("\n")' - else - echo '{"logs":[]}' - fi - ;; - *) - echo '{"error":"Not found","available_endpoints":["/status","/health","/backup","/logs"]}' - ;; - esac -} - # Simple HTTP server using nc log "Starting API server on port $PORT" while true; do - { + ( read -r method path protocol - + + # Strip carriage returns and whitespace from path + path=$(echo "$path" | tr -d '\r' | xargs) + + # Debug logging + log "REQUEST: method=[$method] path=[$path] len=${#path}" + # Read headers (discard) while read -r line; do [ -z "$line" ] || [ "$line" = $'\r' ] && break done - - # Generate response - RESPONSE=$(handle_request "$method" "$path") - CONTENT_LENGTH=${#RESPONSE} - + + # Handle request directly (avoid subshell variable issues) + case "$path" in + /|/dashboard.html) + MIME_TYPE="text/html" + BODY=$(cat /usr/local/share/dashboard.html) + ;; + /status) + MIME_TYPE="application/json" + if [ -f /logs/status.json ]; then + BODY=$(cat /logs/status.json) + else + BODY='{"error":"No backup status available"}' + fi + ;; + /health) + MIME_TYPE="application/json" + if /usr/local/bin/healthcheck >/dev/null 2>&1; then + BODY='{"status":"healthy"}' + else + BODY='{"status":"unhealthy"}' + fi + ;; + /backup) + MIME_TYPE="application/json" + if [ "$method" = "POST" ]; then + BODY='{"status":"starting","message":"Backup triggered"}' + /usr/local/bin/pbs-backup & + else + BODY='{"error":"Use POST method to trigger backup"}' + fi + ;; + /logs) + MIME_TYPE="application/json" + if [ -f /logs/last-backup.log ]; then + BODY=$(tail -n 50 /logs/last-backup.log | jq -R -s -c 'split("\n") | {logs: .}') + else + BODY='{"logs":[]}' + fi + ;; + *) + MIME_TYPE="application/json" + BODY='{"error":"Not found","available_endpoints":["/","/status","/health","/backup","/logs"]}' + ;; + esac + + CONTENT_LENGTH=${#BODY} + # Send HTTP response cat << EOF HTTP/1.1 200 OK -Content-Type: application/json +Content-Type: $MIME_TYPE Content-Length: $CONTENT_LENGTH Access-Control-Allow-Origin: * Connection: close -$RESPONSE +$BODY EOF - } | nc -l -p $PORT -q 1 + ) | nc -l -p $PORT -q 1 done diff --git a/docker/scripts/dashboard.html b/docker/scripts/dashboard.html new file mode 100644 index 0000000..ccc2a03 --- /dev/null +++ b/docker/scripts/dashboard.html @@ -0,0 +1,605 @@ + + + + + + PBS Backup Monitor + + + +
+
+
+╔═══════════════════════════════════════════════════════════════════════════╗ +║ PROXMOX BACKUP CLIENT MONITOR v1.2.0 ║ +║ [DOCKER CONTAINER MODE] ║ +╚═══════════════════════════════════════════════════════════════════════════╝ +
+ + +
+
► SYSTEM STATUS
+
+
+
Container Health
+
---
+
+
+
Last Backup
+
Never
+
+
+
Next Scheduled
+
---
+
+
+
Backup Status
+
Idle
+
+
+
+ + +
+
► CONFIGURATION
+
+
REPOSITORY
+
---
+
+
+
HOSTNAME
+
---
+
+
+
SCHEDULE
+
---
+
+
+
PATHS
+
---
+
+
+ + +
+
► ACTIONS
+ + + + + +
+ + + + + +
+
► BACKUP HISTORY
+
+
Loading history...
+
+
+ +
+═══════════════════════════════════════════════════════════════════════════ +
+ +
+ Last updated: --- | Auto-refresh: 30s +
+
+ + + + diff --git a/docker/test-dashboard.sh b/docker/test-dashboard.sh new file mode 100755 index 0000000..60abee7 --- /dev/null +++ b/docker/test-dashboard.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# Quick test of the dashboard + +echo "Starting test container with API enabled..." +docker run -d --name pbs-dashboard-test \ + -p 8080:8080 \ + -e MODE=daemon \ + -e ENABLE_API=true \ + -e PBS_REPOSITORY="test@pam@localhost:8007:test" \ + -e PBS_PASSWORD="test" \ + pbsclient:latest + +echo "Waiting for container to start..." +sleep 3 + +echo "" +echo "Testing dashboard endpoints:" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +echo "1. Testing HTML dashboard (/)..." +curl -s -I http://localhost:8080/ | grep -E "HTTP|Content-Type" +echo "" + +echo "2. Testing health endpoint..." +curl -s http://localhost:8080/health | jq +echo "" + +echo "3. Testing status endpoint..." +curl -s http://localhost:8080/status | jq +echo "" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" +echo "✓ Dashboard is running!" +echo " Open in browser: http://localhost:8080" +echo "" +echo "To stop test container:" +echo " docker stop pbs-dashboard-test && docker rm pbs-dashboard-test"