Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/stretchr/testify v1.11.1
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20250923172217-bf5a74e51c65
github.com/vmware-tanzu/vm-operator/external/byok v0.0.0-20250509154507-b93e51fc90fa
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203163802-5ce652387dac
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203213634-99f18b71ea8e
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.43.0
golang.org/x/sync v0.18.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,8 @@ github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20250923172217-bf5a74e51c65 h1:
github.com/vmware-tanzu/vm-operator/api v1.9.1-0.20250923172217-bf5a74e51c65/go.mod h1:nWTPpxfe4gHuuYuFcrs86+NMxfkqPk3a3IlvI8TCWak=
github.com/vmware-tanzu/vm-operator/external/byok v0.0.0-20250509154507-b93e51fc90fa h1:4MKu14YJ7J54O6QKmT4ds5EUpysWLLtQRMff73cVkmU=
github.com/vmware-tanzu/vm-operator/external/byok v0.0.0-20250509154507-b93e51fc90fa/go.mod h1:8tiuyYslzjLIUmOlXZuGKQdQP2ZgWGCVhVeyptmZYnk=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203163802-5ce652387dac h1:E3W+2J1I0B5LyIillKYVQHIb6CpslGcogt7Q+8FHT3c=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203163802-5ce652387dac/go.mod h1:FM3GTg002dFFN7l2/hNS0YWC4f78HTw4kvgUwAE52cM=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203213634-99f18b71ea8e h1:TG9xuPu9N29Ak1gNs85VsMImNv1bd2l0yNfAMc3imOU=
github.com/vmware/govmomi v0.53.0-alpha.0.0.20251203213634-99f18b71ea8e/go.mod h1:FM3GTg002dFFN7l2/hNS0YWC4f78HTw4kvgUwAE52cM=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk=
Expand Down
318 changes: 300 additions & 18 deletions pkg/common/cns-lib/volume/manager.go

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions pkg/common/cns-lib/volume/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,3 +632,17 @@ func IsCnsVolumeAlreadyExistsFault(ctx context.Context, faultType string) bool {
log.Infof("Checking fault type: %q is vim.fault.CnsVolumeAlreadyExistsFault", faultType)
return faultType == "vim.fault.CnsVolumeAlreadyExistsFault"
}

// IsCnsNotRegisteredFault checks if the fault is CnsNotRegisteredFault
func IsCnsNotRegisteredFault(ctx context.Context, fault *types.LocalizedMethodFault) bool {
log := logger.GetLogger(ctx)
if fault == nil || fault.Fault == nil {
log.Infof("fault is nil or fault.Fault is nil. Not a CnsNotRegisteredFault")
return false
}
if _, ok := fault.Fault.(*cnstypes.CnsNotRegisteredFault); ok {
log.Infof("observed CnsNotRegisteredFault")
return true
}
return false
}
2 changes: 1 addition & 1 deletion pkg/common/utils/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func getCommonUtilsTest(t *testing.T) *commonUtilsTest {
t.Fatal(err)
}

volumeManager, err := cnsvolumes.GetManager(ctx, virtualCenter, nil, false, false, false, "")
volumeManager, err := cnsvolumes.GetManager(ctx, virtualCenter, nil, false, false, false, "", "", "")
if err != nil {
t.Fatalf("failed to create an instance of volume manager. err=%v", err)
}
Expand Down
33 changes: 11 additions & 22 deletions pkg/csi/service/common/vsphereutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -1225,32 +1225,21 @@ func DeleteSnapshotUtil(ctx context.Context, volumeManager cnsvolume.Manager, cs
return cnsSnapshotInfo, nil
}

// GetCnsVolumeType is the helper function that determines the volume type based on the volume-id
func GetCnsVolumeType(ctx context.Context, volumeManager cnsvolume.Manager, volumeId string) (string, error) {
// GetCnsVolumeType is the helper function that determines the volume type based on the volume-id prefix.
// If volume ID begins with "file:", it is a file volume, otherwise it is a block volume.
func GetCnsVolumeType(ctx context.Context, volumeId string) string {
log := logger.GetLogger(ctx)
var volumeType string
queryFilter := cnstypes.CnsQueryFilter{
VolumeIds: []cnstypes.CnsVolumeId{{Id: volumeId}},
}
querySelection := cnstypes.CnsQuerySelection{
Names: []string{
string(cnstypes.QuerySelectionNameTypeVolumeType),
},
}
// Select only the volume type.
queryResult, err := volumeManager.QueryAllVolume(ctx, queryFilter, querySelection)
if err != nil {
return "", logger.LogNewErrorCodef(log, codes.Internal,
"queryVolume failed for volumeID: %q with err=%+v", volumeId, err)
}

if len(queryResult.Volumes) == 0 {
log.Infof("volume: %s not found during query while determining CNS volume type", volumeId)
return "", ErrNotFound
// Determine volume type based on volume ID prefix
if strings.HasPrefix(volumeId, "file:") {
volumeType = FileVolumeType
} else {
volumeType = BlockVolumeType
}
volumeType = queryResult.Volumes[0].VolumeType
log.Infof("volume: %s is of type: %s", volumeId, volumeType)
return volumeType, nil

log.Infof("volume: %s is of type: %s (determined from volume ID prefix)", volumeId, volumeType)
return volumeType
}

// GetNodeVMsWithAccessToDatastore finds out NodeVMs which have access to the given
Expand Down
14 changes: 3 additions & 11 deletions pkg/csi/service/vanilla/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,8 @@ func (c *controller) Init(config *cnsconfig.Config, version string) error {
c.managers.VcenterConfigs[vcenterconfig.Host] = vcenterconfig
volumeManager, err := cnsvolume.GetManager(ctx, vcenter,
operationStore, true, true,
multivCenterTopologyDeployment, cnstypes.CnsClusterFlavorVanilla)
multivCenterTopologyDeployment, cnstypes.CnsClusterFlavorVanilla, config.Global.ClusterID,
config.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down Expand Up @@ -1617,16 +1618,7 @@ func (c *controller) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequ
}

if cnsVolumeType == common.UnknownVolumeType {
cnsVolumeType, err = common.GetCnsVolumeType(ctx, volumeManager, req.VolumeId)
if err != nil {
if err.Error() == common.ErrNotFound.Error() {
// The volume couldn't be found during query, assuming the delete operation as success
return &csi.DeleteVolumeResponse{}, "", nil
} else {
return nil, csifault.CSIInternalFault, logger.LogNewErrorCodef(log, codes.Internal,
"failed to determine CNS volume type for volume: %q. Error: %+v", req.VolumeId, err)
}
}
cnsVolumeType = common.GetCnsVolumeType(ctx, req.VolumeId)
volumeType = convertCnsVolumeType(ctx, cnsVolumeType)
}
// Check if the volume contains CNS snapshots only for block volumes.
Expand Down
2 changes: 1 addition & 1 deletion pkg/csi/service/vanilla/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func getControllerTest(t *testing.T) *controllerTest {

volumeManager, err := cnsvolume.GetManager(ctx, vcenter,
fakeOpStore, true, false,
false, cnstypes.CnsClusterFlavorVanilla)
false, cnstypes.CnsClusterFlavorVanilla, "", "")
if err != nil {
t.Fatalf("failed to create an instance of volume manager. err=%v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/csi/service/vanilla/controller_topology_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ func getControllerTestWithTopology(t *testing.T) *controllerTestTopology {

volumeManager, err := cnsvolume.GetManager(ctxtopology, vcenter,
fakeOpStore, true, false,
false, cnstypes.CnsClusterFlavorVanilla)
false, cnstypes.CnsClusterFlavorVanilla, "", "")
if err != nil {
t.Fatalf("failed to create an instance of volume manager. err=%v", err)
}
Expand Down
53 changes: 20 additions & 33 deletions pkg/csi/service/wcp/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ func (c *controller) Init(config *cnsconfig.Config, version string) error {

volumeManager, err := cnsvolume.GetManager(ctx, vcenter, operationStore,
idempotencyHandlingEnabled, false,
false, cnstypes.CnsClusterFlavorWorkload)
false, cnstypes.CnsClusterFlavorWorkload, config.Global.SupervisorID, config.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down Expand Up @@ -431,10 +431,9 @@ func (c *controller) ReloadConfiguration(reconnectToVCFromNewConfig bool) error
return logger.LogNewErrorf(log, "failed to reset volume manager. err=%v", err)
}
c.manager.VcenterConfig = newVCConfig

volumeManager, err := cnsvolume.GetManager(ctx, vcenter, operationStore,
idempotencyHandlingEnabled, false,
false, cnstypes.CnsClusterFlavorWorkload)
false, cnstypes.CnsClusterFlavorWorkload, cfg.Global.SupervisorID, cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down Expand Up @@ -1726,16 +1725,7 @@ func (c *controller) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequ
return nil, csifault.CSIInvalidArgumentFault, err
}
if cnsVolumeType == common.UnknownVolumeType {
cnsVolumeType, err = common.GetCnsVolumeType(ctx, c.manager.VolumeManager, req.VolumeId)
if err != nil {
if err.Error() == common.ErrNotFound.Error() {
// The volume couldn't be found during query, assuming the delete operation as success
return &csi.DeleteVolumeResponse{}, "", nil
} else {
return nil, csifault.CSIInternalFault, logger.LogNewErrorCodef(log, codes.Internal,
"failed to determine CNS volume type for volume: %q. Error: %+v", req.VolumeId, err)
}
}
cnsVolumeType = common.GetCnsVolumeType(ctx, req.VolumeId)
volumeType = convertCnsVolumeType(ctx, cnsVolumeType)
}
// Check if the volume contains CNS snapshots only for block volumes.
Expand Down Expand Up @@ -2437,31 +2427,21 @@ func (c *controller) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshot
}
volumeID := req.GetSourceVolumeId()
volumeType = prometheus.PrometheusBlockVolumeType
// Query capacity in MB for block volume snapshot
volumeIds := []cnstypes.CnsVolumeId{{Id: volumeID}}
cnsVolumeDetailsMap, err := utils.QueryVolumeDetailsUtil(ctx, c.manager.VolumeManager, volumeIds)
if err != nil {
return nil, err
}
if _, ok := cnsVolumeDetailsMap[volumeID]; !ok {
return nil, logger.LogNewErrorCodef(log, codes.Internal,
"cns query volume did not return the volume: %s", volumeID)
}
snapshotSizeInMB := cnsVolumeDetailsMap[volumeID].SizeInMB

if cnsVolumeDetailsMap[volumeID].VolumeType != common.BlockVolumeType {
cnsvolumeType := common.GetCnsVolumeType(ctx, volumeID)
if cnsvolumeType != common.BlockVolumeType {
return nil, logger.LogNewErrorCodef(log, codes.FailedPrecondition,
"queried volume doesn't have the expected volume type. Expected VolumeType: %v. "+
"Queried VolumeType: %v", volumeType, cnsVolumeDetailsMap[volumeID].VolumeType)
"Expected VolumeType: %v. "+
"Observed VolumeType: %v", volumeType, cnsvolumeType)
}

// TODO: We may need to add logic to check the limit of max number of snapshots by using
// GlobalMaxSnapshotsPerBlockVolume etc. variables in the future.

// the returned snapshotID below is a combination of CNS VolumeID and CNS SnapshotID concatenated by the "+"
// sign. That is, a string of "<UUID>+<UUID>". Because, all other CNS snapshot APIs still require both
// VolumeID and SnapshotID as the input, while corresponding snapshot APIs in upstream CSI require SnapshotID.
// So, we need to bridge the gap in vSphere CSI driver and return a combined SnapshotID to CSI Snapshotter.
var err error
var snapshotID string
var cnsSnapshotInfo *cnsvolume.CnsSnapshotInfo
var cnsVolumeInfo *cnsvolumeinfov1alpha1.CNSVolumeInfo
Expand Down Expand Up @@ -2517,6 +2497,17 @@ func (c *controller) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshot
"failed to create snapshot on volume %q with error: %v", volumeID, err)
}
}
// Query capacity in MB for block volume snapshot
volumeIds := []cnstypes.CnsVolumeId{{Id: volumeID}}
cnsVolumeDetailsMap, err := utils.QueryVolumeDetailsUtil(ctx, c.manager.VolumeManager, volumeIds)
if err != nil {
return nil, err
}
if _, ok := cnsVolumeDetailsMap[volumeID]; !ok {
return nil, logger.LogNewErrorCodef(log, codes.Internal,
"cns query volume did not return the volume: %s", volumeID)
}
snapshotSizeInMB := cnsVolumeDetailsMap[volumeID].SizeInMB
snapshotCreateTimeInProto := timestamppb.New(cnsSnapshotInfo.SnapshotLatestOperationCompleteTime)
createSnapshotResponse := &csi.CreateSnapshotResponse{
Snapshot: &csi.Snapshot{
Expand Down Expand Up @@ -2708,11 +2699,7 @@ func (c *controller) ControllerExpandVolume(ctx context.Context, req *csi.Contro
// Later we may need to define different csi faults.
// Check if the volume contains CNS snapshots only for block volumes.
if cnsVolumeType == common.UnknownVolumeType {
cnsVolumeType, err = common.GetCnsVolumeType(ctx, c.manager.VolumeManager, req.VolumeId)
if err != nil {
return nil, csifault.CSIInternalFault, logger.LogNewErrorCodef(log, codes.Internal,
"failed to determine CNS volume type for volume: %q. Error: %+v", req.VolumeId, err)
}
cnsVolumeType = common.GetCnsVolumeType(ctx, req.VolumeId)
volumeType = convertCnsVolumeType(ctx, cnsVolumeType)
}
if cnsVolumeType == common.BlockVolumeType &&
Expand Down
2 changes: 1 addition & 1 deletion pkg/csi/service/wcp/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func getControllerTest(t *testing.T) *controllerTest {

volumeManager, err := cnsvolume.GetManager(ctx, vcenter,
fakeOpStore, true, false,
false, cnstypes.CnsClusterFlavorWorkload)
false, cnstypes.CnsClusterFlavorWorkload, "", "")
if err != nil {
t.Fatalf("failed to create an instance of volume manager. err=%v", err)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/syncer/byokoperator/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ func NewManager(
return nil, err
}

volumeManager, err := volume.GetManager(ctx, vcClient, nil, false, false, false, clusterFlavor)
volumeManager, err := volume.GetManager(ctx, vcClient, nil, false,
false, false, clusterFlavor, configInfo.Cfg.Global.SupervisorID, configInfo.Cfg.Global.ClusterDistribution)
if err != nil {
return nil, fmt.Errorf("failed to create an instance of volume manager: %w", err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,12 @@ func removeFinalizerAndStatusEntry(ctx context.Context, client client.Client, k8

// processBatchAttach first constructs the batch attach volume request for all volumes in instance spec
// and then calls CNS batch attach for them.
// TODO: When QueryBackingTypeFromVirtualDiskInfo is used to query backing type for volumes
// (from PR kubernetes-sigs/vsphere-csi-driver#3799), handle the case where a volume is not
// registered with CNS. If the query returns no results because the volume is unregistered
// (CnsNotRegisteredFault scenario), we need to re-register the volume using reRegisterVolume()
// and retry the query. Without this handling, unregistered volumes will fail to attach because
// QueryBackingTypeFromVirtualDiskInfo will return "no volume found" error.
func (r *Reconciler) processBatchAttach(ctx context.Context, k8sClient kubernetes.Interface,
vm *cnsvsphere.VirtualMachine,
instance *v1alpha1.CnsNodeVMBatchAttachment,
Expand Down
9 changes: 8 additions & 1 deletion pkg/syncer/cnsoperator/manager/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,14 @@ func InitCnsOperator(ctx context.Context, clusterFlavor cnstypes.CnsClusterFlavo
return err
}

volumeManager, err = volumes.GetManager(ctx, vCenter, nil, false, false, false, clusterFlavor)
var clusterId string
if clusterFlavor == cnstypes.CnsClusterFlavorWorkload {
clusterId = cnsOperator.configInfo.Cfg.Global.SupervisorID
} else {
clusterId = cnsOperator.configInfo.Cfg.Global.ClusterID
}
volumeManager, err = volumes.GetManager(ctx, vCenter, nil, false, false, false,
clusterFlavor, clusterId, cnsOperator.configInfo.Cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down
8 changes: 5 additions & 3 deletions pkg/syncer/metadatasyncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ func InitMetadataSyncer(ctx context.Context, clusterFlavor cnstypes.CnsClusterFl
volumeOperationsLock[metadataSyncer.host] = &sync.Mutex{}

volumeManager, err := volumes.GetManager(ctx, vCenter,
nil, false, false, false, metadataSyncer.clusterFlavor)
nil, false, false, false,
metadataSyncer.clusterFlavor, configInfo.Cfg.Global.SupervisorID, configInfo.Cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down Expand Up @@ -508,7 +509,8 @@ func InitMetadataSyncer(ctx context.Context, clusterFlavor cnstypes.CnsClusterFl
}
volumeManager, err := volumes.GetManager(ctx, vCenter,
nil, false, true,
multivCenterTopologyDeployment, metadataSyncer.clusterFlavor)
multivCenterTopologyDeployment, metadataSyncer.clusterFlavor, configInfo.Cfg.Global.ClusterID,
configInfo.Cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down Expand Up @@ -2407,7 +2409,7 @@ func ReloadConfiguration(metadataSyncer *metadataSyncInformer, reconnectToVCFrom
return logger.LogNewErrorf(log, "failed to reset volume manager. err=%v", err)
}
volumeManager, err := volumes.GetManager(ctx, vcenter, nil, false, false, false,
metadataSyncer.clusterFlavor)
metadataSyncer.clusterFlavor, cfg.Global.SupervisorID, cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down
8 changes: 7 additions & 1 deletion pkg/syncer/storagepool/diskDecommissionController.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,13 @@ func (w *DiskDecommController) detachVolumes(ctx context.Context, storagePoolNam
if err != nil {
return logger.LogNewErrorf(log, "failed to get cluster flavor. Error: %v", err)
}
volManager, err := volume.GetManager(ctx, &vc, nil, false, false, false, clusterFlavor)
cfg, err := config.GetConfig(ctx)
if err != nil {
return logger.LogNewErrorf(log, "failed to get config. Error: %v", err)
}
volManager, err := volume.GetManager(ctx, &vc, nil, false,
false, false,
clusterFlavor, cfg.Global.SupervisorID, cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/syncer/storagepool/migrationController.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,12 @@ func (m *migrationController) relocateCNSVolume(ctx context.Context, volumeID st
if err != nil {
return logger.LogNewErrorf(log, "failed to get cluster flavor. Error: %v", err)
}
volManager, err := volume.GetManager(ctx, m.vc, nil, false, false, false, clusterFlavor)
cfg, err := config.GetConfig(ctx)
if err != nil {
return logger.LogNewErrorf(log, "failed to get config. Error: %v", err)
}
volManager, err := volume.GetManager(ctx, m.vc, nil, false, false, false,
clusterFlavor, cfg.Global.SupervisorID, cfg.Global.ClusterDistribution)
if err != nil {
return logger.LogNewErrorf(log, "failed to create an instance of volume manager. err=%v", err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/syncer/syncer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func TestSyncerWorkflows(t *testing.T) {
}
}()

volumeManager, err = cnsvolumes.GetManager(ctx, virtualCenter, nil, false, false, false, "")
volumeManager, err = cnsvolumes.GetManager(ctx, virtualCenter, nil, false, false, false, "", "", "")
if err != nil {
t.Fatalf("failed to create an instance of volume manager. err=%v", err)
}
Expand Down