deploy: ops dev deploy --home — swap the dev home service too (#1267)
The dev-mesh deploy verb swapped only the control/router binary; the home service (lchat-home on the dev apex box) had no verb at all, so home changes were being hand-swapped — exactly the runbook drift ops exists to close. --home builds ./home for each target's arch, stages it beside the control binary (incoming/home-new), and swap_home moves it into place with a home.prev-<ver> rollback + an is-active health check. Boxes without the unit (Helsinki today) are skipped, never failed. Opt-in so a router-only deploy doesn't restart home for no reason.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 file changed,
+41
−2
deploy/ops-dev.sh+41 −2
diff --git a/deploy/ops-dev.sh b/deploy/ops-dev.sh| index 9493b5b..d8639a8 100755 |
| --- a/deploy/ops-dev.sh |
| +++ b/deploy/ops-dev.sh |
| @@ -5,6 +5,7 @@ |
| # ./deploy/ops dev plan # tofu plan, with the AMI-replacement guard |
| # ./deploy/ops dev deploy [ie|fi] # build -> scp -> swap -> restart (both by default) |
| # ./deploy/ops dev deploy --stage-only # stop after scp (pair the swap with env edits) |
| +# ./deploy/ops dev deploy --home # ALSO swap the home service binary (lchat-home) |
| # ./deploy/ops dev provision [ie|fi] # refresh systemd units + route the short-link apex |
| # ./deploy/ops dev rebuild --yes # destroy + recreate the Dublin box (new keys) |
| # |
| @@ -76,7 +77,7 @@ scp_ie() { if [ -f "$KEY_IE" ]; then scp -i "$KEY_IE" "$@"; else scp "$@"; fi; } |
| usage() { |
| echo "usage: ops dev plan [tofu args] | ops dev apply [tofu args] |" >&2 |
| - echo " ops dev deploy [ie|fi] [--stage-only] | ops dev provision [ie|fi] |" >&2 |
| + echo " ops dev deploy [ie|fi] [--stage-only] [--home] | ops dev provision [ie|fi] |" >&2 |
| echo " ops dev rebuild [--yes]" >&2 |
| exit 2 |
| } |
| @@ -294,6 +295,33 @@ swap_box() { |
| fi |
| } |
| +# swap_home <ie|fi> <ver>: the home service rides its own binary (releases |
| +# ship it as lchat-home-linux-* via updaterservices.go; the dev mesh swaps it |
| +# directly, same as the control binary). A box without the unit (Helsinki |
| +# today — home runs on the dev apex box only) is skipped, never failed. |
| +swap_home() { |
| + which_box="$1"; ver="$2" |
| + if [ "$which_box" = ie ]; then box="$BOX_IE"; run() { ssh_ie "$box" "$@"; } |
| + else box="$BOX_FI"; run() { ssh -o ConnectTimeout=10 "$box" "$@"; } |
| + fi |
| + if ! run 'systemctl list-unit-files lchat-home.service --no-legend 2>/dev/null' | grep -q lchat-home; then |
| + echo " $which_box: no lchat-home unit — home skipped" |
| + return 0 |
| + fi |
| + run "sudo cp /opt/lchat/home /opt/lchat/home.prev-$ver 2>/dev/null || true; \ |
| + sudo mv /opt/lchat/incoming/home-new /opt/lchat/home \ |
| + && sudo chmod +x /opt/lchat/home \ |
| + && sudo systemctl restart lchat-home" |
| + if run 'systemctl is-active --quiet lchat-home'; then |
| + echo " $which_box: lchat-home running ($ver)" |
| + else |
| + echo "ops dev: $which_box lchat-home is NOT active after the swap" >&2 |
| + echo " inspect: ssh $box journalctl -u lchat-home -n 60 --no-pager" >&2 |
| + echo " rollback: ssh $box 'sudo mv /opt/lchat/home.prev-$ver /opt/lchat/home && sudo systemctl restart lchat-home'" >&2 |
| + exit 1 |
| + fi |
| +} |
| + |
| cmd="${1:-}" |
| [ $# -gt 0 ] && shift |
| case "$cmd" in |
| @@ -318,11 +346,12 @@ apply) |
| ;; |
| deploy) |
| - targets="ie fi"; stage_only=no |
| + targets="ie fi"; stage_only=no; with_home=no |
| for a in "$@"; do |
| case "$a" in |
| ie|fi) targets="$a" ;; |
| --stage-only) stage_only=yes ;; |
| + --home) with_home=yes ;; |
| *) usage ;; |
| esac |
| done |
| @@ -343,6 +372,12 @@ deploy) |
| esac |
| echo "ops dev: building $ver for linux/$arch ($t)" |
| OUT="$tmp/lchat-$t" ARCH="$arch" "$here/build-linux.sh" "$ver" |
| + if [ "$with_home" = yes ]; then |
| + # The home service is its own package/binary (like release-server.sh's |
| + # service builds) — no version stamp, the unit check gates the swap. |
| + echo "ops dev: building home for linux/$arch ($t)" |
| + GOOS=linux GOARCH="$arch" CGO_ENABLED=0 go build -o "$tmp/home-$t" ./home |
| + fi |
| done |
| for t in $targets; do |
| @@ -354,14 +389,17 @@ deploy) |
| if [ "$t" = ie ]; then |
| ssh_ie "$box" 'sudo mkdir -p /opt/lchat/incoming' |
| scp_ie -q "$tmp/lchat-$t" "$box:/opt/lchat/incoming/lchat-new" |
| + [ "$with_home" = yes ] && scp_ie -q "$tmp/home-$t" "$box:/opt/lchat/incoming/home-new" |
| else |
| ssh -o ConnectTimeout=10 "$box" 'sudo mkdir -p /opt/lchat/incoming' |
| scp -q "$tmp/lchat-$t" "$box:/opt/lchat/incoming/lchat-new" |
| + [ "$with_home" = yes ] && scp -q "$tmp/home-$t" "$box:/opt/lchat/incoming/home-new" |
| fi |
| done |
| if [ "$stage_only" = yes ]; then |
| echo "ops dev: staged at /opt/lchat/incoming/lchat-new on: $targets (not swapped)" |
| + [ "$with_home" = yes ] && echo " (home staged beside it as incoming/home-new)" |
| echo " swap by hand when ready (pairs with env edits — see the cutover runbook)" |
| exit 0 |
| fi |
| @@ -369,6 +407,7 @@ deploy) |
| for t in $targets; do |
| echo "ops dev: swapping + restarting $t" |
| swap_box "$t" "$ver" |
| + [ "$with_home" = yes ] && swap_home "$t" "$ver" |
| done |
| echo |
| echo "note: this opened dev-box SSH sessions — if this session hasn't written its" |