Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions infra/server/relay-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ set -euo pipefail
REPO=/home/deploy/relay # our repo, cloned by setup-deploy-user.sh
LAST_GOOD_FILE=/home/deploy/.relay-last-good # the last commit that deployed successfully
export KUBECONFIG=/home/deploy/.kube/config # the "deployer" badge
# No kubectl call below says "-n relay": the namespace comes from this kubeconfig's context,
# which setup-deploy-user.sh sets to "relay". If that ever changes, these commands follow it.

fail() { echo "relay-deploy: $*" >&2; exit 1; }

Expand All @@ -24,10 +26,13 @@ if ! [[ "$SHA" =~ ^[0-9a-f]{40}$ ]]; then
fail "invalid commit SHA: $SHA"
fi

# 2. One deploy at a time: a second deploy waits here for up to 5 minutes.
# 2. One deploy at a time: a second deploy waits here for up to 15 minutes. That's longer
# than the worst case (deploy + rollback, 180 s per Deployment each). In CI this rarely
# waits at all, because the pipeline already runs main's deploys one after the other;
# it protects against an admin deploying by hand at the same moment.
# The lock is released by itself when the script ends, even if it crashes.
exec 9>/home/deploy/.relay-deploy.lock
flock --wait 300 9 || fail "another deploy is still running"
flock --wait 900 9 || fail "another deploy is still running after 15 minutes: nothing was changed, re-run this job"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes #16 wrong until #16 is updated, so the merge order now matters.

#16 still has timeout-minutes: 20, with the comment "5 min waiting for the server's lock + 3 min rollout + 3 min rollback". Raising the lock wait to 15 min changes that sum:

lock rollout rollback total #16's job timeout
before this PR 5 6 6 17 20 — fits
after this PR 15 6 6 27 20 — over

So if this merges and #16 goes in unchanged, a deploy that actually waits on the lock gets killed by GitHub mid-rollback: the cluster is left half-reverted and the log says "timed out" with none of the show_state output. That's the failure I was worried about in my comment on #16, now made more likely rather than less.

You say the 30-minute change happens in #16, and I believe you — it just isn't there yet, and #16 is a draft that gets rebased. Could the 30 go in before this merges, or could this PR carry it? Whichever is easier; I mainly want them not to be able to drift apart.

Smaller, for later rather than now: at three Deployments (worker, phase 2) it's 15 + 9 + 9 = 33, over even the new 30. Your argument that the lock rarely waits — because the pipeline's concurrency group already serialises main — is fair, and I'm not asking you to change the number. But the rule behind both numbers is "180 s × however many Deployments are in k8s/app/", and that rule still isn't written down next to either of them. One sentence in this comment block would mean whoever adds the worker knows there are two numbers to revisit, in two different files.


# 3. Gate 2: the commit must be on main, which means it was merged through a reviewed PR.
git -C "$REPO" fetch --quiet origin main
Expand Down Expand Up @@ -78,6 +83,7 @@ deploy_commit() {
return 1
fi
done
return 0 # says "success" on purpose, not by luck of what happens to run last
}

# 4. Deploy the commit. On success, remember it as the last good one.
Expand Down
9 changes: 8 additions & 1 deletion infra/server/test-relay-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ case "\$*" in
get*) echo "fake kubectl \$*" ;;
esac
EOF
printf '#!/usr/bin/env bash\nexit 0\n' > "$T/bin/flock"
# flock: gets the lock, unless lock-busy exists (another deploy holds it the whole time).
printf '#!/usr/bin/env bash\n[ -e "%s/lock-busy" ] && exit 1\nexit 0\n' "$T" > "$T/bin/flock"
chmod +x "$T/bin/"*
: > "$T/broken"
}
Expand Down Expand Up @@ -98,5 +99,11 @@ setup; echo "not a commit; touch /tmp/pwned" > "$T/home/.relay-last-good"; echo
check "exits 1" "$code" 1
check "never checks out what's in the note" "$(cat "$T/checked-out")" $BAD

echo "10. Another deploy still holds the lock"
setup; touch "$T/lock-busy"; code=$(run $GOOD)
check "exits 1" "$code" 1
check "says to re-run" "$(grep -q 're-run this job' "$T/out" && echo yes || echo no)" yes
check "changes nothing" "$(exists "$T/checked-out")" no

echo; echo "$passed passed, $failed failed"
[ "$failed" -eq 0 ]
8 changes: 7 additions & 1 deletion k8s/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ How each folder gets onto the cluster, and who may apply it.
by hand: the tag would be wrong.
- **Removing a file from `k8s/app/` doesn't remove it from the cluster.** The `deployer`
account has no delete, so one of us deletes the resource by hand:
`kubectl -n relay delete <kind>/<name>`.
`kubectl -n relay delete <kind>/<name>`. **Renaming is the dangerous case:** the new name is
created, but the old object stays and keeps serving (two Services or two Ingresses for the
same thing). A rename = the new name in the PR, plus deleting the old object right after it
merges.
- **Server and platform changes are applied by the one who merges, right after merging**, and
the check output is posted on the PR (for example `auth can-i` and the script `diff`).
Otherwise git and the server drift apart, and it only shows when something fails.
- **No Secrets in git.** They are created on the server with `kubectl create secret`.
- **Git and the cluster must match.** Everything applied by hand is committed in the same PR.

Expand Down