Repository: kubernetes-sigs/vsphere-csi-driver

Issue:
Unnecessary CSI migration errors  in vSphere Syncer in multi-VC clusterss
We are noticing vsphere-syncer spamming following log messages, when K8s cluster spans multiple-VCs and have CSI migration **disabled**:

```
sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer.initVolumeMigrationService
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/pkg/syncer/util.go:366
sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer.podAdded
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/pkg/syncer/metadatasyncer.go:1852
sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer.InitMetadataSyncer.func7
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/pkg/syncer/metadatasyncer.go:530
k8s.io/client-go/tools/cache.ResourceEventHandlerFuncs.OnAdd
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/controller.go:243
k8s.io/client-go/tools/cache.(*processorListener).run.func1
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/shared_informer.go:973
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:226
k8s.io/apimachinery/pkg/util/wait.BackoffUntil
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:227
k8s.io/apimachinery/pkg/util/wait.JitterUntil
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:204
k8s.io/apimachinery/pkg/util/wait.Until
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:161
k8s.io/client-go/tools/cache.(*processorListener).run
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/shared_informer.go:967
k8s.io/apimachinery/pkg/util/wait.(*Group).Start.func1
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/wait.go:72
2024-12-12T20:35:41.93236794Z syncer/metadatasyncer.go:1853 podAdded: failed to get migration service. Err: volume-migration feature is not supported on Multi-vCenter deployment
sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer.podAdded
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/pkg/syncer/metadatasyncer.go:1853
sigs.k8s.io/vsphere-csi-driver/v3/pkg/syncer.InitMetadataSyncer.func7
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/pkg/syncer/metadatasyncer.go:530
k8s.io/client-go/tools/cache.ResourceEventHandlerFuncs.OnAdd
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/controller.go:243
k8s.io/client-go/tools/cache.(*processorListener).run.func1
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/shared_informer.go:973
k8s.io/apimachinery/pkg/util/wait.BackoffUntil.func1
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:226
k8s.io/apimachinery/pkg/util/wait.BackoffUntil
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:227
k8s.io/apimachinery/pkg/util/wait.JitterUntil
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:204
k8s.io/apimachinery/pkg/util/wait.Until
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/apimachinery/pkg/util/wait/backoff.go:161
k8s.io/client-go/tools/cache.(*processorListener).run
        /go/src/github.com/kubernetes-sigs/vsphere-csi-driver/vendor/k8s.io/client-go/tools/cache/shared_informer.go:967
k8s.io/apimachinery/pkg/util/wait.(*Group).Start.func1
```

Do we even need to watch for `podAdd` events in clusters where CSI migration is disabled?

cc @divyenpatel 


Hints from issue comments:
@gnufied: Also, I actually had `csi-migration: false` set in featurestate configmap. But apparently this feature is hardcoded and can't be turned off. 

So, I am thinking of multi-vc are detected, we should simply disable the migration feature.@gnufied: cc @xing-yang 

Solution patch:
diff --git a/pkg/syncer/metadatasyncer.go b/pkg/syncer/metadatasyncer.go
index dce6cadb..24ecebb2 100644
--- a/pkg/syncer/metadatasyncer.go
+++ b/pkg/syncer/metadatasyncer.go
@@ -1175,7 +1175,7 @@ func syncStorageQuotaReserved(ctx context.Context,
 		log.Errorf("syncStorageQuotaReserved: failed to fetch storage policy quota instances, Error: %+v", err)
 		return
 	}
-	log.Infof("syncStorageQuotaReserved: Retrieved StoragePolicyQuota instances for syncing", "Count: %d",
+	log.Debugf("syncStorageQuotaReserved: Retrieved StoragePolicyQuota instances for syncing", "Count: %d",
 		len(spqList.Items))
 	namespaces := make(map[string]string)
 	// create namespace map to be able to calculate reserved namespace wise
@@ -1190,11 +1190,11 @@ func syncStorageQuotaReserved(ctx context.Context,
 	}
 	var totalStoragePolicyReserved map[string]*resource.Quantity
 	expectedReservedValues := []sqperiodicsyncv1alpha1.ExpectedReservedValues{}
-	log.Info("syncStorageQuotaReserved: iterate through namespaces and calcuate reserved values")
+	log.Debug("syncStorageQuotaReserved: iterate through namespaces and calcuate reserved values")
 	// loop over namespaces and calcuate reserved values
 	for ns := range namespaces {
 		totalStoragePolicyReserved = make(map[string]*resource.Quantity)
-		log.Infof("syncStorageQuotaReserved: processing storage quota sync for namespace %q", ns)
+		log.Debugf("syncStorageQuotaReserved: processing storage quota sync for namespace %q", ns)
 		// calculate storagepolicyusage reserved values for given namespace
 		spuVmServiceReserved, err := calculateVMServiceStoragePolicyUsageReservedForNamespace(ctx,
 			cnsOperatorClient, ns)
@@ -1229,7 +1229,7 @@ func syncStorageQuotaReserved(ctx context.Context,
 		})
 	}
 	updateStorageQuotaPeriodicSyncCR(ctx, cnsOperatorClient, expectedReservedValues, lastSyncTime)
