Skip to content

VMOwnedVolume- Attach Detach Implementation#4097

Open
deepakkinni wants to merge 8 commits into
kubernetes-sigs:masterfrom
deepakkinni:topic/dk016388/vmown-att-det-v1
Open

VMOwnedVolume- Attach Detach Implementation#4097
deepakkinni wants to merge 8 commits into
kubernetes-sigs:masterfrom
deepakkinni:topic/dk016388/vmown-att-det-v1

Conversation

@deepakkinni

@deepakkinni deepakkinni commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Description

Implements the CSI (vSphere CSI driver / syncer) side of VM-owned volume attach/detach (VGL-62908) for greenfield VMs on supervisor clusters, behind the cluster-wide VMOwnedVolumes feature gate.

Disk ownership is transferred based on attachment state: a detached volume is a CNS-managed FCD; once attached in dependent-persistent mode it becomes a plain VMDK owned by the VM (FCD unregistered, volume leaves CNS). CSI owns only the catalog side of that transfer — unregister the FCD on first attach, re-register on last detach — driven declaratively off a new per-volume CR, CsiVolumeInfo (CVI). vm-operator owns all VM reconfiguration and snapshot correlation; the two never cross boundaries.

What this adds

  • CsiVolumeInfo CRD (cns.vmware.com/v1alpha1, namespaced to vmware-system-csi, deterministic name cns-volume-<volumeID>, PV ownerRef, status subresource, cvi short name) + service layer (idempotent CRUD, finalizer add/remove, conflict-only patch retry) + RBAC.
  • VMOwnedVolumes FSS gate — all new behavior is gated; FSS-off creates no CVIs and uses legacy paths.
  • CNS two-phase unregister wrappers on volume.Manager: UnregisterVolumeEx, QueryPendingUnregisters, AckUnregister (wired to the vetted govmomi fork pinned at bccc2167).
  • Declarative CVI reconciler (new standalone controller): len(spec.vms)>0 ∧ CSIManaged → Unregister; len(spec.vms)==0 ∧ VMManaged → Register; otherwise idle. Handles brownfield-lazy CVIs (absent status.ownership treated as CSIManaged), advances observedGeneration/phase as the green signal, and surfaces CNS faults to status.
  • Lifecycle plumbing: CVI creation at provisioning, PV-bind reconcile (incl. cross-namespace Retain rebind), explicit CVI delete on DeleteVolume, and startup PENDING_UNREGISTER recovery for crash-interrupted unregisters.
  • Cross-cutting guards: PVC-deletion validating webhook + volume-protection finalizer while VMManaged, and VolumeSnapshot-create rejection while VMManaged.

