One reviewed step instead of a hand-typed sequence on the host: back up the config, convert the passwd file into the plugin's store with every hash intact, rewrite mosquitto.conf, restart, and prove the server and the health probe reconnect. ROLLBACK=1 restores the previous config. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KGcjxF1cNLcuwc3DAPcnfj
60 lines
3.5 KiB
Bash
Executable File
60 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Move a running broker from passwd/acl files to the dynamic-security plugin,
|
|
# keeping every existing login and password. Run AFTER deploy.sh has put a
|
|
# server on the host that has `broker-init`.
|
|
#
|
|
# server/broker-cutover.sh do it
|
|
# ROLLBACK=1 server/broker-cutover.sh put the previous config back
|
|
#
|
|
# What it does: backs up mosquitto/config, converts passwd → the plugin's store
|
|
# inside the broker's data volume (same hashes, so no shop PC re-claims),
|
|
# rewrites mosquitto.conf, restarts the broker, and proves the server and the
|
|
# health probe reconnect. Every step before the restart is reversible by not
|
|
# doing the restart; the rollback restores the backed-up config and restarts.
|
|
set -euo pipefail
|
|
HOST=${HOST:-root@66.116.226.161}
|
|
KEY=${KEY:-$HOME/.ssh/behavision_deploy}
|
|
DIR=/root/behavision
|
|
SSH=(ssh -i "$KEY" -o BatchMode=yes -o ConnectTimeout=10 "$HOST")
|
|
step() { printf '\n\033[1m%s\033[0m\n' "$*"; }
|
|
|
|
if [ -n "${ROLLBACK:-}" ]; then
|
|
step "Rolling back to the passwd/acl configuration"
|
|
"${SSH[@]}" "cd $DIR && latest=\$(ls -d mosquitto/config.bak-* | tail -1) && cp \$latest/mosquitto.conf mosquitto/config/mosquitto.conf && docker compose restart mosquitto && sleep 3 && docker logs --tail 5 behavision-mqtt"
|
|
exit 0
|
|
fi
|
|
|
|
step "1. Back up the broker configuration"
|
|
"${SSH[@]}" "cd $DIR && cp -a mosquitto/config mosquitto/config.bak-\$(date +%Y%m%d-%H%M%S) && ls -d mosquitto/config.bak-* | tail -1"
|
|
|
|
step "2. Convert passwd into the plugin's store (hashes unchanged)"
|
|
# The data volume belongs to the broker's user (1883); the init runs as root to
|
|
# write there and then hands the file over. Refuses if a store already exists.
|
|
"${SSH[@]}" "cd $DIR && docker run --rm --user root \
|
|
-v $DIR/mosquitto/config:/m:ro -v behavision_mosquitto-data:/d \
|
|
--entrypoint /usr/local/bin/behavision-server behavision-backend:latest \
|
|
broker-init -passwd /m/passwd -out /d/dynamic-security.json \
|
|
&& docker run --rm --user root -v behavision_mosquitto-data:/d alpine:3.20 sh -c 'chown 1883:1883 /d/dynamic-security.json && chmod 600 /d/dynamic-security.json && ls -la /d/dynamic-security.json'"
|
|
|
|
step "3. Rewrite mosquitto.conf for the plugin"
|
|
"${SSH[@]}" "cd $DIR && python3 - <<'PY'
|
|
import re
|
|
p = 'mosquitto/config/mosquitto.conf'
|
|
s = open(p).read()
|
|
s = re.sub(r'^per_listener_settings\s+true\s*$', 'per_listener_settings false', s, flags=re.M)
|
|
s = re.sub(r'^(password_file|acl_file)\s+.*\n', '', s, flags=re.M)
|
|
if 'mosquitto_dynamic_security' not in s:
|
|
s = s.rstrip('\n') + '\n\n# Logins and topic permissions live in the dynamic-security plugin now.\n# The server creates a shop\'s login over the control topic; nothing is\n# edited by hand and nothing is reloaded.\nplugin /usr/lib/mosquitto_dynamic_security.so\nplugin_opt_config_file /mosquitto/data/dynamic-security.json\n'
|
|
open(p, 'w').write(s)
|
|
print(open(p).read())
|
|
PY"
|
|
|
|
step "4. Restart the broker"
|
|
"${SSH[@]}" "cd $DIR && docker compose restart mosquitto && sleep 4 && docker logs --tail 8 behavision-mqtt 2>&1 | grep -i 'error\|plugin\|running\|connected' | tail -6"
|
|
|
|
step "5. Prove the server and the health probe are back"
|
|
"${SSH[@]}" "cd $DIR && sleep 6 && docker logs --since 30s behavision-backend 2>&1 | grep -i 'broker\|subscribed' | tail -3; docker inspect behavision-mqtt --format 'health: {{.State.Health.Status}}' 2>/dev/null || true; docker logs --since 40s behavision-mqtt 2>&1 | grep -i 'not authori\|denied' | head -3 || true"
|
|
echo
|
|
echo "If step 5 shows 'subscribed to bv/#' and no 'not authorised', the cutover is done."
|
|
echo "Anything wrong: ROLLBACK=1 server/broker-cutover.sh"
|