Skip to content

test(e2e): add a runner-layer fixed-work canary around the node-join wait - #3919

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
feat/e2e-runner-canary
Aug 20, 2026
Merged

test(e2e): add a runner-layer fixed-work canary around the node-join wait#3919
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
feat/e2e-runner-canary

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What this PR does

The diagnostics around the node-join wait already carry counter pairs that report time in the CPU rows, events in the KVM exits, and instantaneous values and running maxima in the files beside those. None of them is a fixed quantity of work, so none can separate a machine that was given fewer turns from a machine that took its turns and got less done with them.

This adds a collector that runs two fixed amounts of work on the runner VM and times them: an integer loop and a streaming write, each under a ceiling of its own. It takes one sample before the node-join wait and one after it, on the failing and the passing path alike. Each sample is an absolute reading rather than half a difference, so one alone is still readable against the expected ranges the capture prints, and the pair says whether a slowdown began inside the interval it brackets or was already there going into it.

The collector sits outside the three counter pairs that bracket the same wait rather than among them, because it occupies a core while it runs, and a burn placed inside one of those intervals would be charged to the join window it is supposed to measure.

A new bats suite of 57 tests covers the collector. The existing node-join guards were extended to price it against the phase budget and to keep the spend order documented in both kubernetes suites in step with the order the block actually runs.

On the budget: the sample taken before the wait is bounded at two arms of the canary ceiling plus grace, so it can add up to fifty seconds ahead of the wait, and the guard prices it at exactly that, while the guard's total stays below an honest worst case because collectors it already priced can spend more than the figures it prices them at.

This branch was reviewed extensively before it was opened, and what is known to be incomplete is written down rather than left implied: the words describing how each floor sits against its healthy band are marked in the code as written rather than derived, so they are the part that can go stale when a constant moves, and the phase budget residuals are tracked in the issue the comments beside them cite.

Screenshots

Not a UI change.

Downstream repositories

Walked the trigger map in docs/agents/contributing.md against the diff, file by file. The diff is five files: the e2e diagnostics collector library, its two new and extended bats suites, and the two chainsaw suite definitions that document the spend order.

