From 7ed0f5c23bfb4b02837e953fa341ef976446ad88 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Sun, 16 Aug 2026 20:32:14 -0400 Subject: [PATCH] Send the webhook setup to the path the partner actually uses, and arm the sync gates before the seed that depends on them --- Partnership/partnership_onboard.sh | 177 ++++++++++++++++------------- Tools/webhook_setup.sh | 16 ++- 2 files changed, 114 insertions(+), 79 deletions(-) diff --git a/Partnership/partnership_onboard.sh b/Partnership/partnership_onboard.sh index 335effd..ebf9e53 100755 --- a/Partnership/partnership_onboard.sh +++ b/Partnership/partnership_onboard.sh @@ -32,11 +32,13 @@ # Step 8: Partnership onboard — configure WebUIs → owner IP, write state, Emby # Step 9: Arr bootstrap — bidirectional library sync (arr_sync.sh) # Step 9b: Webhook setup — register download webhook in arrs on both servers -# Step 9c: Media seed — rsync all DAILY_SYNC_SHARES to mirror (--seed) +# Step 9c: Arm sync gates — open RSYNC/CONF_SYNC/ARR_SYNC in master.conf, which the +# template ships closed so a fresh node cannot sync early. +# Ahead of the seed because the seed is itself an rsync and +# Tier 1 stops every rsync, including that one +# Step 9d: Media seed — rsync all DAILY_SYNC_SHARES to mirror (--seed) # prevents arrs treating every file as missing after bootstrap -# Step 9d: Webhook listener — start listener on mirror (runs continuously, no reboot needed) -# Step 9e: Arm sync gates — open RSYNC/CONF_SYNC/ARR_SYNC in master.conf, which the -# template ships closed so a fresh node cannot sync early +# Step 9e: Webhook listener — start listener on mirror (runs continuously, no reboot needed) # Step 10: Conf push — push master.conf + setup state to all listed hosts # # ============================================================================================== @@ -153,15 +155,15 @@ # Skip webhook registration in arrs (Step 9b) # # Partnership/partnership_onboard.sh --skip-media-seed -# Skip initial media share rsync to mirror (Step 9c) +# Skip initial media share rsync to mirror (Step 9d) # Use when mirror already has files or you want to seed manually # # Partnership/partnership_onboard.sh --skip-webhook-listener -# Skip starting webhook listener on mirror (Step 9d) +# Skip starting webhook listener on mirror (Step 9e) # Listener will start automatically on next array restart # # Partnership/partnership_onboard.sh --no-arm -# Leave RSYNC_ENABLED / CONF_SYNC_ENABLED / ARR_SYNC_ENABLED as they are (Step 9e). +# Leave RSYNC_ENABLED / CONF_SYNC_ENABLED / ARR_SYNC_ENABLED as they are (Step 9c). # Use when onboarding a node you want to keep inert — a rebuild test, or a mirror whose # shares are not populated yet. # @@ -196,7 +198,7 @@ SKIP_WEBHOOK_LISTENER=false PHASE1_ONLY=false # OWNER: SSH + conf push only (HOST2 not yet installed) # MIRROR: SSH key install only, no owner notification PHASE2_ONLY=false # OWNER: containers/arr/onboard only (triggered by HOST2 after it onboards) -SKIP_ARM=false # leave the sync gates as they are — see Step 9e +SKIP_ARM=false # leave the sync gates as they are — see Step 9c FILTERED_ARGS=() for arg in "$@"; do @@ -799,67 +801,7 @@ else fi unset _webhook_script -# ── Step 9c: Seed media shares on mirror ───────────────────────────────────────────────────── -# arr_sync.sh bootstrapped the databases — mirror's arrs now know about all content but -# have no files on disk. Without this rsync, every imported item looks missing and arrs -# will immediately queue searches. --seed skips the empty-remote guard and does a clean push. -echo "" -echo "━━━ Step 9c — Media Share Seed ━━━" - -if [[ "$SKIP_MEDIA_SEED" == true ]]; then - warn "Skipping (--skip-media-seed)" -elif [[ "${#DAILY_SYNC_SHARES[@]}" -eq 0 ]]; then - warn "DAILY_SYNC_SHARES empty for $MY_ID — skipping media seed" - warn "Configure HOST${MY_ID: -1}_DAILY_SYNC_SHARES in host${MY_ID: -1}.conf and run Rsync/rsync.sh --seed manually" -else - echo " Seeding ${#DAILY_SYNC_SHARES[@]} share(s) to $MIRROR — this may take a while" - _rsync_script="$SCRIPTS_ROOT/Rsync/rsync.sh" - _seed_flags=(--seed) - [[ "$DRY_RUN" == true ]] && _seed_flags+=(--dry-run) - [[ "$ENABLE_LOGGING" == true ]] && _seed_flags+=(--log) - for _share in "${DAILY_SYNC_SHARES[@]}"; do - echo " Seeding: $_share" - if bash "$_rsync_script" "$_share" "${_seed_flags[@]}"; then - (( MEDIA_SEED_COUNT++ )) || true - else - warn " Seed failed for $_share — re-run: Rsync/rsync.sh $_share --seed" - fi - done - if [[ "$MEDIA_SEED_COUNT" -gt 0 ]]; then - echo "Media seed complete — ${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} share(s) ✅" - MEDIA_SEED_OK=true - else - warn "Media seed: no shares completed — check errors above" - fi - unset _rsync_script _seed_flags _share -fi - -# ── Step 9d: Start webhook listener on mirror ───────────────────────────────────────────────── -# Listener is in ARRAY_START_SCRIPTS so it starts on next boot, but the mirror's array is -# already running — kick it now so events are captured immediately after onboard. -echo "" -echo "━━━ Step 9d — Webhook Listener (Mirror) ━━━" - -_listener_script="$SCRIPTS_ROOT/Arrs_Stack/start_webhook_listener.sh" -if [[ "$SKIP_WEBHOOK_LISTENER" == true ]]; then - warn "Skipping (--skip-webhook-listener)" -elif [[ "${WEBHOOK_PORT:-0}" -eq 0 ]]; then - warn "WEBHOOK_PORT=0 — webhook disabled, skipping" -elif [[ "$DRY_RUN" == true ]]; then - warn "DRY RUN — would start webhook listener on $MIRROR" - WEBHOOK_LISTENER_OK=true -elif timeout "$SSH_TIMEOUT" ssh -i "$MIRROR_SSH_KEY" \ - -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$MIRROR_IP" \ - "nohup bash '$_listener_script' > /var/log/varaverk/upgrade_webhook.log 2>&1 & echo started" \ - 2>/dev/null | grep -q started; then - echo "Webhook listener started on $MIRROR ✅" - WEBHOOK_LISTENER_OK=true -else - warn "Could not start listener on $MIRROR — it will start automatically on next array restart" -fi -unset _listener_script - -# ── Step 9e: Arm the sync gates ─────────────────────────────────────────────────────────────── +# ── Step 9c: Arm the sync gates ─────────────────────────────────────────────────────────────── # master.conf.template ships a fresh node inert — RSYNC_ENABLED, CONF_SYNC_ENABLED and # ARR_SYNC_ENABLED all false — because a node that has just been seeded has empty shares and no # verified partner, and those two facts are what make unattended syncing safe to do. @@ -868,14 +810,19 @@ unset _listener_script # one-way door: the node stayed inert for ever and somebody had to remember to hand-edit three # toggles, on the machine where forgetting looks exactly like everything working. # -# Runs before Step 10 on purpose. The push carries the owner's master.conf to every listed host, -# so arming here means both sides come up agreeing about whether sync is on; arming after the -# push would leave the mirror a version behind until the next conf save. +# Ahead of the media seed, which it used to follow. The seed calls Rsync/rsync.sh, and Tier 1 +# stops *every* rsync — so with the gates still closed all of it exited cleanly having moved +# nothing, and, because a clean exit is exit 0, the seed counted each share as a success and +# reported "14/14 shares ✅" over an empty mirror. +# +# Still ahead of Step 10 on purpose. The push carries the owner's master.conf to every listed +# host, so arming before it means both sides come up agreeing about whether sync is on; arming +# after the push would leave the mirror a version behind until the next conf save. # # Owner only — the mirror receives these values in the push rather than deciding for itself. ARM_OK=true echo "" -echo "━━━ $ICON_GEAR Step 9e — Arm Sync Gates ━━━" +echo "━━━ $ICON_GEAR Step 9c — Arm Sync Gates ━━━" if [[ "$ONBOARD_OK" == false ]]; then warn "Skipping — onboard did not complete, leaving the gates closed" @@ -903,6 +850,82 @@ else unset _master_conf fi +# ── Step 9d: Seed media shares on mirror ───────────────────────────────────────────────────── +# arr_sync.sh bootstrapped the databases — mirror's arrs now know about all content but +# have no files on disk. Without this rsync, every imported item looks missing and arrs +# will immediately queue searches. --seed skips the empty-remote guard and does a clean push. +echo "" +echo "━━━ Step 9d — Media Share Seed ━━━" + +# Read the gate back off disk rather than trusting the value sourced at startup: Step 9c has +# just rewritten master.conf, and each rsync.sh below is a separate process that will source +# the file fresh. A closed gate here means every share would exit 0 having moved nothing, so +# say so once and skip, instead of counting fourteen no-ops as fourteen successes. +# +# The trailing comment is cut before the value is read. master.conf writes this gate as +# RSYNC_ENABLED=true # Tier 1 — global gate, overrides everything below +# so stopping at `cut -d= -f2` and squeezing whitespace yields "true#Tier1—globalgate,…", +# which is not "true" — and the seed would then skip itself on every single run, including +# the ones where the gate is open. +_rsync_gate=$(grep -m1 -E '^[[:space:]]*RSYNC_ENABLED=' "$SCRIPTS_ROOT/Configurations/master.conf" 2>/dev/null \ + | cut -d= -f2- | cut -d'#' -f1 | tr -d '"'"'" | tr -d '[:space:]') + +if [[ "$SKIP_MEDIA_SEED" == true ]]; then + warn "Skipping (--skip-media-seed)" +elif [[ "$DRY_RUN" == false && "$_rsync_gate" != "true" ]]; then + warn "RSYNC_ENABLED is '$_rsync_gate' — skipping media seed, rsync.sh would move nothing" + warn "Arm it and re-run: Rsync/rsync.sh --seed" +elif [[ "${#DAILY_SYNC_SHARES[@]}" -eq 0 ]]; then + warn "DAILY_SYNC_SHARES empty for $MY_ID — skipping media seed" + warn "Configure HOST${MY_ID: -1}_DAILY_SYNC_SHARES in host${MY_ID: -1}.conf and run Rsync/rsync.sh --seed manually" +else + echo " Seeding ${#DAILY_SYNC_SHARES[@]} share(s) to $MIRROR — this may take a while" + _rsync_script="$SCRIPTS_ROOT/Rsync/rsync.sh" + _seed_flags=(--seed) + [[ "$DRY_RUN" == true ]] && _seed_flags+=(--dry-run) + [[ "$ENABLE_LOGGING" == true ]] && _seed_flags+=(--log) + for _share in "${DAILY_SYNC_SHARES[@]}"; do + echo " Seeding: $_share" + if bash "$_rsync_script" "$_share" "${_seed_flags[@]}"; then + (( MEDIA_SEED_COUNT++ )) || true + else + warn " Seed failed for $_share — re-run: Rsync/rsync.sh $_share --seed" + fi + done + if [[ "$MEDIA_SEED_COUNT" -gt 0 ]]; then + echo "Media seed complete — ${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} share(s) ✅" + MEDIA_SEED_OK=true + else + warn "Media seed: no shares completed — check errors above" + fi + unset _rsync_script _seed_flags _share +fi + +# ── Step 9e: Start webhook listener on mirror ───────────────────────────────────────────────── +# Listener is in ARRAY_START_SCRIPTS so it starts on next boot, but the mirror's array is +# already running — kick it now so events are captured immediately after onboard. +echo "" +echo "━━━ Step 9e — Webhook Listener (Mirror) ━━━" + +_listener_script="$SCRIPTS_ROOT/Arrs_Stack/start_webhook_listener.sh" +if [[ "$SKIP_WEBHOOK_LISTENER" == true ]]; then + warn "Skipping (--skip-webhook-listener)" +elif [[ "${WEBHOOK_PORT:-0}" -eq 0 ]]; then + warn "WEBHOOK_PORT=0 — webhook disabled, skipping" +elif [[ "$DRY_RUN" == true ]]; then + warn "DRY RUN — would start webhook listener on $MIRROR" + WEBHOOK_LISTENER_OK=true +elif timeout "$SSH_TIMEOUT" ssh -i "$MIRROR_SSH_KEY" \ + -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$MIRROR_IP" \ + "nohup bash '$_listener_script' > /var/log/varaverk/upgrade_webhook.log 2>&1 & echo started" \ + 2>/dev/null | grep -q started; then + echo "Webhook listener started on $MIRROR ✅" + WEBHOOK_LISTENER_OK=true +else + warn "Could not start listener on $MIRROR — it will start automatically on next array restart" +fi +unset _listener_script + # ── Step 10: Push master.conf to all listed hosts ───────────────────────────────────────────── # SSH is now established and all partners have the plugin installed. # Push the authoritative master.conf so every listed host is in sync immediately. @@ -953,9 +976,11 @@ echo " Step 7 — Services stack: $( [[ "$SKIP_SERVICES_STACK" == true ]] && echo " Step 8 — Onboard: $(_ok "$ONBOARD_OK")" echo " Step 9 — Arr bootstrap: $( [[ "$SKIP_ARR_SYNC" == true || "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$ARR_SYNC_OK")" )" echo " Step 9b — Webhook setup: $(_skip "$SKIP_WEBHOOK_SETUP" "$WEBHOOK_SETUP_OK")" -echo " Step 9c — Media seed: $( [[ "$SKIP_MEDIA_SEED" == true ]] && echo "skipped" || echo "${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} shares $(_ok "$MEDIA_SEED_OK")" )" -echo " Step 9d — Webhook listener: $(_skip "$SKIP_WEBHOOK_LISTENER" "$WEBHOOK_LISTENER_OK")" -echo " Step 9e — Arm sync gates: $( [[ "$SKIP_ARM" == true ]] && echo "skipped (--no-arm)" || { [[ "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$ARM_OK")"; } )" +echo " Step 9c — Arm sync gates: $( [[ "$SKIP_ARM" == true ]] && echo "skipped (--no-arm)" || { [[ "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$ARM_OK")"; } )" +echo " Step 9d — Media seed: $( [[ "$SKIP_MEDIA_SEED" == true ]] && echo "skipped" \ + || { [[ "$DRY_RUN" == false && "${_rsync_gate:-}" != "true" ]] && echo "skipped (rsync gate closed)" \ + || echo "${MEDIA_SEED_COUNT}/${#DAILY_SYNC_SHARES[@]} shares $(_ok "$MEDIA_SEED_OK")"; } )" +echo " Step 9e — Webhook listener: $(_skip "$SKIP_WEBHOOK_LISTENER" "$WEBHOOK_LISTENER_OK")" echo " Step 10 — Conf push: $( [[ "$ONBOARD_OK" == false ]] && echo "skipped" || echo "$(_ok "$MASTER_PUSH_OK")" )" echo "" diff --git a/Tools/webhook_setup.sh b/Tools/webhook_setup.sh index 70cb707..30e0a5a 100755 --- a/Tools/webhook_setup.sh +++ b/Tools/webhook_setup.sh @@ -253,10 +253,20 @@ if [[ "$LOCAL_ONLY" == false && -n "${REMOTE_ID:-}" ]]; then remote_flags="--local-only" [[ "$DRY_RUN" == true ]] && remote_flags="$remote_flags --dry-run" - ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o StrictHostKeyChecking=no \ + # The remote's own SCRIPTS_DIR, read from its varaverk.cfg — never the flash plugin path. + # That was hardcoded here, so a partner in appdata storage mode got + # "bash: .../Tools/webhook_setup.sh: No such file or directory" and the generic + # "check SSH and that Varaverk is installed" message, which pointed at two things that + # were both fine. HOST2 has run in appdata mode since it was installed. + SSH_TIMEOUT="${SSH_TIMEOUT:-10}" + remote_sd=$(resolve_remote_scripts_dir "$remote_ip" "$SSH_KEY" "no") + remote_script="${remote_sd}/Tools/webhook_setup.sh" + + ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=yes -o StrictHostKeyChecking=no \ root@"$remote_ip" \ - "OVERRIDE_SECRET='$WEBHOOK_SECRET' bash /boot/config/plugins/varaverk/Tools/webhook_setup.sh $remote_flags" \ - || echo " Remote setup failed — check SSH and that Varaverk is installed on $REMOTE_SERVER_NAME" + "[ -f '$remote_script' ] || { echo missing; exit 127; } + OVERRIDE_SECRET='$WEBHOOK_SECRET' bash '$remote_script' $remote_flags" \ + || echo " Remote setup failed — no webhook_setup.sh at $remote_script on $REMOTE_SERVER_NAME, or SSH refused" fi echo ""