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  }