The closest call is cozystack/ccp, whose skills gate on hack/package.mk and hack/common-envs.mk and drive make generate. Neither file is touched, nothing under hack/ is moved or renamed, and no make target changes what it does: the new suite is picked up because BATS_UNIT_FILES already globs hack/*.bats, so the file list grows and the target's contract does not.

Nothing else matches. No package is added, renamed or removed, so the website app lists are unaffected. No values.schema.json, version enum, default or ApplicationDefinition changes, so the Terraform provider is unaffected. hack/e2e-prepare-cluster.bats is untouched, so the node prerequisites that ansible-cozystack and talm restate are unchanged. hack/update-crd.sh, the release.labels convention and the chart source kinds are untouched, so external-apps-example and cozyhr are unaffected. No label, annotation or metric name changes, so cozy-proxy and cozystack-telemetry-server are unaffected. Minimum node and network requirements are unchanged, so examples is unaffected.

Release note

test(e2e): the node-join diagnostics now time two fixed amounts of work on the runner before and after the wait, so a run that spent its wall clock without completing work is visible in the report. No user-facing change.

Summary by CodeRabbit

  • New Features

    • Added a runner fixed-work canary to Kubernetes diagnostics, measuring compute and memory throughput around node-join operations.
    • Reports execution rates, timeout conditions, and alerts when performance falls below healthy thresholds.
    • Includes diagnostic output explaining expected ranges, sampling behavior, and measurement overhead.
  • Documentation

    • Updated Kubernetes test documentation to describe the additional canary and diagnostic timing.
  • Tests

    • Added comprehensive coverage for canary execution, reporting, thresholds, timeout behavior, and integration with diagnostic collection.

…wait

The counters the node-join failure path collects are read in whatever
unit their source publishes: time in the CPU rows, events in the KVM
exits, instantaneous values and running maxima in the files beside
those. Not one of them carries a unit of work of its own, so a machine
that spent every tick and got a fraction of the work done reads healthy
in all of them.

Add a collector that carries its own unit of work. It runs two fixed
amounts of work at the runner layer and times each: a loop over a
handful of integer-valued scalars, which pressure on the shared cache or
the memory controller moves little, and a store stream through blocks
larger than the last-level cache one core can allocate into, which is
dominated by it. Fixed work gives each reading a scale of its own, so a
red run can be read with no green one beside it, and the capture states
the expected range and where the estimate comes from.

Sampled where the three counter pairs already are, before the wait on
every run and after it on both paths, but outside their brackets: it
occupies a core rather than reading a file, and a burn inside one of
those intervals would land in the interval each pair divides by:
runner-kernel CPU time charged to the join window, and for the two
counting the guests, a core taken away from what they count.

Two arms, each under a twenty-second ceiling with the five-second kill
grace behind it, so fifty seconds at worst against the 420s diagnostics
budget. The budget guard derives that from the ceiling the source
declares, and the phase-warning guard names the canary among the
collectors that keep running when timeout is missing. An exit shaped
like the ceiling is attributed to it only when the whole bound was on
the clock: an outside kill produces the same status, and read by status
alone it would publish exactly the finding this collector exists to
detect.

A reading below the range the legend states, and an arm the ceiling
stopped before it could produce one, reach the job log from all three
reporting sites, each naming where it was taken, the way a missing
reading does from the two outside the diagnostics block. On the passing
path the report that holds the figure is the artifact nobody downloads.
Each floor is printed in the legend it comes from and sits where a
bounded arm crosses it before the ceiling stops the arm, because a floor
the ceiling reaches first never fires: the arm is cut off before its
rate can fall that far, and every alert then arrives as a bound rather
than as the slowdown the floor was meant to name.

Assisted-By: Claude <noreply@anthropic.com>
Signed-off-by: Aleksei Sviridkin <3811295@gmail.com>
@github-actions github-actions Bot added area/testing Issues or PRs related to testing (e2e, bats, unit tests) size/XXL This PR changes 1000+ lines, ignoring generated files labels Aug 20, 2026
@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 68d83cb into main Aug 20, 2026
12 of 14 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the feat/e2e-runner-canary branch August 20, 2026 08:25
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f2f8b048-d94b-43bd-ac13-f6224e8b090d

📥 Commits

Reviewing files that changed from the base of the PR and between 899529b and 7ec5dff.

📒 Files selected for processing (5)
  • hack/e2e-chainsaw/_lib/run-kubernetes.sh
  • hack/e2e-chainsaw/kubernetes-latest/chainsaw-test.yaml
  • hack/e2e-chainsaw/kubernetes-previous/chainsaw-test.yaml
  • hack/run-kubernetes-node-join_test.bats
  • hack/run-kubernetes-runner-canary_test.bats

📝 Walkthrough

Walkthrough

Changes

The Kubernetes e2e diagnostics now include a runner fixed-work canary. It measures fixed compute and memory workloads with optional time bounds, records rates and alerts, and runs samples around the node-join wait. Tests and budget documentation cover the new collector.

Runner canary diagnostics

Layer / File(s) Summary
Canary measurement and reporting
hack/e2e-chainsaw/_lib/run-kubernetes.sh
Adds canary constants, clock parsing, bounded arm execution, rate reporting, capture output, legends, and run-bound validation.
Node-join sampling integration
hack/e2e-chainsaw/_lib/run-kubernetes.sh, hack/e2e-chainsaw/kubernetes-*/chainsaw-test.yaml
Collects samples before and after node joining on success and failure paths. Updates diagnostic ordering and budget comments.
Budget and diagnostic test integration
hack/run-kubernetes-node-join_test.bats
Updates stubs, budget arithmetic, timeout-warning checks, ordering checks, and residual-budget documentation.
Canary regression coverage
hack/run-kubernetes-runner-canary_test.bats
Adds coverage for parsing, execution, termination handling, rates, persistence, legends, ordering, thresholds, sizing, and documentation.

Estimated code review effort: 5 (Critical) | ~90 minutes

Possibly related issues

Possibly related PRs

Suggested labels: debug

Suggested reviewers: myasnikovdaniil

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/e2e-runner-canary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/testing Issues or PRs related to testing (e2e, bats, unit tests) size/XXL This PR changes 1000+ lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant