Partnership echo/log audit pass + exit trap

Exit trap (_pm_trap_restart_stopped) in partnership_manager.sh: restarts locally
stopped containers if script crashes mid-cleanup; partnership_offboard.sh registers
same trap. echo/log audit: step result lines (stack deployed counts, state writes,
onboard/offboard complete) → echo; check mode ACTIVE/INACTIVE status → echo;
ssh_setup.sh key-exists and install/verify results → echo. Manual-Partnership.md:
added Output Tiers section.
This commit is contained in:
Gmer4Lfe
2026-05-21 17:11:05 -04:00
parent 588cde1cc4
commit 86b31256ed
5 changed files with 60 additions and 15 deletions
+23
View File
@@ -371,6 +371,29 @@ Counter resets after `SSH_STRIKE_RESET_HRS` of clean connectivity.
--- ---
## ━━━ OUTPUT TIERS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
All scripts use a two-tier output model: `echo` lines are always visible; `log`
lines only appear when `--log` is passed.
**partnership_onboard.sh** — one-shot setup. Without `--log`, step headers, per-step
result lines (deployed/failed counts), and the final summary are visible. Per-container
deploy detail suppressed.
**partnership_offboard.sh** — one-shot teardown. Without `--log`, step headers, key
state transitions, and the final checklist summary are visible. Per-container cleanup
detail suppressed.
**partnership_manager.sh** — check/status/transfer/onboard modes. Without `--log`,
mode-specific result lines (`--check` prints ACTIVE/INACTIVE status always), state
transitions, warnings, and summary blocks are visible. Per-operation detail suppressed.
**ssh_setup.sh** — one-shot key setup. Without `--log`, section headers and per-step
results (key created, key installed, auth verified) are visible. Strike-counter
management (`--validate`) uses `log` for healthy cycles; `warn` for failures.
---
## ━━━ FLAG REFERENCE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ## ━━━ FLAG REFERENCE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
### partnership_onboard.sh ### partnership_onboard.sh
+22 -3
View File
@@ -270,6 +270,21 @@ OWNER_STATE_FILE="/boot/config/partnership_${OWNER}.db"
MIRROR_STATE_FILE="/boot/config/partnership_${MIRROR}.db" MIRROR_STATE_FILE="/boot/config/partnership_${MIRROR}.db"
OFFLINE_COUNTER="/boot/config/partnership_offline_days.db" OFFLINE_COUNTER="/boot/config/partnership_offline_days.db"
# ── Exit Trap — restart locally stopped containers if script crashes mid-cleanup ──────────────
# Used by folderview3_remove_partner_folder() and cleanup_partner_containers() — also shared
# with partnership_offboard.sh which sources this file and registers the same trap.
declare -a _PM_TRAP_STOPPED=()
_pm_trap_restart_stopped() {
[[ ${#_PM_TRAP_STOPPED[@]} -eq 0 ]] && return
for c in "${_PM_TRAP_STOPPED[@]}"; do
[[ -z "$c" ]] && continue
if docker inspect "$c" >/dev/null 2>&1; then
warn "Exit trap: restarting $c (stopped but not removed)"
docker start "$c" >/dev/null 2>&1 || warn " Failed to restart $c"
fi
done
}
if [[ "${PARTNERSHIP_LIB_MODE:-}" != "1" ]]; then if [[ "${PARTNERSHIP_LIB_MODE:-}" != "1" ]]; then
if [[ -z "$MODE" ]]; then if [[ -z "$MODE" ]]; then
error "No mode specified" error "No mode specified"
@@ -297,6 +312,8 @@ if [[ "${PARTNERSHIP_LIB_MODE:-}" != "1" ]]; then
# Lock for all modes except --check (frequent) and --offboard (offboard script holds its own) # Lock for all modes except --check (frequent) and --offboard (offboard script holds its own)
[[ "$MODE" != "check" && "$MODE" != "offboard" ]] && acquire_lock "strict" [[ "$MODE" != "check" && "$MODE" != "offboard" ]] && acquire_lock "strict"
trap _pm_trap_restart_stopped EXIT
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes will be made" [[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes will be made"
fi fi
@@ -679,6 +696,7 @@ folderview3_remove_partner_folder() {
if timeout "${DOCKER_TIMEOUT:-30}" docker inspect "$container" >/dev/null 2>&1; then if timeout "${DOCKER_TIMEOUT:-30}" docker inspect "$container" >/dev/null 2>&1; then
if timeout "${DOCKER_TIMEOUT:-30}" docker stop "$container" >/dev/null 2>&1; then if timeout "${DOCKER_TIMEOUT:-30}" docker stop "$container" >/dev/null 2>&1; then
log "$container stopped ✅" log "$container stopped ✅"
_PM_TRAP_STOPPED+=("$container")
(( stopped++ )) (( stopped++ ))
else else
warn "$container stop failed" warn "$container stop failed"
@@ -822,6 +840,7 @@ cleanup_partner_containers() {
fi fi
if timeout "${DOCKER_TIMEOUT:-30}" docker inspect "$container" >/dev/null 2>&1; then if timeout "${DOCKER_TIMEOUT:-30}" docker inspect "$container" >/dev/null 2>&1; then
timeout "${DOCKER_TIMEOUT:-30}" docker stop "$container" >/dev/null 2>&1 || true timeout "${DOCKER_TIMEOUT:-30}" docker stop "$container" >/dev/null 2>&1 || true
_PM_TRAP_STOPPED+=("$container")
timeout "${DOCKER_TIMEOUT:-30}" docker rm "$container" >/dev/null 2>&1 && \ timeout "${DOCKER_TIMEOUT:-30}" docker rm "$container" >/dev/null 2>&1 && \
log "$container removed ✅" || warn "$container rm failed" log "$container removed ✅" || warn "$container rm failed"
else else
@@ -1337,7 +1356,7 @@ if [[ "$MODE" == "check" ]]; then
# Both agree and active — healthy, silent # Both agree and active — healthy, silent
if [[ "$LOCAL_STATE" == "$REMOTE_STATE" ]] && [[ "$LOCAL_STATE" == "ACTIVE" ]]; then if [[ "$LOCAL_STATE" == "$REMOTE_STATE" ]] && [[ "$LOCAL_STATE" == "ACTIVE" ]]; then
log "Partnership check — ACTIVE, both servers agree ✅" echo "Partnership check — ACTIVE, both servers agree ✅"
exit 0 exit 0
fi fi
@@ -1397,7 +1416,7 @@ if [[ "$MODE" == "check" ]]; then
# Both inactive — nothing to do # Both inactive — nothing to do
if [[ "$LOCAL_STATE" == "INACTIVE" ]] && [[ "$REMOTE_STATE" == "INACTIVE" ]]; then if [[ "$LOCAL_STATE" == "INACTIVE" ]] && [[ "$REMOTE_STATE" == "INACTIVE" ]]; then
log "Partnership check — INACTIVE on both servers" echo "Partnership check — INACTIVE on both servers"
exit 0 exit 0
fi fi
@@ -1489,7 +1508,7 @@ if [[ "$MODE" == "onboard" ]]; then
if [[ "$DRY_RUN" == false ]]; then if [[ "$DRY_RUN" == false ]]; then
write_state_file "$LOCAL_STATE_FILE" "ACTIVE" "$NOW" "" "$LOCAL_SERVER_NAME" "onboard" write_state_file "$LOCAL_STATE_FILE" "ACTIVE" "$NOW" "" "$LOCAL_SERVER_NAME" "onboard"
log "Local state: ACTIVE ✅" echo "Local state: ACTIVE ✅"
remove_from_blocklist "$MIRROR" remove_from_blocklist "$MIRROR"
push_state_to_remote "$LOCAL_STATE_FILE" "$MIRROR_IP" "$MIRROR_SSH_KEY" push_state_to_remote "$LOCAL_STATE_FILE" "$MIRROR_IP" "$MIRROR_SSH_KEY"
echo "0" > "$OFFLINE_COUNTER" echo "0" > "$OFFLINE_COUNTER"
+5 -2
View File
@@ -124,6 +124,8 @@ OFFLINE_COUNTER="/boot/config/partnership_offline_days.db"
acquire_lock "strict" acquire_lock "strict"
trap _pm_trap_restart_stopped EXIT
# Check already offboarded # Check already offboarded
if [[ -f "$LOCAL_STATE_FILE" ]]; then if [[ -f "$LOCAL_STATE_FILE" ]]; then
CURRENT_STATE=$(read_state_file "$LOCAL_STATE_FILE" "state") CURRENT_STATE=$(read_state_file "$LOCAL_STATE_FILE" "state")
@@ -265,6 +267,7 @@ cleanup_deployed_stack_locally() {
--format '{{range .HostConfig.Binds}}{{println .}}{{end}}' \ --format '{{range .HostConfig.Binds}}{{println .}}{{end}}' \
"$cname" 2>/dev/null | awk -F: '{print $1}' | grep '^/mnt/.*/appdata') "$cname" 2>/dev/null | awk -F: '{print $1}' | grep '^/mnt/.*/appdata')
timeout "${DOCKER_TIMEOUT:-30}" docker stop "$cname" >/dev/null 2>&1 || true timeout "${DOCKER_TIMEOUT:-30}" docker stop "$cname" >/dev/null 2>&1 || true
_PM_TRAP_STOPPED+=("$cname")
timeout "${DOCKER_TIMEOUT:-30}" docker rm "$cname" >/dev/null 2>&1 && \ timeout "${DOCKER_TIMEOUT:-30}" docker rm "$cname" >/dev/null 2>&1 && \
log " $cname removed ✅" || warn " $cname rm failed" log " $cname removed ✅" || warn " $cname rm failed"
else else
@@ -428,7 +431,7 @@ if [[ "$AM_MIRROR" == true ]]; then
if [[ "$DRY_RUN" == false ]]; then if [[ "$DRY_RUN" == false ]]; then
write_state_file "$LOCAL_STATE_FILE" \ write_state_file "$LOCAL_STATE_FILE" \
"INACTIVE" "" "$NOW" "$LOCAL_SERVER_NAME" "$REASON" "INACTIVE" "" "$NOW" "$LOCAL_SERVER_NAME" "$REASON"
log "Local state: INACTIVE ✅" echo "Local state: INACTIVE ✅"
add_to_blocklist "$OWNER" "$REASON" add_to_blocklist "$OWNER" "$REASON"
else else
warn "DRY RUN — would write INACTIVE state and blocklist $OWNER" warn "DRY RUN — would write INACTIVE state and blocklist $OWNER"
@@ -626,7 +629,7 @@ fi
if [[ ${#PARTNERSHIP_MIRROR_BACKUPS[@]} -gt 0 ]]; then if [[ ${#PARTNERSHIP_MIRROR_BACKUPS[@]} -gt 0 ]]; then
echo "" echo ""
echo "━━━ $ICON_DISK Backup Handover ━━━" echo "━━━ $ICON_DISK Backup Handover ━━━"
log "Backups available for $MIRROR:" echo "Backups available for $MIRROR:"
for path in "${PARTNERSHIP_MIRROR_BACKUPS[@]}"; do for path in "${PARTNERSHIP_MIRROR_BACKUPS[@]}"; do
[[ -z "$path" ]] && continue [[ -z "$path" ]] && continue
echo " $path" echo " $path"
+6 -6
View File
@@ -553,7 +553,7 @@ else
deploy_xml_stack PARTNERSHIP_AUTH_STACK deploy_xml_stack PARTNERSHIP_AUTH_STACK
AUTH_DEPLOYED=$_STACK_DEPLOYED AUTH_DEPLOYED=$_STACK_DEPLOYED
AUTH_FAILED=$_STACK_FAILED AUTH_FAILED=$_STACK_FAILED
log "Auth stack: $AUTH_DEPLOYED deployed, $AUTH_FAILED failed" echo "Auth stack: $AUTH_DEPLOYED deployed, $AUTH_FAILED failed"
[[ "$AUTH_FAILED" -gt 0 ]] && STEP_AUTH_OK=false [[ "$AUTH_FAILED" -gt 0 ]] && STEP_AUTH_OK=false
fi fi
@@ -580,7 +580,7 @@ else
deploy_xml_stack PARTNERSHIP_ARR_STACK deploy_xml_stack PARTNERSHIP_ARR_STACK
ARR_DEPLOYED=$_STACK_DEPLOYED ARR_DEPLOYED=$_STACK_DEPLOYED
ARR_FAILED=$_STACK_FAILED ARR_FAILED=$_STACK_FAILED
log "Arr stack: $ARR_DEPLOYED deployed, $ARR_FAILED failed" echo "Arr stack: $ARR_DEPLOYED deployed, $ARR_FAILED failed"
[[ "$ARR_FAILED" -gt 0 ]] && STEP_ARR_OK=false [[ "$ARR_FAILED" -gt 0 ]] && STEP_ARR_OK=false
fi fi
@@ -589,7 +589,7 @@ echo ""
echo "━━━ Step 7/8 — Partnership Onboard ━━━" echo "━━━ Step 7/8 — Partnership Onboard ━━━"
if bash "$SCRIPTS_ROOT/Partnership/partnership_manager.sh" --onboard "${EXTRA_FLAGS[@]}"; then if bash "$SCRIPTS_ROOT/Partnership/partnership_manager.sh" --onboard "${EXTRA_FLAGS[@]}"; then
log "Partnership onboard complete ✅" echo "Partnership onboard complete ✅"
ONBOARD_OK=true ONBOARD_OK=true
else else
error "Partnership onboard failed" error "Partnership onboard failed"
@@ -607,7 +607,7 @@ elif [[ "$SKIP_ARR_SYNC" == true ]]; then
elif [[ ! -f "$SCRIPTS_ROOT/Media/arr_sync.sh" ]]; then elif [[ ! -f "$SCRIPTS_ROOT/Media/arr_sync.sh" ]]; then
warn "arr_sync.sh not found — run Media/arr_sync.sh manually once arrs are live" warn "arr_sync.sh not found — run Media/arr_sync.sh manually once arrs are live"
elif bash "$SCRIPTS_ROOT/Media/arr_sync.sh" "${EXTRA_FLAGS[@]}"; then elif bash "$SCRIPTS_ROOT/Media/arr_sync.sh" "${EXTRA_FLAGS[@]}"; then
log "Arr bootstrap complete ✅" echo "Arr bootstrap complete ✅"
ARR_SYNC_OK=true ARR_SYNC_OK=true
else else
warn "Arr sync had errors — partnership still valid" warn "Arr sync had errors — partnership still valid"
@@ -637,8 +637,8 @@ echo ""
if [[ "$ONBOARD_OK" == true ]]; then if [[ "$ONBOARD_OK" == true ]]; then
[[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes made" || \ [[ "$DRY_RUN" == true ]] && warn "DRY RUN — no changes made" || \
log "$ICON_DONE DONE — partnership established ✅" echo "$ICON_DONE DONE — partnership established ✅"
log "Verify with: Partnership/partnership_manager.sh --status" echo "Verify with: Partnership/partnership_manager.sh --status"
else else
error "Setup incomplete — resolve errors above and re-run" error "Setup incomplete — resolve errors above and re-run"
fi fi
+4 -4
View File
@@ -290,8 +290,8 @@ echo "━━━ $ICON_GEAR Key Generation ━━━"
if [[ -f "$SSH_KEY_PATH" ]] && [[ "$FORCE" == false ]]; then if [[ -f "$SSH_KEY_PATH" ]] && [[ "$FORCE" == false ]]; then
local_fp=$(ssh-keygen -lf "$SSH_KEY_PATH" 2>/dev/null || echo "unreadable") local_fp=$(ssh-keygen -lf "$SSH_KEY_PATH" 2>/dev/null || echo "unreadable")
log "Key already exists — skipping generation (--force to regenerate)" echo "Key already exists — skipping generation (--force to regenerate)"
log " $local_fp" echo " $local_fp"
else else
if [[ "$FORCE" == true ]] && [[ -f "$SSH_KEY_PATH" ]]; then if [[ "$FORCE" == true ]] && [[ -f "$SSH_KEY_PATH" ]]; then
warn "Regenerating key (--force) — existing key will be replaced" warn "Regenerating key (--force) — existing key will be replaced"
@@ -339,7 +339,7 @@ else
if ssh-copy-id -i "$SSH_PUB_PATH" -o ConnectTimeout="${SSH_TIMEOUT:-15}" \ if ssh-copy-id -i "$SSH_PUB_PATH" -o ConnectTimeout="${SSH_TIMEOUT:-15}" \
root@"$REMOTE_SERVER" 2>/dev/null; then root@"$REMOTE_SERVER" 2>/dev/null; then
log "Public key installed on $REMOTE_SERVER_NAME" echo "Public key installed on $REMOTE_SERVER_NAME"
else else
error "ssh-copy-id failed — check that:" error "ssh-copy-id failed — check that:"
error " 1. Remote server is reachable: tailscale status" error " 1. Remote server is reachable: tailscale status"
@@ -355,7 +355,7 @@ echo "━━━ $ICON_VERIFY Verify SSH Auth ━━━"
if [[ "$DRY_RUN" == false ]]; then if [[ "$DRY_RUN" == false ]]; then
if test_ssh_auth "$REMOTE_SERVER"; then if test_ssh_auth "$REMOTE_SERVER"; then
log "SSH auth to $REMOTE_SERVER_NAME working ✅" echo "SSH auth to $REMOTE_SERVER_NAME working ✅"
# Reset any existing strikes # Reset any existing strikes
if [[ -f "$SSH_STRIKE_FILE" ]]; then if [[ -f "$SSH_STRIKE_FILE" ]]; then
write_strike_file 0 "" "$(date '+%Y-%m-%d %H:%M:%S')" write_strike_file 0 "" "$(date '+%Y-%m-%d %H:%M:%S')"