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