@@ -18,6 +18,7 @@ package cnsregistervolume
18
18
19
19
import (
20
20
"context"
21
+ "encoding/json"
21
22
"fmt"
22
23
"reflect"
23
24
"testing"
@@ -791,18 +792,22 @@ var _ = Describe("checkExistingPVCDataSourceRef", func() {
791
792
792
793
var _ = Describe ("validatePVCTopologyCompatibility" , func () {
793
794
var (
794
- ctx context.Context
795
- pvc * corev1.PersistentVolumeClaim
796
- volumeDatastoreURL string
797
- mockTopologyMgr * mockTopologyService
798
- mockVC * cnsvsphere.VirtualCenter
795
+ ctx context.Context
796
+ pvc * corev1.PersistentVolumeClaim
797
+ volumeDatastoreURL string
798
+ mockTopologyMgr * mockTopologyService
799
+ mockVC * cnsvsphere.VirtualCenter
800
+ datastoreAccessibleTopology []map [string ]string
799
801
)
800
802
801
803
BeforeEach (func () {
802
804
ctx = context .Background ()
803
805
volumeDatastoreURL = "dummy-datastore-url"
804
806
mockTopologyMgr = & mockTopologyService {}
805
807
mockVC = & cnsvsphere.VirtualCenter {}
808
+ datastoreAccessibleTopology = []map [string ]string {
809
+ {"topology.kubernetes.io/zone" : "zone-1" },
810
+ }
806
811
807
812
pvc = & corev1.PersistentVolumeClaim {
808
813
ObjectMeta : metav1.ObjectMeta {
@@ -814,7 +819,8 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
814
819
815
820
Context ("when PVC has no topology annotation" , func () {
816
821
It ("should return nil without error" , func () {
817
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
822
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
823
+ datastoreAccessibleTopology )
818
824
Expect (err ).To (BeNil ())
819
825
})
820
826
})
@@ -827,7 +833,8 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
827
833
})
828
834
829
835
It ("should return nil without error" , func () {
830
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
836
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
837
+ datastoreAccessibleTopology )
831
838
Expect (err ).To (BeNil ())
832
839
})
833
840
})
@@ -840,7 +847,8 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
840
847
})
841
848
842
849
It ("should return error for invalid JSON" , func () {
843
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
850
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
851
+ datastoreAccessibleTopology )
844
852
Expect (err ).ToNot (BeNil ())
845
853
Expect (err .Error ()).To (ContainSubstring ("failed to parse topology annotation" ))
846
854
})
@@ -855,7 +863,8 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
855
863
})
856
864
857
865
It ("should return error from topology manager" , func () {
858
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
866
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
867
+ datastoreAccessibleTopology )
859
868
Expect (err ).ToNot (BeNil ())
860
869
Expect (err .Error ()).To (ContainSubstring ("failed to get topology for volume datastore" ))
861
870
})
@@ -872,7 +881,8 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
872
881
})
873
882
874
883
It ("should return nil without error" , func () {
875
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
884
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
885
+ datastoreAccessibleTopology )
876
886
Expect (err ).To (BeNil ())
877
887
})
878
888
})
@@ -888,11 +898,110 @@ var _ = Describe("validatePVCTopologyCompatibility", func() {
888
898
})
889
899
890
900
It ("should return error for incompatible zones" , func () {
891
- err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC )
901
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
902
+ datastoreAccessibleTopology )
892
903
Expect (err ).ToNot (BeNil ())
893
904
Expect (err .Error ()).To (ContainSubstring ("is not compatible with volume placement" ))
894
905
})
895
906
})
907
+
908
+ Context ("when PVC exists without topology annotation and annotation needs to be added" , func () {
909
+ var originalPVC * corev1.PersistentVolumeClaim
910
+
911
+ BeforeEach (func () {
912
+ // Create a PVC with some existing annotations but no topology annotation
913
+ originalPVC = & corev1.PersistentVolumeClaim {
914
+ ObjectMeta : metav1.ObjectMeta {
915
+ Name : "existing-pvc" ,
916
+ Namespace : "test-namespace" ,
917
+ Annotations : map [string ]string {
918
+ "some.other/annotation" : "existing-value" ,
919
+ "another/annotation" : "another-value" ,
920
+ },
921
+ },
922
+ Spec : corev1.PersistentVolumeClaimSpec {
923
+ AccessModes : []corev1.PersistentVolumeAccessMode {corev1 .ReadWriteOnce },
924
+ },
925
+ }
926
+ pvc = originalPVC
927
+ })
928
+
929
+ It ("should add topology annotation to existing PVC and return nil" , func () {
930
+ // Verify PVC initially has no topology annotation
931
+ _ , exists := pvc .Annotations ["csi.vsphere.volume-accessible-topology" ]
932
+ Expect (exists ).To (BeFalse ())
933
+
934
+ // Call the function
935
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC ,
936
+ datastoreAccessibleTopology )
937
+ Expect (err ).To (BeNil ())
938
+
939
+ // Verify topology annotation was added
940
+ topologyAnnotation , exists := pvc .Annotations ["csi.vsphere.volume-accessible-topology" ]
941
+ Expect (exists ).To (BeTrue ())
942
+ Expect (topologyAnnotation ).ToNot (BeEmpty ())
943
+
944
+ // Verify the annotation contains the expected topology data
945
+ expectedAnnotation := `[{"topology.kubernetes.io/zone":"zone-1"}]`
946
+ Expect (topologyAnnotation ).To (Equal (expectedAnnotation ))
947
+
948
+ // Verify existing annotations are preserved
949
+ Expect (pvc .Annotations ["some.other/annotation" ]).To (Equal ("existing-value" ))
950
+ Expect (pvc .Annotations ["another/annotation" ]).To (Equal ("another-value" ))
951
+ })
952
+
953
+ It ("should handle PVC with nil annotations map" , func () {
954
+ // Create PVC with nil annotations
955
+ pvcWithNilAnnotations := & corev1.PersistentVolumeClaim {
956
+ ObjectMeta : metav1.ObjectMeta {
957
+ Name : "pvc-nil-annotations" ,
958
+ Namespace : "test-namespace" ,
959
+ Annotations : nil ,
960
+ },
961
+ }
962
+
963
+ // Call the function
964
+ err := validatePVCTopologyCompatibility (ctx , pvcWithNilAnnotations , volumeDatastoreURL , mockTopologyMgr ,
965
+ mockVC , datastoreAccessibleTopology )
966
+ Expect (err ).To (BeNil ())
967
+
968
+ // Verify annotations map was created and topology annotation was added
969
+ Expect (pvcWithNilAnnotations .Annotations ).ToNot (BeNil ())
970
+ topologyAnnotation , exists := pvcWithNilAnnotations .Annotations ["csi.vsphere.volume-accessible-topology" ]
971
+ Expect (exists ).To (BeTrue ())
972
+ Expect (topologyAnnotation ).To (Equal (`[{"topology.kubernetes.io/zone":"zone-1"}]` ))
973
+ })
974
+
975
+ It ("should handle complex topology data with multiple zones" , func () {
976
+ // Use more complex topology data
977
+ complexTopology := []map [string ]string {
978
+ {"topology.kubernetes.io/zone" : "zone-a" , "topology.kubernetes.io/region" : "us-west" },
979
+ {"topology.kubernetes.io/zone" : "zone-b" , "topology.kubernetes.io/region" : "us-west" },
980
+ }
981
+
982
+ err := validatePVCTopologyCompatibility (ctx , pvc , volumeDatastoreURL , mockTopologyMgr , mockVC , complexTopology )
983
+ Expect (err ).To (BeNil ())
984
+
985
+ // Verify the complex topology was properly serialized
986
+ topologyAnnotation := pvc .Annotations ["csi.vsphere.volume-accessible-topology" ]
987
+ Expect (topologyAnnotation ).ToNot (BeEmpty ())
988
+
989
+ // Parse the annotation to verify it contains both topology segments
990
+ var parsedTopology []map [string ]string
991
+ err = json .Unmarshal ([]byte (topologyAnnotation ), & parsedTopology )
992
+ Expect (err ).To (BeNil ())
993
+ Expect (len (parsedTopology )).To (Equal (2 ))
994
+ Expect (parsedTopology [0 ]).To (Equal (map [string ]string {
995
+ "topology.kubernetes.io/zone" : "zone-a" ,
996
+ "topology.kubernetes.io/region" : "us-west" ,
997
+ }))
998
+ Expect (parsedTopology [1 ]).To (Equal (map [string ]string {
999
+ "topology.kubernetes.io/zone" : "zone-b" ,
1000
+ "topology.kubernetes.io/region" : "us-west" ,
1001
+ }))
1002
+ })
1003
+
1004
+ })
896
1005
})
897
1006
898
1007
var _ = Describe ("isTopologyCompatible" , func () {
0 commit comments