Skip to content

feat(csi)!: adopt CSI spec v1.13.0 and migrate to the VolumeHealth API - #364

Closed
sticky-gecko[bot] wants to merge 8 commits into
mainfrom
renovate/github.com-container-storage-interface-spec-1.x
Closed

feat(csi)!: adopt CSI spec v1.13.0 and migrate to the VolumeHealth API#364
sticky-gecko[bot] wants to merge 8 commits into
mainfrom
renovate/github.com-container-storage-interface-spec-1.x

Conversation

@sticky-gecko

@sticky-gecko sticky-gecko Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Updates github.com/container-storage-interface/spec from v1.12.0 to v1.13.0, and migrates the driver onto the API that replaces the one v1.13.0 deleted.

Why this is more than a version bump

The v1.13.0 release notes say "Breaking changes/Deprecations: None", but the release removed the alpha VolumeCondition API outright:

  • the VolumeCondition message,
  • ControllerServiceCapability.RPC.VOLUME_CONDITION (11) and NodeServiceCapability.RPC.VOLUME_CONDITION (4),
  • the volume_condition field on NodeGetVolumeStatsResponse, ControllerGetVolumeResponse.VolumeStatus and ListVolumesResponse.VolumeStatus.

internal/csi used all of it, so the bare bump failed to compile (Go Test / Go Lint / Build / every E2E leg).

What replaces it

CSI v1.13.0 adds an alpha VolumeHealth API — a VolumeHealthErrorType enum (DEGRADED, INACCESSIBLE, DATA_LOSS) plus dedicated RPCs. The driver now implements all three and advertises the matching capabilities (GET_VOLUME_HEALTH, LIST_VOLUME_HEALTH on the controller; GET_VOLUME_HEALTH on the node):

Condition Status Reason
DRBD split-brain DATA_LOSS SplitBrain
Backing disk detached on I/O error DEGRADED BackingDiskFailed
Provisioning failed, no device INACCESSIBLE ProvisioningFailed
Replica missing current data DEGRADED ReplicaOutOfSync

VolumeHealth carries a list, so every condition that holds is now reported (ordered most-urgent first) instead of only the highest-ranked one — a split-brain volume reports the failed disk and the degraded replication alongside it. ControllerListVolumeHealth returns only the abnormal set, paginated with the same positional tokens ListVolumes uses.

csi-test

csi-test/v5 v5.5.0 (latest tag) still references the removed constants and does not compile against the new spec. Fixed on master by csi-test#614 but unreleased, so this pins the master pseudo-version v5.5.1-0.20260728125401-ae8a63a708ab. Swap it for the tag once one is cut. The sanity suite passes against it.

BREAKING: the health-monitor sidecar is removed

external-health-monitor v0.18.0 is still built against spec v1.12.0 and calls klog.FlushAndExit(…, 1) at startup when the driver does not advertise VOLUME_CONDITION. Left in place it would put the controller pod into CrashLoopBackOff for anyone running sidecars.healthMonitor.enabled: true, so the sidecar and the whole sidecars.healthMonitor values block are gone from the chart. Its support for the new RPCs is in external-health-monitor#376, still unmerged.

Upgrade action: if you set sidecars.healthMonitor.*, drop it from your values. The generated schema does not set additionalProperties, so a stale key is ignored rather than rejected — the sidecar simply stops being rendered, no failed upgrade. Volume health is unchanged on the miroir_volume_* metrics and the shipped alerts/dashboard, which is where the chart already pointed operators.

What this costs on Kubernetes 1.36

Nothing on a stock cluster. In release-1.36, CSIVolumeHealth is {Version: 1.21, Default: false, PreRelease: Alpha} (pkg/features/kube_features.go), and kubelet's entire volume-condition path sits inside if utilfeature.DefaultFeatureGate.Enabled(features.CSIVolumeHealth) (pkg/volume/csi/csi_client.go). With the gate off — the default since 1.21 — kubelet never queries the capability and never reads volume_condition, so kubelet_volume_stats_health_status_abnormal was never being emitted for miroir volumes in the first place.

On a cluster that explicitly enables the gate there are two effects: that metric stops appearing, and raw-block volumes lose a side effect. miroir returns an empty NodeGetVolumeStatsResponse for a raw-block path (statfs there would report the host filesystem, not the volume), and kubelet errors failed to get usage from response. usage is nil when the driver offers neither usage nor the volume-condition capability. The capability used to suppress that; now it doesn't. It is a stats-collection error only — mounting and pod health are unaffected — and it is already the behaviour on every default-gate cluster.

kubelet's replacement (pkg/kubelet/volumemanager/volumehealth, calling NodeGetVolumeHealth and folding results into PodStatus.VolumeHealth and CSINode.Status.StorageHealth) is on Kubernetes master, so it lands in a release after v1.36. The driver is ready ahead of it; until then the miroir_volume_* gauges remain the surface to alert on.

Verified locally

go build ./..., go vet ./..., the full unit suite, mise run test-sanity, golangci-lint run, helm lint, helm-unittest (119 tests), helm-docs-check and the docs build all pass.


Upstream release notes: container-storage-interface/spec v1.13.0

Compare Source

Breaking changes/Deprecations:
  • None
Additions:
  • #604 - [ALPHA] Add Controller List/Get VolumeHealth RPCs by @gnufied
  • #606 - [ALPHA] Add Snapshot Topology by @mdzraf
