Skip to content

fix(kubernetes): validate MachineHealthCheck condition timeouts at render time - #3901

Merged
Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/duration-guard-canonical-and-mhc
Aug 18, 2026
Merged

Aleksei Sviridkin (lexfrei) merged 1 commit into
mainfrom
fix/duration-guard-canonical-and-mhc

Conversation

@lexfrei

@lexfrei Aleksei Sviridkin (lexfrei) commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

Follow-up to #3898, closing two gaps in the render-time duration guard it introduced. Context: #3513.

First, the guard now also covers the MachineHealthCheck condition timeouts (readyUnknownTimeout, readyFalseTimeout) in both the kubernetes and kubernetes-nodes charts. They need it more than the autoscaler annotation does: the CAPI webhook validates nodeStartupTimeout with a 30s floor but does not validate unhealthyConditions timeouts at all, so a zero or negative value used to apply silently and remediate a Machine the moment its Ready condition flipped, which for a KubeVirt worker means deleting the VM.

Second, the guard accepts the canonical form a Go duration serializes back to ("20m0s", "1h0m0s"). metav1.Duration prints that shape, so a value copied from kubectl get -o yaml output previously failed the render. The first segment must still be positive and later segments may be zero, so every accepted string still parses to a positive duration and the overflow and fraction-to-zero rejections stay.

Mechanically, the guard moves into a kubernetes.positiveDuration named template in each chart's _helpers.tpl, and the error message format is unchanged. Tests cover the canonical form on all three fields and the rejection of unitless, zero, and negative condition timeouts in both charts. The previous test case that passed unitless values through verbatim is reworked into rejections: a unitless value used to fail only at CAPI decode on apply, and a zero or negative one did not fail anywhere.

Downstream repositories

Release note

fix(kubernetes): reject zero and negative MachineHealthCheck condition timeouts at render time, and accept the canonical Go duration form ("20m0s", "1h0m0s") for the worker join timer values

Summary by CodeRabbit

  • Bug Fixes

    • Added consistent render-time validation for node provisioning and health-check timeout values.
    • Rejects zero, negative, unitless, and improperly formatted durations with field-specific errors.
    • Supports canonical duration formats such as 20m0s and 1h0m0s.
  • Documentation

    • Clarified accepted duration formats, validation behavior, timeout effects, and fallback handling across configuration references.

…nder time

The CAPI webhook validates nodeStartupTimeout with a 30s floor but does
not validate unhealthyConditions timeouts at all, so a zero or negative
readyUnknownTimeout or readyFalseTimeout applied and remediated a
Machine the moment its Ready condition flipped. Route both fields
through the same render-time duration guard as maxNodeProvisionTime,
extracted into a kubernetes.positiveDuration helper in each chart.

The guard now also accepts the canonical form a duration serializes
back to ("20m0s", "1h0m0s"): metav1.Duration prints that shape, so a
value copied from kubectl output previously failed the render. The
first segment must still be positive and later segments may be zero,
which keeps every accepted string a positive duration.

Assisted-By: Claude <[email protected]>
Signed-off-by: Aleksei Sviridkin <[email protected]>
@lexfrei
Aleksei Sviridkin (lexfrei) merged commit 7194edf into main Aug 18, 2026
10 of 11 checks passed
@lexfrei
Aleksei Sviridkin (lexfrei) deleted the fix/duration-guard-canonical-and-mhc branch August 18, 2026 19:41
@coderabbitai

coderabbitai Bot commented Aug 18, 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: 786fb42a-7c68-435e-8ed8-c2f775435581

📥 Commits

Reviewing files that changed from the base of the PR and between b32ca5c and 3710541.

📒 Files selected for processing (18)
  • api/apps/v1alpha1/kubernetes/types.go
  • api/apps/v1alpha1/kubernetesnodes/types.go
  • packages/apps/kubernetes-nodes/README.md
  • packages/apps/kubernetes-nodes/templates/_helpers.tpl
  • packages/apps/kubernetes-nodes/templates/nodegroup.yaml
  • packages/apps/kubernetes-nodes/tests/max_node_provision_time_test.yaml
  • packages/apps/kubernetes-nodes/tests/mhc_timeouts_test.yaml
  • packages/apps/kubernetes-nodes/values.schema.json
  • packages/apps/kubernetes-nodes/values.yaml
  • packages/apps/kubernetes/README.md
  • packages/apps/kubernetes/templates/_helpers.tpl
  • packages/apps/kubernetes/templates/cluster.yaml
  • packages/apps/kubernetes/tests/max_node_provision_time_test.yaml
  • packages/apps/kubernetes/tests/mhc_timeouts_test.yaml
  • packages/apps/kubernetes/values.schema.json
  • packages/apps/kubernetes/values.yaml
  • packages/system/kubernetes-nodes-rd/cozyrds/kubernetes-nodes.yaml
  • packages/system/kubernetes-rd/cozyrds/kubernetes.yaml

📝 Walkthrough

Walkthrough

The change adds shared Helm validation for positive, whole-unit durations. It applies validation to node provisioning and readiness timeouts, adds coverage for accepted and rejected formats, and updates API, schema, values, OpenAPI, and README documentation.

Changes

Duration validation

Layer / File(s) Summary
Shared duration validation and template wiring
packages/apps/kubernetes*/templates/_helpers.tpl, packages/apps/kubernetes*/templates/{cluster,nodegroup}.yaml
Both charts add kubernetes.positiveDuration and use it for provisioning and readiness timeout rendering.
Duration validation coverage
packages/apps/kubernetes*/tests/*timeout*.yaml, packages/apps/kubernetes*/tests/max_node_provision_time_test.yaml
Tests cover canonical durations, zero-valued segments, unitless values, zero values, negative values, and field-specific errors.
Duration contracts and documentation
api/apps/v1alpha1/*/types.go, packages/apps/kubernetes*/README.md, packages/apps/kubernetes*/values*, packages/system/*/cozyrds/*.yaml
Documentation describes render-time validation, timeout behavior, accepted duration formats, and fallback behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

✨ 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 fix/duration-guard-canonical-and-mhc

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Trivy (0.72.0)

Trivy execution failed: 2026-08-18T19:42:49Z FATAL Fatal error run error: fs scan error: scan error: scan failed: failed analysis: post analysis error: post analysis error: helm scan error: fs filter error: fs filter error: walk error range error: stat api/apps/v1alpha1/.golangci.yml: no such file or directory: range error: stat api/apps/v1alpha1/.golangci.yml: no such file or directory


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/kubernetes Issues or PRs related to the tenant Kubernetes app kind/bug Categorizes issue or PR as related to a bug size/L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant