diff --git a/Partnership/partnership_onboard.sh b/Partnership/partnership_onboard.sh index 8f2d7cb..295670b 100755 --- a/Partnership/partnership_onboard.sh +++ b/Partnership/partnership_onboard.sh @@ -369,17 +369,74 @@ if [[ "$AM_MIRROR" == true ]]; then OWNER_SCRIPTS_DIR=$(resolve_remote_scripts_dir "$OWNER_IP") if [[ "$DRY_RUN" == true ]]; then - warn "DRY RUN — would SSH to $OWNER ($OWNER_IP) and trigger Phase 2" - PHASE2_TRIGGERED=true - elif timeout "$SSH_TIMEOUT" ssh -i "$SSH_KEY" \ - -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$OWNER_IP" \ - "nohup bash '${OWNER_SCRIPTS_DIR}/Partnership/partnership_onboard.sh' --phase2-only > /tmp/vv_phase2_onboard.log 2>&1 & echo triggered" \ - 2>/dev/null | grep -q triggered; then - echo "Phase 2 triggered on $OWNER ✅" - log "Watch progress on $OWNER: tail -f /tmp/vv_phase2_onboard.log" + warn "DRY RUN — would SSH to $OWNER ($OWNER_IP) and trigger Phase 2 via run_job.sh" PHASE2_TRIGGERED=true else - warn "Could not auto-trigger Phase 2 on $OWNER" + # Launched through run_job.sh, the same path cron and api/run.php use, so Phase 2 + # gets a stat file, a job log and a Scheduler entry on the owner. It used to be a + # bare `nohup … > /tmp/vv_phase2_onboard.log`, which ran fine and left the owner's + # entire half of onboarding invisible to its own WebGUI — no job record, nothing + # under /var/log/varaverk, nothing for the operator to look at when asking why + # pressing Onboard here appeared to do nothing. + # + # setsid, not bare nohup: the job must lead its own process group so api/stop.php + # can signal the whole tree. api/run.php carries the same note for the same reason. + # + # Reported triggered only after the stat file proves run_job.sh actually started. + # The old `& echo triggered` printed unconditionally — it would have claimed success + # for a path that does not exist on the owner, which is exactly the failure mode a + # mirror in a different storage mode hits. + # Its own timeout, not SSH_TIMEOUT: the remote waits for the runner to prove itself, + # and 15s would cut that short and report a healthy launch as a failure. + _phase2_out=$(timeout 40 ssh -i "$SSH_KEY" \ + -o ConnectTimeout="$SSH_TIMEOUT" -o BatchMode=yes root@"$OWNER_IP" \ + "bash -s -- $(printf '%q' "$OWNER_SCRIPTS_DIR")" 2>/dev/null <<'PHASE2_TRIGGER' +sd="$1" +runner="$sd/Plugin/unraid/run_job.sh" +script="$sd/Partnership/partnership_onboard.sh" +stat_file="/var/log/varaverk/Partnership/partnership_onboard.json" + +[ -f "$runner" ] || { echo "missing-runner:$runner"; exit 1; } +[ -f "$script" ] || { echo "missing-script:$script"; exit 1; } + +# Absolute, not "newer than the file we saw a moment ago". A previous run's stat file rewritten +# inside the same second would compare equal and read as a failed launch. +t0=$(date +%s) + +setsid nohup bash "$runner" "Partnership/partnership_onboard.sh" "$script" \ + --manual --phase2-only >/dev/null 2>&1 /dev/null || echo 0) + [ "$now" -ge "$t0" ] && { echo triggered; exit 0; } +done +echo start-failed +exit 1 +PHASE2_TRIGGER + ) + case "$_phase2_out" in + *triggered*) + echo "Phase 2 triggered on $OWNER ✅" + log "Watch on $OWNER: Scheduler tab, or tail -f /var/log/varaverk/Partnership/partnership_onboard.log" + PHASE2_TRIGGERED=true + ;; + missing-runner:*) + error "Phase 2 not started — no run_job.sh at ${_phase2_out#missing-runner:} on $OWNER" + ;; + missing-script:*) + error "Phase 2 not started — no partnership_onboard.sh at ${_phase2_out#missing-script:} on $OWNER" + ;; + *start-failed*) + error "Phase 2 launch on $OWNER did not produce a job record — check run_job.sh there" + ;; + *) + warn "Could not auto-trigger Phase 2 on $OWNER" + ;; + esac fi else warn "Cannot resolve $OWNER Tailscale IP"