Files
kit-busrouter/scripts/provision-synology.sh
T
allen f15ac69925 feat: kit-busrouter v2.0 — complete Synology + GL fleet router platform
Includes:
- package/ GL-XE3000 kit-busrouter (opkg)
- scripts/provision.sh (GL) and provision-synology.sh (Synology)
- syno-balance/ — new WAN balancer replacing aiwanbal (SmartWAN adapter)
- kit-connect/ — unified connectivity SPK (Tailscale + reverse SSH)
- docs/deployment/synology-rt2600ac-checklist.md — 62-point checklist
- docs/provisioning/device-identity.md — fleet identity spec
- docs/pilot/checklist.md — field pilot validation
- x4078_20260721.dss — reference config backup

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 00:07:14 +00:00

299 lines
14 KiB
Bash
Executable File

#!/bin/sh
# provision-synology.sh — Bootstrap a Synology RT2600ac Pioneer Bus Router
#
# Run once from router LAN or console on a fresh/factory Synology SRM unit.
#
# Usage:
# provision-synology.sh <DEVICE_ID> [TAILSCALE_AUTH_KEY]
#
# DEVICE_ID : bus identifier, e.g. B0042
# Becomes the WiFi SSID on both bands (plan spec).
# TAILSCALE_AUTH_KEY : Tailscale pre-auth key (tskey-...).
# Omit if Tailscale is already configured.
#
# Prerequisites:
# - SRM 1.3.1+ with SSH enabled (Control Panel → Terminal & SNMP)
# - SD card inserted (for persistent storage)
# - aiwanbal SPK at /tmp/aiwanbal-latest.spk (or set AIWANBAL_SPK env)
# - Tailscale SPK installed (or TAILSCALE_AUTH_KEY provided to configure)
# - Eyeride Eyenet reachable at 192.168.10.1 (if GPS is used)
# - Edit HUB_TAILSCALE_IP constant below before deploying
#
# Idempotent: safe to re-run after partial failure.
set -e
DEVICE_ID="${1:?Usage: provision-synology.sh <DEVICE_ID> [TAILSCALE_AUTH_KEY]}"
TAILSCALE_AUTH_KEY="${2:-}"
AIWANBAL_SPK="${AIWANBAL_SPK:-/tmp/aiwanbal-latest.spk}"
# ── Fleet-wide constants (edit before deploying) ──────────────────────────────────
HUB_TAILSCALE_IP="100.76.128.1" # hub's Tailscale IP
HUB_TELEMETRY_PORT="8080" # telemetry API port on hub
HUB_TELEMETRY_PATH="/api/telemetry" # telemetry endpoint path
WIFI_PASS="Pioneer123"
ADMIN_PASS="Pioneer321!"
TIMEZONE="UTC"
# Guard: catch forgotten placeholder before any changes are made
case "$HUB_TAILSCALE_IP" in
REPLACE_*|CHANGE_ME*|"")
echo "[provision] ERROR: edit HUB_TAILSCALE_IP in provision-synology.sh before running" >&2
exit 1
;;
esac
TELEMETRY_HUB="http://${HUB_TAILSCALE_IP}:${HUB_TELEMETRY_PORT}${HUB_TELEMETRY_PATH}"
echo "[provision] === Pioneer Bus Router Provisioning (Synology SRM) ==="
echo "[provision] DEVICE_ID : $DEVICE_ID"
echo "[provision] HUB_TAILSCALE_IP : $HUB_TAILSCALE_IP"
echo "[provision] TELEMETRY_HUB : $TELEMETRY_HUB"
echo ""
# ── 1. Device identity ───────────────────────────────────────────────────────────
echo "[provision] 1/11 Device identity"
mkdir -p /etc/busrouter
printf '%s\n' "$DEVICE_ID" > /etc/busrouter/device-id
if [ ! -f /etc/busrouter/version ]; then
printf '0.0\n' > /etc/busrouter/version
fi
echo "[provision] device-id: $(cat /etc/busrouter/device-id)"
echo "[provision] version: $(cat /etc/busrouter/version)"
# ── 2. Hostname ──────────────────────────────────────────────────────────────────
# SRM stores hostname in /etc/synoinfo.conf and /etc/hostname
echo "[provision] 2/11 Hostname → ${DEVICE_ID}"
if command -v synosetkeyvalue >/dev/null 2>&1; then
synosetkeyvalue /etc/synoinfo.conf system hostname "$DEVICE_ID" 2>/dev/null || true
fi
hostname "$DEVICE_ID" 2>/dev/null || true
printf '%s\n' "$DEVICE_ID" > /etc/hostname 2>/dev/null || true
# ── 3. Admin accounts ────────────────────────────────────────────────────────────
# Synology SRM: the web admin user is typically "admin" (created at setup).
# SSH uses root (set via SRM Control Panel → Terminal & SNMP).
# We set the root password for fleet SSH access.
echo "[provision] 3/11 Admin account (root password)"
printf '%s\n%s\n' "$ADMIN_PASS" "$ADMIN_PASS" | passwd root 2>/dev/null || \
echo "root:${ADMIN_PASS}" | chpasswd 2>/dev/null || \
echo "[provision] WARNING: failed to set root password"
# ── 4. WiFi SSID ─────────────────────────────────────────────────────────────────
# SRM WiFi is managed through the web UI (Wi-Fi Connect app).
# We can configure it via synowifi if available, but the authoritative path
# is the SRM Network Center. Log the expected values and attempt CLI config.
echo "[provision] 4/11 WiFi SSID=${DEVICE_ID} (2.4G + 5G)"
echo "[provision] Password: ${WIFI_PASS}"
echo "[provision] NOTE: If WiFi doesn't change, configure manually in SRM:"
echo "[provision] Wi-Fi Connect → Radio 1 (2.4G) → SSID: ${DEVICE_ID}"
echo "[provision] Wi-Fi Connect → Radio 2 (5G) → SSID: ${DEVICE_ID}"
# Try synowifi if present (may not exist on all SRM versions)
if command -v synowifi >/dev/null 2>&1; then
synowifi --set-ssid "$DEVICE_ID" --set-security wpa2-personal --set-passphrase "$WIFI_PASS" 2>/dev/null || \
echo "[provision] WARNING: synowifi command failed — configure WiFi via SRM web UI"
elif command -v /usr/syno/bin/synowifi >/dev/null 2>&1; then
/usr/syno/bin/synowifi --set-ssid "$DEVICE_ID" --set-security wpa2-personal --set-passphrase "$WIFI_PASS" 2>/dev/null || \
echo "[provision] WARNING: synowifi command failed — configure WiFi via SRM web UI"
fi
# ── 5. Install aiwanbal ──────────────────────────────────────────────────────────
echo "[provision] 5/11 aiwanbal WAN balancer"
if [ -f "$AIWANBAL_SPK" ]; then
echo "[provision] Installing aiwanbal from $AIWANBAL_SPK"
synopkg install "$AIWANBAL_SPK" 2>/dev/null || \
echo "[provision] WARNING: synopkg install failed — install manually"
else
echo "[provision] WARNING: $AIWANBAL_SPK not found"
echo "[provision] Build aiwanbal SPK first, then copy to router:"
echo "[provision] cd /home/node/workspace/aiwanbal && bash build.sh"
echo "[provision] scp -O aiwanbal-*.spk kitadmin@<router>:/tmp/aiwanbal-latest.spk"
fi
# Ensure aiwanbal is running
if synopkg status aiwanbal >/dev/null 2>&1; then
synopkg start aiwanbal 2>/dev/null || true
echo "[provision] aiwanbal started"
else
echo "[provision] WARNING: aiwanbal package not found — install before continuing"
fi
# ── 6. Configure aiwanbal for busrouter (mobile environment) ─────────────────────
echo "[provision] 6/11 aiwanbal busrouter tuning"
AIWANBAL_CONF="/etc/aiwanbal/aiwanbal.conf"
if [ -f "$AIWANBAL_CONF" ]; then
# Set environment to mobile for faster scoring adaptations
if grep -q '^ENVIRONMENT=' "$AIWANBAL_CONF" 2>/dev/null; then
sed -i 's/^ENVIRONMENT=.*/ENVIRONMENT="mobile"/' "$AIWANBAL_CONF"
else
echo 'ENVIRONMENT="mobile"' >> "$AIWANBAL_CONF"
fi
# Set device name for fleet logging
if grep -q '^DEVICE_NAME=' "$AIWANBAL_CONF" 2>/dev/null; then
sed -i "s/^DEVICE_NAME=.*/DEVICE_NAME=\"$DEVICE_ID\"/" "$AIWANBAL_CONF"
else
echo "DEVICE_NAME=\"$DEVICE_ID\"" >> "$AIWANBAL_CONF"
fi
# Metered cellular: disable automatic speed tests to save data
if grep -q '^SPEEDTEST_AUTO=' "$AIWANBAL_CONF" 2>/dev/null; then
sed -i 's/^SPEEDTEST_AUTO=.*/SPEEDTEST_AUTO="0"/' "$AIWANBAL_CONF"
else
echo 'SPEEDTEST_AUTO="0"' >> "$AIWANBAL_CONF"
fi
# Log the config update
logger -t provision "aiwanbal tuned for busrouter: mobile mode, auto-speedtest disabled"
echo "[provision] ENVIRONMENT=mobile, SPEEDTEST_AUTO=0, DEVICE_NAME=${DEVICE_ID}"
else
echo "[provision] WARNING: aiwanbal.conf not found — tune manually"
fi
# ── 7. Tailscale ─────────────────────────────────────────────────────────────────
echo "[provision] 7/11 Tailscale"
if command -v tailscale >/dev/null 2>&1; then
if [ -n "$TAILSCALE_AUTH_KEY" ]; then
echo "[provision] Authenticating with pre-auth key..."
tailscale up --authkey="$TAILSCALE_AUTH_KEY" --hostname="$DEVICE_ID" 2>/dev/null || \
echo "[provision] WARNING: tailscale up failed — check auth key"
else
ts_status=$(tailscale status --json 2>/dev/null || echo '{"BackendState":"NeedsLogin"}')
ts_state=$(echo "$ts_status" | grep -o '"BackendState":"[^"]*"' | cut -d'"' -f4)
if [ "$ts_state" = "Running" ]; then
echo "[provision] Tailscale is running"
else
echo "[provision] WARNING: Tailscale not authenticated"
echo "[provision] Run: tailscale up --hostname=${DEVICE_ID}"
echo "[provision] Or re-run with: provision-synology.sh ${DEVICE_ID} <AUTH_KEY>"
fi
fi
# Show Tailscale IP for fleet records
ts_ip=$(tailscale ip -4 2>/dev/null || echo "unknown")
echo "[provision] Tailscale IP: ${ts_ip}"
else
echo "[provision] WARNING: tailscale not found — install Tailscale SPK first"
echo "[provision] Download from: https://pkgs.tailscale.com/stable/#synology"
fi
# ── 8. Telemetry script + cron ───────────────────────────────────────────────────
echo "[provision] 8/11 Telemetry agent"
# Determine where to install the telemetry script
TELEM_SRC="/usr/lib/busrouter/telemetry-synology.sh"
TELEM_DEST="${TELEM_DEST:-/usr/lib/busrouter/telemetry-synology.sh}"
# Check if this script is bundled with the repo (running from checkout) or
# needs to be copied from a pre-staged location.
if [ -f "$TELEM_SRC" ]; then
echo "[provision] Using telemetry script from ${TELEM_SRC}"
elif [ -f "/tmp/telemetry-synology.sh" ]; then
TELEM_SRC="/tmp/telemetry-synology.sh"
echo "[provision] Using telemetry script from /tmp/"
else
# The script should be copied alongside provision-synology.sh before running
echo "[provision] WARNING: telemetry-synology.sh not found"
echo "[provision] Copy it to /tmp/telemetry-synology.sh and re-run:"
echo "[provision] scp package/kit-busrouter/files/usr/lib/busrouter/telemetry-synology.sh \\"
echo "[provision] kitadmin@<router>:/tmp/"
fi
if [ -f "$TELEM_SRC" ]; then
mkdir -p "$(dirname "$TELEM_DEST")"
cp "$TELEM_SRC" "$TELEM_DEST"
chmod +x "$TELEM_DEST"
# Configure the hub endpoint in the script
sed -i "s|TELEMETRY_HUB:=http://10.88.0.1:8080/api/telemetry|TELEMETRY_HUB:=${TELEMETRY_HUB}|" "$TELEM_DEST"
# Add cron job: run telemetry every 60 seconds
# SRM uses /etc/crontab with user field (standard vixie-cron format)
CRON_JOB="* * * * * root ${TELEM_DEST} 2>/dev/null"
if [ -f /etc/crontab ]; then
if ! grep -qF "$TELEM_DEST" /etc/crontab 2>/dev/null; then
# Sleep offset to spread fleet load: use the last octet of device ID as stagger
_stagger=0
_dev_suffix=$(echo "$DEVICE_ID" | grep -o '[0-9]*$' || echo "0")
_stagger=$(( _dev_suffix % 60 ))
printf '%s\n' "* * * * * root sleep ${_stagger}; ${TELEM_DEST} 2>/dev/null" >> /etc/crontab
echo "[provision] Cron job added (${_stagger}s offset)"
else
echo "[provision] Cron job already present"
fi
else
# Fallback: use crontab -e style
(crontab -l 2>/dev/null || true; echo "* * * * * ${TELEM_DEST} 2>/dev/null") | crontab - 2>/dev/null || \
echo "[provision] WARNING: failed to add cron job — add manually"
fi
echo "[provision] Telemetry installed at ${TELEM_DEST}"
fi
# ── 9. Hub SSH jump key ──────────────────────────────────────────────────────────
echo "[provision] 9/11 Hub SSH jump key"
mkdir -p /root/.ssh
JUMP_KEY='ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMS842ZbXPXHbVd9IjyVGubq7M/yQA/cn/vHgB5R0/ZE busfleet-hub-jump'
if ! grep -qF 'busfleet-hub-jump' /root/.ssh/authorized_keys 2>/dev/null; then
printf '%s\n' "$JUMP_KEY" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
echo "[provision] Hub jump key installed"
else
echo "[provision] Hub jump key already present"
fi
# ── 10. Eyeride GPS config (optional) ────────────────────────────────────────────
echo "[provision] 10/11 Eyeride GPS"
EYERIDE_IP="${EYERIDE_IP:-192.168.10.1}"
EYERIDE_PORT="${EYERIDE_PORT:-8080}"
echo "[provision] Eyeride target: ${EYERIDE_IP}:${EYERIDE_PORT}"
echo "[provision] Set EYERIDE_PASSWORD env before running telemetry for GPS"
echo "[provision] To configure permanently, add to aiwanbal.conf:"
echo "[provision] EYERIDE_IP=${EYERIDE_IP}"
echo "[provision] EYERIDE_PORT=${EYERIDE_PORT}"
echo "[provision] EYERIDE_PASSWORD=<your-eyenet-password>"
# ── 11. Verify + start services ──────────────────────────────────────────────────
echo "[provision] 11/11 Final checks"
# Ensure aiwanbal is running
if synopkg status aiwanbal >/dev/null 2>&1; then
synopkg start aiwanbal 2>/dev/null || true
echo "[provision] aiwanbal is running"
fi
# Run one telemetry cycle to verify
if [ -x "$TELEM_DEST" ]; then
if "$TELEM_DEST" 2>/dev/null; then
echo "[provision] Telemetry dry-run OK"
else
echo "[provision] Telemetry dry-run completed (check logs for POST result)"
fi
fi
# ── Done ──────────────────────────────────────────────────────────────────────────
echo ""
echo "[provision] ============================================"
echo "[provision] DONE: $DEVICE_ID provisioned (Synology SRM)."
echo ""
echo " Device ID : $DEVICE_ID"
echo " Hostname : $DEVICE_ID"
echo " WiFi SSID : $DEVICE_ID (2.4G + 5G) pw: Pioneer123"
echo " Admin SSH : ssh root@<router-lan-ip> pw: Pioneer321!"
if command -v tailscale >/dev/null 2>&1; then
echo " Tailscale IP : $(tailscale ip -4 2>/dev/null || echo 'check `tailscale status`')"
fi
echo " Telemetry : ${TELEMETRY_HUB} (every 60s via cron)"
echo ""
echo " Verify:"
echo " cat /etc/busrouter/device-id"
echo " synopkg status aiwanbal"
echo " tailscale status"
echo " grep telemetry /etc/crontab"
echo " tail -f /var/log/messages | grep busrouter"
echo "[provision] ============================================"
echo ""
# ── Reboot ───────────────────────────────────────────────────────────────────────
echo "[provision] Rebooting in 5 s ..."
sleep 5
reboot