github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/quickcreate/quickcreate_test.go (about)

     1  // Copyright (c) 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 quickcreate
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"fmt"
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  	"github.com/pkg/errors"
    13  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    14  	"github.com/verrazzano/verrazzano/tests/e2e/backup/helpers"
    15  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    16  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/update"
    17  	"go.uber.org/zap"
    18  	corev1 "k8s.io/api/core/v1"
    19  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    20  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    21  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    22  	"k8s.io/apimachinery/pkg/runtime"
    23  	"k8s.io/apimachinery/pkg/runtime/schema"
    24  	"k8s.io/client-go/dynamic"
    25  	"k8s.io/client-go/kubernetes"
    26  	"k8s.io/client-go/rest"
    27  	"k8s.io/client-go/tools/clientcmd"
    28  	"os"
    29  	"sigs.k8s.io/cluster-api/api/v1beta1"
    30  	clipkg "sigs.k8s.io/controller-runtime/pkg/client"
    31  	"strings"
    32  	"text/tabwriter"
    33  	"time"
    34  )
    35  
    36  const (
    37  	minimumVersion  = "1.7.0"
    38  	waitTimeOut     = 40 * time.Minute
    39  	pollingInterval = 30 * time.Second
    40  
    41  	shortWaitTimeout            = 15 * time.Minute
    42  	shortPollingInterval        = 60 * time.Second
    43  	vzPollingInterval           = 60 * time.Second
    44  	addonControllerPodNamespace = "verrazzano-capi"
    45  	nodeLabel                   = "node-role.kubernetes.io/node"
    46  	controlPlaneLabel           = "node-role.kubernetes.io/control-plane"
    47  	addonControllerPodLabel     = "cluster.x-k8s.io/provider"
    48  )
    49  
    50  var (
    51  	client              clipkg.Client
    52  	ctx                 *QCContext
    53  	ImagePullSecret     = os.Getenv("IMAGE_PULL_SECRET")
    54  	DockerRepo          = os.Getenv("DOCKER_REPO")
    55  	DockerCredsUser     = os.Getenv("DOCKER_CREDS_USR")
    56  	DockerCredsPassword = os.Getenv("DOCKER_CREDS_PSW")
    57  )
    58  
    59  var beforeSuite = t.BeforeSuiteFunc(func() {
    60  	// Get Kubeconfig information and create clients
    61  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
    62  	Expect(err).To(BeNil())
    63  	cfg, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
    64  	Expect(err).To(BeNil())
    65  	scheme := runtime.NewScheme()
    66  	_ = v1beta1.AddToScheme(scheme)
    67  	_ = corev1.AddToScheme(scheme)
    68  	c, err := clipkg.New(cfg, clipkg.Options{
    69  		Scheme: scheme,
    70  	})
    71  	Expect(err).To(BeNil())
    72  	client = c
    73  
    74  	// Create test context and setup
    75  	ctx, err = newContext(client, clusterType)
    76  	Expect(err).To(BeNil())
    77  	err = ctx.setup()
    78  	Expect(err).To(BeNil())
    79  
    80  	t.Logs.Infof("Creating Cluster of type [%s] - parameters [%s] = namespace [%s] - clustername [%s] - clusternamespace [%s]", ctx.ClusterType, ctx.Parameters, ctx.Namespace, clusterName, clusterNamespace)
    81  	if err != nil {
    82  		t.Fail(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error()))
    83  	}
    84  	supported, err := pkg.IsVerrazzanoMinVersion(minimumVersion, kubeconfigPath)
    85  	if err != nil {
    86  		t.Logs.Errorf("Error getting Verrazzano version: %v", err)
    87  	}
    88  	if !supported {
    89  		t.Logs.Infof("Skipping test because Verrazzano version is less than %s", minimumVersion)
    90  		//return
    91  	}
    92  	createCluster()
    93  	t.Logs.Infof("Wait for 30 seconds before verification")
    94  	time.Sleep(30 * time.Second)
    95  	err = CreateImagePullSecrets(clusterName, t.Logs)
    96  	if err != nil {
    97  		t.Logs.Errorf("Error creating image pull secrets")
    98  	}
    99  })
   100  var afterSuite = t.AfterSuiteFunc(func() {
   101  	if ctx == nil {
   102  		return
   103  	}
   104  	Eventually(func() error {
   105  		err := ctx.cleanupCAPICluster()
   106  		if err != nil {
   107  			t.Logs.Info(err)
   108  		}
   109  		return err
   110  	}).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred())
   111  	Eventually(func() error {
   112  		err := ctx.deleteObject(ctx.namespaceObject())
   113  		if err != nil {
   114  			t.Logs.Info(err)
   115  		}
   116  		return err
   117  	}).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred())
   118  })
   119  var _ = BeforeSuite(beforeSuite)
   120  var _ = AfterSuite(afterSuite)
   121  
   122  func createCluster() {
   123  	err := ctx.applyCluster()
   124  	Expect(err).To(BeNil())
   125  	Eventually(func() error {
   126  		err := ctx.isClusterReady()
   127  		if err != nil {
   128  			t.Logs.Info(err)
   129  		}
   130  		return err
   131  	}).WithPolling(pollingInterval).WithTimeout(waitTimeOut).ShouldNot(HaveOccurred())
   132  }
   133  
   134  // 'It' Wrapper to only run spec if the ClusterAPI is supported on the current Verrazzano version
   135  func WhenClusterAPIInstalledIt(description string, f func()) {
   136  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   137  	if err != nil {
   138  		t.It(description, func() {
   139  			Fail(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error()))
   140  		})
   141  	}
   142  	supported, err := pkg.IsVerrazzanoMinVersion("1.6.0", kubeconfigPath)
   143  	if err != nil {
   144  		t.It(description, func() {
   145  			Fail(fmt.Sprintf("Failed to check Verrazzano version 1.6.0: %s", err.Error()))
   146  		})
   147  	}
   148  	if supported {
   149  		t.It(description, f)
   150  	} else {
   151  		t.Logs.Infof("Skipping check '%v',clusterAPI is not supported", description)
   152  	}
   153  }
   154  
   155  func ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, namespace string, log *zap.SugaredLogger) bool {
   156  	k8sclient, err := getCapiClusterK8sClient(clusterName, log)
   157  	if err != nil {
   158  		t.Logs.Info("Failed to get k8s client for workload cluster")
   159  		return false
   160  	}
   161  	vpo, err := pkg.SpecificPodsRunningInClusterWithClient(namespace, "app=verrazzano-platform-operator", k8sclient)
   162  	if err != nil {
   163  		t.Logs.Error(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err))
   164  	}
   165  	vpoWebhook, err := pkg.SpecificPodsRunningInClusterWithClient(namespace, "app=verrazzano-platform-operator-webhook", k8sclient)
   166  	if err != nil {
   167  		t.Logs.Error(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err))
   168  	}
   169  
   170  	if err != nil {
   171  		log.Errorf("Unable to display resources from workload cluster ", zap.Error(err))
   172  		return false
   173  	}
   174  
   175  	return vpo && vpoWebhook
   176  }
   177  
   178  func getCapiClusterKubeConfig(clusterName string, log *zap.SugaredLogger) ([]byte, error) {
   179  	clientset, err := k8sutil.GetKubernetesClientset()
   180  	if err != nil {
   181  		log.Errorf("Failed to get clientset with error: %v", err)
   182  		return nil, err
   183  	}
   184  
   185  	secret, err := clientset.CoreV1().Secrets(clusterNamespace).Get(context.TODO(), fmt.Sprintf("%s-kubeconfig", clusterName), metav1.GetOptions{})
   186  	if err != nil {
   187  		log.Infof("Error fetching secret ", zap.Error(err))
   188  		return nil, err
   189  	}
   190  
   191  	return secret.Data["value"], nil
   192  }
   193  
   194  func getCapiClusterK8sClient(clusterName string, log *zap.SugaredLogger) (client *kubernetes.Clientset, err error) {
   195  	capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	k8sRestConfig, err := GetRESTConfigGivenString(capiK8sConfig)
   200  	if err != nil {
   201  		return nil, errors.Wrap(err, "Failed to get k8s rest config")
   202  	}
   203  
   204  	return k8sutil.GetKubernetesClientsetWithConfig(k8sRestConfig)
   205  }
   206  
   207  func GetRESTConfigGivenString(kubeconfig []byte) (*rest.Config, error) {
   208  	config, err := clientcmd.RESTConfigFromKubeConfig(kubeconfig)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	setConfigQPSBurst(config)
   213  	return config, nil
   214  }
   215  
   216  func setConfigQPSBurst(config *rest.Config) {
   217  	config.Burst = 150
   218  	config.QPS = 100
   219  }
   220  
   221  func CreateImagePullSecrets(clusterName string, log *zap.SugaredLogger) error {
   222  	log.Infof("Creating image pull secrets on workload cluster ...")
   223  
   224  	capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log)
   225  	if err != nil {
   226  		return err
   227  	}
   228  	tmpFile, err := os.CreateTemp(os.TempDir(), clusterName)
   229  	if err != nil {
   230  		log.Error("Failed to create temporary file ", zap.Error(err))
   231  		return err
   232  	}
   233  
   234  	if err = os.WriteFile(tmpFile.Name(), capiK8sConfig, 0600); err != nil {
   235  		log.Error("failed to write to destination file ", zap.Error(err))
   236  		return err
   237  	}
   238  
   239  	var cmdArgs []string
   240  	var bcmd helpers.BashCommand
   241  	dockerSecretCommand := fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry %s --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), ImagePullSecret, DockerRepo, DockerCredsUser, DockerCredsPassword)
   242  	cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand)
   243  	bcmd.CommandArgs = cmdArgs
   244  	secretCreateResponse := helpers.Runner(&bcmd, log)
   245  	if secretCreateResponse.CommandError != nil {
   246  		return secretCreateResponse.CommandError
   247  	}
   248  
   249  	cmdArgs = []string{}
   250  	dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s  create ns verrazzano-install", tmpFile.Name())
   251  	cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand)
   252  	bcmd.CommandArgs = cmdArgs
   253  	secretCreateResponse = helpers.Runner(&bcmd, log)
   254  	if secretCreateResponse.CommandError != nil {
   255  		return secretCreateResponse.CommandError
   256  	}
   257  
   258  	cmdArgs = []string{}
   259  	dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry %s --docker-server=%s --docker-username=%s --docker-password=%s -n verrazzano-install", tmpFile.Name(), ImagePullSecret, DockerRepo, DockerCredsUser, DockerCredsPassword)
   260  	cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand)
   261  	bcmd.CommandArgs = cmdArgs
   262  	secretCreateResponse = helpers.Runner(&bcmd, log)
   263  	if secretCreateResponse.CommandError != nil {
   264  		return secretCreateResponse.CommandError
   265  	}
   266  
   267  	cmdArgs = []string{}
   268  	dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry github-packages --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), DockerRepo, DockerCredsUser, DockerCredsPassword)
   269  	cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand)
   270  	bcmd.CommandArgs = cmdArgs
   271  	secretCreateResponse = helpers.Runner(&bcmd, log)
   272  	if secretCreateResponse.CommandError != nil {
   273  		return secretCreateResponse.CommandError
   274  	}
   275  
   276  	cmdArgs = []string{}
   277  	dockerSecretCommand = fmt.Sprintf("kubectl --kubeconfig %s create secret docker-registry ocr --docker-server=%s --docker-username=%s --docker-password=%s", tmpFile.Name(), DockerRepo, DockerCredsUser, DockerCredsPassword)
   278  	cmdArgs = append(cmdArgs, "/bin/bash", "-c", dockerSecretCommand)
   279  	bcmd.CommandArgs = cmdArgs
   280  	secretCreateResponse = helpers.Runner(&bcmd, log)
   281  	if secretCreateResponse.CommandError != nil {
   282  		return secretCreateResponse.CommandError
   283  	}
   284  	return nil
   285  }
   286  
   287  func ensureVerrazzano(clusterName string, log *zap.SugaredLogger) error {
   288  
   289  	vzFetched, err := getVerrazzano(clusterName, "default", "verrazzano", log)
   290  	if err != nil {
   291  		log.Errorf("unable to fetch vz resource from %s due to '%v'", clusterName, zap.Error(err))
   292  		return err
   293  	}
   294  	var vz Verrazzano
   295  	modBinaryData, err := json.Marshal(vzFetched)
   296  	if err != nil {
   297  		log.Error("json marshalling error ", zap.Error(err))
   298  		return err
   299  	}
   300  
   301  	err = json.Unmarshal(modBinaryData, &vz)
   302  	if err != nil {
   303  		log.Error("json unmarshalling error ", zap.Error(err))
   304  		return err
   305  	}
   306  
   307  	curState := "InstallStarted"
   308  	for _, cond := range vz.Status.Conditions {
   309  		if cond.Type == "InstallComplete" {
   310  			curState = cond.Type
   311  		}
   312  	}
   313  
   314  	if curState == "InstallComplete" {
   315  		return nil
   316  	}
   317  	return fmt.Errorf("All components are not ready: Current State = %v", curState)
   318  }
   319  
   320  func ensureVerrazzanoFleetBindingExists(clusterName string, log *zap.SugaredLogger) error {
   321  	log.Infof("Wait for 30 seconds before verification")
   322  	time.Sleep(30 * time.Second)
   323  
   324  	vfbFetched, err := getVerrazzanoFleetBinding(log)
   325  	if err != nil {
   326  		log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err))
   327  		return err
   328  	}
   329  	var vfb VerrazzanoFleetBinding
   330  	modBinaryData, err := json.Marshal(vfbFetched)
   331  	if err != nil {
   332  		log.Error("json marshalling error ", zap.Error(err))
   333  		return err
   334  	}
   335  
   336  	err = json.Unmarshal(modBinaryData, &vfb)
   337  	if err != nil {
   338  		log.Error("json unmarshalling error ", zap.Error(err))
   339  		return err
   340  	}
   341  
   342  	curState := "Ready"
   343  	for _, cond := range vfb.Status.Conditions {
   344  		if cond.Type == "Ready" {
   345  			curState = cond.Type
   346  		}
   347  	}
   348  
   349  	if curState == "Ready" {
   350  		return nil
   351  	}
   352  	return fmt.Errorf("All components are not ready: Current State = %v", curState)
   353  }
   354  
   355  func ensureVerrazzanoFleetExists(clusterName string, log *zap.SugaredLogger) error {
   356  	log.Infof("Wait for 30 seconds before verification")
   357  	time.Sleep(30 * time.Second)
   358  
   359  	vfFetched, err := getVerrazzanoFleet(log)
   360  	if err != nil {
   361  		log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err))
   362  		return err
   363  	}
   364  	var vf VerrazzanoFleet
   365  	modBinaryData, err := json.Marshal(vfFetched)
   366  	if err != nil {
   367  		log.Error("json marshalling error ", zap.Error(err))
   368  		return err
   369  	}
   370  
   371  	err = json.Unmarshal(modBinaryData, &vf)
   372  	if err != nil {
   373  		log.Error("json unmarshalling error ", zap.Error(err))
   374  		return err
   375  	}
   376  
   377  	curState := "Ready"
   378  	for _, cond := range vf.Status.Conditions {
   379  		if cond.Type == "Ready" {
   380  			curState = cond.Type
   381  		}
   382  	}
   383  
   384  	if curState == "Ready" {
   385  		return nil
   386  	}
   387  	return fmt.Errorf("VerrazzanoFleet is not ready: Current State = %v", curState)
   388  }
   389  
   390  func createFleetForUnknownCluster(clusterName string, log *zap.SugaredLogger) error {
   391  	dclient, err := k8sutil.GetDynamicClient()
   392  	if err != nil {
   393  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   394  		return err
   395  	}
   396  
   397  	gvr := getVerrazzanoFleetGVR()
   398  	vfFetched, err := getVerrazzanoFleet(log)
   399  	if err != nil {
   400  		log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err))
   401  		return err
   402  	}
   403  	vfDeepCopy := vfFetched.DeepCopy()
   404  	vfDeepCopy.Object["spec"].(map[string]interface{})["clusterSelector"].(map[string]interface{})["name"] = "test-clustername"
   405  	vfDeepCopy.Object["metadata"].(map[string]interface{})["name"] = "new-fleet-name"
   406  	delete(vfDeepCopy.Object["metadata"].(map[string]interface{}), "resourceVersion")
   407  
   408  	_, err = dclient.Resource(gvr).Namespace(clusterNamespace).Create(context.TODO(), vfDeepCopy, metav1.CreateOptions{})
   409  	if err != nil {
   410  		log.Errorf("Unable to create the verrazzanofleet resource", err)
   411  		return err
   412  	}
   413  	return nil
   414  }
   415  
   416  func updateVerrazzanoFleet(clusterName string, log *zap.SugaredLogger) error {
   417  	dclient, err := k8sutil.GetDynamicClient()
   418  	if err != nil {
   419  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   420  		return err
   421  	}
   422  
   423  	gvr := getVerrazzanoFleetGVR()
   424  	vfFetched, err := getVerrazzanoFleet(log)
   425  	if err != nil {
   426  		log.Errorf("unable to fetch verrazzanofleet resource from %s due to '%v'", clusterName, zap.Error(err))
   427  		return err
   428  	}
   429  	if vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"] == nil {
   430  		vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"] = make(map[string]interface{})
   431  	}
   432  	vfFetched.Object["spec"].(map[string]interface{})["verrazzano"].(map[string]interface{})["spec"].(map[string]interface{})["components"].(map[string]interface{})["console"] = map[string]interface{}{"enabled": true}
   433  
   434  	_, err = dclient.Resource(gvr).Namespace(clusterNamespace).Update(context.TODO(), vfFetched, metav1.UpdateOptions{})
   435  	if err != nil {
   436  		log.Errorf("Unable to update the verrazzanofleet resource", err)
   437  		return err
   438  	}
   439  	return nil
   440  }
   441  
   442  func createMultipleFleetForSameCluster(clusterName string, log *zap.SugaredLogger) error {
   443  	dclient, err := k8sutil.GetDynamicClient()
   444  	if err != nil {
   445  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   446  		return err
   447  	}
   448  
   449  	gvr := getVerrazzanoFleetGVR()
   450  	vfFetched, err := getVerrazzanoFleet(log)
   451  	if err != nil {
   452  		log.Errorf("unable to fetch verrazzanofleetbinding resource from %s due to '%v'", clusterName, zap.Error(err))
   453  		return err
   454  	}
   455  	vfDeepCopy := vfFetched.DeepCopy()
   456  	vfDeepCopy.Object["metadata"].(map[string]interface{})["name"] = "duplicate-fleet-name"
   457  	delete(vfDeepCopy.Object["metadata"].(map[string]interface{}), "resourceVersion")
   458  	_, err = dclient.Resource(gvr).Namespace(clusterNamespace).Create(context.TODO(), vfDeepCopy, metav1.CreateOptions{})
   459  	if err != nil {
   460  		log.Errorf("Unable to create the verrazzanofleet resource", err)
   461  		return err
   462  	}
   463  	return nil
   464  }
   465  
   466  func getVerrazzano(clusterName, namespace, vzinstallname string, log *zap.SugaredLogger) (*unstructured.Unstructured, error) {
   467  	dclient, err := getCapiClusterDynamicClient(clusterName, log)
   468  	if err != nil {
   469  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   470  		return nil, err
   471  	}
   472  
   473  	gvr := schema.GroupVersionResource{
   474  		Group:    "install.verrazzano.io",
   475  		Version:  "v1beta1",
   476  		Resource: "verrazzanos",
   477  	}
   478  
   479  	return dclient.Resource(gvr).Namespace(namespace).Get(context.TODO(), vzinstallname, metav1.GetOptions{})
   480  }
   481  
   482  // DisplayWorkloadClusterResources displays the pods of workload OCNE cluster as a formatted table.
   483  func displayWorkloadClusterResources(clusterName string, log *zap.SugaredLogger) error {
   484  	client, err := getCapiClusterK8sClient(clusterName, log)
   485  	if err != nil {
   486  		return errors.Wrap(err, "Failed to get k8s client for workload cluster")
   487  	}
   488  
   489  	log.Infof("----------- Node in workload cluster ---------------------")
   490  	err = showNodeInfo(client, clusterName, log)
   491  	if err != nil {
   492  		return err
   493  	}
   494  
   495  	log.Infof("----------- Pods running on workload cluster ---------------------")
   496  	return showPodInfo(client, clusterName, log)
   497  }
   498  
   499  // ShowPodInfo displays the pods of workload OCNE cluster as a formatted table.
   500  func showPodInfo(client *kubernetes.Clientset, clusterName string, log *zap.SugaredLogger) error {
   501  	nsList, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
   502  	if err != nil {
   503  		return errors.Wrap(err, fmt.Sprintf("failed to get list of namespaces from cluster '%s'", clusterName))
   504  	}
   505  	writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
   506  	fmt.Fprintln(writer, "Name\tNamespace\tStatus\tIP\tNode\tAge")
   507  	//var dnsPod, ccmPod, calicokubePod *v1.Pod
   508  	for _, ns := range nsList.Items {
   509  		podList, err := client.CoreV1().Pods(ns.Name).List(context.TODO(), metav1.ListOptions{})
   510  		if err != nil {
   511  			return errors.Wrap(err, fmt.Sprintf("failed to get list of pods from cluster '%s'", clusterName))
   512  		}
   513  		for _, pod := range podList.Items {
   514  			podData, err := client.CoreV1().Pods(ns.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{})
   515  			if err != nil {
   516  				if apierrors.IsNotFound(err) {
   517  					log.Infof("No pods in namespace '%s'", ns.Name)
   518  				} else {
   519  					return errors.Wrap(err, fmt.Sprintf("failed to get pod '%s' from cluster '%s'", pod.Name, clusterName))
   520  				}
   521  			}
   522  
   523  			fmt.Fprintf(writer, "%v\n", fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v",
   524  				podData.GetName(), podData.GetNamespace(), podData.Status.Phase, podData.Status.PodIP, podData.Spec.NodeName,
   525  				time.Until(podData.GetCreationTimestamp().Time).Abs()))
   526  		}
   527  	}
   528  	writer.Flush()
   529  	return nil
   530  }
   531  
   532  // ShowNodeInfo displays the nodes of workload OCNE cluster as a formatted table.
   533  func showNodeInfo(client *kubernetes.Clientset, clustername string, log *zap.SugaredLogger) error {
   534  	writer := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', tabwriter.AlignRight)
   535  	fmt.Fprintln(writer, "Name\tRole\tVersion\tInternalIP\tExternalIP\tOSImage\tKernelVersion\tContainerRuntime\tAge")
   536  	nodeList, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
   537  	if err != nil {
   538  		return errors.Wrap(err, fmt.Sprintf("failed to get list of nodes from cluster '%s'", clustername))
   539  	}
   540  	for _, node := range nodeList.Items {
   541  		labels := node.GetLabels()
   542  		_, nodeOK := labels[nodeLabel]
   543  		_, controlPlaneOK := labels[nodeLabel]
   544  		var role, internalIP string
   545  		if nodeOK {
   546  			role = strings.Split(nodeLabel, "/")[len(strings.Split(nodeLabel, "/"))-1]
   547  		}
   548  		if controlPlaneOK {
   549  			role = strings.Split(controlPlaneLabel, "/")[len(strings.Split(controlPlaneLabel, "/"))-1]
   550  		}
   551  
   552  		addresses := node.Status.Addresses
   553  		for _, address := range addresses {
   554  			if address.Type == "InternalIP" {
   555  				internalIP = address.Address
   556  				break
   557  			}
   558  		}
   559  		fmt.Fprintf(writer, "%v\n", fmt.Sprintf("%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v\t%v",
   560  			node.GetName(), role, node.Status.NodeInfo.KubeletVersion, internalIP, "None", node.Status.NodeInfo.OSImage, node.Status.NodeInfo.KernelVersion,
   561  			node.Status.NodeInfo.ContainerRuntimeVersion, time.Until(node.GetCreationTimestamp().Time).Abs()))
   562  	}
   563  	writer.Flush()
   564  	return nil
   565  }
   566  
   567  func getVerrazzanoFleetBinding(log *zap.SugaredLogger) (*unstructured.Unstructured, error) {
   568  	dclient, err := k8sutil.GetDynamicClient()
   569  	if err != nil {
   570  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   571  		return nil, err
   572  	}
   573  
   574  	gvr := schema.GroupVersionResource{
   575  		Group:    "addons.cluster.x-k8s.io",
   576  		Version:  "v1alpha1",
   577  		Resource: "verrazzanofleetbindings",
   578  	}
   579  	return dclient.Resource(gvr).Namespace(clusterNamespace).Get(context.TODO(), clusterName, metav1.GetOptions{})
   580  }
   581  
   582  func getVerrazzanoFleet(log *zap.SugaredLogger) (*unstructured.Unstructured, error) {
   583  	dclient, err := k8sutil.GetDynamicClient()
   584  	if err != nil {
   585  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   586  		return nil, err
   587  	}
   588  
   589  	gvr := getVerrazzanoFleetGVR()
   590  	return dclient.Resource(gvr).Namespace(clusterNamespace).Get(context.TODO(), vzFleetName, metav1.GetOptions{})
   591  }
   592  
   593  func getVerrazzanoFleetGVR() schema.GroupVersionResource {
   594  	gvr := schema.GroupVersionResource{
   595  		Group:    "addons.cluster.x-k8s.io",
   596  		Version:  "v1alpha1",
   597  		Resource: "verrazzanofleets",
   598  	}
   599  	return gvr
   600  }
   601  func deleteVerrazzanoFleet(log *zap.SugaredLogger) error {
   602  	dclient, err := k8sutil.GetDynamicClient()
   603  	if err != nil {
   604  		log.Errorf("unable to get workload kubeconfig ", zap.Error(err))
   605  		return err
   606  	}
   607  
   608  	gvr := getVerrazzanoFleetGVR()
   609  
   610  	return dclient.Resource(gvr).Namespace(clusterNamespace).Delete(context.TODO(), vzFleetName, metav1.DeleteOptions{})
   611  }
   612  
   613  func getCapiClusterDynamicClient(clusterName string, log *zap.SugaredLogger) (dynamic.Interface, error) {
   614  
   615  	capiK8sConfig, err := getCapiClusterKubeConfig(clusterName, log)
   616  	if err != nil {
   617  		return nil, err
   618  	}
   619  
   620  	k8sRestConfig, err := GetRESTConfigGivenString(capiK8sConfig)
   621  	if err != nil {
   622  		log.Errorf("failed to obtain k8s rest config : %v", zap.Error(err))
   623  		return nil, err
   624  	}
   625  
   626  	dclient, err := dynamic.NewForConfig(k8sRestConfig)
   627  	if err != nil {
   628  		log.Errorf("unable to create dynamic client for workload cluster %v", zap.Error(err))
   629  		return nil, err
   630  	}
   631  	return dclient, nil
   632  
   633  }
   634  
   635  var _ = t.Describe("addon e2e tests ,", Label("f:addon-provider-verrazzano-e2e-tests"), Serial, func() {
   636  	WhenClusterAPIInstalledIt("Verify  addon controller running", func() {
   637  		update.ValidatePods("verrazzano-fleet", addonControllerPodLabel, addonControllerPodNamespace, 1, false)
   638  	})
   639  	t.Context(fmt.Sprintf("Create VerrazzanoFleet resource  '%s'", clusterName), func() {
   640  		WhenClusterAPIInstalledIt("Create verrrazanoFleet", func() {
   641  			Eventually(func() error {
   642  				return ctx.applyVerrazzanoFleet()
   643  			}, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred(), "Create verrazzanoFleet resource")
   644  		})
   645  		WhenClusterAPIInstalledIt("Verify if VerrazzanoFleetBinding resource created", func() {
   646  			Eventually(func() error {
   647  				return ensureVerrazzanoFleetBindingExists(clusterName, t.Logs)
   648  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil(), "verify VerrazzanoFleetBinding resource")
   649  		})
   650  
   651  		WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() {
   652  			Eventually(func() error {
   653  				return displayWorkloadClusterResources(clusterName, t.Logs)
   654  			}, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster")
   655  		})
   656  
   657  		WhenClusterAPIInstalledIt("Verify VPO on the workload cluster", func() {
   658  			Eventually(func() bool {
   659  				return ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, "verrazzano-install", t.Logs)
   660  			}, shortWaitTimeout, vzPollingInterval).Should(BeTrue(), "verify VPO")
   661  		})
   662  
   663  		WhenClusterAPIInstalledIt("Verify verrazzano CR resource", func() {
   664  			Eventually(func() error {
   665  				return ensureVerrazzano(clusterName, t.Logs)
   666  			}, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify verrazzano resource")
   667  		})
   668  
   669  		WhenClusterAPIInstalledIt("create verrazzanofleet for unknown workload cluster", func() {
   670  			Eventually(func() error {
   671  				return createFleetForUnknownCluster(clusterName, t.Logs)
   672  			}, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "create verrazzanofleet for unknown workload cluster")
   673  		})
   674  
   675  		WhenClusterAPIInstalledIt("verify create multiple verrazzanofleet for the same workload cluster", func() {
   676  			Eventually(func() error {
   677  				return createMultipleFleetForSameCluster(clusterName, t.Logs)
   678  			}, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "verify create multiple verrazzanofleet for the same workload cluster")
   679  		})
   680  
   681  		WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() {
   682  			Eventually(func() error {
   683  				return displayWorkloadClusterResources(clusterName, t.Logs)
   684  			}, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster")
   685  		})
   686  
   687  		WhenClusterAPIInstalledIt("verify update verrazzano spec in verrazzanofleet", func() {
   688  			Eventually(func() error {
   689  				return updateVerrazzanoFleet(clusterName, t.Logs)
   690  			}, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify update verrazzano spec in verrazzanofleet")
   691  		})
   692  
   693  		WhenClusterAPIInstalledIt("Verify update to verrazzano CR resource ", func() {
   694  			Eventually(func() error {
   695  				return ensureVerrazzano(clusterName, t.Logs)
   696  			}, waitTimeOut, vzPollingInterval).Should(BeNil(), "verify update to verrazzano resource")
   697  		})
   698  
   699  		WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() {
   700  			Eventually(func() error {
   701  				return displayWorkloadClusterResources(clusterName, t.Logs)
   702  			}, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster")
   703  		})
   704  
   705  		WhenClusterAPIInstalledIt("Delete VerrazzanoFleet from admin cluster", func() {
   706  			Eventually(func() error {
   707  				return deleteVerrazzanoFleet(t.Logs)
   708  			}, shortWaitTimeout, pollingInterval).Should(BeNil(), "Delete VerrazzanoFleet resource from admin cluster")
   709  		})
   710  
   711  		WhenClusterAPIInstalledIt("Verify VerrazzanoFleet resource does not exist on adminc luster", func() {
   712  			Eventually(func() error {
   713  				return ensureVerrazzanoFleetExists(clusterName, t.Logs)
   714  			}, shortWaitTimeout, shortPollingInterval).Should(HaveOccurred(), "verify VerrazzanoFleetBinding resource does not exist on admin cluster")
   715  		})
   716  
   717  		WhenClusterAPIInstalledIt("Verify VerrazzanoFleetBinding resource does not exist on admin cluster", func() {
   718  			Eventually(func() error {
   719  				return ensureVerrazzanoFleetBindingExists(clusterName, t.Logs)
   720  			}, shortWaitTimeout, shortPollingInterval).Should(HaveOccurred(), "verify VerrazzanoFleetBinding resource does not exist on admin cluster")
   721  		})
   722  
   723  		WhenClusterAPIInstalledIt("Verify VPO does not exist on the workload cluster", func() {
   724  			Eventually(func() bool {
   725  				return ensureVPOPodsAreRunningOnWorkloadCluster(clusterName, "verrazzano-install", t.Logs)
   726  			}, shortWaitTimeout, vzPollingInterval).Should(BeFalse(), "verify VPO does not exist")
   727  		})
   728  
   729  		WhenClusterAPIInstalledIt("Verify verrazzano CR resource on workload cluster after deleting VerrazzanoFleet resource", func() {
   730  			Eventually(func() error {
   731  				return ensureVerrazzano(clusterName, t.Logs)
   732  			}, waitTimeOut, vzPollingInterval).Should(HaveOccurred(), "verify verrazzano resource on workload cluster after deleting VerrazzanoFleet resource")
   733  		})
   734  
   735  		WhenClusterAPIInstalledIt("Display objects from CAPI workload cluster", func() {
   736  			Eventually(func() error {
   737  				return displayWorkloadClusterResources(clusterName, t.Logs)
   738  			}, shortWaitTimeout, pollingInterval).Should(BeNil(), "Display objects from CAPI workload cluster")
   739  		})
   740  	})
   741  })