-	log.Info("syncStorageQuotaReserved: updated the StorageQuotaPeriodicSync CR")
+	log.Debug("syncStorageQuotaReserved: updated the StorageQuotaPeriodicSync CR")
 }
 
 // mergeStoragePolicyReserved will sum up  and return the total reserved value
@@ -1249,7 +1249,7 @@ func mergeStoragePolicyReserved(storagePolicyReserved,
 func calculateVMServiceStoragePolicyUsageReservedForNamespace(ctx context.Context, cnsOperatorClient client.Client,
 	namespace string) (map[string]*resource.Quantity, error) {
 	log := logger.GetLogger(ctx)
-	log.Infof("calculateVMServiceStoragePolicyUsageReservedForNamespace: Fetching StoragePolicyUsage for namespace %q",
+	log.Debugf("calculateVMServiceStoragePolicyUsageReservedForNamespace: Fetching StoragePolicyUsage for namespace %q",
 		namespace)
 	supList := &storagepolicyv1alpha2.StoragePolicyUsageList{}
 	err := cnsOperatorClient.List(ctx, supList, &client.ListOptions{Namespace: namespace})
@@ -1259,17 +1259,17 @@ func calculateVMServiceStoragePolicyUsageReservedForNamespace(ctx context.Contex
 	storagePolicyToReservedMap := make(map[string]*resource.Quantity)
 	for _, storagePolicyUsage := range supList.Items {
 		if storagePolicyUsage.Spec.ResourceExtensionName == VMServiceExtensionServiceName {
-			log.Infof("calculateVMServiceStoragePolicyUsageReservedForNamespace: Processing StoragePolicyUsage"+
+			log.Debugf("calculateVMServiceStoragePolicyUsageReservedForNamespace: Processing StoragePolicyUsage"+
 				" Name: %q, Namespace: %q", storagePolicyUsage.Name, storagePolicyUsage.Namespace)
 			storagePolicyToReservedMap[storagePolicyUsage.Spec.StoragePolicyId] = resource.NewQuantity(0, resource.BinarySI)
 			if storagePolicyUsage.DeletionTimestamp != nil {
-				log.Infof("calculateVMServiceStoragePolicyUsageReservedForNamespace:"+
+				log.Debugf("calculateVMServiceStoragePolicyUsageReservedForNamespace:"+
 					" StoragePolicyUsage is marked for deletion, ignoring Name: %q, Namespace: %q",
 					storagePolicyUsage.Name, storagePolicyUsage.Namespace)
 				continue
 			}
 			if storagePolicyUsage.Status.ResourceTypeLevelQuotaUsage == nil {
-				log.Infof("calculateVMServiceStoragePolicyUsageReservedForNamespace: StoragePolicyUsage"+
+				log.Debugf("calculateVMServiceStoragePolicyUsageReservedForNamespace: StoragePolicyUsage"+
 					" status not populated, continue processing other PVCs Name: %q, Namespace: %q",
 					storagePolicyUsage.Name, storagePolicyUsage.Namespace)
 				continue
@@ -1291,7 +1291,7 @@ func calculatePVCReservedForNamespace(ctx context.Context, volumeMap map[string]
 		return nil, err
 	}
 	// fetch pvc for given namespace
-	log.Infof("calculatePVCReservedForNamespace: Fetching PersistentVolumeClaim for namespace %q", namespace)
+	log.Debugf("calculatePVCReservedForNamespace: Fetching PersistentVolumeClaim for namespace %q", namespace)
 	pvcList, err := metadataSyncer.pvcLister.PersistentVolumeClaims(namespace).List(labels.NewSelector())
 	if err != nil {
 		log.Errorf("calculatePVCReservedForNamespace: unable to fetch all pvc from namespace %q, Error %v",
@@ -1300,20 +1300,20 @@ func calculatePVCReservedForNamespace(ctx context.Context, volumeMap map[string]
 	}
 	storagePolicyToReservedMap := make(map[string]*resource.Quantity)
 	for _, pvc := range pvcList {
-		log.Infof("calculatePVCReservedForNamespace: Processing PersistentVolumeClaim Name: %q, Namespace: %q",
+		log.Debugf("calculatePVCReservedForNamespace: Processing PersistentVolumeClaim Name: %q, Namespace: %q",
 			pvc.Name, pvc.Namespace)
 		if pvc.DeletionTimestamp != nil {
-			log.Infof("calculatePVCReservedForNamespace: pvc is marked for deletion, ignoring Name: %q, Namespace: %q",
+			log.Debugf("calculatePVCReservedForNamespace: pvc is marked for deletion, ignoring Name: %q, Namespace: %q",
 				pvc.Name, pvc.Namespace)
 			continue
 		}
 		if pvc.Status.Phase == "" {
-			log.Infof("calculatePVCReservedForNamespace: pvc status not populated, continuing processing others"+
+			log.Debugf("calculatePVCReservedForNamespace: pvc status not populated, continuing processing others"+
 				" Name: %q, Namespace: %q", pvc.Name, pvc.Namespace)
 			continue
 		}
 		if pvc.Spec.StorageClassName == nil {
-			log.Infof("calculatePVCReservedForNamespace: storageclass is not provided for pvc,"+
+			log.Debugf("calculatePVCReservedForNamespace: storageclass is not provided for pvc,"+
 				" continue processing other PVCs Name: %q, Namespace: %q", pvc.Name, pvc.Namespace)
 			continue
 		}
@@ -1326,7 +1326,7 @@ func calculatePVCReservedForNamespace(ctx context.Context, volumeMap map[string]
 		pvcSize := pvc.Spec.Resources.Requests[v1.ResourceStorage]
 		if pvc.Status.Phase == v1.ClaimPending {
 			if storagePolicyID, ok := scToStoragePolicyIDMap[*pvc.Spec.StorageClassName]; ok {
-				log.Infof("calculatePVCReservedForNamespace: pvc is in pending state,"+
+				log.Debugf("calculatePVCReservedForNamespace: pvc is in pending state,"+
 					" Name: %q, Namespace: %q adding pvc capacity to reserved", pvc.Name, pvc.Namespace)
 				storagePolicyToReservedMap[storagePolicyID].Add(pvcSize)
 			}
@@ -1334,7 +1334,7 @@ func calculatePVCReservedForNamespace(ctx context.Context, volumeMap map[string]
 			pvSize := pv.Spec.Capacity[v1.ResourceStorage]
 			// check if pvc is under expansion
 			if !pvcSize.Equal(pvSize) {
-				log.Infof("calculatePVCReservedForNamespace: pvc size being expanded"+
+				log.Debugf("calculatePVCReservedForNamespace: pvc size being expanded"+
 					" Name: %q, Namespace: %q adding pvc capacity to reserved", pvc.Name, pvc.Namespace)
 				if storagePolicyID, ok := scToStoragePolicyIDMap[*pvc.Spec.StorageClassName]; ok {
 					// get accurate expected reserved value
@@ -1355,7 +1355,7 @@ func calculateVolumeSnapshotReservedForNamespace(ctx context.Context,
 	if err != nil {
 		return nil, err
 	}
-	log.Infof("calculateVolumeSnapshotReservedForNamespace: Fetching VolumeSnapshots for namespace %q", namespace)
+	log.Debugf("calculateVolumeSnapshotReservedForNamespace: Fetching VolumeSnapshots for namespace %q", namespace)
 	snapshotterClient, err := k8s.NewSnapshotterClient(ctx)
 	if err != nil {
 		log.Errorf("calculateVolumeSnapshotReservedForNamespace: failed to get snapshotterClient with error: %v", err)
@@ -1373,20 +1373,20 @@ func calculateVolumeSnapshotReservedForNamespace(ctx context.Context,
 	storagePolicyIdToReservedMap := make(map[string]*resource.Quantity)
 	for _, vs := range vsList.Items {
 		if vs.DeletionTimestamp != nil {
-			log.Infof("calculateVolumeSnapshotReservedForNamespace: volumesnapshot is marked for deletion,"+
+			log.Debugf("calculateVolumeSnapshotReservedForNamespace: volumesnapshot is marked for deletion,"+
 				" ignoring Name: %q, Namespace: %q",
 				vs.Name, vs.Namespace)
 			continue
 		}
 		if vs.Status != nil && *vs.Status.ReadyToUse {
-			log.Infof("calculateVolumeSnapshotReservedForNamespace: skipping volumesnapshot"+
+			log.Debugf("calculateVolumeSnapshotReservedForNamespace: skipping volumesnapshot"+
 				" as it is ready to use, ignoring Name: %q, Namespace: %q", vs.Name, vs.Namespace)
 			continue
 		} else {
-			log.Infof("calculateVolumeSnapshotReservedForNamespace: Processing VolumeSnapshot"+
+			log.Debugf("calculateVolumeSnapshotReservedForNamespace: Processing VolumeSnapshot"+
 				" Name: %q, Namespace: %q", vs.Name, vs.Namespace)
 			if len(pvcList.Items) == 0 {
-				log.Infof("calculateVolumeSnapshotReservedForNamespace: Fetching PersistentVolumeClaim "+
+				log.Debugf("calculateVolumeSnapshotReservedForNamespace: Fetching PersistentVolumeClaim "+
 					" for Namespace: %q", vs.Namespace)
 				pvcList, err := metadataSyncer.pvcLister.PersistentVolumeClaims(namespace).List(labels.NewSelector())
 				if err != nil {
@@ -1416,7 +1416,7 @@ func calculateVolumeSnapshotReservedForNamespace(ctx context.Context,
 func updateStorageQuotaPeriodicSyncCR(ctx context.Context, cnsOperatorClient client.Client,
 	expectedReservedvalues []sqperiodicsyncv1alpha1.ExpectedReservedValues, lastSyncTime metav1.Time) {
 	log := logger.GetLogger(ctx)
-	log.Infof("updateStorageQuotaPeriodicSyncCR: Updating StorageQuotaPeriodicSyncCR %s",
+	log.Debugf("updateStorageQuotaPeriodicSyncCR: Updating StorageQuotaPeriodicSyncCR %s",
 		StorageQuotaPeriodicSyncInstanceName)
 	sqPeriodicSync := &sqperiodicsyncv1alpha1.StorageQuotaPeriodicSync{}
 	err := cnsOperatorClient.Get(ctx,
@@ -1470,7 +1470,7 @@ func fetchPVs(ctx context.Context, metadataSyncer *metadataSyncInformer) (map[st
 // fetchStorageClassToStoragePolicyMapping will fetch storageclass and returns mapping with storagepolicy id
 func fetchStorageClassToStoragePolicyMapping(ctx context.Context) (map[string]string, error) {
 	log := logger.GetLogger(ctx)
-	log.Info("fetchStorageClassToStoragePolicyMapping: Fetching StorageClass and create mapping for storageclass" +
+	log.Debug("fetchStorageClassToStoragePolicyMapping: Fetching StorageClass and create mapping for storageclass" +
 		"and storagepolicyid")
 	// Prepare map of storagepolicyID to storageclassnames.
 	k8sconfig, err := k8s.GetKubeConfig(ctx)
@@ -2627,7 +2627,8 @@ func pvDeleted(obj interface{}, metadataSyncer *metadataSyncInformer) {
 	}
 }
 
-// podAdded helps register inline vSphere in-tree volumes
+// podAdded helps register inline vSphere in-tree volumes.
+// NOTE: This functionality will be skipped if it is called in a multi-VC environment.
 func podAdded(obj interface{}, metadataSyncer *metadataSyncInformer) {
 	ctx, log := logger.GetNewContextWithLogger()
 	if metadataSyncer.clusterFlavor == cnstypes.CnsClusterFlavorVanilla && IsMigrationEnabled {
@@ -2637,6 +2638,11 @@ func podAdded(obj interface{}, metadataSyncer *metadataSyncInformer) {
 			log.Warnf("podAdded: unrecognized new object %+v", obj)
 			return
 		}
+		if len(metadataSyncer.configInfo.Cfg.VirtualCenter) > 1 {
+			log.Info("podAdded: In-tree vSphere volume are not supported in a multi VC setup. " +
+				"Skipping addition of Pod metadata.")
+			return
+		}
 		// In case if feature state switch is enabled after syncer is
 		// deployed, we need to initialize the volumeMigrationService.
 		if err := initVolumeMigrationService(ctx, metadataSyncer); err != nil {



Test patch:
diff --git a/tests/e2e/csi_snapshot_basic.go b/tests/e2e/csi_snapshot_basic.go
index c4424809..4b7035c4 100644
--- a/tests/e2e/csi_snapshot_basic.go
+++ b/tests/e2e/csi_snapshot_basic.go
@@ -77,7 +77,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 		labelsMap                  map[string]string
 		scName                     string
 		volHandle                  string
-		isStorageQuotaFSSEnabled   bool
+		isQuotaValidationSupported bool
 	)
 
 	ginkgo.BeforeEach(func() {
@@ -205,9 +205,10 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			pandoraSyncWaitTime = defaultPandoraSyncWaitTime
 		}
 
-		//Remove this code once the FSS is enabled
 		vcAddress := e2eVSphere.Config.Global.VCenterHostname + ":" + sshdPort
-		isStorageQuotaFSSEnabled = isFssEnabled(ctx, vcAddress, "STORAGE_QUOTA_M2")
+		//if isQuotaValidationSupported is true then quotaValidation is considered in tests
+		vcVersion = getVCversion(ctx, vcAddress)
+		isQuotaValidationSupported = isVersionGreaterOrEqual(vcVersion, quotaSupportedVCVersion)
 	})
 
 	ginkgo.AfterEach(func() {
@@ -291,7 +292,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}()
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName)
@@ -358,7 +359,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 
 		snapshotSize := getAggregatedSnapshotCapacityInMb(e2eVSphere, volHandle)
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName,
@@ -372,7 +373,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			volumeSnapshot, pandoraSyncWaitTime, volHandle, snapshotId, true)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, snapshotUsage,
 				snapshotExtensionName, snapshotSize, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 				storagePolicyUsageAfter)
@@ -1600,7 +1601,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}()
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName)
@@ -1641,7 +1642,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 
 		snapshotSize := getAggregatedSnapshotCapacityInMb(e2eVSphere, volHandle)
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 				storageclass.Name, namespace, snapshotUsage, snapshotExtensionName,
 				snapshotSize, totalQuotaUsedBefore, storagePolicyQuotaBefore,
@@ -1676,7 +1677,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			scName = storagePolicyName2
 			storageclass1, err = client.StorageV1().StorageClasses().Get(ctx, scName, metav1.GetOptions{})
 
-			if isStorageQuotaFSSEnabled && supervisorCluster {
+			if isQuotaValidationSupported && supervisorCluster {
 				// setting resource quota for storage policy tagged to supervisor namespace
 				setStoragePolicyQuota(ctx, restConfig, storagePolicyName2, namespace, rqLimit)
 			}
@@ -2438,7 +2439,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName)
@@ -2506,7 +2507,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 		framework.Logf("snapshotSize1  + snapshotSize2 = snapshotSize, %d + %d = %d",
 			snapshotSize1, snapshotSize2, snapshotSize)
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName,
@@ -2566,7 +2567,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			volumeSnapshot2, pandoraSyncWaitTime, volHandle2, snapshotId2, true)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, snapshotUsage,
 				snapshotExtensionName, snapshotSize, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 				storagePolicyUsageAfter)
@@ -3680,7 +3681,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}()
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName)
@@ -3721,7 +3722,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 
 		snapshotSize := getAggregatedSnapshotCapacityInMb(e2eVSphere, volHandle)
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName,
@@ -3786,7 +3787,7 @@ var _ = ginkgo.Describe("Volume Snapshot Basic Test", func() {
 			volumeSnapshot, pandoraSyncWaitTime, volHandle, snapshotId, false)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled && supervisorCluster {
+		if isQuotaValidationSupported && supervisorCluster {
 			validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, snapshotUsage,
 				snapshotExtensionName, snapshotSize, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 				storagePolicyUsageAfter)
diff --git a/tests/e2e/csi_static_provisioning_basic.go b/tests/e2e/csi_static_provisioning_basic.go
index b5424a50..42cd69bb 100644
--- a/tests/e2e/csi_static_provisioning_basic.go
+++ b/tests/e2e/csi_static_provisioning_basic.go
@@ -79,7 +79,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		ctx                        context.Context
 		nonSharedDatastoreURL      string
 		fullSyncWaitTime           int
-		isStorageQuotaFSSEnabled   bool
+		isQuotaValidationSupported bool
 	)
 
 	ginkgo.BeforeEach(func() {
@@ -144,9 +144,11 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		} else {
 			fullSyncWaitTime = defaultFullSyncWaitTime
 		}
-		//Remove this code once the FSS is enabled
+
 		vcAddress := e2eVSphere.Config.Global.VCenterHostname + ":" + sshdPort
-		isStorageQuotaFSSEnabled = isFssEnabled(ctx, vcAddress, "STORAGE_QUOTA_M2")
+		//if isQuotaValidationSupported is true then quotaValidation is considered in tests
+		vcVersion = getVCversion(ctx, vcAddress)
+		isQuotaValidationSupported = isVersionGreaterOrEqual(vcVersion, quotaSupportedVCVersion)
 
 	})
 
@@ -219,7 +221,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		}
 		framework.Logf("storageclass name :%s", storageclass.GetName())
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			ginkgo.By("create resource quota")
 			setStoragePolicyQuota(ctx, restConfig, storagePolicyName, namespace, rqLimit)
 		}
@@ -892,7 +894,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 
 		restConfig, storageclass, profileID := staticProvisioningPreSetUpUtil(ctx)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName)
@@ -922,7 +924,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		pv := getPvFromClaim(client, namespace, pvcName)
 		verifyBidirectionalReferenceOfPVandPVC(ctx, client, pvc, pv, fcdID)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName,
@@ -960,7 +962,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		defer func() {
 			testCleanUpUtil(ctx, restConfig, cnsRegisterVolume, namespace, pvc.Name, pv.Name)
 
-			if isStorageQuotaFSSEnabled {
+			if isQuotaValidationSupported {
 				validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, pvcUsage,
 					volExtensionName, diskSizeInMb, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 					storagePolicyUsageAfter)
@@ -1001,7 +1003,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 
 		restConfig, _, profileID := staticProvisioningPreSetUpUtil(ctx)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storagePolicyName, namespace, pvcUsage, volExtensionName)
@@ -1055,7 +1057,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 		_, err = e2eVSphere.getVMByUUID(ctx, vmUUID)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storagePolicyName, namespace, pvcUsage, volExtensionName,
@@ -1076,7 +1078,7 @@ var _ = ginkgo.Describe("Basic Static Provisioning", func() {
 				vmUUID, pv.Spec.CSI.VolumeHandle))
 		defer func() {
 			testCleanUpUtil(ctx, restConfig, cnsRegisterVolume, namespace, pvc.Name, pv.Name)
-			if isStorageQuotaFSSEnabled {
+			if isQuotaValidationSupported {
 				validateQuotaUsageAfterCleanUp(ctx, restConfig, storagePolicyName, namespace, pvcUsage,
 					volExtensionName, diskSizeInMb, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 					storagePolicyUsageAfter)
diff --git a/tests/e2e/e2e_common.go b/tests/e2e/e2e_common.go
index 18db4137..29572b2a 100644
--- a/tests/e2e/e2e_common.go
+++ b/tests/e2e/e2e_common.go
@@ -271,6 +271,7 @@ const (
 	storageQuotaWebhookPrefix                = "storage-quota-webhook"
 	envStoragePolicyNameForVsanNfsDatastores = "STORAGE_POLICY_FOR_VSAN_NFS_DATASTORES"
 	devopsKubeConf                           = "DEV_OPS_USER_KUBECONFIG"
+	quotaSupportedVCVersion                  = "9.0.0"
 )
 
 /*
diff --git a/tests/e2e/statefulsets.go b/tests/e2e/statefulsets.go
index f86fa7ab..aba2b659 100644
--- a/tests/e2e/statefulsets.go
+++ b/tests/e2e/statefulsets.go
@@ -68,20 +68,20 @@ var _ = ginkgo.Describe("statefulset", func() {
 	f := framework.NewDefaultFramework("e2e-vsphere-statefulset")
 	f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged
 	var (
-		namespace                string
-		client                   clientset.Interface
-		storagePolicyName        string
-		scParameters             map[string]string
-		storageClassName         string
-		zonalPolicy              string
-		zonalWffcPolicy          string
-		categories               []string
-		labels_ns                map[string]string
-		allowedTopologyHAMap     map[string][]string
-		nodeList                 *v1.NodeList
-		stsReplicas              int32
-		allowedTopologies        []v1.TopologySelectorLabelRequirement
-		isStorageQuotaFSSEnabled bool
+		namespace                  string
+		client                     clientset.Interface
+		storagePolicyName          string
+		scParameters               map[string]string
+		storageClassName           string
+		zonalPolicy                string
+		zonalWffcPolicy            string
+		categories                 []string
+		labels_ns                  map[string]string
+		allowedTopologyHAMap       map[string][]string
+		nodeList                   *v1.NodeList
+		stsReplicas                int32
+		allowedTopologies          []v1.TopologySelectorLabelRequirement
+		isQuotaValidationSupported bool
 	)
 
 	ginkgo.BeforeEach(func() {
@@ -129,10 +129,10 @@ var _ = ginkgo.Describe("statefulset", func() {
 			nodeList, err = fnodes.GetReadySchedulableNodes(ctx, client)
 			framework.ExpectNoError(err, "Unable to find ready and schedulable Node")
 		}
-		//Remove this code once the FSS is enabled
 		vcAddress := e2eVSphere.Config.Global.VCenterHostname + ":" + sshdPort
-		isStorageQuotaFSSEnabled = isFssEnabled(ctx, vcAddress, "STORAGE_QUOTA_M2")
-
+		//if isQuotaValidationSupported is true then quotaValidation is considered in tests
+		vcVersion = getVCversion(ctx, vcAddress)
+		isQuotaValidationSupported = isVersionGreaterOrEqual(vcVersion, quotaSupportedVCVersion)
 	})
 
 	ginkgo.AfterEach(func() {
@@ -194,7 +194,7 @@ var _ = ginkgo.Describe("statefulset", func() {
 		}
 
 		restConfig := getRestConfigClient()
-		if supervisorCluster && isStorageQuotaFSSEnabled {
+		if supervisorCluster && isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storagePolicyName, namespace, pvcUsage, volExtensionName)
@@ -250,7 +250,7 @@ var _ = ginkgo.Describe("statefulset", func() {
 			}
 		}
 
-		if supervisorCluster && isStorageQuotaFSSEnabled {
+		if supervisorCluster && isQuotaValidationSupported {
 			validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 				storagePolicyName, namespace, pvcUsage, volExtensionName,
 				diskSize1Gi*3, totalQuotaUsedBefore, storagePolicyQuotaBefore,
diff --git a/tests/e2e/tkgs_ha.go b/tests/e2e/tkgs_ha.go
index 9c801d4f..999f94bb 100644
--- a/tests/e2e/tkgs_ha.go
+++ b/tests/e2e/tkgs_ha.go
@@ -71,7 +71,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		labels_ns                  map[string]string
 		isVcRebooted               bool
 		vcAddress                  string
-		isStorageQuotaFSSEnabled   bool
+		isQuotaValidationSupported bool
 	)
 	ginkgo.BeforeEach(func() {
 		client = f.ClientSet
@@ -142,9 +142,10 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		} else {
 			pandoraSyncWaitTime = defaultPandoraSyncWaitTime
 		}
-		//Remove this code once the FSS is enabled
 		vcAddress := e2eVSphere.Config.Global.VCenterHostname + ":" + sshdPort
-		isStorageQuotaFSSEnabled = isFssEnabled(ctx, vcAddress, "STORAGE_QUOTA_M2")
+		//if isQuotaValidationSupported is true then quotaValidation is considered in tests
+		vcVersion = getVCversion(ctx, vcAddress)
+		isQuotaValidationSupported = isVersionGreaterOrEqual(vcVersion, quotaSupportedVCVersion)
 
 	})
 
@@ -216,7 +217,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName)
@@ -237,7 +238,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		svcPVCName := pv.Spec.CSI.VolumeHandle
 		svcPVC := getPVCFromSupervisorCluster(svcPVCName)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			_, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName,
@@ -298,7 +299,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 			pvclaim, volHandle, diskSize, false)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			tqAfterSanpshot, _, _, _, _, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, snapshotUsage, snapshotExtensionName)
@@ -356,7 +357,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 			volumeSnapshot, pandoraSyncWaitTime, volHandle, dynamicSnapshotId, true)
 		gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, pvcUsage,
 				volExtensionName, diskSizeInMb, tqAfterSanpshot, storagePolicyQuotaAfter,
 				storagePolicyUsageAfter)
@@ -414,7 +415,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 			deleteService(namespace, client, service)
 		}()
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					zonalPolicy, namespace, pvcUsage, volExtensionName)
@@ -430,7 +431,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		CreateStatefulSet(namespace, statefulset, client)
 		replicas := *(statefulset.Spec.Replicas)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedAfter, storagePolicyQuotaAfter, storagePolicyUsageAfter =
 				validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName,
@@ -457,7 +458,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 						"kubernetes", volumeHandle))
 			}
 
-			if isStorageQuotaFSSEnabled {
+			if isQuotaValidationSupported {
 				validateQuotaUsageAfterCleanUp(ctx, restConfig, storageclass.Name, namespace, pvcUsage,
 					volExtensionName, diskSizeInMb*3, totalQuotaUsedAfter, storagePolicyQuotaAfter,
 					storagePolicyUsageAfter)
@@ -660,7 +661,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		svcPVCName := pv.Spec.CSI.VolumeHandle
 		svcPVC := getPVCFromSupervisorCluster(svcPVCName)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName)
@@ -710,7 +711,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 
 		verifyOnlineVolumeExpansionOnGc(client, namespace, svcPVCName, volHandle, pvclaim, pod, f)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalquotaUsedAfterExpansion, _ := getTotalQuotaConsumedByStoragePolicy(ctx, restConfig,
 				storageclass.Name, svNamespace)
 			framework.Logf("totalquotaUsedAfterExpansion :%v", totalquotaUsedAfterExpansion)
@@ -789,7 +790,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 		svcPVCName := pv.Spec.CSI.VolumeHandle
 		svcPVC := getPVCFromSupervisorCluster(svcPVCName)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName)
@@ -839,7 +840,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 
 		verifyOfflineVolumeExpansionOnGc(ctx, client, pvclaim, svcPVCName, namespace, volHandle, pod, pv, f)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalquotaUsedAfterExpansion, _ := getTotalQuotaConsumedByStoragePolicy(ctx, restConfig,
 				storageclass.Name, svNamespace)
 			framework.Logf("totalquotaUsedAfterExpansion :%v", totalquotaUsedAfterExpansion)
@@ -919,7 +920,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 			gomega.Expect(err).NotTo(gomega.HaveOccurred())
 		}
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storageclass.Name, namespace, pvcUsage, volExtensionName)
@@ -1017,7 +1018,7 @@ var _ = ginkgo.Describe("[csi-tkgs-ha] Tkgs-HA-SanityTests", func() {
 					staticPv.Spec.CSI.VolumeHandle, pod.Spec.NodeName))
 		}()
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 				storageclass.Name, namespace, pvcUsage, volExtensionName,
 				diskSizeInMb, totalQuotaUsedBefore, storagePolicyQuotaBefore,
diff --git a/tests/e2e/util.go b/tests/e2e/util.go
index cd8ea9b1..25c4a42b 100644
--- a/tests/e2e/util.go
+++ b/tests/e2e/util.go
@@ -32,6 +32,7 @@ import (
 	"os/exec"
 	"path/filepath"
 	"reflect"
+	"regexp"
 	"sort"
 	"strconv"
 	"strings"
@@ -108,6 +109,7 @@ var (
 	pvZone                 string
 	pvRegion               string
 	vmIp2MoMap             map[string]vim25types.ManagedObjectReference
+	vcVersion              string
 )
 
 type TKGCluster struct {
@@ -1457,23 +1459,6 @@ func invokeVCenterServiceControl(ctx context.Context, command, service, host str
 	return nil
 }
 
-/*
-isFssEnabled invokes the given command to check if vCenter has a particular FSS enabled or not
-*/
-func isFssEnabled(ctx context.Context, host, fss string) bool {
-	sshCmd := fmt.Sprintf("python /usr/sbin/feature-state-wrapper.py %s", fss)
-	framework.Logf("Checking if fss is enabled on vCenter host %v", host)
-	result, err := fssh.SSH(ctx, sshCmd, host, framework.TestContext.Provider)
-	fssh.LogResult(result)
-	if err == nil && result.Code == 0 {
-		return strings.TrimSpace(result.Stdout) == "enabled"
-	} else {
-		ginkgo.By(fmt.Sprintf("couldn't execute command: %s on vCenter host: %v", sshCmd, err))
-		gomega.Expect(err).NotTo(gomega.HaveOccurred())
-	}
-	return false
-}
-
 // waitVCenterServiceToBeInState invokes the status check for the given service and waits
 // via service-control on the given vCenter host over SSH.
 func waitVCenterServiceToBeInState(ctx context.Context, serviceName string, host string, state string) error {
@@ -7441,3 +7426,48 @@ func expandVolumeInParallel(client clientset.Interface, pvclaims []*v1.Persisten
 		}
 	}
 }
+
+/*
+getVCversion returns the VC version
+*/
+func getVCversion(ctx context.Context, vcAddress string) string {
+	if vcVersion == "" {
+		sshCmd := "vpxd -v"
+		framework.Logf("Checking if fss is enabled on vCenter host %v", vcAddress)
+		result, err := fssh.SSH(ctx, sshCmd, vcAddress, framework.TestContext.Provider)
+		fssh.LogResult(result)
+		if err == nil && result.Code == 0 {
+			vcVersion = strings.TrimSpace(result.Stdout)
+		} else {
+			ginkgo.By(fmt.Sprintf("couldn't execute command: %s on vCenter host: %v", sshCmd, err))
+			gomega.Expect(err).NotTo(gomega.HaveOccurred())
+		}
+		// Regex to find version in the format X.Y.Z
+		re := regexp.MustCompile(`\d+\.\d+\.\d+`)
+		vcVersion = re.FindString(vcVersion)
+	}
+	framework.Logf("vcVersion %s", vcVersion)
+	return vcVersion
+}
+
+/*
+isVersionGreaterOrEqual returns true if presentVersion is equal to or greater than expectedVCversion
+*/
+func isVersionGreaterOrEqual(presentVersion, expectedVCversion string) bool {
+	// Split the version strings by dot
+	v1Parts := strings.Split(presentVersion, ".")
+	v2Parts := strings.Split(expectedVCversion, ".")
+
+	// Compare parts
+	for i := 0; i < len(v1Parts); i++ {
+		v1, _ := strconv.Atoi(v1Parts[i]) // Convert each part to integer
+		v2, _ := strconv.Atoi(v2Parts[i])
+
+		if v1 > v2 {
+			return true
+		} else if v1 < v2 {
+			return false
+		}
+	}
+	return true // If all parts are equal, the versions are equal
+}
diff --git a/tests/e2e/vmservice_vm.go b/tests/e2e/vmservice_vm.go
index dae5093a..59d269ad 100644
--- a/tests/e2e/vmservice_vm.go
+++ b/tests/e2e/vmservice_vm.go
@@ -67,7 +67,7 @@ var _ bool = ginkgo.Describe("[vmsvc] vm service with csi vol tests", func() {
 		isVsanHealthServiceStopped bool
 		isSPSserviceStopped        bool
 		vcAddress                  string
-		isStorageQuotaFSSEnabled   bool
+		isQuotaValidationSupported bool
 		defaultDatastore           *object.Datastore
 	)
 
@@ -129,9 +129,10 @@ var _ bool = ginkgo.Describe("[vmsvc] vm service with csi vol tests", func() {
 		vmi = waitNGetVmiForImageName(ctx, vmopC, vmImageName)
 		gomega.Expect(vmi).NotTo(gomega.BeEmpty())
 
-		//Remove this code once the FSS is enabled
 		vcAddress := e2eVSphere.Config.Global.VCenterHostname + ":" + sshdPort
-		isStorageQuotaFSSEnabled = isFssEnabled(ctx, vcAddress, "STORAGE_QUOTA_M2")
+		//if isQuotaValidationSupported is true then quotaValidation is considered in tests
+		vcVersion = getVCversion(ctx, vcAddress)
+		isQuotaValidationSupported = isVersionGreaterOrEqual(vcVersion, quotaSupportedVCVersion)
 
 		var datacenters []string
 		datastoreURL = GetAndExpectStringEnvVar(envSharedDatastoreURL)
@@ -1428,7 +1429,7 @@ var _ bool = ginkgo.Describe("[vmsvc] vm service with csi vol tests", func() {
 		time.Sleep(1 * time.Minute)
 		setStoragePolicyQuota(ctx, restConfig, storagePolicyName, namespace, rqLimit)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 			totalQuotaUsedBefore, _, storagePolicyQuotaBefore, _, storagePolicyUsageBefore, _ =
 				getStoragePolicyUsedAndReservedQuotaDetails(ctx, restConfig,
 					storagePolicyName, namespace, pvcUsage, volExtensionName)
@@ -1460,7 +1461,7 @@ var _ bool = ginkgo.Describe("[vmsvc] vm service with csi vol tests", func() {
 		pv := getPvFromClaim(client, namespace, pvcName)
 		verifyBidirectionalReferenceOfPVandPVC(ctx, client, pvc, pv, fcdID)
 
-		if isStorageQuotaFSSEnabled {
+		if isQuotaValidationSupported {
 
 			validateQuotaUsageAfterResourceCreation(ctx, restConfig,
 				storagePolicyName, namespace, pvcUsage, volExtensionName,