@@ -2556,12 +2556,12 @@ func DeleteService(ns string, c clientset.Interface, service *v1.Service) {
2556
2556
2557
2557
// GetStatefulSetFromManifest creates a StatefulSet from the statefulset.yaml
2558
2558
// file present in the manifest path.
2559
- func GetStatefulSetFromManifest (e2eTestConfig * config.E2eTestConfig , ns string ) * appsv1.StatefulSet {
2559
+ func GetStatefulSetFromManifest (e2eTestConfig * config.TestInputData , ns string ) * appsv1.StatefulSet {
2560
2560
ssManifestFilePath := filepath .Join (constants .ManifestPath , "statefulset.yaml" )
2561
2561
framework .Logf ("Parsing statefulset from %v" , ssManifestFilePath )
2562
2562
ss , err := manifest .StatefulSetFromManifest (ssManifestFilePath , ns )
2563
2563
framework .ExpectNoError (err )
2564
- if e2eTestConfig .TestInput . TestBedInfo .WindowsEnv {
2564
+ if e2eTestConfig .TestBedInfo .WindowsEnv {
2565
2565
ss .Spec .Template .Spec .Containers [0 ].Image = constants .WindowsImageOnMcr
2566
2566
ss .Spec .Template .Spec .Containers [0 ].Command = []string {"Powershell.exe" }
2567
2567
ss .Spec .Template .Spec .Containers [0 ].Args = []string {"-Command" , constants .WindowsExecCmd }
@@ -3053,6 +3053,7 @@ func TrimQuotes(str string) string {
3053
3053
// Returns a de-serialized structured config data
3054
3054
func ReadConfigFromSecretString (cfg string ) (config.E2eTestConfig , error ) {
3055
3055
var config1 config.E2eTestConfig
3056
+ var testInput config.TestInputData
3056
3057
var netPerm config.NetPermissionConfig
3057
3058
key , value := "" , ""
3058
3059
var permissions vsanfstypes.VsanFileShareAccessType
@@ -3082,7 +3083,7 @@ func ReadConfigFromSecretString(cfg string) (config.E2eTestConfig, error) {
3082
3083
value = words [1 ]
3083
3084
// Remove trailing '"]' characters from value.
3084
3085
value = strings .TrimSuffix (value , "]" )
3085
- config1 . TestInput .Global .VCenterHostname = TrimQuotes (value )
3086
+ testInput .Global .VCenterHostname = TrimQuotes (value )
3086
3087
fmt .Printf ("Key: VirtualCenter, Value: %s\n " , value )
3087
3088
}
3088
3089
continue
@@ -3093,47 +3094,47 @@ func ReadConfigFromSecretString(cfg string) (config.E2eTestConfig, error) {
3093
3094
switch key {
3094
3095
case "insecure-flag" :
3095
3096
if strings .Contains (value , "true" ) {
3096
- config1 . TestInput .Global .InsecureFlag = true
3097
+ testInput .Global .InsecureFlag = true
3097
3098
} else {
3098
- config1 . TestInput .Global .InsecureFlag = false
3099
+ testInput .Global .InsecureFlag = false
3099
3100
}
3100
3101
case "cluster-id" :
3101
- config1 . TestInput .Global .ClusterID = value
3102
+ testInput .Global .ClusterID = value
3102
3103
case "cluster-distribution" :
3103
- config1 . TestInput .Global .ClusterDistribution = value
3104
+ testInput .Global .ClusterDistribution = value
3104
3105
case "user" :
3105
- config1 . TestInput .Global .User = value
3106
+ testInput .Global .User = value
3106
3107
case "password" :
3107
- config1 . TestInput .Global .Password = value
3108
+ testInput .Global .Password = value
3108
3109
case "datacenters" :
3109
- config1 . TestInput .Global .Datacenters = value
3110
+ testInput .Global .Datacenters = value
3110
3111
case "port" :
3111
- config1 . TestInput .Global .VCenterPort = value
3112
+ testInput .Global .VCenterPort = value
3112
3113
case "cnsregistervolumes-cleanup-intervalinmin" :
3113
- config1 . TestInput .Global .CnsRegisterVolumesCleanupIntervalInMin , strconvErr = strconv .Atoi (value )
3114
+ testInput .Global .CnsRegisterVolumesCleanupIntervalInMin , strconvErr = strconv .Atoi (value )
3114
3115
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3115
3116
case "topology-categories" :
3116
- config1 . TestInput .Labels .TopologyCategories = value
3117
+ testInput .Labels .TopologyCategories = value
3117
3118
case "global-max-snapshots-per-block-volume" :
3118
- config1 . TestInput .Snapshot .GlobalMaxSnapshotsPerBlockVolume , strconvErr = strconv .Atoi (value )
3119
+ testInput .Snapshot .GlobalMaxSnapshotsPerBlockVolume , strconvErr = strconv .Atoi (value )
3119
3120
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3120
3121
case "csi-fetch-preferred-datastores-intervalinmin" :
3121
- config1 . TestInput .Global .CSIFetchPreferredDatastoresIntervalInMin , strconvErr = strconv .Atoi (value )
3122
+ testInput .Global .CSIFetchPreferredDatastoresIntervalInMin , strconvErr = strconv .Atoi (value )
3122
3123
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3123
3124
case "query-limit" :
3124
- config1 . TestInput .Global .QueryLimit , strconvErr = strconv .Atoi (value )
3125
+ testInput .Global .QueryLimit , strconvErr = strconv .Atoi (value )
3125
3126
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3126
3127
case "list-volume-threshold" :
3127
- config1 . TestInput .Global .ListVolumeThreshold , strconvErr = strconv .Atoi (value )
3128
+ testInput .Global .ListVolumeThreshold , strconvErr = strconv .Atoi (value )
3128
3129
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3129
3130
case "ca-file" :
3130
- config1 . TestInput .Global .CaFile = value
3131
+ testInput .Global .CaFile = value
3131
3132
case "supervisor-id" :
3132
- config1 . TestInput .Global .SupervisorID = value
3133
+ testInput .Global .SupervisorID = value
3133
3134
case "targetvSANFileShareClusters" :
3134
- config1 . TestInput .Global .TargetVsanFileShareClusters = value
3135
+ testInput .Global .TargetVsanFileShareClusters = value
3135
3136
case "fileVolumeActivated" :
3136
- config1 . TestInput .Global .FileVolumeActivated , strconvErr = strconv .ParseBool (value )
3137
+ testInput .Global .FileVolumeActivated , strconvErr = strconv .ParseBool (value )
3137
3138
gomega .Expect (strconvErr ).NotTo (gomega .HaveOccurred ())
3138
3139
case "ips" :
3139
3140
netPerm .Ips = value
@@ -3145,6 +3146,7 @@ func ReadConfigFromSecretString(cfg string) (config.E2eTestConfig, error) {
3145
3146
return config1 , fmt .Errorf ("unknown key %s in the input string" , key )
3146
3147
}
3147
3148
}
3149
+ config1 .TestInput = & testInput
3148
3150
return config1 , nil
3149
3151
}
3150
3152
@@ -5783,7 +5785,7 @@ func CreateParallelStatefulSets(client clientset.Interface, namespace string,
5783
5785
gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
5784
5786
}
5785
5787
5786
- func CreateParallelStatefulSetSpec (e2eTestConfig * config.E2eTestConfig ,
5788
+ func CreateParallelStatefulSetSpec (e2eTestConfig * config.TestInputData ,
5787
5789
namespace string , no_of_sts int , replicas int32 ) []* appsv1.StatefulSet {
5788
5790
stss := []* appsv1.StatefulSet {}
5789
5791
var statefulset * appsv1.StatefulSet
@@ -7315,3 +7317,142 @@ func ListStoragePolicyUsages(ctx context.Context, c clientset.Interface, restCli
7315
7317
7316
7318
fmt .Println ("All required storage policy usages are available." )
7317
7319
}
7320
+
7321
+ // ExitHostMM exits a host from maintenance mode with a particular timeout
7322
+ func ExitHostMM (ctx context.Context , host * object.HostSystem , timeout int32 ) {
7323
+ task , err := host .ExitMaintenanceMode (ctx , timeout )
7324
+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
7325
+
7326
+ _ , err = task .WaitForResultEx (ctx , nil )
7327
+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
7328
+
7329
+ framework .Logf ("Host: %v exited from maintenance mode" , host )
7330
+ }
7331
+
7332
+ /*
7333
+ CreateStatefulSetAndVerifyPVAndPodNodeAffinty creates user specified statefulset and
7334
+ further checks the node and volumes affinities
7335
+ */
7336
+ func CreateStatefulSetAndVerifyPVAndPodNodeAffinty (ctx context.Context , client clientset.Interface ,
7337
+ vs * config.E2eTestConfig , namespace string , parallelPodPolicy bool , replicas int32 , nodeAffinityToSet bool ,
7338
+ allowedTopologies []v1.TopologySelectorLabelRequirement ,
7339
+ podAntiAffinityToSet bool , parallelStatefulSetCreation bool , modifyStsSpec bool ,
7340
+ accessMode v1.PersistentVolumeAccessMode ,
7341
+ sc * storagev1.StorageClass , verifyTopologyAffinity bool , storagePolicy string ) (* v1.Service ,
7342
+ * appsv1.StatefulSet , error ) {
7343
+
7344
+ ginkgo .By ("Create service" )
7345
+ service := CreateService (namespace , client )
7346
+
7347
+ framework .Logf ("Create StatefulSet" )
7348
+ statefulset := CreateCustomisedStatefulSets (ctx , client , vs .TestInput , namespace , parallelPodPolicy ,
7349
+ replicas , nodeAffinityToSet , allowedTopologies , podAntiAffinityToSet , modifyStsSpec ,
7350
+ "" , accessMode , sc , storagePolicy )
7351
+
7352
+ if verifyTopologyAffinity {
7353
+ framework .Logf ("Verify PV node affinity and that the PODS are running on appropriate node" )
7354
+ err := VerifyPVnodeAffinityAndPODnodedetailsForStatefulsetsLevel5 (ctx , vs , client , statefulset ,
7355
+ namespace , allowedTopologies , parallelStatefulSetCreation )
7356
+ if err != nil {
7357
+ return nil , nil , fmt .Errorf ("error verifying PV node affinity and POD node details: %v" , err )
7358
+ }
7359
+ }
7360
+
7361
+ return service , statefulset , nil
7362
+ }
7363
+
7364
+ /*
7365
+ createCustomisedStatefulSets util methods creates statefulset as per the user's
7366
+ specific requirement and returns the customised statefulset
7367
+ */
7368
+ func CreateCustomisedStatefulSets (ctx context.Context , client clientset.Interface , vs * config.TestInputData ,
7369
+ namespace string , isParallelPodMgmtPolicy bool , replicas int32 , nodeAffinityToSet bool ,
7370
+ allowedTopologies []v1.TopologySelectorLabelRequirement ,
7371
+ podAntiAffinityToSet bool , modifyStsSpec bool , stsName string ,
7372
+ accessMode v1.PersistentVolumeAccessMode , sc * storagev1.StorageClass , storagePolicy string ) * appsv1.StatefulSet {
7373
+ framework .Logf ("Preparing StatefulSet Spec" )
7374
+ statefulset := GetStatefulSetFromManifest (vs , namespace )
7375
+
7376
+ if accessMode == "" {
7377
+ // If accessMode is not specified, set the default accessMode.
7378
+ defaultAccessMode := v1 .ReadWriteOnce
7379
+ statefulset .Spec .VolumeClaimTemplates [len (statefulset .Spec .VolumeClaimTemplates )- 1 ].
7380
+ Spec .AccessModes [0 ] = defaultAccessMode
7381
+ } else {
7382
+ statefulset .Spec .VolumeClaimTemplates [len (statefulset .Spec .VolumeClaimTemplates )- 1 ].Spec .AccessModes [0 ] =
7383
+ accessMode
7384
+ }
7385
+
7386
+ if modifyStsSpec {
7387
+ if vs .TestBedInfo .MultipleSvc {
7388
+ statefulset .Spec .VolumeClaimTemplates [len (statefulset .Spec .VolumeClaimTemplates )- 1 ].
7389
+ Spec .StorageClassName = & storagePolicy
7390
+ } else {
7391
+ statefulset .Spec .VolumeClaimTemplates [len (statefulset .Spec .VolumeClaimTemplates )- 1 ].
7392
+ Spec .StorageClassName = & sc .Name
7393
+ }
7394
+
7395
+ if stsName != "" {
7396
+ statefulset .Name = stsName
7397
+ statefulset .Spec .Template .Labels ["app" ] = statefulset .Name
7398
+ statefulset .Spec .Selector .MatchLabels ["app" ] = statefulset .Name
7399
+ }
7400
+
7401
+ }
7402
+ if nodeAffinityToSet {
7403
+ nodeSelectorTerms := GetNodeSelectorTerms (allowedTopologies )
7404
+ statefulset .Spec .Template .Spec .Affinity = new (v1.Affinity )
7405
+ statefulset .Spec .Template .Spec .Affinity .NodeAffinity = new (v1.NodeAffinity )
7406
+ statefulset .Spec .Template .Spec .Affinity .NodeAffinity .
7407
+ RequiredDuringSchedulingIgnoredDuringExecution = new (v1.NodeSelector )
7408
+ statefulset .Spec .Template .Spec .Affinity .NodeAffinity .
7409
+ RequiredDuringSchedulingIgnoredDuringExecution .NodeSelectorTerms = nodeSelectorTerms
7410
+ }
7411
+ if podAntiAffinityToSet {
7412
+ statefulset .Spec .Template .Spec .Affinity = & v1.Affinity {
7413
+ PodAntiAffinity : & v1.PodAntiAffinity {
7414
+ RequiredDuringSchedulingIgnoredDuringExecution : []v1.PodAffinityTerm {
7415
+ {
7416
+ LabelSelector : & metav1.LabelSelector {
7417
+ MatchLabels : map [string ]string {
7418
+ "key" : "app" ,
7419
+ },
7420
+ },
7421
+ TopologyKey : "topology.kubernetes.io/zone" ,
7422
+ },
7423
+ },
7424
+ },
7425
+ }
7426
+
7427
+ }
7428
+ if isParallelPodMgmtPolicy {
7429
+ statefulset .Spec .PodManagementPolicy = appsv1 .ParallelPodManagement
7430
+ }
7431
+ statefulset .Spec .Replicas = & replicas
7432
+
7433
+ framework .Logf ("Creating statefulset" )
7434
+ CreateStatefulSet (namespace , statefulset , client )
7435
+
7436
+ framework .Logf ("Wait for StatefulSet pods to be in up and running state" )
7437
+ fss .WaitForStatusReadyReplicas (ctx , client , statefulset , replicas )
7438
+ gomega .Expect (fss .CheckMount (ctx , client , statefulset , constants .MountPath )).NotTo (gomega .HaveOccurred ())
7439
+ ssPodsBeforeScaleDown , err := fss .GetPodList (ctx , client , statefulset )
7440
+ gomega .Expect (err ).NotTo (gomega .HaveOccurred ())
7441
+ gomega .Expect (ssPodsBeforeScaleDown .Items ).NotTo (gomega .BeEmpty (),
7442
+ fmt .Sprintf ("Unable to get list of Pods from the Statefulset: %v" , statefulset .Name ))
7443
+ gomega .Expect (len (ssPodsBeforeScaleDown .Items ) == int (replicas )).To (gomega .BeTrue (),
7444
+ "Number of Pods in the statefulset should match with number of replicas" )
7445
+
7446
+ return statefulset
7447
+ }
7448
+
7449
+ // CreateStatefulSet creates a StatefulSet from the manifest at manifestPath in the given namespace.
7450
+ func CreateStatefulSet (ns string , ss * appsv1.StatefulSet , c clientset.Interface ) {
7451
+ ctx , cancel := context .WithCancel (context .Background ())
7452
+ defer cancel ()
7453
+ framework .Logf ("Creating statefulset %v/%v with %d replicas and selector %+v" ,
7454
+ ss .Namespace , ss .Name , * (ss .Spec .Replicas ), ss .Spec .Selector )
7455
+ _ , err := c .AppsV1 ().StatefulSets (ns ).Create (ctx , ss , metav1.CreateOptions {})
7456
+ framework .ExpectNoError (err )
7457
+ fss .WaitForRunningAndReady (ctx , c , * ss .Spec .Replicas , ss )
7458
+ }
0 commit comments