Preview mode that survives a reboot, and a fallback log that survives one too
This commit is contained in:
@@ -865,6 +865,17 @@
|
|||||||
# Success returns on the first try, so a healthy cycle costs
|
# Success returns on the first try, so a healthy cycle costs
|
||||||
# nothing extra. Only a failure pays: 3×4s + 2×2s = 16s worst
|
# nothing extra. Only a failure pays: 3×4s + 2×2s = 16s worst
|
||||||
# case, which must stay under FALLBACK_CHECK_INTERVAL.
|
# case, which must stay under FALLBACK_CHECK_INTERVAL.
|
||||||
|
FALLBACK_DRY_RUN=false # run the daemon in PREVIEW mode, permanently
|
||||||
|
# Survives array start, unlike a --dry-run typed at a shell:
|
||||||
|
# array_started.sh launches with no arguments, so a hand-run
|
||||||
|
# preview is replaced by the LIVE daemon at the next boot.
|
||||||
|
# Decides nothing, starts nothing, moves no DNS, sends no
|
||||||
|
# notification — it only reports what it WOULD have done.
|
||||||
|
# Set true to observe real outages before arming for real.
|
||||||
|
FALLBACK_LOG_MAX_MB=5 # size cap for data/logs/fallback.log before one rotation
|
||||||
|
# Event-only output (the default, no --log) is a few lines
|
||||||
|
# per incident and holds years; --log fills this in about a
|
||||||
|
# fortnight and keeps the previous one as fallback.log.1
|
||||||
FALLBACK_STATE_FILE="$STATE_DIR/fallback_state.db"
|
FALLBACK_STATE_FILE="$STATE_DIR/fallback_state.db"
|
||||||
FALLBACK_ENABLED=false # set true once both servers are configured and paired
|
FALLBACK_ENABLED=false # set true once both servers are configured and paired
|
||||||
# false = suppresses "not running" warnings in status scripts
|
# false = suppresses "not running" warnings in status scripts
|
||||||
|
|||||||
@@ -314,6 +314,50 @@ if [[ "$EUID" -ne 0 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# ── Persistent dry-run ────────────────────────────────────────────────────────────────────────
|
||||||
|
# Conf-driven, not argument-driven, deliberately. array_started.sh launches every entry as a bare
|
||||||
|
# `bash script.sh &` with no arguments, so a --dry-run typed at a terminal survives exactly until
|
||||||
|
# the next array start — and then the LIVE daemon comes up in its place, silently, which is the
|
||||||
|
# one transition nobody would be watching for.
|
||||||
|
#
|
||||||
|
# Setting it here means the mode is a property of the install rather than of how the process
|
||||||
|
# happened to be started: array start, the Fallback tab's button, and a hand-run all agree.
|
||||||
|
#
|
||||||
|
# OR, never override: --dry-run on the command line still wins over a conf that says false, so an
|
||||||
|
# ad-hoc preview against a live install needs no conf edit.
|
||||||
|
if [[ "${FALLBACK_DRY_RUN:-false}" == "true" ]]; then
|
||||||
|
DRY_RUN=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ── Persistent log ────────────────────────────────────────────────────────────────────────────
|
||||||
|
# array_started.sh launches every entry as a bare `bash script.sh &` with no redirection, so this
|
||||||
|
# daemon's output has never been captured anywhere: /var/log/varaverk has a directory for every
|
||||||
|
# other script family and none for Fallback. A month of dry-run observation would have persisted
|
||||||
|
# nothing at all.
|
||||||
|
#
|
||||||
|
# /var/log is a 128 MB tmpfs on Unraid — RAM, and cleared on reboot — so the log goes to
|
||||||
|
# LOG_ARCHIVE_DIR, which follows DATA_DIR onto real storage.
|
||||||
|
#
|
||||||
|
# Only when stdout is not a terminal. Run by hand, output still goes to the terminal exactly as
|
||||||
|
# before; run by array_started or the Fallback tab's button, it lands in the file. A plain append
|
||||||
|
# redirect rather than `tee` through process substitution: no extra child to outlive, and nothing
|
||||||
|
# for the shutdown trap to race.
|
||||||
|
FALLBACK_LOG="${LOG_ARCHIVE_DIR:-${DATA_DIR:-/tmp}/logs}/fallback.log"
|
||||||
|
if [[ ! -t 1 ]]; then
|
||||||
|
mkdir -p "$(dirname "$FALLBACK_LOG")" 2>/dev/null
|
||||||
|
# One rotation, sized rather than line-counted — the whole point of this log is a long run,
|
||||||
|
# and _orch_trim_log()'s 1000-line cap would discard weeks of it. Event-only output (no
|
||||||
|
# --log) is a few lines per incident, so this holds years; --log fills it in about a fortnight
|
||||||
|
# and then keeps the most recent fortnight plus the one before it.
|
||||||
|
_fb_max=$(( ${FALLBACK_LOG_MAX_MB:-5} * 1048576 ))
|
||||||
|
if [[ -f "$FALLBACK_LOG" ]] && (( $(stat -c %s "$FALLBACK_LOG" 2>/dev/null || echo 0) > _fb_max )); then
|
||||||
|
mv -f "$FALLBACK_LOG" "${FALLBACK_LOG}.1" 2>/dev/null
|
||||||
|
fi
|
||||||
|
exec >> "$FALLBACK_LOG" 2>&1
|
||||||
|
echo ""
|
||||||
|
echo "═══ fallback.sh started $(date '+%Y-%m-%d %H:%M:%S') — dry_run=${DRY_RUN} pid=$$ ═══"
|
||||||
|
fi
|
||||||
# FALLBACK_ENABLED gate — exits cleanly when disabled.
|
# FALLBACK_ENABLED gate — exits cleanly when disabled.
|
||||||
# Fail-closed: anything that isn't exactly "true" disables fallback. Matching only the
|
# Fail-closed: anything that isn't exactly "true" disables fallback. Matching only the
|
||||||
# literal "false" would let a typo ("no", "0", "FALSE") hand this script DDNS authority
|
# literal "false" would let a typo ("no", "0", "FALSE") hand this script DDNS authority
|
||||||
|
|||||||
@@ -84,9 +84,11 @@ $scripts = rtrim(SCRIPTS_DIR, '/');
|
|||||||
$cmds = [
|
$cmds = [
|
||||||
'stop' => 'bash ' . escapeshellarg("$scripts/Fallback/fallback.sh") . ' --stop 2>&1',
|
'stop' => 'bash ' . escapeshellarg("$scripts/Fallback/fallback.sh") . ' --stop 2>&1',
|
||||||
'stop_test' => 'bash ' . escapeshellarg("$scripts/Fallback/fallback_test.sh") . ' --stop 2>&1',
|
'stop_test' => 'bash ' . escapeshellarg("$scripts/Fallback/fallback_test.sh") . ' --stop 2>&1',
|
||||||
// setsid so it outlives this request; own log so the page can show what the preview said.
|
// setsid so it outlives this request. No redirect: fallback.sh writes its own persistent
|
||||||
|
// log when stdout is not a terminal, so an ad-hoc preview and the array-start daemon leave
|
||||||
|
// their record in the same file rather than one going to tmpfs and vanishing on reboot.
|
||||||
'start_dry' => 'setsid bash ' . escapeshellarg("$scripts/Fallback/fallback.sh")
|
'start_dry' => 'setsid bash ' . escapeshellarg("$scripts/Fallback/fallback.sh")
|
||||||
. ' --dry-run --log > /tmp/varaverk/fallback_dryrun.log 2>&1 < /dev/null & echo started',
|
. ' --dry-run --log > /dev/null 2>&1 < /dev/null & echo started',
|
||||||
'clear_lock' => 'rm -f /tmp/unraid_locks/fallback.lock /tmp/unraid_locks/fallback_test.lock && echo cleared',
|
'clear_lock' => 'rm -f /tmp/unraid_locks/fallback.lock /tmp/unraid_locks/fallback_test.lock && echo cleared',
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -119,8 +121,8 @@ if ($remoteDir === '') $remoteDir = '/boot/config/plugins/varaverk';
|
|||||||
$remoteCmds = [
|
$remoteCmds = [
|
||||||
'stop' => "bash '$remoteDir/Fallback/fallback.sh' --stop 2>&1",
|
'stop' => "bash '$remoteDir/Fallback/fallback.sh' --stop 2>&1",
|
||||||
'stop_test' => "bash '$remoteDir/Fallback/fallback_test.sh' --stop 2>&1",
|
'stop_test' => "bash '$remoteDir/Fallback/fallback_test.sh' --stop 2>&1",
|
||||||
'start_dry' => "mkdir -p /tmp/varaverk; setsid bash '$remoteDir/Fallback/fallback.sh'"
|
'start_dry' => "setsid bash '$remoteDir/Fallback/fallback.sh'"
|
||||||
. " --dry-run --log > /tmp/varaverk/fallback_dryrun.log 2>&1 < /dev/null & echo started",
|
. " --dry-run --log > /dev/null 2>&1 < /dev/null & echo started",
|
||||||
'clear_lock' => 'rm -f /tmp/unraid_locks/fallback.lock /tmp/unraid_locks/fallback_test.lock && echo cleared',
|
'clear_lock' => 'rm -f /tmp/unraid_locks/fallback.lock /tmp/unraid_locks/fallback_test.lock && echo cleared',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -353,6 +353,7 @@ function vv_fb_all(): array {
|
|||||||
'fb_enabled' => $fbEnabled,
|
'fb_enabled' => $fbEnabled,
|
||||||
'partnership_enabled' => $ptEnabled,
|
'partnership_enabled' => $ptEnabled,
|
||||||
'fb_rsync_enabled' => $rsyncEnabled,
|
'fb_rsync_enabled' => $rsyncEnabled,
|
||||||
|
'dry_run' => vv_fb_scalar($masterRaw, 'FALLBACK_DRY_RUN') === 'true',
|
||||||
'handback_req' => $handbackReq,
|
'handback_req' => $handbackReq,
|
||||||
'check_interval' => $checkInterval,
|
'check_interval' => $checkInterval,
|
||||||
'suspend_after' => $suspendAfter,
|
'suspend_after' => $suspendAfter,
|
||||||
|
|||||||
@@ -237,6 +237,19 @@ if (vv_ai_ui_on()) vv_ai_chat_assets();
|
|||||||
</div>
|
</div>
|
||||||
<div class="vv-fb-tog" id="vv-fb-rsync-tog" onclick="vvFbToggle(this,'FALLBACK_RSYNC_ENABLED')"></div>
|
<div class="vv-fb-tog" id="vv-fb-rsync-tog" onclick="vvFbToggle(this,'FALLBACK_RSYNC_ENABLED')"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<hr class="vv-fb-sep">
|
||||||
|
|
||||||
|
<!-- Persistent preview. Distinct from the per-card "Start dry run" button: that launches one
|
||||||
|
now, this decides what array_started.sh launches at every boot. Without it a preview lasts
|
||||||
|
exactly until the next array start and is then silently replaced by the live daemon. -->
|
||||||
|
<div class="vv-fb-ctrl-row">
|
||||||
|
<div>
|
||||||
|
<div class="vv-fb-ctrl-lbl">Preview mode <span style="font-size:9px;color:#4a9eff;border:1px solid #1e3a5a;background:#101a26;border-radius:3px;padding:1px 5px;margin-left:5px;">DRY RUN</span></div>
|
||||||
|
<div class="vv-fb-ctrl-sub">Watch and report, change nothing — no containers, no DDNS, no notifications. Survives reboots, so a long observation run stays a preview.</div>
|
||||||
|
</div>
|
||||||
|
<div class="vv-fb-tog" id="vv-fb-dry-tog" onclick="vvFbToggle(this,'FALLBACK_DRY_RUN')"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mesh verdict — one line answering "is this armed and is anything watching" before any detail -->
|
<!-- Mesh verdict — one line answering "is this armed and is anything watching" before any detail -->
|
||||||
@@ -712,6 +725,7 @@ function _setToggles(data) {
|
|||||||
['vv-fb-pt-tog', !!data.partnership_enabled],
|
['vv-fb-pt-tog', !!data.partnership_enabled],
|
||||||
['vv-fb-en-tog', !!data.fb_enabled],
|
['vv-fb-en-tog', !!data.fb_enabled],
|
||||||
['vv-fb-rsync-tog', !!data.fb_rsync_enabled],
|
['vv-fb-rsync-tog', !!data.fb_rsync_enabled],
|
||||||
|
['vv-fb-dry-tog', !!data.dry_run],
|
||||||
];
|
];
|
||||||
pairs.forEach(([id, on]) => {
|
pairs.forEach(([id, on]) => {
|
||||||
const el = document.getElementById(id);
|
const el = document.getElementById(id);
|
||||||
|
|||||||
Reference in New Issue
Block a user