Repository navigation
🤖 tests: pool Kind phases P10 to P12: scale to 0, KEDA cron autoscaling, active-version rollout (#153 PR 15b) - #452
Conversation
…lout) with offline stubs (#153 PR 15b) Change-Id: If6af85642696e66e33b6a2b414c0c5e83cc4cb0e Signed-off-by: Thomas Kosiewski <tk@coder.com>
Change-Id: I060edce66d1a377c9251bc9e004306d6bf657dad Signed-off-by: Thomas Kosiewski <tk@coder.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
@codex security review |
Dogfood (plan row 15)I ran plan 14.2 steps 2 to 5, 7, and 8 by hand on a Kind cluster with the operator image built from this PR's tree (Coder, the agent fixture template
The recording: pr15-dogfood.mp4 |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |


Summary
The Kind E2E pool step now also runs phases P10 to P12 of the #153 plan:
replicas: 0makes no workspaces, and a claim still gets one: the pool builds a member on demand and binds it.cronScaledObject. The HPA that KEDA makes reportsScalingActive=True(risk R4).readyReplicasnever drops below 2.Every new phase has offline stub scenarios in
hack/e2e-workspace-pool_test.sh. No controller code changes.Refs #153
This is plan PR 15b, the second half of a split. PR 15 grew past the plan's 550-line limit. PR 15a (#447, merged as 19041e8) added refresh and idle reaping. This PR adds the Kind phases P10 to P12, the KEDA install, and their offline stubs. It is based on main after PR 14 (#446, Share mode, merged as 30e9cf8), so P9 runs too.
Background
Plan 10.4 lists P10 to P12 for PR 15, and the plan's risk table names R4: the HPA that KEDA makes can fail on a pool whose
status.selectormatches no pods. Only a real HPA catches selector and metric-type mistakes, so decision D8 (in the #153 plan) puts a KEDA cron phase in the Kind job (option B). If the whole job grows by more than 10 minutes over main, P11 moves to a nightly job (option C). The measurement is in Validation below.Implementation
hack/e2e-workspace-pool.sh, after P9 and before the cleanup:replicas: 0and checks that it is Ready with no members. A claim then binds to a member built on demand, and only that member exists. Deleting the claim deletes the member and its workspace in Coder.v1beta1.external.metrics.k8s.ioAPIService. AcronScaledObject (minReplicaCount: 0,maxReplicaCount: 2,cooldownPeriod: 30,desiredReplicas: 2) opens a 3-minute window at the next minute. The driver waits forspec.replicas2 with 2 ready members, then for KEDA's HPA withScalingActive=True. It checks that the HPA targets theCoderWorkspacePoolwith an ExternalAverageValuemetric. Then it waits for 0 and checks that the scaled-up workspaces are deleted in Coder. It removes the ScaledObject, the APIService first, then the rest of KEDA. A stale APIService stalls namespace deletion.spec.files["main.tf"]of the fixtureCoderTemplate. That update imports and activates a new version. The driver samplesreadyReplicasevery 2 s and fails at once if a sample is below 2. It passes when both live members pin the new version and the pool is ready. The driver then checks that the old workspaces are deleted in Coder, deletes the pool, and checks that the new workspaces are deleted too.on_demand_member,keda_up_seconds,keda_down_seconds,keda_hpa, androllout_ready_samples.sha256sumjoins the tool check.hack/e2e-workspace-pool_test.sh: the fake pool controller now follows KEDA's cron window, builds a member on demand for a waiting claim, and replaces outdated members new before old. The pass scenario must run P1 to P12 and leave no ScaledObject or KEDA behind. Six new scenarios each break one behavior, and the driver must fail with the check that covers it:no-on-demand,keda-tampered,hpa-not-active,keda-stays-up,rollout-dips,rollout-stays-old..github/workflows/ci.yaml: the pool step name lists the new phases, and the failure dump adds the ScaledObjects, the HPAs, and the KEDA pods.docs/how-to/workspace-pools.md: one paragraph on the autoscaler contract. The pool's selector matches no pods, so an HPA needs External or Object metrics withAverageValue. KEDA's HPAs do that, and the Kind test proves 0 to 2 to 0. PR 16 owns the rest of the pool docs.Validation
CI on 88767b9 (E2E job): P1 to P12 pass, and every required check passes.
e2e-pool-v2pz9, a member built on demand.CoderWorkspacePoolwith anAverageValuemetric and reportsScalingActive=Truewith reasonValidMetricFound.readyReplicassamples during the rollout were 2.Job growth (D8): the E2E job took 22m54s. The #446 E2E job on its final PR head took 15m29s, and its merge-queue E2E job took 15m45s. That is 7m25s and 7m09s of growth. The pool step grew by 6m00s (3m36s to 9m36s), and P10 to P12 account for 5m55s of it. The growth is under 10 minutes, so P11 stays in the PR job (D8 option B), and no nightly job is needed.
Local Kind replica of the CI job on the same tree (image built from this tree): P1 to P12 pass.
In that run, KEDA scaled the pool 0 to 2 in 57 s and 2 to 0 in 179 s. Its HPA reported
ScalingActive=Truewith reasonValidMetricFoundand anAverageValuetarget. EveryreadyReplicassample during the rollout was 2.make test-scriptspasses (the pool driver: all scenarios, including the 6 new ones).make verify-vendor test build lint test-integration docs-checkpass on the head.shellcheck -S warningon both scripts, actionlint onci.yaml, markdownlint-cli2 and cspell on the changed doc: clean.Dogfood (plan row 15): the KEDA cron window with
kubectl get hpaevery 15 s, and the pool's workspaces in the Coder UI.Risks
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:xhigh