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:
@@ -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
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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')"
|
||||||
|
|||||||
Reference in New Issue
Block a user