github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/workloads/mccoherence/coherence_workload_mc_test.go (about) 1 // Copyright (c) 2022, 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 mccoherence 5 6 import ( 7 "fmt" 8 "net/http" 9 "os" 10 "strconv" 11 "time" 12 13 . "github.com/onsi/ginkgo/v2" 14 . "github.com/onsi/gomega" 15 "github.com/verrazzano/verrazzano/pkg/k8s/resource" 16 "github.com/verrazzano/verrazzano/pkg/k8sutil" 17 "github.com/verrazzano/verrazzano/tests/e2e/multicluster" 18 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 19 dump "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/clusterdump" 20 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 21 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework/metrics" 22 ) 23 24 const ( 25 // wait intervals 26 pollingInterval = 5 * time.Second 27 waitTimeout = 5 * time.Minute 28 shortWaitTimeout = 10 * time.Minute 29 shortPollingInterval = 10 * time.Second 30 consistentlyDuration = 1 * time.Minute 31 longWaitTimeout = 10 * time.Minute 32 longPollingInterval = 20 * time.Second 33 34 // application specific constants 35 helloCoherence = "hello-coherence" 36 appNamespace = "mc-hello-coherence" 37 appConfigName = "hello-appconf" 38 projectName = helloCoherence 39 componentName = helloCoherence 40 41 cohClusterName = "HelloCoherence" 42 podName = "hello-coh-0" 43 containerName = "coherence" 44 appName = "hello-coh" 45 appEndPoint = "catalogue" 46 expectedResponse = "A perfect example of a swivel chair trained calf" 47 48 // metrics 49 jvmUptime = "base_jvm_uptime_seconds" 50 vendorRequestsCount = "vendor_requests_count_total" 51 memUsageBytes = "container_memory_usage_bytes" 52 clusterSize = "vendor:coherence_cluster_size" 53 serviceMessagesLocal = "vendor:coherence_service_messages_local" 54 55 // various labels 56 k8sLabelOAMComp = "kubernetes.labels.app_oam_dev\\/component" 57 k8sLabelOAMCompKeyword = "kubernetes.labels.app_oam_dev\\/component.keyword" 58 k8sLabelOAMApp = "kubernetes.labels.app_oam_dev\\/name" 59 k8sLabelContainerName = "kubernetes.container_name" 60 k8sLabelContainerNameKeyword = "kubernetes.container_name.keyword" 61 k8sLabelCoherenceCluster = "kubernetes.labels.coherenceCluster" 62 k8sPodName = "kubernetes.pod_name" 63 labelApp = "app" 64 labelNS = "namespace" 65 labelCluster = "cluster" 66 skipVerifications = "Skip Verifications" 67 skipDeletions = "Skip Deletions" 68 69 // application resources 70 appConfiguration = "tests/testdata/test-applications/coherence/hello-coherence/hello-coherence-mc-app.yaml" 71 compConfiguration = "tests/testdata/test-applications/coherence/hello-coherence/hello-coherence-comp.yaml" 72 projectConfiguration = "tests/testdata/test-applications/coherence/hello-coherence/verrazzano-project.yaml" 73 ) 74 75 var ( 76 appComp = []string{helloCoherence} 77 appPod = []string{"hello-coh-"} 78 clusterName = os.Getenv("MANAGED_CLUSTER_NAME") 79 adminKubeconfig = os.Getenv("ADMIN_KUBECONFIG") 80 managedKubeconfig = os.Getenv("MANAGED_KUBECONFIG") 81 metricsTest pkg.MetricsTest 82 failed = false 83 beforeSuitePassed = false 84 ) 85 86 var t = framework.NewTestFramework("mccoherence") 87 88 var _ = t.AfterEach(func() { 89 failed = failed || CurrentSpecReport().Failed() 90 }) 91 92 var beforeSuite = t.BeforeSuiteFunc(func() { 93 if !skipDeploy { 94 start := time.Now() 95 96 // deploy the VerrazzanoProject 97 Eventually(func() error { 98 return multicluster.DeployVerrazzanoProject(projectConfiguration, adminKubeconfig) 99 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 100 101 // wait for the namespace to be created on the cluster before deploying app 102 Eventually(func() bool { 103 return multicluster.TestNamespaceExists(adminKubeconfig, appNamespace) 104 }, waitTimeout, pollingInterval).Should(BeTrue()) 105 106 Eventually(func() error { 107 return multicluster.DeployCompResource(compConfiguration, appNamespace, adminKubeconfig) 108 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 109 110 Eventually(func() error { 111 return multicluster.DeployAppResource(appConfiguration, appNamespace, adminKubeconfig) 112 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 113 metrics.Emit(t.Metrics.With("deployment_elapsed_time", time.Since(start).Milliseconds())) 114 } 115 116 var err error 117 metricsTest, err = pkg.NewMetricsTest(adminKubeconfig, map[string]string{}, managedKubeconfig) 118 if err != nil { 119 AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err)) 120 } 121 122 beforeSuitePassed = true 123 }) 124 125 var _ = BeforeSuite(beforeSuite) 126 127 var afterSuite = t.AfterSuiteFunc(func() { 128 if failed || !beforeSuitePassed { 129 err := dump.ExecuteBugReport(appNamespace) 130 if err != nil { 131 return 132 } 133 } 134 }) 135 136 var _ = AfterSuite(afterSuite) 137 138 var _ = t.Describe("In Multi-cluster, verify Coherence application", Label("f:multicluster.mc-app-lcm"), func() { 139 140 t.Context("Admin Cluster", func() { 141 // GIVEN an admin cluster and at least one managed cluster 142 // WHEN the example application has been deployed to the admin cluster 143 // THEN expect that the multi-cluster resources have been created on the admin cluster 144 t.It("Has multi cluster resources", func() { 145 if skipVerify { 146 Skip(skipVerifications) 147 } 148 Eventually(func() bool { 149 return multicluster.VerifyMCResources(adminKubeconfig, true, false, appNamespace, appConfigName, appComp) 150 }, waitTimeout, pollingInterval).Should(BeTrue()) 151 }) 152 153 // GIVEN an admin cluster 154 // WHEN the multi-cluster example application has been created on admin cluster but not placed there 155 // THEN expect that the app is not deployed to the admin cluster consistently for some length of time 156 t.It("Does not have application placed", func() { 157 if skipVerify { 158 Skip(skipVerifications) 159 } 160 Consistently(func() bool { 161 result, err := multicluster.VerifyAppResourcesInCluster(adminKubeconfig, true, false, projectName, appNamespace, appPod) 162 if err != nil { 163 AbortSuite(fmt.Sprintf("Verification of application resources failed for admin cluster, error: %v", err)) 164 } 165 return result 166 }, consistentlyDuration, pollingInterval).Should(BeTrue()) 167 }) 168 }) 169 170 t.Context("Managed Cluster", func() { 171 // GIVEN an admin cluster and at least one managed cluster 172 // WHEN the example application has been deployed to the admin cluster 173 // THEN expect that the multi-cluster resources have been created on the managed cluster 174 t.It("Has multi cluster resources", func() { 175 if skipVerify { 176 Skip(skipVerifications) 177 } 178 Eventually(func() bool { 179 return multicluster.VerifyMCResources(managedKubeconfig, false, true, appNamespace, appConfigName, appComp) 180 }, waitTimeout, pollingInterval).Should(BeTrue()) 181 }) 182 // GIVEN an admin cluster and at least one managed cluster 183 // WHEN the multi-cluster example application has been created on admin cluster and placed in managed cluster 184 // THEN expect that the app is deployed to the managed cluster 185 t.It("Has application placed", func() { 186 if skipVerify { 187 Skip(skipVerifications) 188 } 189 Eventually(func() bool { 190 result, err := multicluster.VerifyAppResourcesInCluster(managedKubeconfig, false, true, projectName, appNamespace, appPod) 191 if err != nil { 192 AbortSuite(fmt.Sprintf("Verification of application resources failed for managed cluster, error: %v", err)) 193 } 194 return result 195 }, longWaitTimeout, longPollingInterval).Should(BeTrue()) 196 }) 197 }) 198 199 t.Context("Remaining Managed Clusters", func() { 200 clusterCountStr := os.Getenv("CLUSTER_COUNT") 201 if clusterCountStr == "" { 202 // skip tests 203 return 204 } 205 clusterCount, err := strconv.Atoi(clusterCountStr) 206 if err != nil { 207 // skip tests 208 return 209 } 210 211 kubeconfigDir := os.Getenv("KUBECONFIG_DIR") 212 for i := 3; i <= clusterCount; i++ { 213 kubeconfig := kubeconfigDir + "/" + fmt.Sprintf("%d", i) + "/kube_config" 214 t.It("Does not have multi cluster resources", func() { 215 if skipVerify { 216 Skip(skipVerifications) 217 } 218 Eventually(func() bool { 219 return multicluster.VerifyMCResources(kubeconfig, false, false, appNamespace, appConfigName, appComp) 220 }, waitTimeout, pollingInterval).Should(BeTrue()) 221 }) 222 t.It("Does not have application placed", func() { 223 if skipVerify { 224 Skip(skipVerifications) 225 } 226 Eventually(func() bool { 227 result, err := multicluster.VerifyAppResourcesInCluster(kubeconfig, false, false, projectName, appNamespace, appPod) 228 if err != nil { 229 AbortSuite(fmt.Sprintf("Verification of application resources failed for the cluster with kubeconfig: %v, error: %v", kubeconfig, err)) 230 } 231 return result 232 }, waitTimeout, pollingInterval).Should(BeTrue()) 233 }) 234 } 235 }) 236 237 t.Context("for Ingress", Label("f:mesh.ingress"), func() { 238 var host = "" 239 var err error 240 // Get the host from the Istio gateway resource. 241 // GIVEN the Istio gateway for the app namespace 242 // WHEN GetHostnameFromGateway is called 243 // THEN return the host name found in the gateway. 244 t.It("Get host from gateway.", func() { 245 if skipVerify { 246 Skip(skipVerifications) 247 } 248 Eventually(func() (string, error) { 249 host, err = k8sutil.GetHostnameFromGatewayInCluster(appNamespace, "", managedKubeconfig) 250 return host, err 251 }, waitTimeout, pollingInterval).Should(Not(BeEmpty())) 252 }) 253 254 // Verify the application REST endpoint is working. 255 // GIVEN the Coherence app is deployed 256 // WHEN the UI is accessed 257 // THEN the expected returned page should contain an expected value. 258 t.It("Verify '/catalogue' endpoint is working.", func() { 259 if skipVerify { 260 Skip(skipVerifications) 261 } 262 Eventually(func() (*pkg.HTTPResponse, error) { 263 url := fmt.Sprintf("https://%s/%s", host, appEndPoint) 264 return pkg.GetWebPageInCluster(url, host, managedKubeconfig) 265 }, waitTimeout, pollingInterval).Should(And(pkg.HasStatus(http.StatusOK), pkg.BodyContains(expectedResponse))) 266 }) 267 }) 268 269 t.Context("for Logging", Label("f:observability.logging.es"), func() { 270 indexName, err := pkg.GetOpenSearchAppIndexWithKC(appNamespace, adminKubeconfig) 271 Expect(err).To(BeNil()) 272 // GIVEN an admin cluster and at least one managed cluster 273 // WHEN the example application has been deployed to the admin cluster 274 // THEN expect the Elasticsearch index for the app exists on the admin cluster Elasticsearch 275 t.It("Verify Elasticsearch index exists on admin cluster", func() { 276 if skipVerify { 277 Skip(skipVerifications) 278 } 279 Eventually(func() bool { 280 return pkg.LogIndexFoundInCluster(indexName, adminKubeconfig) 281 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find log index for Coherence application") 282 }) 283 284 t.It("Verify recent log record exists", func() { 285 if skipVerify { 286 Skip(skipVerifications) 287 } 288 Eventually(func() bool { 289 return pkg.LogRecordFoundInCluster(indexName, time.Now().Add(-24*time.Hour), map[string]string{ 290 k8sLabelOAMComp: componentName, 291 k8sLabelOAMApp: appConfigName, 292 k8sLabelContainerName: componentName, 293 }, adminKubeconfig) 294 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue(), "Expected to find a recent log record") 295 }) 296 297 t.It("Verify recent application log record", func() { 298 if skipVerify { 299 Skip(skipVerifications) 300 } 301 Eventually(func() bool { 302 return pkg.LogRecordFoundInCluster(indexName, time.Now().Add(-24*time.Hour), map[string]string{ 303 k8sLabelCoherenceCluster: cohClusterName, 304 k8sLabelOAMCompKeyword: componentName, 305 k8sPodName: podName, 306 k8sLabelContainerNameKeyword: containerName, 307 }, adminKubeconfig) 308 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue(), "Expected to find a recent log record") 309 }) 310 }) 311 312 t.Context("for Prometheus Metrics", Label("f:observability.monitoring.prom"), func() { 313 // Coherence metric fix available only from 1.3.0 314 if ok, _ := pkg.IsVerrazzanoMinVersion("1.3.0", adminKubeconfig); ok { 315 t.It("Retrieve application Prometheus scraped metrics", func() { 316 if skipVerify { 317 Skip(skipVerifications) 318 } 319 pkg.Concurrently( 320 func() { 321 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 322 Eventually(func() bool { 323 m := make(map[string]string) 324 m[labelApp] = appName 325 m[clusterNameMetricsLabel] = clusterName 326 return metricsTest.MetricsExist(jvmUptime, m) 327 }, longWaitTimeout, longPollingInterval).Should(BeTrue()) 328 }, 329 func() { 330 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 331 Eventually(func() bool { 332 m := make(map[string]string) 333 m[labelApp] = appName 334 m[clusterNameMetricsLabel] = clusterName 335 return metricsTest.MetricsExist(vendorRequestsCount, m) 336 }, longWaitTimeout, longPollingInterval).Should(BeTrue()) 337 }, 338 func() { 339 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 340 Eventually(func() bool { 341 m := make(map[string]string) 342 m[labelNS] = appNamespace 343 m[clusterNameMetricsLabel] = clusterName 344 return metricsTest.MetricsExist(memUsageBytes, m) 345 }, longWaitTimeout, longPollingInterval).Should(BeTrue()) 346 }, 347 func() { 348 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 349 Eventually(func() bool { 350 m := make(map[string]string) 351 m[labelCluster] = cohClusterName 352 m[clusterNameMetricsLabel] = clusterName 353 return metricsTest.MetricsExist(clusterSize, m) 354 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find coherence metric") 355 }, 356 func() { 357 clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig) 358 Eventually(func() bool { 359 m := make(map[string]string) 360 m[labelCluster] = cohClusterName 361 m[clusterNameMetricsLabel] = clusterName 362 return metricsTest.MetricsExist(serviceMessagesLocal, m) 363 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find coherence metric") 364 }, 365 ) 366 }) 367 } 368 }) 369 370 t.Context("Delete resources", func() { 371 t.It("on admin cluster", func() { 372 if skipUndeploy { 373 Skip(skipDeletions) 374 } 375 Eventually(func() error { 376 return cleanUp(adminKubeconfig) 377 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 378 }) 379 380 t.It("Verify deletion on admin cluster", func() { 381 if skipUndeploy { 382 Skip(skipDeletions) 383 } 384 Eventually(func() bool { 385 return multicluster.VerifyDeleteOnAdminCluster(adminKubeconfig, false, appNamespace, projectName, appConfigName, appPod) 386 }, waitTimeout, pollingInterval).Should(BeTrue()) 387 }) 388 389 t.It("Verify automatic deletion on managed cluster", func() { 390 if skipUndeploy { 391 Skip(skipDeletions) 392 } 393 Eventually(func() bool { 394 return multicluster.VerifyDeleteOnManagedCluster(managedKubeconfig, appNamespace, projectName, appConfigName, appPod) 395 }, waitTimeout, pollingInterval).Should(BeTrue()) 396 }) 397 398 t.It("Delete test namespace on managed cluster", func() { 399 if skipUndeploy { 400 Skip(skipDeletions) 401 } 402 Eventually(func() error { 403 return pkg.DeleteNamespaceInCluster(appNamespace, managedKubeconfig) 404 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 405 }) 406 407 t.It("Delete test namespace on admin cluster", func() { 408 if skipUndeploy { 409 Skip(skipDeletions) 410 } 411 Eventually(func() error { 412 return pkg.DeleteNamespaceInCluster(appNamespace, adminKubeconfig) 413 }, waitTimeout, pollingInterval).ShouldNot(HaveOccurred()) 414 }) 415 }) 416 }) 417 418 func cleanUp(kubeconfigPath string) error { 419 start := time.Now() 420 file, err := pkg.FindTestDataFile(appConfiguration) 421 if err != nil { 422 return err 423 } 424 if err := resource.DeleteResourceFromFileInClusterInGeneratedNamespace(file, kubeconfigPath, appNamespace); err != nil { 425 return fmt.Errorf("failed to delete application resource: %v", err) 426 } 427 file, err = pkg.FindTestDataFile(compConfiguration) 428 if err != nil { 429 return err 430 } 431 if err := resource.DeleteResourceFromFileInClusterInGeneratedNamespace(file, kubeconfigPath, appNamespace); err != nil { 432 return fmt.Errorf("failed to delete component resource: %v", err) 433 } 434 435 file, err = pkg.FindTestDataFile(projectConfiguration) 436 if err != nil { 437 return err 438 } 439 if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil { 440 return fmt.Errorf("failed to delete project resource: %v", err) 441 } 442 metrics.Emit(t.Metrics.With("undeployment_elapsed_time", time.Since(start).Milliseconds())) 443 return nil 444 }