Add no-cache response header to dashboard for immediate visibility after deploys; enhance Proxmox monitoring documentation and update flash script to allow Backup without a golden image.
This commit is contained in:
@@ -14,6 +14,16 @@ from flask import Flask, render_template, jsonify, request, send_file, Response
|
|||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.after_request
|
||||||
|
def no_cache(response):
|
||||||
|
"""Prevent browser from caching the dashboard so deploys are visible immediately."""
|
||||||
|
if request.path == "/" or request.path.startswith("/api/"):
|
||||||
|
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
||||||
|
response.headers["Pragma"] = "no-cache"
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
BASE_DIR = Path(os.environ.get("CM4_PROVISIONING_DIR", "/var/lib/cm4-provisioning"))
|
BASE_DIR = Path(os.environ.get("CM4_PROVISIONING_DIR", "/var/lib/cm4-provisioning"))
|
||||||
STATUS_FILE = os.environ.get("CM4_STATUS_FILE", str(BASE_DIR / "status.json"))
|
STATUS_FILE = os.environ.get("CM4_STATUS_FILE", str(BASE_DIR / "status.json"))
|
||||||
LOG_FILE = os.environ.get("CM4_LOG_FILE", str(BASE_DIR / "flash.log"))
|
LOG_FILE = os.environ.get("CM4_LOG_FILE", str(BASE_DIR / "flash.log"))
|
||||||
|
|||||||
@@ -141,6 +141,32 @@ Then open **http://<LXC-201-IP>:5000** (get the IP with `pct exec 201 -- h
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Monitoring from the host
|
||||||
|
|
||||||
|
From the **Proxmox host** you can monitor:
|
||||||
|
|
||||||
|
| What | How |
|
||||||
|
|------|-----|
|
||||||
|
| **USB device** | `lsusb` — CM4 in boot mode shows as **2b8e** (RPi) or **0a5c:2711** (Broadcom BCM2711) |
|
||||||
|
| **Live status** | `cat /var/lib/cm4-provisioning/status.json` — same JSON the dashboard shows (phase, message, error) |
|
||||||
|
| **Flash log** | `tail -f /var/lib/cm4-provisioning/flash.log` — script log (rpiboot, dd, errors) |
|
||||||
|
| **Flash job** | `systemctl status cm4-flash-once` — whether the udev-triggered job is running/failed |
|
||||||
|
| **Journal** | `journalctl -u cm4-flash-once -f` or `journalctl -t cm4-flash -f` — systemd/log output |
|
||||||
|
| **Block devices** | `lsblk` — after rpiboot, the eMMC appears as a new disk (e.g. `/dev/sdb`) |
|
||||||
|
| **Backups** | `ls /var/lib/cm4-provisioning/backups/` — backup images created from the dashboard |
|
||||||
|
| **Config** | `cat /opt/cm4-provisioning/env` — GOLDEN_IMAGE, RPIBOOT_DIR, EMMC_SIZE_BYTES |
|
||||||
|
|
||||||
|
**One-command snapshot:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From your machine (stream script to host):
|
||||||
|
ssh root@10.130.60.224 'bash -s' < chromium-setup/emmc-provisioning/scripts/monitor-from-host.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Or copy `scripts/monitor-from-host.sh` to the host and run `./monitor-from-host.sh` for a full status dump (USB, status.json, flash unit, last log lines, block devices, config).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Redeploy / update scripts
|
## Redeploy / update scripts
|
||||||
|
|
||||||
From your repo (e.g. after changing scripts):
|
From your repo (e.g. after changing scripts):
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# When reTerminal (CM4) is connected in USB boot mode (eMMC disable jumper),
|
# When reTerminal (CM4) is connected in USB boot mode (eMMC disable jumper),
|
||||||
# Raspberry Pi Foundation USB device appears (vendor 2b8e). Trigger provisioning:
|
# the device appears as either Raspberry Pi Foundation (2b8e) or Broadcom BCM2711 Boot (0a5c:2711).
|
||||||
# run rpiboot to expose eMMC, then wait for user to choose Backup or Deploy in the portal.
|
# Trigger provisioning: run rpiboot, then wait for user to choose Backup or Deploy in the portal.
|
||||||
# No auto-flash — action runs only after portal choice.
|
|
||||||
# Install: sudo cp 90-cm4-boot-mode.rules /etc/udev/rules.d/
|
# Install: sudo cp 90-cm4-boot-mode.rules /etc/udev/rules.d/
|
||||||
# sudo udevadm control --reload-rules
|
# sudo udevadm control --reload-rules
|
||||||
# The trigger script starts the provisioning script via systemd so udev does not block.
|
|
||||||
|
|
||||||
SUBSYSTEM=="usb", ATTR{idVendor}=="2b8e", ACTION=="add", \
|
SUBSYSTEM=="usb", ATTR{idVendor}=="2b8e", ACTION=="add", \
|
||||||
RUN+="/usr/local/bin/cm4-flash-trigger.sh"
|
RUN+="/usr/local/bin/cm4-flash-trigger.sh"
|
||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="0a5c", ATTR{idProduct}=="2711", ACTION=="add", \
|
||||||
|
RUN+="/usr/local/bin/cm4-flash-trigger.sh"
|
||||||
|
|||||||
@@ -48,11 +48,9 @@ ACTION_REQUEST_FILE="${ACTION_REQUEST_FILE:-/var/lib/cm4-provisioning/action_req
|
|||||||
CURRENT_DEVICE_FILE="${CURRENT_DEVICE_FILE:-/var/lib/cm4-provisioning/current_device}"
|
CURRENT_DEVICE_FILE="${CURRENT_DEVICE_FILE:-/var/lib/cm4-provisioning/current_device}"
|
||||||
DEVICE_SOURCE_FILE="${DEVICE_SOURCE_FILE:-/var/lib/cm4-provisioning/device_source}"
|
DEVICE_SOURCE_FILE="${DEVICE_SOURCE_FILE:-/var/lib/cm4-provisioning/device_source}"
|
||||||
WAIT_TIMEOUT="${WAIT_TIMEOUT:-600}"
|
WAIT_TIMEOUT="${WAIT_TIMEOUT:-600}"
|
||||||
# Golden image required for deploy
|
# Golden image required only for Deploy; allow Backup without it
|
||||||
if [[ ! -f "$GOLDEN_IMAGE" ]]; then
|
if [[ ! -f "$GOLDEN_IMAGE" ]]; then
|
||||||
log "Golden image not found (required for deploy): $GOLDEN_IMAGE"
|
log "Golden image not found (Deploy will be unavailable): $GOLDEN_IMAGE"
|
||||||
write_status "error" "Golden image not found" "null" "Golden image not found. Add golden.img for deploy."
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RPIBOOT_BIN="$RPIBOOT_DIR/rpiboot"
|
RPIBOOT_BIN="$RPIBOOT_DIR/rpiboot"
|
||||||
@@ -140,6 +138,12 @@ for (( i = 0; i < WAIT_TIMEOUT; i += 2 )); do
|
|||||||
write_status "error" "Backup failed" "null" "dd failed"
|
write_status "error" "Backup failed" "null" "dd failed"
|
||||||
fi
|
fi
|
||||||
elif [[ "$action" == "deploy" ]]; then
|
elif [[ "$action" == "deploy" ]]; then
|
||||||
|
if [[ ! -f "$GOLDEN_IMAGE" ]]; then
|
||||||
|
log "Golden image not found; cannot deploy."
|
||||||
|
write_status "error" "Deploy unavailable" "null" "Golden image not found. Add golden.img to /var/lib/cm4-provisioning/ for deploy."
|
||||||
|
rm -f "$CURRENT_DEVICE_FILE" "$DEVICE_SOURCE_FILE" 2>/dev/null || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
write_status "flashing" "Writing golden image…" "null"
|
write_status "flashing" "Writing golden image…" "null"
|
||||||
log "Flashing $GOLDEN_IMAGE to $target_dev..."
|
log "Flashing $GOLDEN_IMAGE to $target_dev..."
|
||||||
if dd if="$GOLDEN_IMAGE" of="$target_dev" bs=4M status=progress conv=fsync 2>>"$LOG_FILE"; then
|
if dd if="$GOLDEN_IMAGE" of="$target_dev" bs=4M status=progress conv=fsync 2>>"$LOG_FILE"; then
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Run on the Proxmox HOST (where USB is connected) to verify the reTerminal in boot mode is seen.
|
||||||
|
# Usage: ssh root@10.130.60.224 'bash -s' < scripts/check-usb-on-host.sh
|
||||||
|
# Or copy to host and run: ./check-usb-on-host.sh
|
||||||
|
|
||||||
|
echo "=== CM4 boot-mode USB (2b8e = RPi, 0a5c:2711 = Broadcom BCM2711) ==="
|
||||||
|
lsusb | grep -E "2b8e|0a5c" || echo "None found. Connect reTerminal in boot mode (eMMC disable jumper) and use the USB slave port."
|
||||||
|
echo ""
|
||||||
|
echo "=== All USB devices ==="
|
||||||
|
lsusb
|
||||||
|
echo ""
|
||||||
|
echo "=== Provisioning status ==="
|
||||||
|
cat /var/lib/cm4-provisioning/status.json 2>/dev/null || echo "No status.json (script has not run yet)."
|
||||||
|
echo ""
|
||||||
|
echo "=== Last flash log ==="
|
||||||
|
tail -15 /var/lib/cm4-provisioning/flash.log 2>/dev/null || echo "No flash.log"
|
||||||
|
echo ""
|
||||||
|
echo "=== udev rule and rpiboot ==="
|
||||||
|
test -f /etc/udev/rules.d/90-cm4-boot-mode.rules && echo "90-cm4-boot-mode.rules: present" || echo "90-cm4-boot-mode.rules: MISSING"
|
||||||
|
test -x /opt/usbboot/rpiboot && echo "rpiboot: present" || echo "rpiboot: MISSING"
|
||||||
|
test -f /etc/cm4-provisioning/enabled && echo "enabled: yes" || echo "enabled: no (provisioning disabled)"
|
||||||
33
chromium-setup/emmc-provisioning/scripts/deploy-dashboard-to-lxc.sh
Executable file
33
chromium-setup/emmc-provisioning/scripts/deploy-dashboard-to-lxc.sh
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Deploy only the dashboard to the LXC by IP (no Proxmox host needed).
|
||||||
|
# Usage: ./deploy-dashboard-to-lxc.sh [user@lxc_ip]
|
||||||
|
# Example: ./deploy-dashboard-to-lxc.sh root@10.130.60.119
|
||||||
|
|
||||||
|
set -e
|
||||||
|
LXC="${1:-root@10.130.60.119}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
REPO_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
DASHBOARD_DIR="$REPO_DIR/dashboard"
|
||||||
|
REMOTE_DIR="/opt/cm4-provisioning/dashboard"
|
||||||
|
|
||||||
|
if [[ ! -d "$DASHBOARD_DIR" ]]; then
|
||||||
|
echo "Error: dashboard dir not found: $DASHBOARD_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Deploying dashboard to $LXC ($REMOTE_DIR) ..."
|
||||||
|
ssh "$LXC" "mkdir -p $REMOTE_DIR/templates"
|
||||||
|
|
||||||
|
rsync -avz \
|
||||||
|
"$DASHBOARD_DIR/app.py" \
|
||||||
|
"$DASHBOARD_DIR/cm4-dashboard.service" \
|
||||||
|
"$LXC:$REMOTE_DIR/"
|
||||||
|
|
||||||
|
rsync -avz \
|
||||||
|
"$DASHBOARD_DIR/templates/" \
|
||||||
|
"$LXC:$REMOTE_DIR/templates/"
|
||||||
|
|
||||||
|
echo "Restarting cm4-dashboard service ..."
|
||||||
|
ssh "$LXC" "systemctl restart cm4-dashboard && systemctl is-active --quiet cm4-dashboard && echo 'Dashboard restarted and running.'"
|
||||||
|
|
||||||
|
echo "Done. Dashboard at http://$(echo "$LXC" | cut -d@ -f2):5000"
|
||||||
44
chromium-setup/emmc-provisioning/scripts/monitor-from-host.sh
Executable file
44
chromium-setup/emmc-provisioning/scripts/monitor-from-host.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Run on the Proxmox HOST to see provisioning status, USB, flash job, and logs.
|
||||||
|
# Usage: ./monitor-from-host.sh or: ssh root@10.130.60.224 'bash -s' < scripts/monitor-from-host.sh
|
||||||
|
|
||||||
|
PROV=/var/lib/cm4-provisioning
|
||||||
|
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo " CM4 provisioning – host monitor"
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- USB (CM4 boot mode: 2b8e or 0a5c:2711) ---"
|
||||||
|
lsusb | grep -E "2b8e|0a5c" || echo " No CM4 boot device seen."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Current status (dashboard reads this) ---"
|
||||||
|
if [[ -f "$PROV/status.json" ]]; then
|
||||||
|
cat "$PROV/status.json" | python3 -m json.tool 2>/dev/null || cat "$PROV/status.json"
|
||||||
|
else
|
||||||
|
echo " No status.json (no run yet)."
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Flash job (systemd unit) ---"
|
||||||
|
systemctl show cm4-flash-once --property=ActiveState,SubState,ExecMainPID 2>/dev/null || echo " Unit not run yet."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Last 20 lines of flash.log ---"
|
||||||
|
tail -20 "$PROV/flash.log" 2>/dev/null || echo " No flash.log"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Provisioning dir ---"
|
||||||
|
ls -la "$PROV/" 2>/dev/null || echo " Dir missing."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Block devices (eMMC appears here after rpiboot) ---"
|
||||||
|
lsblk -d -o NAME,SIZE,MODEL,TRAN 2>/dev/null | head -15
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- Config ---"
|
||||||
|
echo " enabled: $([ -f /etc/cm4-provisioning/enabled ] && echo yes || echo no)"
|
||||||
|
echo " rpiboot: $([ -x /opt/usbboot/rpiboot ] && echo /opt/usbboot/rpiboot || echo MISSING)"
|
||||||
|
echo " golden: $([ -f $PROV/golden.img ] && echo present || echo not set)"
|
||||||
|
echo " backups: $(ls "$PROV/backups" 2>/dev/null | wc -l) file(s)"
|
||||||
Reference in New Issue
Block a user