fix(scripts): re-apply secubox-haproxy-regen-safe sub-command fix

A merge from feature/83 reverted the fix from commit 22014865, which had
already replaced `haproxyctl regen` (non-existent sub-command, printed
help text and exited 0) with the correct `haproxyctl generate`.

This commit re-applies the same fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-05-12 11:17:34 +02:00
parent 443e375f46
commit ba9f6b20c1

View File

@ -1,55 +1,58 @@
#!/bin/bash
# secubox-haproxy-regen-safe — Safe haproxy.cfg regeneration with validate + atomic swap + rollback
# secubox-haproxy-regen-safe — Safe haproxy.cfg regeneration with validate + rollback
#
# Usage: secubox-haproxy-regen-safe [--no-reload]
#
# Flow:
# 1. Snapshot current /etc/haproxy/haproxy.cfg
# 2. Generate new cfg via haproxyctl regen (output to .new)
# 3. Validate new cfg with haproxy -c -f
# 4. On success: atomic swap + reload haproxy
# 5. On failure: keep current cfg, exit non-zero
# 1. Snapshot /etc/haproxy/haproxy.cfg
# 2. Run `haproxyctl generate` (writes new cfg in place)
# 3. Validate with `haproxy -c -f` — if invalid, restore snapshot
# 4. Reload haproxy on success (skip with --no-reload)
#
# CyberMind — added 2026-05-12 after Session 155 haproxy regression incident.
# CyberMind — 2026-05-12 (post Session 156 regression).
set -euo pipefail
CFG=/etc/haproxy/haproxy.cfg
TS=$(date +%s)
SNAP="$CFG.bak.$TS-pre-regen"
NEW="$CFG.new.$TS"
RELOAD=1
[[ "${1:-}" == "--no-reload" ]] && RELOAD=0
log() { echo "[$(date "+%F %T")] $*" >&2; }
[[ -x /usr/sbin/haproxyctl ]] || { log "FATAL: haproxyctl missing"; exit 2; }
[[ -x /usr/sbin/haproxyctl ]] || { log "FATAL: /usr/sbin/haproxyctl missing"; exit 2; }
[[ -r "$CFG" ]] || { log "FATAL: $CFG missing or unreadable"; exit 2; }
log "Snapshot current cfg -> $SNAP"
cp "$CFG" "$SNAP"
log "Snapshot $CFG → $SNAP"
cp -p "$CFG" "$SNAP"
log "Generate new cfg via haproxyctl"
# haproxyctl writes to $CFG directly; redirect by temporarily moving
cp "$CFG" "$NEW"
if ! /usr/sbin/haproxyctl regen 2>&1 | tail -5; then
log "regen failed; restoring snapshot"
mv "$SNAP" "$CFG"
rm -f "$NEW"
log "Run: haproxyctl generate"
if ! /usr/sbin/haproxyctl generate; then
log "haproxyctl generate failed; restoring snapshot"
cp -p "$SNAP" "$CFG"
exit 3
fi
mv "$CFG" "$NEW"
mv "$SNAP" "$CFG" # restore current while we validate the new
log "Validate new cfg"
if haproxy -c -f "$NEW" >/dev/null 2>&1; then
log "validation OK"
mv "$NEW" "$CFG"
if [[ $RELOAD -eq 1 ]]; then
log "reload haproxy"
systemctl reload haproxy && log "reload OK" || { log "reload FAILED"; exit 4; }
fi
log "regen-safe complete"
else
log "validation FAILED; cfg untouched; broken candidate saved as $NEW.broken"
mv "$NEW" "$NEW.broken"
log "Validate new $CFG"
if ! haproxy -c -f "$CFG" >/dev/null 2>&1; then
log "validation FAILED; saving broken candidate and restoring snapshot"
cp -p "$CFG" "$CFG.broken.$TS"
cp -p "$SNAP" "$CFG"
log "broken candidate kept at $CFG.broken.$TS for forensics"
exit 5
fi
log "validation OK"
if [[ $RELOAD -eq 1 ]]; then
log "Reload haproxy"
if systemctl reload haproxy; then
log "reload OK"
else
log "reload failed; rolling back to snapshot"
cp -p "$SNAP" "$CFG"
systemctl reload haproxy && log "rollback reload OK" || log "rollback reload ALSO failed — manual intervention needed"
exit 4
fi
fi
log "regen-safe complete (snapshot kept: $SNAP)"