Skip to content

e2e: the diagnostics phase budget can be spent on cheap reads, declining every capture it exists to run #3686

Description

The diagnostics phase budget introduced with the per-read bounds can be spent almost entirely on the cheap reads that precede the heavy collectors, leaving nothing for the collectors the phase exists to run.

The numbers are in hack/e2e-chainsaw/_lib/run-kubernetes.sh: COZY_DIAG_PHASE_BUDGET_DEFAULT=480, COZY_DIAG_READ_TIMEOUT_DEFAULT=20, COZY_DIAG_READ_GRACE_DEFAULT=5. Each bounded read therefore costs up to 25 seconds, and the node-join failure block issues about fifteen of them before the first heavy collector, plus an importer listing and a wedge check with their own bounds. At the ceiling that is roughly 435 to 460 seconds of the 480, so the serial console (~350s), the guest Talos capture and the image-cache diagnosis are all declined.

Two things keep this from being alarming on every run, and both are worth stating so the number is not read as larger than it is. The ceiling is only reached when the reads genuinely hit their deadlines, which means a wedged apiserver. In the ordinary failure shape, where the apiserver answers and the worker simply never boots, those reads return in milliseconds and the budget is barely touched. And the budget is a ceiling on what may start, not a prediction of a run.

But the case where the ceiling is reached is exactly the case the diagnostics exist for. A wedged apiserver is when the cheap reads are least informative and the guest-side captures are most. Spending the phase on the former and declining the latter inverts the intent.

There is a second, smaller problem in the gate itself. cozy_diag_phase_has_time admits a collector if the deadline has not passed yet:

cozy_diag_phase_has_time() {
  [ "${_COZY_DIAG_PHASE_DEADLINE}" -ne 0 ] || return 0
  [ "$(date +%s)" -ge "${_COZY_DIAG_PHASE_DEADLINE}" ] || return 0
  ...

So a collector admitted one second before the deadline runs to completion and overruns the budget by its whole cost. The gate bounds when work may begin, not what fits, which means the budget is advisory for the last admitted collector and absolute for everyone after it.

Finally, the comment in both chainsaw-test.yaml files states that the reads ahead of the heavy collectors fit inside the budget "with room left". At the ceiling that is 435 to 460 of 480. The sentence describes the ordinary case while sitting next to an inventory whose purpose is to size the pathological one, and it is the sentence the next person adding a collector will read.

Directions, in the order they seem worth considering. Give the cheap reads their own sub-budget so they cannot consume the phase. Or order the phase so the irreplaceable captures run before the reads that merely describe state. Or make the gate reason about cost rather than start time, which requires each collector to declare a bound the gate can compare against the remainder.

Activity

  1. added
    kind/bugCategorizes issue or PR as related to a bug
    area/testingIssues or PRs related to testing (e2e, bats, unit tests)
    triage/acceptedIndicates an issue is ready to be actively worked on
    priority/backlogGeneral backlog priority. Lower than priority/important-longterm
    and removed
    triage/needs-triageIndicates an issue needs triage by a maintainer
    on Sep 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/testingIssues or PRs related to testing (e2e, bats, unit tests)kind/bugCategorizes issue or PR as related to a bugpriority/backlogGeneral backlog priority. Lower than priority/important-longtermtriage/acceptedIndicates an issue is ready to be actively worked on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions