github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/verify-register/verify_register_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 register_test
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"os"
    10  	"time"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	clustersv1alpha1 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1"
    15  	"github.com/verrazzano/verrazzano/application-operator/constants"
    16  	"github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    17  	vmcClient "github.com/verrazzano/verrazzano/cluster-operator/clientset/versioned"
    18  	vzconst "github.com/verrazzano/verrazzano/pkg/constants"
    19  	"github.com/verrazzano/verrazzano/pkg/k8s/resource"
    20  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    21  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    22  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework"
    23  	v1 "k8s.io/api/core/v1"
    24  	"k8s.io/apimachinery/pkg/api/errors"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/client-go/tools/clientcmd"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  )
    30  
    31  const waitTimeout = 10 * time.Minute
    32  const pollingInterval = 10 * time.Second
    33  
    34  const longWaitTimeout = 20 * time.Minute
    35  const longPollingInterval = 30 * time.Second
    36  
    37  const multiclusterNamespace = "verrazzano-mc"
    38  const verrazzanoSystemNamespace = "verrazzano-system"
    39  
    40  var managedClusterName = os.Getenv("MANAGED_CLUSTER_NAME")
    41  var managedKubeconfig = os.Getenv("MANAGED_KUBECONFIG")
    42  var vmiEsIngressURL = getVmiEsIngressURL()
    43  var adminKubeconfig = os.Getenv("ADMIN_KUBECONFIG")
    44  var externalEsURL = pkg.GetExternalOpenSearchURL(adminKubeconfig)
    45  var metricsTest pkg.MetricsTest
    46  
    47  var t = framework.NewTestFramework("register_test")
    48  
    49  var afterSuite = t.AfterSuiteFunc(func() {})
    50  var _ = AfterSuite(afterSuite)
    51  var beforeSuite = t.BeforeSuiteFunc(func() {
    52  	var err error
    53  	metricsTest, err = pkg.NewMetricsTest(adminKubeconfig, map[string]string{}, managedKubeconfig)
    54  	if err != nil {
    55  		AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err))
    56  	}
    57  })
    58  var _ = BeforeSuite(beforeSuite)
    59  var _ = t.AfterEach(func() {})
    60  
    61  var _ = t.Describe("Multi Cluster Verify Register", Label("f:multicluster.register"), func() {
    62  	t.Context("Admin Cluster", func() {
    63  		t.BeforeEach(func() {
    64  			os.Setenv(k8sutil.EnvVarTestKubeConfig, os.Getenv("ADMIN_KUBECONFIG"))
    65  		})
    66  
    67  		t.It("create VerrazzanoProject", func() {
    68  			if minimalVerification {
    69  				Skip("Skipping since not part of minimal verification")
    70  			}
    71  			// create a project
    72  			Eventually(func() error {
    73  				file, err := pkg.FindTestDataFile(fmt.Sprintf("testdata/multicluster/verrazzanoproject-%s.yaml", managedClusterName))
    74  				if err != nil {
    75  					return err
    76  				}
    77  				return resource.CreateOrUpdateResourceFromFile(file, t.Logs)
    78  			}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
    79  
    80  			Eventually(func() (bool, error) {
    81  				return findVerrazzanoProject(fmt.Sprintf("project-%s", managedClusterName))
    82  			}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find VerrazzanoProject")
    83  		})
    84  
    85  		// This test is part of the minimal verification.
    86  		t.It("has the expected VerrazzanoManagedCluster", func() {
    87  			var client *vmcClient.Clientset
    88  			// If registration happened in VZ versions 1.4 and above on admin cluster, check the ManagedCARetrieved condition as well
    89  			adminVersionAtRegistration := os.Getenv("ADMIN_VZ_VERSION_AT_REGISTRATION")
    90  			pkg.Log(pkg.Info, fmt.Sprintf("Admin cluster VZ version at registration is '%s'", adminVersionAtRegistration))
    91  			regVersion14 := false
    92  			var err error
    93  			if adminVersionAtRegistration != "" {
    94  				regVersion14, err = pkg.IsMinVersion(adminVersionAtRegistration, "1.4.0")
    95  				if err != nil {
    96  					Fail(err.Error())
    97  				}
    98  			}
    99  			curAdminVersion14, err := pkg.IsVerrazzanoMinVersion("1.4.0", adminKubeconfig)
   100  			if err != nil {
   101  				Fail(err.Error())
   102  			}
   103  			Eventually(func() (*vmcClient.Clientset, error) {
   104  				kubePath, err := k8sutil.GetKubeConfigLocation()
   105  				if err != nil {
   106  					return nil, err
   107  				}
   108  				client, err = pkg.GetClusterOperatorClientset(kubePath)
   109  				return client, err
   110  			}, waitTimeout, pollingInterval).ShouldNot(BeNil())
   111  			Eventually(func() bool {
   112  				vmc, err := client.ClustersV1alpha1().VerrazzanoManagedClusters(multiclusterNamespace).Get(context.TODO(), managedClusterName, metav1.GetOptions{})
   113  				if vmc.Status.LastAgentConnectTime == nil {
   114  					pkg.Log(pkg.Info, "Last agent connect time is nil")
   115  				} else {
   116  					pkg.Log(pkg.Info, fmt.Sprintf("Last agent connect time: %v", vmc.Status.LastAgentConnectTime))
   117  				}
   118  				return err == nil &&
   119  					vmcStatusCheckOkay(vmc, regVersion14) &&
   120  					vmcRancherStatusCheckOkay(vmc, curAdminVersion14) &&
   121  					vmc.Status.LastAgentConnectTime != nil &&
   122  					vmc.Status.LastAgentConnectTime.After(time.Now().Add(-30*time.Minute))
   123  			}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find VerrazzanoManagedCluster")
   124  		})
   125  
   126  		t.It("has the expected ServiceAccounts", func() {
   127  			if minimalVerification {
   128  				Skip("Skipping since not part of minimal verification")
   129  			}
   130  			pkg.Concurrently(
   131  				func() {
   132  					Eventually(func() (bool, error) {
   133  						return pkg.DoesServiceAccountExist(multiclusterNamespace, fmt.Sprintf("verrazzano-cluster-%s", managedClusterName))
   134  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find ServiceAccount")
   135  				},
   136  			)
   137  		})
   138  
   139  		t.It("no longer has a ClusterRoleBinding for a managed cluster", func() {
   140  			if minimalVerification {
   141  				Skip("Skipping since not part of minimal verification")
   142  			}
   143  			supported, err := pkg.IsVerrazzanoMinVersion("1.1.0", adminKubeconfig)
   144  			if err != nil {
   145  				Fail(err.Error())
   146  			}
   147  			if supported {
   148  				Eventually(func() (bool, error) {
   149  					return pkg.DoesClusterRoleBindingExist(fmt.Sprintf("verrazzano-cluster-%s", managedClusterName))
   150  				}, waitTimeout, pollingInterval).Should(BeFalse(), "Expected not to find ClusterRoleBinding")
   151  			} else {
   152  				pkg.Log(pkg.Info, "Skipping check, Verrazzano minimum version is not V1.1.0")
   153  			}
   154  		})
   155  
   156  		t.It("has a ClusterRoleBinding for a managed cluster", func() {
   157  			if minimalVerification {
   158  				Skip("Skipping since not part of minimal verification")
   159  			}
   160  			supported, err := pkg.IsVerrazzanoMinVersion("1.1.0", adminKubeconfig)
   161  			if err != nil {
   162  				Fail(err.Error())
   163  			}
   164  			if !supported {
   165  				Eventually(func() (bool, error) {
   166  					return pkg.DoesClusterRoleBindingExist(fmt.Sprintf("verrazzano-cluster-%s", managedClusterName))
   167  				}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find ClusterRoleBinding")
   168  			} else {
   169  				pkg.Log(pkg.Info, "Skipping check, Verrazzano minimum version is not less than V1.1.0")
   170  			}
   171  		})
   172  
   173  		t.It("has the expected secrets", func() {
   174  			if minimalVerification {
   175  				Skip("Skipping since not part of minimal verification")
   176  			}
   177  			pkg.Concurrently(
   178  				func() {
   179  					secretName := fmt.Sprintf("verrazzano-cluster-%s-manifest", managedClusterName)
   180  					Eventually(func() bool {
   181  						return findSecret(multiclusterNamespace, secretName)
   182  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find secret "+secretName)
   183  				},
   184  				func() {
   185  					secretName := fmt.Sprintf("verrazzano-cluster-%s-agent", managedClusterName)
   186  					Eventually(func() bool {
   187  						return findSecret(multiclusterNamespace, secretName)
   188  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find secret "+secretName)
   189  				},
   190  				func() {
   191  					secretName := fmt.Sprintf("verrazzano-cluster-%s-registration", managedClusterName)
   192  					Eventually(func() bool {
   193  						return findSecret(multiclusterNamespace, secretName)
   194  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find secret "+secretName)
   195  				},
   196  			)
   197  		})
   198  
   199  		t.It("has the expected system logs from admin and managed cluster", func() {
   200  			if minimalVerification {
   201  				Skip("Skipping since not part of minimal verification")
   202  			}
   203  			if skipLogging {
   204  				Skip("Skipping logging tests for registration")
   205  			}
   206  			verrazzanoIndex, err := pkg.GetOpenSearchSystemIndex("verrazzano-system")
   207  			Expect(err).To(BeNil())
   208  			systemdIndex, err := pkg.GetOpenSearchSystemIndex("systemd-journal")
   209  			Expect(err).To(BeNil())
   210  			pkg.Concurrently(
   211  				func() {
   212  					Eventually(func() bool {
   213  						return pkg.FindLog(verrazzanoIndex,
   214  							[]pkg.Match{
   215  								{Key: "kubernetes.container_name", Value: "verrazzano-application-operator"},
   216  								{Key: "cluster_name.keyword", Value: constants.DefaultClusterName}},
   217  							[]pkg.Match{
   218  								{Key: "cluster_name", Value: managedClusterName}})
   219  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find a systemd log record")
   220  				},
   221  				func() {
   222  					Eventually(func() bool {
   223  						return pkg.FindLog(systemdIndex,
   224  							[]pkg.Match{
   225  								{Key: "tag", Value: "systemd"},
   226  								{Key: "cluster_name.keyword", Value: constants.DefaultClusterName},
   227  								{Key: "SYSTEMD_UNIT", Value: "kubelet.service"}},
   228  							[]pkg.Match{
   229  								{Key: "cluster_name", Value: managedClusterName}})
   230  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find a systemd log record")
   231  				},
   232  				func() {
   233  					Eventually(func() bool {
   234  						return pkg.FindLog(verrazzanoIndex,
   235  							[]pkg.Match{
   236  								{Key: "kubernetes.container_name", Value: "verrazzano-application-operator"},
   237  								{Key: "cluster_name.keyword", Value: managedClusterName}},
   238  							[]pkg.Match{
   239  								{Key: "cluster_name.keyword", Value: constants.DefaultClusterName}})
   240  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find a systemd log record")
   241  				},
   242  				func() {
   243  					Eventually(func() bool {
   244  						return pkg.FindLog(systemdIndex,
   245  							[]pkg.Match{
   246  								{Key: "tag", Value: "systemd"},
   247  								{Key: "cluster_name", Value: managedClusterName},
   248  								{Key: "SYSTEMD_UNIT.keyword", Value: "kubelet.service"}},
   249  							[]pkg.Match{
   250  								{Key: "cluster_name", Value: constants.DefaultClusterName}})
   251  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find a systemd log record")
   252  				},
   253  			)
   254  		})
   255  
   256  		t.It("has the expected metrics from managed cluster", func() {
   257  			if minimalVerification {
   258  				Skip("Skipping since not part of minimal verification")
   259  			}
   260  			clusterNameMetricsLabel := getClusterNameMetricLabel(adminKubeconfig)
   261  			pkg.Log(pkg.Info, fmt.Sprintf("Looking for metric with label %s with value %s", clusterNameMetricsLabel, managedClusterName))
   262  			Eventually(func() (bool, error) {
   263  				return metricsTest.MetricsExist("up", map[string]string{clusterNameMetricsLabel: managedClusterName}), nil
   264  			}, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find metrics from managed cluster")
   265  		})
   266  
   267  		t.It("Fluentd should point to the correct ES", func() {
   268  			if minimalVerification {
   269  				Skip("Skipping since not part of minimal verification")
   270  			}
   271  			if skipLogging {
   272  				Skip("Skipping logging tests for registration")
   273  			}
   274  			supported, err := pkg.IsVerrazzanoMinVersion("1.3.0", adminKubeconfig)
   275  			if err != nil {
   276  				Fail(err.Error())
   277  			}
   278  			if pkg.UseExternalOpensearch() {
   279  				Eventually(func() bool {
   280  					return pkg.AssertFluentdURLAndSecret(externalEsURL, "external-es-secret")
   281  				}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected external ES in admin cluster fluentd Daemonset setting")
   282  			} else {
   283  				var secret string
   284  				if supported {
   285  					secret = pkg.VmiESInternalSecret
   286  				} else {
   287  					secret = pkg.VmiESLegacySecret
   288  				}
   289  				Eventually(func() bool {
   290  					return pkg.AssertFluentdURLAndSecret("", secret)
   291  				}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected VMI ES in admin cluster fluentd Daemonset setting")
   292  			}
   293  		})
   294  	})
   295  
   296  	t.Context("Managed Cluster", func() {
   297  		t.BeforeEach(func() {
   298  			os.Setenv(k8sutil.EnvVarTestKubeConfig, managedKubeconfig)
   299  		})
   300  
   301  		t.It("has the expected secrets", func() {
   302  			if minimalVerification {
   303  				Skip("Skipping since not part of minimal verification")
   304  			}
   305  			pkg.Concurrently(
   306  				func() {
   307  					Eventually(func() bool {
   308  						return findSecret(verrazzanoSystemNamespace, "verrazzano-cluster-agent")
   309  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find secret verrazzano-cluster-agent")
   310  				},
   311  				func() {
   312  					Eventually(func() bool {
   313  						return findSecret(verrazzanoSystemNamespace, "verrazzano-cluster-registration")
   314  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find secret verrazzano-cluster-registration")
   315  					assertRegistrationSecret()
   316  				},
   317  			)
   318  		})
   319  
   320  		t.It("has the expected VerrazzanoProject", func() {
   321  			if minimalVerification {
   322  				Skip("Skipping since not part of minimal verification")
   323  			}
   324  			Eventually(func() (bool, error) {
   325  				return findVerrazzanoProject(fmt.Sprintf("project-%s", managedClusterName))
   326  			}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find VerrazzanoProject")
   327  		})
   328  
   329  		t.It("has the expected namespace", func() {
   330  			if minimalVerification {
   331  				Skip("Skipping since not part of minimal verification")
   332  			}
   333  			Eventually(func() bool {
   334  				return findNamespace(fmt.Sprintf("ns-%s", managedClusterName))
   335  			}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find namespace")
   336  		})
   337  
   338  		t.It("has the expected RoleBindings", func() {
   339  			if minimalVerification {
   340  				Skip("Skipping since not part of minimal verification")
   341  			}
   342  			namespace := fmt.Sprintf("ns-%s", managedClusterName)
   343  			pkg.Concurrently(
   344  				func() {
   345  					Eventually(func() (bool, error) {
   346  						return pkg.DoesRoleBindingContainSubject(namespace, "verrazzano-project-admin", "User", "test-user")
   347  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find role binding verrazzano-project-admin")
   348  				},
   349  				func() {
   350  					Eventually(func() (bool, error) {
   351  						return pkg.DoesRoleBindingContainSubject(namespace, "admin", "User", "test-user")
   352  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find role binding admin")
   353  				},
   354  				func() {
   355  					Eventually(func() (bool, error) {
   356  						return pkg.DoesRoleBindingContainSubject(namespace, "verrazzano-project-monitor", "Group", "test-viewers")
   357  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find role binding verrazzano-project-monitor")
   358  				},
   359  				func() {
   360  					Eventually(func() (bool, error) {
   361  						return pkg.DoesRoleBindingContainSubject(namespace, "view", "Group", "test-viewers")
   362  					}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected to find role binding view")
   363  				},
   364  			)
   365  		})
   366  
   367  		t.It("Fluentd should point to the correct ES", func() {
   368  			if minimalVerification {
   369  				Skip("Skipping since not part of minimal verification")
   370  			}
   371  			if skipLogging {
   372  				Skip("Skipping logging tests for registration")
   373  			}
   374  			if pkg.UseExternalOpensearch() {
   375  				Eventually(func() bool {
   376  					return pkg.AssertFluentdURLAndSecret(externalEsURL, "verrazzano-cluster-registration")
   377  				}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected external ES in managed cluster fluentd Daemonset setting")
   378  			} else {
   379  				Eventually(func() bool {
   380  					return pkg.AssertFluentdURLAndSecret("", "verrazzano-cluster-registration")
   381  				}, waitTimeout, pollingInterval).Should(BeTrue(), "Expected VMI ES  in managed cluster fluentd Daemonset setting")
   382  			}
   383  		})
   384  	})
   385  })
   386  
   387  func vmcRancherStatusCheckOkay(vmc *v1alpha1.VerrazzanoManagedCluster, versionSupportsClusterID bool) bool {
   388  	pkg.Log(pkg.Info, fmt.Sprintf("VMC %s has Rancher status %s and cluster id %s\n",
   389  		vmc.Name, vmc.Status.RancherRegistration.Status, vmc.Status.RancherRegistration.ClusterID))
   390  	clusterIDConditionMet := true
   391  	if versionSupportsClusterID {
   392  		// if this VZ version supports cluster id in rancher reg status, then it should be present
   393  		clusterIDConditionMet = vmc.Status.RancherRegistration.ClusterID != ""
   394  	}
   395  	return vmc.Status.RancherRegistration.Status == v1alpha1.RegistrationCompleted && clusterIDConditionMet
   396  }
   397  
   398  func vmcStatusCheckOkay(vmc *v1alpha1.VerrazzanoManagedCluster, managedCAConditionSupported bool) bool {
   399  	pkg.Log(pkg.Info, fmt.Sprintf("VMC %s has %d status conditions\n", vmc.Name, len(vmc.Status.Conditions)))
   400  	readyConditionMet := false
   401  	managedCAConditionMet := false
   402  	for _, cond := range vmc.Status.Conditions {
   403  		pkg.Log(pkg.Info, fmt.Sprintf("VMC %s has status condition %s with value %s with message %s\n", vmc.Name, cond.Type, cond.Status, cond.Message))
   404  		if cond.Type == v1alpha1.ConditionReady && cond.Status == v1.ConditionTrue {
   405  			readyConditionMet = true
   406  		}
   407  		// If admin cluster VZ version at registration time supports it, check the ManagedCARetrieved condition as well
   408  		if managedCAConditionSupported {
   409  			pkg.Log(pkg.Info, "Checking for ManagedCARetrieved condition")
   410  			if cond.Type == v1alpha1.ConditionManagedCARetrieved && cond.Status == v1.ConditionTrue {
   411  				managedCAConditionMet = true
   412  			}
   413  		} else {
   414  			// In older versions of VZ, no need to check managed CA condition since the condition doesn't exist
   415  			managedCAConditionMet = true
   416  		}
   417  	}
   418  	return readyConditionMet && managedCAConditionMet
   419  }
   420  
   421  func findSecret(namespace, name string) bool {
   422  	s, err := pkg.GetSecret(namespace, name)
   423  	if err != nil {
   424  		pkg.Log(pkg.Error, fmt.Sprintf("Failed to get secret %s in namespace %s with error: %v", name, namespace, err))
   425  		return false
   426  	}
   427  	return s != nil
   428  }
   429  
   430  func findNamespace(namespace string) bool {
   431  	ns, err := pkg.GetNamespace(namespace)
   432  	if err != nil {
   433  		if !errors.IsNotFound(err) {
   434  			pkg.Log(pkg.Error, fmt.Sprintf("Failed to get namespace %s with error: %v", namespace, err))
   435  			return false
   436  		}
   437  		pkg.Log(pkg.Info, fmt.Sprintf("The namespace %q is not found", namespace))
   438  		return false
   439  	}
   440  	labels := ns.GetObjectMeta().GetLabels()
   441  	if labels[vzconst.VerrazzanoManagedLabelKey] != constants.LabelVerrazzanoManagedDefault {
   442  		pkg.Log(pkg.Info, fmt.Sprintf("The namespace %q label %q is set to wrong value of %q", namespace, vzconst.VerrazzanoManagedLabelKey, labels[vzconst.VerrazzanoManagedLabelKey]))
   443  		return false
   444  	}
   445  	if pkg.IsIstioEnabled(managedKubeconfig) && labels[constants.LabelIstioInjection] != constants.LabelIstioInjectionDefault {
   446  		pkg.Log(pkg.Info, fmt.Sprintf("The namespace %q label %q is set to wrong value of %q", namespace, constants.LabelIstioInjection, labels[constants.LabelIstioInjection]))
   447  		return false
   448  	}
   449  	return true
   450  }
   451  
   452  func findVerrazzanoProject(projectName string) (bool, error) {
   453  	config, err := clientcmd.BuildConfigFromFlags("", os.Getenv(k8sutil.EnvVarTestKubeConfig))
   454  	if err != nil {
   455  		pkg.Log(pkg.Info, fmt.Sprintf("Failed to build config from %s with error: %v", os.Getenv(k8sutil.EnvVarTestKubeConfig), err))
   456  		return false, err
   457  	}
   458  
   459  	scheme := runtime.NewScheme()
   460  	_ = clustersv1alpha1.AddToScheme(scheme)
   461  	_ = v1alpha1.AddToScheme(scheme)
   462  
   463  	clustersClient, err := client.New(config, client.Options{Scheme: scheme})
   464  	if err != nil {
   465  		pkg.Log(pkg.Info, fmt.Sprintf("Failed to get clusters client with error: %v", err))
   466  		return false, err
   467  	}
   468  
   469  	projectList := clustersv1alpha1.VerrazzanoProjectList{}
   470  	err = clustersClient.List(context.TODO(), &projectList, &client.ListOptions{Namespace: constants.VerrazzanoMultiClusterNamespace})
   471  	if err != nil {
   472  		pkg.Log(pkg.Error, fmt.Sprintf("Failed to list VerrazzanoProject with error: %v", err))
   473  		return false, err
   474  	}
   475  	for _, item := range projectList.Items {
   476  		if item.Name == projectName && item.Namespace == multiclusterNamespace {
   477  			return true, nil
   478  		}
   479  	}
   480  	return false, nil
   481  }
   482  
   483  func assertRegistrationSecret() {
   484  	regSecret, err := pkg.GetSecret(verrazzanoSystemNamespace, "verrazzano-cluster-registration")
   485  	Expect(err).To(BeNil())
   486  	Expect(regSecret).To(Not(BeNil()))
   487  	if pkg.UseExternalOpensearch() {
   488  		Expect(string(regSecret.Data["es-url"])).To(Equal(externalEsURL))
   489  		esSecret, err := pkg.GetSecretInCluster("verrazzano-system", "external-es-secret", os.Getenv("ADMIN_KUBECONFIG"))
   490  		Expect(err).To(BeNil())
   491  		Expect(regSecret.Data["username"]).To(Equal(esSecret.Data["username"]))
   492  		Expect(regSecret.Data["password"]).To(Equal(esSecret.Data["password"]))
   493  		Expect(regSecret.Data["es-ca-bundle"]).To(Equal(esSecret.Data["ca-bundle"]))
   494  	} else {
   495  		Expect(string(regSecret.Data["es-url"])).To(Equal(vmiEsIngressURL))
   496  		vmiEsInternalSecret, err := pkg.GetSecretInCluster("verrazzano-system", "verrazzano-es-internal", os.Getenv("ADMIN_KUBECONFIG"))
   497  		Expect(err).To(BeNil())
   498  		Expect(regSecret.Data["username"]).To(Equal(vmiEsInternalSecret.Data["username"]))
   499  		Expect(regSecret.Data["password"]).To(Equal(vmiEsInternalSecret.Data["password"]))
   500  	}
   501  }
   502  
   503  func getVmiEsIngressURL() string {
   504  	return fmt.Sprintf("%s:443", pkg.GetSystemOpenSearchIngressURL(adminKubeconfig))
   505  }
   506  
   507  func getClusterNameMetricLabel(kubeconfigPath string) string {
   508  	// ignore error getting the metric label - we'll just use the default value returned
   509  	lbl, err := pkg.GetClusterNameMetricLabel(kubeconfigPath)
   510  	if err != nil {
   511  		pkg.Log(pkg.Error, fmt.Sprintf("Error getting cluster name metric label: %s", err.Error()))
   512  	}
   513  	return lbl
   514  }