github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/clusterapi/oke-capi-driver/oke_cluster_driver_test.go (about) 1 // Copyright (c) 2023, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package okecapidriver 5 6 import ( 7 "fmt" 8 "sync" 9 "time" 10 11 "github.com/verrazzano/verrazzano/pkg/k8sutil" 12 "github.com/verrazzano/verrazzano/tests/e2e/backup/helpers" 13 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 14 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 15 16 . "github.com/onsi/ginkgo/v2" 17 . "github.com/onsi/gomega" 18 ) 19 20 const ( 21 shortWaitTimeout = 10 * time.Minute 22 shortPollingInterval = 10 * time.Second 23 waitTimeout = 45 * time.Minute 24 pollingInterval = 30 * time.Second 25 skipOKEUpgradeMessage = "Skipping test since the kubernetes version is same for install and update operations for OKE cluster upgrade" 26 skipRunAllTestsMessage = "Skipping test since the runAllTests flag was set to false" 27 ) 28 29 var ( 30 t = framework.NewTestFramework("okecapi-driver") 31 32 clusterNameNodePool string 33 clusterNameNodePoolUpdate string 34 clusterNameOKEUpgrade string 35 clusterNameInvalid string 36 ) 37 38 // Part of SynchronizedBeforeSuite, run by only one process 39 func synchronizedBeforeSuiteProcess1Func() []byte { 40 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 41 Expect(err).ShouldNot(HaveOccurred()) 42 if !pkg.IsRancherEnabled(kubeconfigPath) || !pkg.IsClusterAPIEnabled(kubeconfigPath) { 43 AbortSuite("skipping OKE CAPI cluster driver test suite since either of rancher and capi components are not enabled") 44 } 45 46 httpClient, err = pkg.GetVerrazzanoHTTPClient(kubeconfigPath) 47 if err != nil { 48 AbortSuite(fmt.Sprintf("failed getting http client: %v", err)) 49 } 50 51 rancherURL, err = helpers.GetRancherURL(t.Logs) 52 if err != nil { 53 AbortSuite(fmt.Sprintf("failed getting rancherURL: %v", err)) 54 } 55 56 verifyRequiredEnvironmentVariables() 57 58 cloudCredentialName := fmt.Sprintf("strudel-cred-%s", okeCapiClusterNameSuffix) 59 // Create the cloud credential to be used for all tests 60 var credentialID string 61 Eventually(func() error { 62 var err error 63 credentialID, err = createCloudCredential(cloudCredentialName, t.Logs) 64 return err 65 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 66 67 Eventually(func() error { 68 return validateCloudCredential(credentialID, t.Logs) 69 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 70 71 // Return byte encoded cloud credential ID to be shared across all processes 72 return []byte(credentialID) 73 } 74 75 // Part of SynchronizedBeforeSuite, run by all processes 76 func synchronizedBeforeSuiteAllProcessesFunc(credentialIDBytes []byte) { 77 // Define global variables for all processes 78 cloudCredentialID = string(credentialIDBytes) 79 80 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 81 Expect(err).ShouldNot(HaveOccurred()) 82 83 httpClient, err = pkg.GetVerrazzanoHTTPClient(kubeconfigPath) 84 if err != nil { 85 AbortSuite(fmt.Sprintf("failed getting http client: %v", err)) 86 } 87 88 rancherURL, err = helpers.GetRancherURL(t.Logs) 89 if err != nil { 90 AbortSuite(fmt.Sprintf("failed getting rancherURL: %v", err)) 91 } 92 93 // Calling this method again so that all processes have the variables initialized 94 verifyRequiredEnvironmentVariables() 95 96 err = ensureOKEDriverVarsInitialized(t.Logs) 97 Expect(err).ShouldNot(HaveOccurred()) 98 99 t.Logs.Infof("Min k8s version: %s", okeMetadataItemToInstall.KubernetesVersion.Original()) 100 t.Logs.Infof("Max k8s version: %s", okeMetadataItemToUpgrade.KubernetesVersion.Original()) 101 102 clusterNameNodePool = fmt.Sprintf("strudel-pool-%s", okeCapiClusterNameSuffix) 103 clusterNameNodePoolUpdate = fmt.Sprintf("strudel-pool-update-%s", okeCapiClusterNameSuffix) 104 clusterNameInvalid = fmt.Sprintf("strudel-invalid-k8s-%s", okeCapiClusterNameSuffix) 105 clusterNameOKEUpgrade = fmt.Sprintf("strudel-oke-upgrade-%s", okeCapiClusterNameSuffix) 106 } 107 108 var _ = t.SynchronizedBeforeSuite(synchronizedBeforeSuiteProcess1Func, synchronizedBeforeSuiteAllProcessesFunc) 109 110 // Part of SynchronizedAfterSuite, run by only one process 111 func synchronizedAfterSuiteProcess1Func() { 112 // Delete the clusters concurrently 113 clusterNames := []string{clusterNameNodePool} 114 if runAllTests { 115 clusterNames = append(clusterNames, clusterNameNodePoolUpdate, clusterNameInvalid, clusterNameOKEUpgrade) 116 } 117 var wg sync.WaitGroup 118 for _, clusterName := range clusterNames { 119 if clusterName != "" { 120 wg.Add(1) 121 go func(name string) { 122 defer wg.Done() 123 // Delete the OKE cluster 124 Eventually(func() error { 125 return deleteCluster(name, t.Logs) 126 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 127 128 // Verify the cluster is deleted 129 Eventually(func() (bool, error) { return isClusterDeleted(name, t.Logs) }, waitTimeout, pollingInterval).Should( 130 BeTrue(), fmt.Sprintf("cluster %s is not deleted", name)) 131 }(clusterName) 132 } 133 } 134 wg.Wait() 135 136 // Delete the credential 137 deleteCredential(cloudCredentialID, t.Logs) 138 139 // Verify the credential is deleted 140 Eventually(func() (bool, error) { return isCredentialDeleted(cloudCredentialID, t.Logs) }, waitTimeout, pollingInterval).Should( 141 BeTrue(), fmt.Sprintf("cloud credential %s is not deleted", cloudCredentialID)) 142 } 143 144 var _ = t.SynchronizedAfterSuite(func() {}, synchronizedAfterSuiteProcess1Func) 145 146 var _ = t.Describe("OKE CAPI Cluster Driver", Label("f:rancher-capi:okecapi-cluster-driver"), func() { 147 // Cluster 1. Create with a node pool. 148 t.Context("OKE cluster creation with a node pool", Ordered, func() { 149 var poolName string 150 var poolReplicas int 151 var expectedNodeCount int 152 153 // clusterConfig specifies the parameters passed into the cluster creation 154 var clusterConfig RancherOKECluster 155 156 t.BeforeAll(func() { 157 poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix) 158 poolReplicas = 1 159 expectedNodeCount = poolReplicas 160 }) 161 162 // Create the cluster and verify it comes up 163 t.It("create OKE CAPI cluster", func() { 164 Eventually(func() error { 165 volumeSize, ocpus, memory := 150, 2, 32 166 version := kubernetesVersion 167 mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory) 168 return createClusterAndFillConfig(clusterNameNodePool, &clusterConfig, t.Logs, mutateFn) 169 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 170 }) 171 t.It("check OKE cluster is active", func() { 172 Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePool, t.Logs) }, waitTimeout, pollingInterval).Should( 173 BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePool)) 174 Eventually(func() error { 175 return verifyCluster(clusterNameNodePool, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs) 176 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePool)) 177 }) 178 }) 179 180 // Cluster 2. Create with a node pool, then perform an update. 181 t.Context("OKE cluster creation with a node pool update", Ordered, func() { 182 var poolName string 183 var poolReplicas int 184 var expectedNodeCount int 185 186 // clusterConfig specifies the parameters passed into the cluster creation 187 // and is updated as update requests are made 188 var clusterConfig RancherOKECluster 189 190 t.BeforeAll(func() { 191 if !runAllTests { 192 Skip(skipRunAllTestsMessage) 193 } 194 poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix) 195 poolReplicas = 1 196 expectedNodeCount = poolReplicas 197 }) 198 199 // Create the cluster and verify it comes up 200 t.It("create OKE CAPI cluster", func() { 201 Eventually(func() error { 202 volumeSize, ocpus, memory := 150, 2, 32 203 version := kubernetesVersion 204 mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory) 205 return createClusterAndFillConfig(clusterNameNodePoolUpdate, &clusterConfig, t.Logs, mutateFn) 206 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 207 }) 208 t.It("check OKE cluster is active", func() { 209 Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePoolUpdate, t.Logs) }, waitTimeout, pollingInterval).Should( 210 BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePoolUpdate)) 211 Eventually(func() error { 212 return verifyCluster(clusterNameNodePoolUpdate, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs) 213 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePoolUpdate)) 214 }) 215 216 // Update - increase node usage 217 t.It("update OKE cluster to increase node usage", func() { 218 poolReplicas++ 219 expectedNodeCount++ 220 221 Eventually(func() error { 222 volumeSize, ocpus, memory := 150, 2, 32 223 version := kubernetesVersion 224 mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory) 225 return updateConfigAndCluster(&clusterConfig, mutateFn, t.Logs) 226 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 227 }) 228 t.It("check the OKE cluster updated", func() { 229 Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePoolUpdate, t.Logs) }, waitTimeout, pollingInterval).Should( 230 BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePoolUpdate)) 231 Eventually(func() error { 232 return verifyCluster(clusterNameNodePoolUpdate, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs) 233 }, waitTimeout, pollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePoolUpdate)) 234 }) 235 }) 236 237 // Cluster 3. Pass in invalid parameters when creating a cluster. 238 t.Context("OKE cluster creation with invalid kubernetes version", Ordered, func() { 239 var clusterConfig RancherOKECluster 240 241 t.BeforeAll(func() { 242 if !runAllTests { 243 Skip(skipRunAllTestsMessage) 244 } 245 }) 246 247 t.It("create OKE cluster", func() { 248 // Create the cluster 249 Eventually(func() error { 250 mutateFn := func(config *RancherOKECluster) { 251 // setting an invalid kubernetes version 252 config.OKECAPIEngineConfig.KubernetesVersion = "v1.22.7" 253 } 254 return createClusterAndFillConfig(clusterNameInvalid, &clusterConfig, t.Logs, mutateFn) 255 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 256 }) 257 258 t.It("check OKE cluster is not active", func() { 259 // Verify the cluster is not active 260 waitTimeoutNegative := 20 * time.Minute 261 Eventually(func() (bool, error) { return isClusterActive(clusterNameInvalid, t.Logs) }, waitTimeoutNegative, pollingInterval).Should( 262 BeFalse(), fmt.Sprintf("cluster %s is active", clusterNameInvalid)) 263 264 // Verify that the cluster is configured correctly 265 Eventually(func() error { 266 return verifyCluster(clusterNameInvalid, 0, provisioningClusterState, transitioningFlagError, t.Logs) 267 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameInvalid)) 268 }) 269 }) 270 271 // Cluster 4. Create with a single node with the minimum OKE supported Kubernetes version and related info. 272 // Later, update the cluster with the maximum OKE supported Kubernetes version and related info. 273 t.Context("OKE cluster creation with single node with OKE cluster upgrade", Ordered, func() { 274 var poolName string 275 var poolReplicas, volumeSize, ocpus, memory int 276 var expectedNodeCount int 277 var clusterConfig RancherOKECluster 278 279 t.BeforeAll(func() { 280 if !runAllTests { 281 Skip(skipRunAllTestsMessage) 282 } 283 if !okeMetadataItemToInstall.KubernetesVersion.LessThan(okeMetadataItemToUpgrade.KubernetesVersion) { 284 Skip(skipOKEUpgradeMessage) 285 } 286 poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix) 287 poolReplicas = 1 288 expectedNodeCount = poolReplicas 289 volumeSize, ocpus, memory = 150, 2, 32 290 }) 291 292 // Create the cluster 293 t.It("create OKE cluster with the minimum OKE supported Kubernetes version and related info", func() { 294 295 mutateFn := func(config *RancherOKECluster) { 296 config.OKECAPIEngineConfig.KubernetesVersion = okeMetadataItemToInstall.KubernetesVersion.Original() 297 config.OKECAPIEngineConfig.NodePools = []string{ 298 getNodePoolSpec(poolName, okeMetadataItemToInstall.KubernetesVersion.Original(), nodeShape, 299 expectedNodeCount, memory, ocpus, volumeSize), 300 } 301 } 302 Eventually(func() error { 303 return createClusterAndFillConfig(clusterNameOKEUpgrade, &clusterConfig, t.Logs, mutateFn) 304 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 305 }) 306 307 t.It("check OKE cluster is active with the minimum OKE supported Kubernetes version and related info", func() { 308 // Verify the cluster is active 309 Eventually(func() (bool, error) { return isClusterActive(clusterNameOKEUpgrade, t.Logs) }, waitTimeout, pollingInterval).Should( 310 BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameOKEUpgrade)) 311 // Verify that the cluster is configured correctly 312 Eventually(func() error { 313 return verifyCluster(clusterNameOKEUpgrade, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs) 314 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameOKEUpgrade)) 315 }) 316 317 // Update the cluster 318 t.It("update OKE cluster with the maximum OKE supported Kubernetes version and related info", func() { 319 Eventually(func() error { 320 mutateFn := func(config *RancherOKECluster) { 321 config.OKECAPIEngineConfig.KubernetesVersion = okeMetadataItemToUpgrade.KubernetesVersion.Original() 322 config.OKECAPIEngineConfig.NodePools = []string{ 323 getNodePoolSpec(poolName, okeMetadataItemToUpgrade.KubernetesVersion.Original(), nodeShape, 324 expectedNodeCount, memory, ocpus, volumeSize), 325 } 326 } 327 return updateConfigAndCluster(&clusterConfig, mutateFn, t.Logs) 328 }, shortWaitTimeout, shortPollingInterval).Should(BeNil()) 329 }) 330 331 t.It("check the OKE cluster updated with the maximum OKE supported Kubernetes version and related info", func() { 332 Eventually(func() (bool, error) { return isClusterActive(clusterNameOKEUpgrade, t.Logs) }, waitTimeout, pollingInterval).Should( 333 BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameOKEUpgrade)) 334 Eventually(func() error { 335 return verifyCluster(clusterNameOKEUpgrade, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs) 336 }, waitTimeout, pollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameOKEUpgrade)) 337 }) 338 }) 339 })