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  }