1
1
/*
2
- Copyright 2021 The Kubernetes Authors.
2
+ Copyright 2021-2025 The Kubernetes Authors.
3
3
4
4
Licensed under the Apache License, Version 2.0 (the "License");
5
5
you may not use this file except in compliance with the License.
@@ -18,8 +18,10 @@ package cnsfileaccessconfig
18
18
19
19
import (
20
20
"context"
21
+ "errors"
21
22
"fmt"
22
23
"reflect"
24
+ "strings"
23
25
"sync"
24
26
"time"
25
27
@@ -60,6 +62,11 @@ import (
60
62
61
63
const (
62
64
defaultMaxWorkerThreadsForFileAccessConfig = 10
65
+ vmNameLabelKey = "cns.vmware.com/vm-name"
66
+ pvcNameLabelKey = "cns.vmware.com/pvc-name"
67
+ capvVmLabelKey = "capv.vmware.com"
68
+ capvPvcLabelKey = "TKGService"
69
+ devopsUserLabelKey = "cns.vmware.com/user-created"
63
70
)
64
71
65
72
// backOffDuration is a map of cnsfileaccessconfig name's to the time after
@@ -310,12 +317,25 @@ func (r *ReconcileCnsFileAccessConfig) Reconcile(ctx context.Context,
310
317
}
311
318
log .Debugf ("Found virtualMachine instance for VM: %q/%q: %+v" , instance .Namespace , instance .Spec .VMName , vm )
312
319
320
+ ifFileVolumesWithVmserviceVmsSupported := commonco .ContainerOrchestratorUtility .IsFSSEnabled (ctx ,
321
+ common .FileVolumesWithVmService )
322
+
323
+ if ifFileVolumesWithVmserviceVmsSupported {
324
+ err = validateVmAndPvc (ctx , instance .Labels , instance .Name , instance .Spec .PvcName ,
325
+ instance .Namespace , r .client , vm )
326
+ if err != nil {
327
+ log .Errorf ("failed to validate VM %s and PVC %s" , vm .Name , instance .Spec .PvcName )
328
+ setInstanceError (ctx , r , instance , err .Error ())
329
+ return reconcile.Result {RequeueAfter : timeout }, nil
330
+ }
331
+ }
332
+
313
333
if instance .DeletionTimestamp != nil {
314
334
log .Infof ("CnsFileAccessConfig instance %q has deletion timestamp set" , instance .Name )
315
335
volumeExists := true
316
336
volumeID , err := cnsoperatorutil .GetVolumeID (ctx , r .client , instance .Spec .PvcName , instance .Namespace )
317
337
if err != nil {
318
- if commonco . ContainerOrchestratorUtility . IsFSSEnabled ( ctx , common . FileVolumesWithVmService ) &&
338
+ if ifFileVolumesWithVmserviceVmsSupported &&
319
339
apierrors .IsNotFound (err ) {
320
340
log .Infof ("Volume ID for PVC %s in namespace %s not found. No need to configure ACL" ,
321
341
instance .Spec .PvcName , instance .Namespace )
@@ -801,6 +821,66 @@ func (r *ReconcileCnsFileAccessConfig) getVMExternalIP(ctx context.Context,
801
821
return tkgVMIP , nil
802
822
}
803
823
824
+ // validateVmAndPvc validates if the VM and PVC combination given in the instance is correct or not.
825
+ // CnsFileAccessConfig CRs created by devpos users will have "cns.vmware.com/user-created", "cns.vmware.com/vm-name"
826
+ // and "cns.vmware.com/pvc-name" labels.
827
+ // When these labels are present, the PVC and VM must not belong to TKG cluster.
828
+ // This is verified by ensuring that:
829
+ // The VM does not have a label applied by CAPV - example capv.vmware.com/cluster.name.
830
+ // The PVC does not have a label applied by CAPV - example <TKG cluster namespace>/TKGService
831
+ func validateVmAndPvc (ctx context.Context , instanceLabels map [string ]string , instanceName string , pvcName string ,
832
+ namespace string , client client.Client , vm * vmoperatorv1alpha4.VirtualMachine ) error {
833
+ log := logger .GetLogger (ctx )
834
+
835
+ if instanceLabels == nil {
836
+ log .Infof ("No labels found on the instance %s. Nothing to validate." , instanceName )
837
+ return nil
838
+ }
839
+
840
+ isUserCreatedCnsFileAccessConfig := false
841
+ for key := range instanceLabels {
842
+ if key == devopsUserLabelKey {
843
+ isUserCreatedCnsFileAccessConfig = true
844
+ break
845
+ }
846
+ }
847
+
848
+ if ! isUserCreatedCnsFileAccessConfig {
849
+ log .Infof ("Instance %s is not created by devops user. Nothing to validate" , instanceName )
850
+ return nil
851
+ }
852
+
853
+ for key := range vm .Labels {
854
+ if strings .Contains (key , capvVmLabelKey ) {
855
+ msg := fmt .Sprintf ("CnsFileAccessConfig is created by devops user and has TKG VM %s. " +
856
+ "Invalid combination." , vm .Name )
857
+ log .Errorf (msg )
858
+ err := errors .New (msg )
859
+ return err
860
+ }
861
+ }
862
+
863
+ pvc := & v1.PersistentVolumeClaim {}
864
+ err := client .Get (ctx , types.NamespacedName {Name : pvcName , Namespace : namespace }, pvc )
865
+ if err != nil {
866
+ log .Errorf ("failed to get PVC with name %s in namespace %s" , pvcName , namespace )
867
+ return err
868
+ }
869
+
870
+ for key := range pvc .Labels {
871
+ if strings .Contains (key , capvPvcLabelKey ) {
872
+ msg := fmt .Sprintf ("CnsFileAccessConfig is created by devops user and has " +
873
+ "TKG PVC %s. Invalid combination." , pvcName )
874
+ log .Errorf (msg )
875
+ err := errors .New (msg )
876
+ return err
877
+ }
878
+ }
879
+
880
+ log .Infof ("Successfully verified instance %s for VM/PVC combination" , instanceName )
881
+ return nil
882
+ }
883
+
804
884
// setInstanceSuccess sets instance to success and records an event on the
805
885
// CnsFileAccessConfig instance.
806
886
func setInstanceSuccess (ctx context.Context , r * ReconcileCnsFileAccessConfig ,
0 commit comments