Clarifications/Corrections/Fixes:
  • #587 - Add note about possibly lower available capacity on MountVolume volumes by @nixpanic
  • #563 - describe ABORTED as error message for CreateVolumeGroupSnapshot by @nixpanic
  • #605 - Fix RESOURCE_EXHAUSTED error code from 13 to 8 by @nixpanic
Dependencies:
  • #602/#607 - Bump golang from 1.23 to 1.25

Full Changelog: container-storage-interface/spec@v1.12.0...v1.13.0


Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. Do not rebase — the migration commit on this branch would be lost.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


This PR was generated by Mend Renovate and extended by hand with the API migration.

@sticky-gecko sticky-gecko Bot added the type/minor Issue relates to a minor version bump label Jul 27, 2026
@onedr0p
onedr0p enabled auto-merge July 29, 2026 09:20
@sticky-gecko

sticky-gecko Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

Edited/Blocked Notification

Renovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR.

You can manually request rebase by checking the rebase/retry box above.

⚠️ Warning: custom changes will be lost.

CSI spec v1.13 removes the alpha VolumeCondition message, both
VOLUME_CONDITION service capabilities and the volume_condition fields on
NodeGetVolumeStats, ControllerGetVolume and ListVolumes, replacing them
with VolumeHealth and dedicated RPCs.

Answer ControllerGetVolumeHealth, ControllerListVolumeHealth and
NodeGetVolumeHealth, reporting split-brain as DATA_LOSS, a failed
backing disk or a lagging replica as DEGRADED, and a volume whose device
never materialized as INACCESSIBLE. The new message carries a list, so
every condition that holds is reported instead of only the
highest-ranked one.

csi-test has no release that compiles against the new spec, so pin the
master pseudo-version until one is cut.

BREAKING CHANGE: the external-health-monitor sidecar and its
sidecars.healthMonitor values are removed from the chart.
external-health-monitor v0.18.0 exits non-zero against a driver that no
longer advertises VOLUME_CONDITION, so keeping it would crash-loop the
controller pod, and its support for the health RPCs is still unmerged
upstream. Volume health remains available through the miroir_volume_*
metrics and the CSI health RPCs.

Signed-off-by: Devin Buhl <devin@buhl.casa>
@onedr0p onedr0p changed the title feat(go): update module github.com/container-storage-interface/spec (v1.12.0 → v1.13.0) feat(csi)!: adopt CSI spec v1.13.0 and migrate to the VolumeHealth API Jul 29, 2026
@onedr0p
onedr0p added this pull request to the merge queue Jul 29, 2026
@onedr0p
onedr0p removed this pull request from the merge queue due to a manual request Jul 29, 2026
onedr0p and others added 3 commits July 29, 2026 08:51
Follow-ups on the VolumeHealth migration:

- ControllerGetVolume dropped the whole Status message when its only
  populated member went away. v1.13 reserved VolumeCondition inside
  VolumeStatus, not VolumeStatus itself, which is still REQUIRED.
- Gate the phase and split-brain mappings on status.activated/formatted,
  the same latch split-brain auto-recovery keys on. A never-activated
  birth split reports DEGRADED/SplitBrainRecovering instead of the
  DATA_LOSS that would send a CO restoring a snapshot of an empty
  volume; Creating on a volume that has already served is no longer
  reported as healthy; Failed with a surviving leg is DEGRADED, not
  INACCESSIBLE, since a peer keeps serving the pod.
- Sort the entries by severity so "most-urgent first" holds regardless
  of the order the mappers ran in.
- NodeGetVolumeHealth answers for the node that asks: only that node's
  replica status feeds the per-replica signals, plus the live kernel
  view for the quorum loss the CRD never carries. It was a byte-
  identical copy of the controller RPC, reporting peers' faults as the
  local node's while missing the leg that cannot be staged there.
- The health listing's index space shrinks as volumes recover, so a
  positional token routinely falls off the end between two pages of one
  listing. Return an empty page there instead of aborting; ListVolumes
  keeps aborting, its set only moves on create/delete.
- Guard the removed sidecars.healthMonitor values with a fail, matching
  the chart's other removed-key guards, and document 0.12.0 in the
  upgrade notes.
- Correct the doc comments and monitoring.md prose that claimed PVC
  events and kubelet volume-health conditions are live today.
- Extract sortedVolumes and Node.getVolume, wire requireVolume into the
  remaining identical lookups, and assert gRPC codes rather than
  err != nil in the health tests.

Signed-off-by: Devin Buhl <devin@buhl.casa>
@onedr0p
onedr0p added this pull request to the merge queue Jul 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 29, 2026
@onedr0p
onedr0p added this pull request to the merge queue Jul 29, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jul 29, 2026
staticcheck only knows t.Fatalf terminates when the testing package
facts are part of the run; with a restored golangci-lint cache they are
not always there, and SA5011 fires on the deref that follows. Moving it
into an else branch makes the guard structural.

Signed-off-by: Devin Buhl <devin@buhl.casa>
@onedr0p

onedr0p commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closing in favour of tracking issue #376. The migration is done and verified locally, but it's blocked on unreleased upstream deps (csi-test master pin, external-health-monitor#376 unmerged, kubelet's VolumeHealth consumer only on Kubernetes master). #376 captures the follow-up so this isn't lost.

@onedr0p onedr0p closed this Jul 30, 2026
@sticky-gecko
sticky-gecko Bot deleted the renovate/github.com-container-storage-interface-spec-1.x branch July 30, 2026 11:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/minor Issue relates to a minor version bump

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant