github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/examples/helidon/helidon_example_test.go (about) 1 // Copyright (c) 2021, 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 mchelidon 5 6 import ( 7 "fmt" 8 "os" 9 "strconv" 10 "time" 11 12 . "github.com/onsi/ginkgo/v2" 13 . "github.com/onsi/gomega" 14 "github.com/verrazzano/verrazzano/pkg/k8s/resource" 15 "github.com/verrazzano/verrazzano/tests/e2e/multicluster/examples" 16 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 17 dump "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/clusterdump" 18 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 19 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework/metrics" 20 ) 21 22 const ( 23 longPollingInterval = 20 * time.Second 24 longWaitTimeout = 20 * time.Minute 25 pollingInterval = 5 * time.Second 26 waitTimeout = 5 * time.Minute 27 consistentlyDuration = 1 * time.Minute 28 sourceDir = "hello-helidon" 29 testNamespace = "hello-helidon" 30 testProjectName = "hello-helidon" 31 testApp = "hello-helidon" 32 skipVerifications = "Skip Verifications" 33 skipDeletions = "Skip Deletions" 34 ) 35 36 var clusterName = os.Getenv("MANAGED_CLUSTER_NAME") 37 var adminKubeconfig = os.Getenv("ADMIN_KUBECONFIG") 38 var managedKubeconfig = os.Getenv("MANAGED_KUBECONFIG") 39 var metricsTest pkg.MetricsTest 40 41 // failed indicates whether any of the tests has failed 42 var failed = false 43 var beforeSuitePassed = false 44 var t = framework.NewTestFramework("mchelidon") 45 46 var _ = t.AfterEach(func() { 47 // set failed to true if any of the tests has failed 48 failed = failed || CurrentSpecReport().Failed() 49 }) 50 51 // set the kubeconfig to use the admin cluster kubeconfig and deploy the example resources 52 var beforeSuite = t.BeforeSuiteFunc(func() { 53 if !skipDeploy { 54 // deploy the VerrazzanoProject 55 start := time.Now() 56 Eventually(func() error { 57 return examples.DeployHelloHelidonProject(adminKubeconfig, sourceDir) 58 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 59 60 // wait for the namespace to be created on the cluster before deploying app 61 Eventually(func() bool { 62 return examples.HelidonNamespaceExists(adminKubeconfig, sourceDir) 63 }, waitTimeout, pollingInterval).Should(BeTrue()) 64 65 Eventually(func() error { 66 return examples.DeployHelloHelidonApp(adminKubeconfig, sourceDir) 67 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 68 metrics.Emit(t.Metrics.With("deployment_elapsed_time", time.Since(start).Milliseconds())) 69 } 70 71 var err error 72 metricsTest, err = pkg.NewMetricsTest(adminKubeconfig, map[string]string{}, managedKubeconfig) 73 if err != nil { 74 AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err)) 75 } 76 77 beforeSuitePassed = true 78 }) 79 80 var _ = BeforeSuite(beforeSuite) 81 82 var _ = t.Describe("In Multi-cluster, verify hello-helidon", Label("f:multicluster.mc-app-lcm"), func() { 83 t.Context("Admin Cluster", func() { 84 // GIVEN an admin cluster and at least one managed cluster 85 // WHEN the example application has been deployed to the admin cluster 86 // THEN expect that the multi-cluster resources have been created on the admin cluster 87 t.It("Has multi cluster resources", func() { 88 if skipVerify { 89 Skip(skipVerifications) 90 } 91 Eventually(func() bool { 92 return examples.VerifyMCResources(adminKubeconfig, true, false, testNamespace) 93 }, waitTimeout, pollingInterval).Should(BeTrue()) 94 }) 95 // GIVEN an admin cluster 96 // WHEN the multi-cluster example application has been created on admin cluster but not placed there 97 // THEN expect that the app is not deployed to the admin cluster consistently for some length of time 98 t.It("Does not have application placed", func() { 99 if skipVerify { 100 Skip(skipVerifications) 101 } 102 Consistently(func() bool { 103 result, err := examples.VerifyHelloHelidonInCluster(adminKubeconfig, true, false, testProjectName, testNamespace) 104 if err != nil { 105 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 106 } 107 return result 108 }, consistentlyDuration, pollingInterval).Should(BeTrue()) 109 }) 110 }) 111 112 t.Context("Managed Cluster", func() { 113 // GIVEN an admin cluster and at least one managed cluster 114 // WHEN the example application has been deployed to the admin cluster 115 // THEN expect that the multi-cluster resources have been created on the managed cluster 116 t.It("Has multi cluster resources", func() { 117 if skipVerify { 118 Skip(skipVerifications) 119 } 120 Eventually(func() bool { 121 return examples.VerifyMCResources(managedKubeconfig, false, true, testNamespace) 122 }, waitTimeout, pollingInterval).Should(BeTrue()) 123 }) 124 // GIVEN an admin cluster and at least one managed cluster 125 // WHEN the multi-cluster example application has been created on admin cluster and placed in managed cluster 126 // THEN expect that the app is deployed to the managed cluster 127 t.It("Has application placed", func() { 128 if skipVerify { 129 Skip(skipVerifications) 130 } 131 Eventually(func() bool { 132 result, err := examples.VerifyHelloHelidonInCluster(managedKubeconfig, false, true, testProjectName, testNamespace) 133 if err != nil { 134 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 135 } 136 return result 137 }, waitTimeout, pollingInterval).Should(BeTrue()) 138 }) 139 }) 140 141 t.Context("Remaining Managed Clusters", func() { 142 clusterCountStr := os.Getenv("CLUSTER_COUNT") 143 if clusterCountStr == "" { 144 // skip tests 145 return 146 } 147 clusterCount, err := strconv.Atoi(clusterCountStr) 148 if err != nil { 149 // skip tests 150 return 151 } 152 153 kubeconfigDir := os.Getenv("KUBECONFIG_DIR") 154 for i := 3; i <= clusterCount; i++ { 155 kubeconfig := kubeconfigDir + "/" + fmt.Sprintf("%d", i) + "/kube_config" 156 t.It("Does not have multi cluster resources", func() { 157 if skipVerify { 158 Skip(skipVerifications) 159 } 160 Eventually(func() bool { 161 return examples.VerifyMCResources(kubeconfig, false, false, testNamespace) 162 }, waitTimeout, pollingInterval).Should(BeTrue()) 163 }) 164 t.It("Does not have application placed", func() { 165 if skipVerify { 166 Skip(skipVerifications) 167 } 168 Eventually(func() bool { 169 result, err := examples.VerifyHelloHelidonInCluster(kubeconfig, false, false, testProjectName, testNamespace) 170 if err != nil { 171 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 172 } 173 return result 174 }, waitTimeout, pollingInterval).Should(BeTrue()) 175 }) 176 } 177 }) 178 179 t.Context("for Logging", Label("f:observability.logging.es"), func() { 180 indexName, err := pkg.GetOpenSearchAppIndexWithKC(testNamespace, adminKubeconfig) 181 Expect(err).To(BeNil()) 182 // GIVEN an admin cluster and at least one managed cluster 183 // WHEN the example application has been deployed to the admin cluster 184 // THEN expect the Opensearch index for the app exists on the admin cluster Opensearch 185 t.It("Verify Opensearch index exists on admin cluster", func() { 186 if skipVerify { 187 Skip(skipVerifications) 188 } 189 Eventually(func() bool { 190 return pkg.LogIndexFoundInCluster(indexName, adminKubeconfig) 191 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find log index for hello helidon") 192 }) 193 }) 194 195 // GIVEN an admin cluster and at least one managed cluster 196 // WHEN the example application has been deployed to the admin cluster 197 // THEN expect Prometheus metrics for the app to exist in Prometheus on the admin cluster 198 t.Context("for Prometheus Metrics", Label("f:observability.monitoring.prom"), func() { 199 200 t.It("Verify base_jvm_uptime_seconds metrics exist for managed cluster", func() { 201 if skipVerify { 202 Skip(skipVerifications) 203 } 204 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 205 Eventually(func() bool { 206 m := make(map[string]string) 207 m["app"] = testApp 208 m[clusterNameMetricsLabel] = clusterName 209 return metricsTest.MetricsExist("base_jvm_uptime_seconds", m) 210 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find base_jvm_uptime_seconds metric") 211 }) 212 213 t.It("Verify DNE base_jvm_uptime_seconds metrics does not exist for managed cluster", func() { 214 if skipVerify { 215 Skip(skipVerifications) 216 } 217 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 218 Eventually(func() bool { 219 m := make(map[string]string) 220 m["cluster"] = testNamespace 221 m[clusterNameMetricsLabel] = "DNE" 222 return metricsTest.MetricsExist("base_jvm_uptime_seconds", m) 223 }, longWaitTimeout, longPollingInterval).Should(BeFalse(), "Not expected to find base_jvm_uptime_seconds metric") 224 }) 225 226 t.It("Verify vendor_requests_count_total metrics exist for managed cluster", func() { 227 if skipVerify { 228 Skip(skipVerifications) 229 } 230 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 231 Eventually(func() bool { 232 m := make(map[string]string) 233 m["app"] = testApp 234 m[clusterNameMetricsLabel] = clusterName 235 return metricsTest.MetricsExist("vendor_requests_count_total", m) 236 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find vendor_requests_count_total metric") 237 }) 238 239 t.It("Verify container_cpu_cfs_periods_total metrics exist for managed cluster", func() { 240 if skipVerify { 241 Skip(skipVerifications) 242 } 243 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 244 Eventually(func() bool { 245 m := make(map[string]string) 246 m["namespace"] = testNamespace 247 m[clusterNameMetricsLabel] = clusterName 248 return metricsTest.MetricsExist("container_cpu_cfs_periods_total", m) 249 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find container_cpu_cfs_periods_total metric") 250 }) 251 }) 252 253 t.Context("Change Placement of app to Admin Cluster", func() { 254 t.It("Apply patch to change placement to admin cluster", func() { 255 if skipVerify { 256 Skip(skipVerifications) 257 } 258 Eventually(func() error { 259 return examples.ChangePlacementToAdminCluster(adminKubeconfig) 260 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 261 }) 262 263 t.It("MC Resources should be removed from managed cluster", func() { 264 if skipVerify { 265 Skip(skipVerifications) 266 } 267 Eventually(func() bool { 268 // app should not be placed in the managed cluster 269 return examples.VerifyMCResources(managedKubeconfig, false, false, testNamespace) 270 }, waitTimeout, pollingInterval).Should(BeTrue()) 271 }) 272 273 t.It("App should be removed from managed cluster", func() { 274 if skipVerify { 275 Skip(skipVerifications) 276 } 277 Eventually(func() bool { 278 // app should not be placed in the managed cluster 279 result, err := examples.VerifyHelloHelidonInCluster(managedKubeconfig, false, false, testProjectName, testNamespace) 280 if err != nil { 281 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 282 } 283 return result 284 }, waitTimeout, pollingInterval).Should(BeTrue()) 285 }) 286 287 t.It("App should be placed in admin cluster", func() { 288 if skipVerify { 289 Skip(skipVerifications) 290 } 291 Eventually(func() bool { 292 // app should be placed in the admin cluster 293 result, err := examples.VerifyHelloHelidonInCluster(adminKubeconfig, true, true, testProjectName, testProjectName) 294 if err != nil { 295 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 296 } 297 return result 298 }, waitTimeout, pollingInterval).Should(BeTrue()) 299 }) 300 }) 301 302 // Ensure that if we change placement again, back to the original managed cluster, everything functions 303 // as expected. This is needed because the change of placement to admin cluster and the change of placement to 304 // a managed cluster are different, and we want to ensure we test the case where the destination cluster is 305 // each of the 2 types - admin and managed 306 t.Context("Return the app to Managed Cluster", func() { 307 t.It("Apply patch to change placement back to managed cluster", func() { 308 if skipVerify { 309 Skip(skipVerifications) 310 } 311 Eventually(func() error { 312 return examples.ChangePlacementToManagedCluster(adminKubeconfig) 313 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 314 }) 315 316 // GIVEN an admin cluster 317 // WHEN the multi-cluster example application has changed placement from admin back to managed cluster 318 // THEN expect that the app is not deployed to the admin cluster 319 t.It("Admin cluster does not have application placed", func() { 320 if skipVerify { 321 Skip(skipVerifications) 322 } 323 Eventually(func() bool { 324 result, err := examples.VerifyHelloHelidonInCluster(adminKubeconfig, true, false, testProjectName, testNamespace) 325 if err != nil { 326 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 327 } 328 return result 329 }, waitTimeout, pollingInterval).Should(BeTrue()) 330 }) 331 332 // GIVEN a managed cluster 333 // WHEN the multi-cluster example application has changed placement to this managed cluster 334 // THEN expect that the app is now deployed to the cluster 335 t.It("Managed cluster again has application placed", func() { 336 if skipVerify { 337 Skip(skipVerifications) 338 } 339 Eventually(func() bool { 340 result, err := examples.VerifyHelloHelidonInCluster(managedKubeconfig, false, true, testProjectName, testNamespace) 341 if err != nil { 342 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err)) 343 } 344 return result 345 }, waitTimeout, pollingInterval).Should(BeTrue()) 346 }) 347 }) 348 349 t.Context("Delete resources", func() { 350 t.It("Delete resources on admin cluster", func() { 351 if skipUndeploy { 352 Skip(skipDeletions) 353 } 354 Eventually(func() error { 355 return cleanUp(adminKubeconfig) 356 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 357 }) 358 359 t.It("Verify deletion on admin cluster", func() { 360 if skipUndeploy { 361 Skip(skipDeletions) 362 } 363 Eventually(func() bool { 364 return examples.VerifyHelloHelidonDeletedAdminCluster(adminKubeconfig, false, testNamespace, testProjectName) 365 }, waitTimeout, pollingInterval).Should(BeTrue()) 366 }) 367 368 t.It("Verify automatic deletion on managed cluster", func() { 369 if skipUndeploy { 370 Skip(skipDeletions) 371 } 372 Eventually(func() bool { 373 return examples.VerifyHelloHelidonDeletedInManagedCluster(managedKubeconfig, testNamespace, testProjectName) 374 }, waitTimeout, pollingInterval).Should(BeTrue()) 375 }) 376 377 t.It("Delete test namespace on managed cluster", func() { 378 if skipUndeploy { 379 Skip(skipDeletions) 380 } 381 Eventually(func() error { 382 return pkg.DeleteNamespaceInCluster(examples.TestNamespace, managedKubeconfig) 383 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 384 }) 385 386 t.It("Delete test namespace on admin cluster", func() { 387 if skipUndeploy { 388 Skip(skipDeletions) 389 } 390 Eventually(func() error { 391 return pkg.DeleteNamespaceInCluster(examples.TestNamespace, adminKubeconfig) 392 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 393 }) 394 }) 395 }) 396 397 var afterSuite = t.AfterSuiteFunc(func() { 398 if failed || !beforeSuitePassed { 399 dump.ExecuteBugReport(testNamespace) 400 } 401 }) 402 403 var _ = AfterSuite(afterSuite) 404 405 func cleanUp(kubeconfigPath string) error { 406 start := time.Now() 407 file, err := pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/mc-hello-helidon-app.yaml", sourceDir)) 408 if err != nil { 409 return err 410 } 411 if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil { 412 return fmt.Errorf("failed to delete multi-cluster hello-helidon application resource: %v", err) 413 } 414 415 file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/hello-helidon-comp.yaml", sourceDir)) 416 if err != nil { 417 return err 418 } 419 if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil { 420 return fmt.Errorf("failed to delete multi-cluster hello-helidon component resources: %v", err) 421 } 422 423 file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/verrazzano-project.yaml", sourceDir)) 424 if err != nil { 425 return err 426 } 427 if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil { 428 return fmt.Errorf("failed to delete hello-helidon project resource: %v", err) 429 } 430 metrics.Emit(t.Metrics.With("undeployment_elapsed_time", time.Since(start).Milliseconds())) 431 return nil 432 }