Bug fixes included

  • Green-signal stall: observedGeneration now reflects the post-patch generation (the reconciler's own spec.diskPath/diskUUID write advances metadata.generation), so vm-operator's observedGeneration >= generation gate can be satisfied.
  • Re-register idempotency: CnsAlreadyRegisteredFault (and CnsVolumeAlreadyExistsFault) treated as success.
  • Backoff-map entry dropped when a CVI is deleted (no leak); recovery writes the full status shape; conflict-only patch retries; spec-accurate PVC-delete rejection message; removed an invalid CRD print column.
  • Updated the remaining volume.Manager test mocks for the new interface methods so all packages compile.

Closes: #(issue-number)

How Has This Been Tested?

  • Unit tests (new + existing) across pkg/apis/cnsoperator/csivolumeinfo/..., pkg/syncer/cnsoperator/controller/csivolumeinfo/..., pkg/common/cns-lib/volume/..., pkg/syncer/admissionhandler/..., pkg/syncer/, and pkg/csi/service/wcp/... — table-driven over the reconcile state matrix (unregister/register/idle, brownfield-lazy, multi-VM RWM, fault surfacing, observedGeneration advancement, startup recovery incl. double-ACK and orphan records).
  • Added a regression test proving observedGeneration tracks the controller's own spec write (the generation-bump the API server applies but the fake client does not).
  • Full suite: go test ./... — all packages pass, no regressions.
  • Quality gate: gofmt, go vet ./..., staticcheck, and golangci-lint all clean.

Note: the supervisor ValidatingWebhookConfiguration that routes PVC DELETE to the webhook is owned by the WCP deployment (outside this repo) and should be confirmed to register the DELETE operation. End-to-end attach/detach/snapshot-guard validation on a live supervisor is pending.

Modify a existing csi volume to add vms. This will unregister the volume as a fcd.

➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml \
  -n vmware-system-csi patch csivolumeinfo cns-volume-ab377741-2555-4b17-a829-4d6951283c09 \
  --type=merge -p '{"spec":{"vms":[{"vmName":"fake-vm-for-testing"}]}}'

csivolumeinfo.cns.vmware.com/cns-volume-ab377741-2555-4b17-a829-4d6951283c09 patched
➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml -n vmware-system-csi get csivolumeinfos.cns.vmware.com
NAME                                              OWNERSHIP    PHASE       AGE
cns-volume-ab377741-2555-4b17-a829-4d6951283c09   VMManaged    Succeeded   50m
cns-volume-bc42e300-cf0c-488f-84d2-46907454b503   CSIManaged   Succeeded   76m
➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml -n vmware-system-csi get csivolumeinfos.cns.vmware.com cns-volume-ab377741-2555-4b17-a829-4d6951283c09 -o yaml
apiVersion: cns.vmware.com/v1alpha1
kind: CsiVolumeInfo
metadata:
  creationTimestamp: "2026-06-23T08:00:10Z"
  finalizers:
  - csi.vsphere.vmware.com/volume-protection
  generation: 3
  name: cns-volume-ab377741-2555-4b17-a829-4d6951283c09
  namespace: vmware-system-csi
  resourceVersion: "6165144"
  uid: e6586902-20b6-47db-9997-b9662da477d4
spec:
  diskPath: '[sharedVmfs-0] fcd/662e21f35b6143beb16e0d9bc67d4281.vmdk'
  diskUUID: 6000C295-b455-7da3-ce03-94d57dbfebbe
  pvName: pvc-ab377741-2555-4b17-a829-4d6951283c09
  pvcName: src-pvc-vmown-2
  pvcNamespace: testns
  vms:
  - vmName: fake-vm-for-testing
  volumeID: ab377741-2555-4b17-a829-4d6951283c09
status:
  conditions:
  - lastTransitionTime: "2026-06-23T08:50:39Z"
    message: ""
    reason: UnregisterSucceeded
    status: "True"
    type: Ready
  error: ""
  observedGeneration: 3
  ownership: VMManaged
  phase: Succeeded


Remove the vms from the list, this will re-register the disk as fcd

  ➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml \
  -n vmware-system-csi patch csivolumeinfo cns-volume-ab377741-2555-4b17-a829-4d6951283c09 \
  --type=json -p '[{"op":"remove","path":"/spec/vms"}]'
csivolumeinfo.cns.vmware.com/cns-volume-ab377741-2555-4b17-a829-4d6951283c09 patched
➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml -n vmware-system-csi get csivolumeinfos.cns.vmware.com
NAME                                              OWNERSHIP    PHASE       AGE
cns-volume-ab377741-2555-4b17-a829-4d6951283c09   CSIManaged   Succeeded   51m
cns-volume-bc42e300-cf0c-488f-84d2-46907454b503   CSIManaged   Succeeded   77m
➜  vmown kubectl --kubeconfig /Users/dk016388/kubeconfig/vmown/kubeconfig.yaml -n vmware-system-csi get csivolumeinfos.cns.vmware.com cns-volume-ab377741-2555-4b17-a829-4d6951283c09 -o yaml
apiVersion: cns.vmware.com/v1alpha1
kind: CsiVolumeInfo
metadata:
  creationTimestamp: "2026-06-23T08:00:10Z"
  generation: 4
  name: cns-volume-ab377741-2555-4b17-a829-4d6951283c09
  namespace: vmware-system-csi
  resourceVersion: "6165869"
  uid: e6586902-20b6-47db-9997-b9662da477d4
spec:
  diskPath: '[sharedVmfs-0] fcd/662e21f35b6143beb16e0d9bc67d4281.vmdk'
  diskUUID: 6000C295-b455-7da3-ce03-94d57dbfebbe
  pvName: pvc-ab377741-2555-4b17-a829-4d6951283c09
  pvcName: src-pvc-vmown-2
  pvcNamespace: testns
  volumeID: ab377741-2555-4b17-a829-4d6951283c09
status:
  conditions:
  - lastTransitionTime: "2026-06-23T08:51:56Z"
    message: ""
    reason: RegisterSucceeded
    status: "True"
    type: Ready
  error: ""
  observedGeneration: 4
  ownership: CSIManaged
  phase: Succeeded

@linux-foundation-easycla

linux-foundation-easycla Bot commented Jun 21, 2026

Copy link
Copy Markdown

CLA Signed
The committers listed above are authorized under a signed CLA.

@kubernetes-prow kubernetes-prow Bot added the cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. label Jun 21, 2026
@kubernetes-prow

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: deepakkinni

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@kubernetes-prow kubernetes-prow Bot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Jun 21, 2026
@deepakkinni
deepakkinni force-pushed the topic/dk016388/vmown-att-det-v1 branch from c6b35ac to 2d9e905 Compare June 22, 2026 06:40
@kubernetes-prow kubernetes-prow Bot added cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed cncf-cla: no Indicates the PR's author has not signed the CNCF CLA. labels Jun 22, 2026
…ce layer, RBAC

- Wire go.mod replace directive to deepakkinni/govmomi fork (UnregisterVolumeEx APIs)
- Add VMOwnedVolumes FSS constant to WCPFeatureStates and WCPFeatureStatesSupportsLateEnablement
- New pkg/apis/cnsoperator/csivolumeinfo/v1alpha1: CsiVolumeInfo types with new schema
  (vmware-system-csi namespace, cns-volume- prefix, spec.vms[], CSIManaged/VMManaged states)
- New csivolumeinfoservice.go: CRUD service layer with AddVolumeProtectionFinalizer/Remove
- New config/: CRD YAML manifest + embed wrapper
- Register CsiVolumeInfo types in pkg/apis/cnsoperator/register.go
- Add csivolumeinfos RBAC to controller and webhook roles in all 4 supervisor manifests
- Unit tests (6 passing): deepcopy, CRUD idempotency, finalizer add/remove, not-found
… reconciler

- Add UnregisterVolumeEx, QueryPendingUnregisters, AckUnregister to the
  Manager interface with defaultManager and MockManager implementations.
- Create CsiVolumeInfo CR at block-volume provisioning in wcp/controller.go
  when the VMOwnedVolumes capability is enabled; missing CR is a non-fatal
  warning so provisioning is never blocked.
- Add pkg/syncer/cvi_pv_bind.go: ReconcileCsiVolumeInfoOnPVBind patches the
  CsiVolumeInfo spec (pvName, pvcName, pvcNamespace) on PV Available→Bound.
- Unit tests: manager_unreg_test.go (nil-VC guards, mock success/error paths,
  type regression guard) and cvi_pv_bind_test.go (no-transition, non-vSphere,
  missing CR, stale pvName patch, up-to-date no-op, empty volumeHandle).
- Fix MockVolumeManager in unittestcommon/types.go and
  mockVolumeManagerForFullSync in fullsync_test.go to satisfy expanded interface.
Replace raw []cnstypes.CnsUnregisterVolumeResult return type with the
[]PendingUnregisterRecord wrapper struct in the Manager interface,
defaultManager implementation, MockManager, MockVolumeManager, and
mockVolumeManagerForFullSync. Also add the PendingUnregisterRecord
struct definition before the Manager interface declaration.
Add a new standalone controller that watches CsiVolumeInfo CRs and drives
the volume ownership lifecycle based on spec.vms and status.ownership.
Two-state machine: UnregisterVolumeEx on first-attach (CSIManaged→VMManaged),
CreateVolume re-register on last-detach (VMManaged→CSIManaged). Includes
backoff, fault surfacing, brownfield-lazy handling, and table-driven unit tests.
Add RecoverPendingUnregisters to the csivolumeinfo service package. On
syncer startup (when VMOwnedVolumes is enabled), query CNS for any
PENDING_UNREGISTER rows left from a crash, write disk coordinates to the
CsiVolumeInfo spec, advance status to VMManaged, then acknowledge each
row. Double-ACK and orphan rows are handled safely. Per-record errors are
logged and do not abort recovery for subsequent records.
…e block

Add ValidatingAdmissionWebhook guard that rejects PVC deletion when the
volume is VM-managed (fail-open on CVI lookup errors). Add snapshot-create
rejection in CreateSnapshot when the volume is VM-managed. Both guards are
no-ops when VMOwnedVolumes FSS is disabled.
After DeleteVolume succeeds, explicitly delete the CsiVolumeInfo CR for
the volume so it does not become an orphan when the PV ownerReference GC
hasn't run yet. NotFound is treated as success (idempotent). This covers
the permanent-removal path; the normal GC cascade via PV ownerRef still
handles the typical case.
@deepakkinni
deepakkinni force-pushed the topic/dk016388/vmown-att-det-v1 branch from 2d9e905 to abfb049 Compare June 22, 2026 21:26
@kubernetes-prow kubernetes-prow Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 22, 2026
@deepakkinni
deepakkinni force-pushed the topic/dk016388/vmown-att-det-v1 branch 5 times, most recently from 8cfbeec to 01513b3 Compare June 23, 2026 15:52
- Fix green-signal stall: the unregister reconcile wrote observedGeneration
  from the generation observed at reconcile entry, but its own diskPath/diskUUID
  spec write advances metadata.generation. PatchCsiVolumeInfo now returns the
  post-patch generation and the reconciler and startup recovery record that
  value, so observedGeneration >= generation can be satisfied.
- Treat CnsAlreadyRegisteredFault as success on re-register (add
  IsCnsAlreadyRegisteredFault helper; check it alongside CnsVolumeAlreadyExistsFault).
- Drop the backoff map entry when a CsiVolumeInfo is gone so deleted volumes
  do not leak entries.
- Recovery now writes the full status shape (cleared error + Ready condition),
  matching the steady-state unregister status.
- Retry CsiVolumeInfo patches only on conflict; surface other errors immediately.
- PVC-deletion webhook rejection message updated to name the PVC and the action
  to take.
- Remove the invalid integer print column over the spec.vms array.
- Move the pending-unregister recovery test alongside the recovery code.
- Add the new two-phase unregister methods to the remaining volume.Manager
  test mocks so all packages compile.
- Add PV OwnerRef on CsiVolumeInfo.
- Updated webhook

Signed-off-by: Deepak Kinni <deepak.kinni@broadcom.com>
@deepakkinni
deepakkinni force-pushed the topic/dk016388/vmown-att-det-v1 branch from 01513b3 to c251c50 Compare June 23, 2026 18:31
@kubernetes-prow

Copy link
Copy Markdown

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@kubernetes-prow kubernetes-prow Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant