github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/pkg/kubernetes.go (about)

     1  // Copyright (c) 2020, 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 pkg
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"net/http"
    12  	"os"
    13  	"strings"
    14  	"time"
    15  
    16  	certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
    17  	"github.com/google/uuid"
    18  	"github.com/onsi/gomega"
    19  	vaoClient "github.com/verrazzano/verrazzano/application-operator/clientset/versioned"
    20  	vcoClient "github.com/verrazzano/verrazzano/cluster-operator/clientset/versioned"
    21  	"github.com/verrazzano/verrazzano/pkg/k8s/verrazzano"
    22  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    23  	"github.com/verrazzano/verrazzano/pkg/semver"
    24  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    25  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    26  	vpoClient "github.com/verrazzano/verrazzano/platform-operator/clientset/versioned"
    27  	istionetv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
    28  	appsv1 "k8s.io/api/apps/v1"
    29  	v1 "k8s.io/api/authorization/v1"
    30  	corev1 "k8s.io/api/core/v1"
    31  	netv1 "k8s.io/api/networking/v1"
    32  	rbacv1 "k8s.io/api/rbac/v1"
    33  	apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    34  	apiextv1 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/typed/apiextensions/v1"
    35  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    36  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    37  	"k8s.io/apimachinery/pkg/labels"
    38  	"k8s.io/apimachinery/pkg/runtime"
    39  	"k8s.io/apimachinery/pkg/types"
    40  	"k8s.io/apimachinery/pkg/util/wait"
    41  	"k8s.io/client-go/dynamic"
    42  	"k8s.io/client-go/kubernetes"
    43  	"k8s.io/client-go/kubernetes/scheme"
    44  	restclient "k8s.io/client-go/rest"
    45  	"k8s.io/client-go/tools/clientcmd"
    46  	clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
    47  	"k8s.io/client-go/tools/remotecommand"
    48  	"sigs.k8s.io/controller-runtime/pkg/client"
    49  )
    50  
    51  const (
    52  	dockerconfigjsonTemplate string = "{\"auths\":{\"%v\":{\"username\":\"%v\",\"password\":\"%v\",\"auth\":\"%v\"}}}"
    53  	verrazzanoErrorTemplate         = "Error Verrazzano Resource: %v"
    54  )
    55  
    56  // DoesCRDExist returns whether a CRD with the given name exists for the cluster
    57  func DoesCRDExist(crdName string) (bool, error) {
    58  	crds, err := ListCRDs()
    59  	if err != nil {
    60  		return false, err
    61  	}
    62  
    63  	for i := range crds.Items {
    64  		if strings.Compare(crds.Items[i].ObjectMeta.Name, crdName) == 0 {
    65  			return true, nil
    66  		}
    67  	}
    68  
    69  	return false, nil
    70  }
    71  
    72  // DoesNamespaceExist returns whether a namespace with the given name exists for the cluster set in the environment
    73  func DoesNamespaceExist(name string) (bool, error) {
    74  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
    75  	if err != nil {
    76  		Log(Error, fmt.Sprintf("Failed getting kubeconfig: %v", err))
    77  		return false, err
    78  	}
    79  
    80  	return DoesNamespaceExistInCluster(name, kubeconfigPath)
    81  }
    82  
    83  // DoesNamespaceExistInCluster returns whether a namespace with the given name exists in the specified cluster
    84  func DoesNamespaceExistInCluster(name string, kubeconfigPath string) (bool, error) {
    85  	// Get the Kubernetes clientset
    86  	clientset, err := GetKubernetesClientsetForCluster(kubeconfigPath)
    87  	if err != nil {
    88  		return false, err
    89  	}
    90  
    91  	namespace, err := clientset.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
    92  	if err != nil && !k8serrors.IsNotFound(err) {
    93  		Log(Error, fmt.Sprintf("Failed to get namespace %s: %v", name, err))
    94  		return false, err
    95  	}
    96  
    97  	return namespace != nil && len(namespace.Name) > 0, nil
    98  }
    99  
   100  // ListCRDs returns the list of CRDs in a cluster
   101  func ListCRDs() (*apiext.CustomResourceDefinitionList, error) {
   102  	// use the current context in the kubeconfig
   103  	config, err := k8sutil.GetKubeConfig()
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	apixClient, err := apiextv1.NewForConfig(config)
   108  	if err != nil {
   109  		Log(Error, "Could not get apix client")
   110  		return nil, err
   111  	}
   112  
   113  	crds, err := apixClient.CustomResourceDefinitions().List(context.TODO(), metav1.ListOptions{})
   114  	if err != nil {
   115  		Log(Error, fmt.Sprintf("Failed to list CRDS: %v", err))
   116  		return nil, err
   117  	}
   118  
   119  	return crds, nil
   120  }
   121  
   122  // ListNamespaces returns a namespace list for the given list options
   123  func ListNamespaces(opts metav1.ListOptions) (*corev1.NamespaceList, error) {
   124  	client, err := k8sutil.GetKubernetesClientset()
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  	return client.CoreV1().Namespaces().List(context.TODO(), opts)
   129  }
   130  
   131  // ListPods returns a pod list for the given namespace and list options
   132  func ListPods(namespace string, opts metav1.ListOptions) (*corev1.PodList, error) {
   133  	client, err := k8sutil.GetKubernetesClientset()
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  	return client.CoreV1().Pods(namespace).List(context.TODO(), opts)
   138  }
   139  
   140  // ListDeployments returns the list of deployments in a given namespace for the cluster
   141  func ListDeployments(namespace string) (*appsv1.DeploymentList, error) {
   142  	// Get the Kubernetes clientset
   143  	clientset, err := k8sutil.GetKubernetesClientset()
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	deployments, err := clientset.AppsV1().Deployments(namespace).List(context.TODO(), metav1.ListOptions{})
   149  	if err != nil {
   150  		Log(Error, fmt.Sprintf("Failed to list deployments in namespace %s: %v", namespace, err))
   151  		return nil, err
   152  	}
   153  	return deployments, nil
   154  }
   155  
   156  // ListStatefulSets returns the list of StatefulSets in a given namespace for the cluster
   157  func ListStatefulSets(namespace string) (*appsv1.StatefulSetList, error) {
   158  	// Get the Kubernetes clientset
   159  	clientset, err := k8sutil.GetKubernetesClientset()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	statefulsets, err := clientset.AppsV1().StatefulSets(namespace).List(context.TODO(), metav1.ListOptions{})
   165  	if err != nil {
   166  		Log(Error, fmt.Sprintf("Failed to list StatefulSets in namespace %s: %v", namespace, err))
   167  		return nil, err
   168  	}
   169  	return statefulsets, nil
   170  }
   171  
   172  // GetReplicaCounts Builds a map of pod counts for a list of deployments
   173  // expectedDeployments - a list of namespaced names for deployments to look for
   174  // optsBuilder - a callback func to build the right set of options to select pods for the deployment
   175  func GetReplicaCounts(expectedDeployments []types.NamespacedName, optsBuilder func(name types.NamespacedName) (metav1.ListOptions, error)) (map[string]uint32, error) {
   176  	podCountsMap := map[string]uint32{}
   177  	for _, deployment := range expectedDeployments {
   178  		listOpts, err := optsBuilder(deployment)
   179  		if err != nil {
   180  			return map[string]uint32{}, err
   181  		}
   182  		podList, err := ListPods(deployment.Namespace, listOpts)
   183  		if err != nil {
   184  			return map[string]uint32{}, err
   185  		}
   186  		podCountsMap[deployment.String()] = uint32(len(podList.Items))
   187  	}
   188  	return podCountsMap, nil
   189  }
   190  
   191  // DoesDeploymentExist returns whether a deployment with the given name and namespace exists for the cluster
   192  func DoesDeploymentExist(namespace string, name string) (bool, error) {
   193  	deployments, err := ListDeployments(namespace)
   194  	if err != nil {
   195  		Log(Error, fmt.Sprintf("Failed listing deployments in cluster for namespace %s: %v", namespace, err))
   196  		return false, err
   197  	}
   198  	for i := range deployments.Items {
   199  		if strings.HasPrefix(deployments.Items[i].Name, name) {
   200  			return true, nil
   201  		}
   202  	}
   203  	return false, nil
   204  }
   205  
   206  // GetDeployment returns a deployment with the given name and namespace
   207  func GetDeployment(namespace string, deploymentName string) (*appsv1.Deployment, error) {
   208  	// Get the Kubernetes clientset
   209  	clientSet, err := k8sutil.GetKubernetesClientset()
   210  	if err != nil {
   211  		return nil, err
   212  	}
   213  	deployment, err := clientSet.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
   214  	if err != nil {
   215  		if !k8serrors.IsNotFound(err) {
   216  			Log(Error, fmt.Sprintf("Failed to get Deployment %s from namespace %s: %v ", deploymentName, namespace, err))
   217  		}
   218  		return nil, err
   219  	}
   220  	return deployment, nil
   221  }
   222  
   223  // DoesStatefulSetExist returns whether a StatefulSet with the given name and namespace exists for the cluster
   224  func DoesStatefulSetExist(namespace string, name string) (bool, error) {
   225  	statefulsets, err := ListStatefulSets(namespace)
   226  	if err != nil {
   227  		Log(Error, fmt.Sprintf("Failed to list StatefulSets from namespace %s: %v", namespace, err))
   228  		return false, err
   229  	}
   230  	for i := range statefulsets.Items {
   231  		if strings.HasPrefix(statefulsets.Items[i].Name, name) {
   232  			return true, nil
   233  		}
   234  	}
   235  	return false, nil
   236  }
   237  
   238  // GetStatefulSet returns a StatefulSet with the given name and namespace
   239  func GetStatefulSet(namespace string, stsName string) (*appsv1.StatefulSet, error) {
   240  	// Get the Kubernetes clientset
   241  	clientSet, err := k8sutil.GetKubernetesClientset()
   242  	if err != nil {
   243  		return nil, err
   244  	}
   245  	sts, err := clientSet.AppsV1().StatefulSets(namespace).Get(context.TODO(), stsName, metav1.GetOptions{})
   246  	if err != nil {
   247  		if !k8serrors.IsNotFound(err) {
   248  			Log(Error, fmt.Sprintf("Failed to get StatefulSet %s from namespace %s: %v ", stsName, namespace, err))
   249  		}
   250  		return nil, err
   251  	}
   252  	return sts, nil
   253  }
   254  
   255  // GetDaemonSet returns a GetDaemonSet with the given name and namespace
   256  func GetDaemonSet(namespace string, daemonSetName string) (*appsv1.DaemonSet, error) {
   257  	// Get the Kubernetes clientset
   258  	clientSet, err := k8sutil.GetKubernetesClientset()
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	daemonset, err := clientSet.AppsV1().DaemonSets(namespace).Get(context.TODO(), daemonSetName, metav1.GetOptions{})
   263  	if err != nil {
   264  		if !k8serrors.IsNotFound(err) {
   265  			Log(Error, fmt.Sprintf("Failed to get DaemonSet %s from namespace %s: %v ", daemonSetName, namespace, err))
   266  		}
   267  		return nil, err
   268  	}
   269  	return daemonset, nil
   270  }
   271  
   272  // GetService returns a Service with the given name and namespace
   273  func GetService(namespace string, serviceName string) (*corev1.Service, error) {
   274  	// Get the Kubernetes clientset
   275  	clientSet, err := k8sutil.GetKubernetesClientset()
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	svc, err := clientSet.CoreV1().Services(namespace).Get(context.TODO(), serviceName, metav1.GetOptions{})
   280  	if err != nil {
   281  		if !k8serrors.IsNotFound(err) {
   282  			Log(Error, fmt.Sprintf("Failed to get Service %s from namespace %s: %v ", serviceName, namespace, err))
   283  		}
   284  		return nil, err
   285  	}
   286  	return svc, nil
   287  }
   288  
   289  // DoesServiceExist returns whether a Service with the given name and namespace exists for the cluster
   290  func DoesServiceExist(namespace string, name string) (bool, error) {
   291  	_, err := GetService(namespace, name)
   292  	if err != nil {
   293  		return false, err
   294  	}
   295  	return true, nil
   296  }
   297  
   298  // GetIngressList returns a list of ingresses in the given namespace
   299  func GetIngressList(namespace string) (*netv1.IngressList, error) {
   300  	// Get the Kubernetes clientset
   301  	clientSet, err := k8sutil.GetKubernetesClientset()
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  	ingressList, err := clientSet.NetworkingV1().Ingresses(namespace).List(context.TODO(), metav1.ListOptions{})
   306  	if err != nil {
   307  		if !k8serrors.IsNotFound(err) {
   308  			Log(Error, fmt.Sprintf("Failed to get Ingresses in namespace %s: %v ", namespace, err))
   309  		}
   310  		return nil, err
   311  	}
   312  	return ingressList, nil
   313  }
   314  
   315  // GetIngress returns the ingress given a namespace and ingress name
   316  func GetIngress(namespace string, ingressName string) (*netv1.Ingress, error) {
   317  	// Get the Kubernetes clientset
   318  	clientSet, err := k8sutil.GetKubernetesClientset()
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	ingress, err := clientSet.NetworkingV1().Ingresses(namespace).Get(context.TODO(), ingressName, metav1.GetOptions{})
   323  	if err != nil {
   324  		if !k8serrors.IsNotFound(err) {
   325  			Log(Error, fmt.Sprintf("Failed to get Ingress %s in namespace %s: %v ", ingressName, namespace, err))
   326  		}
   327  		return nil, err
   328  	}
   329  	return ingress, nil
   330  }
   331  
   332  // DoesVirtualServiceExist returns whether a VirtualService with the given name and namespace exists for the cluster
   333  func DoesVirtualServiceExist(namespace string, name string) (bool, error) {
   334  	services, err := GetVirtualServiceList(namespace)
   335  	if err != nil {
   336  		Log(Error, fmt.Sprintf("Failed to list VirtualServices from namespace %s: %v", namespace, err))
   337  		return false, err
   338  	}
   339  
   340  	// Verify that the virtual services contain the expected environment name
   341  	for _, virtualService := range services.Items {
   342  		service := virtualService.Name
   343  		if strings.Contains(service, name) {
   344  			return true, nil
   345  		}
   346  	}
   347  	return false, nil
   348  }
   349  
   350  // GetVirtualServiceList returns a list of virtual services in the given namespace
   351  func GetVirtualServiceList(namespace string) (*istionetv1beta1.VirtualServiceList, error) {
   352  	// Get the Istio clientset
   353  	clientSet, err := k8sutil.GetIstioClientset()
   354  	if err != nil {
   355  		return nil, err
   356  	}
   357  	VirtualServiceList, err := clientSet.NetworkingV1beta1().VirtualServices(namespace).List(context.TODO(), metav1.ListOptions{})
   358  	if err != nil {
   359  		if !k8serrors.IsNotFound(err) {
   360  			Log(Error, fmt.Sprintf("Failed to get Gateways in namespace %s: %v ", namespace, err))
   361  		}
   362  		return nil, err
   363  	}
   364  	return VirtualServiceList, nil
   365  }
   366  
   367  // DoesSecretExist returns whether a Secret with the given name and namespace exists for the cluster
   368  func DoesSecretExist(namespace string, name string) (bool, error) {
   369  	secrets, err := ListSecrets(namespace)
   370  	if err != nil {
   371  		Log(Error, fmt.Sprintf("Failed to list Secrets from namespace %s: %v", namespace, err))
   372  		return false, err
   373  	}
   374  	for i := range secrets.Items {
   375  		if strings.HasPrefix(secrets.Items[i].Name, name) {
   376  			return true, nil
   377  		}
   378  	}
   379  	return false, nil
   380  }
   381  
   382  // GetCertificateList returns a list of certificates in the given namespace
   383  func GetCertificateList(namespace string) (*certmanagerv1.CertificateList, error) {
   384  	// Get the Cert-manager clientset
   385  	clientSet, err := k8sutil.GetCertManagerClienset()
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  	certificateList, err := clientSet.Certificates(namespace).List(context.TODO(), metav1.ListOptions{})
   390  	if err != nil {
   391  		if !k8serrors.IsNotFound(err) {
   392  			Log(Error, fmt.Sprintf("Failed to get Certificates in namespace %s: %v ", namespace, err))
   393  		}
   394  		return nil, err
   395  	}
   396  	return certificateList, nil
   397  }
   398  
   399  // GetIssuerList returns a list of cluster issuers
   400  func GetIssuerList(namespace string) (*certmanagerv1.IssuerList, error) {
   401  	// Get the Cert-manager clientset
   402  	clientSet, err := k8sutil.GetCertManagerClienset()
   403  	if err != nil {
   404  		return nil, err
   405  	}
   406  	issuerList, err := clientSet.Issuers(namespace).List(context.TODO(), metav1.ListOptions{})
   407  	if err != nil {
   408  		if !k8serrors.IsNotFound(err) {
   409  			Log(Error, fmt.Sprintf("Failed to get Issuers in namespace %s: %v ", namespace, err))
   410  		}
   411  		return nil, err
   412  	}
   413  	return issuerList, nil
   414  }
   415  
   416  // ListNodes returns the list of nodes for the cluster
   417  func ListNodes() (*corev1.NodeList, error) {
   418  	// Get the Kubernetes clientset
   419  	clientset, err := k8sutil.GetKubernetesClientset()
   420  	if err != nil {
   421  		return nil, err
   422  	}
   423  
   424  	nodes, err := clientset.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
   425  	if err != nil {
   426  		Log(Error, fmt.Sprintf("Failed to list nodes: %v", err))
   427  		return nil, err
   428  	}
   429  	return nodes, nil
   430  }
   431  
   432  // GetNodeCount returns the number of nodes for the cluster
   433  func GetNodeCount() (uint32, error) {
   434  	nodes, err := ListNodes()
   435  	if err != nil {
   436  		return 0, err
   437  	}
   438  	if len(nodes.Items) < 1 {
   439  		return 0, fmt.Errorf("can not find node in the cluster")
   440  	}
   441  	return uint32(len(nodes.Items)), nil
   442  }
   443  
   444  // GetSchedulableNodeCount returns the number of schedulabe nodes in the cluster
   445  func GetSchedulableNodeCount() (uint32, error) {
   446  	nodes, err := ListNodes()
   447  	if err != nil {
   448  		return 0, err
   449  	}
   450  	nodeCount := 0
   451  	for _, node := range nodes.Items {
   452  		if NodeIsSchedulable(node) {
   453  			nodeCount++
   454  		}
   455  	}
   456  	if nodeCount < 1 {
   457  		return 0, fmt.Errorf("can not find node in the cluster")
   458  	}
   459  	return uint32(nodeCount), nil
   460  }
   461  
   462  // NodeIsSchedulable returns false if a node has the control-plane/master taint and is unschedulable, true otherwise
   463  func NodeIsSchedulable(node corev1.Node) bool {
   464  	for _, taint := range node.Spec.Taints {
   465  		switch taint.Key {
   466  		case "node-role.kubernetes.io/control-plane":
   467  		case "node-role.kubernetes.io/master":
   468  			if taint.Effect == corev1.TaintEffectNoSchedule {
   469  				return false
   470  			}
   471  		}
   472  	}
   473  	return true
   474  }
   475  
   476  // GetPodsFromSelector returns a collection of pods for the given namespace and selector
   477  func GetPodsFromSelector(selector *metav1.LabelSelector, namespace string) ([]corev1.Pod, error) {
   478  	var pods *corev1.PodList
   479  	var err error
   480  	if selector == nil {
   481  		pods, err = ListPods(namespace, metav1.ListOptions{})
   482  	} else {
   483  		var labelMap map[string]string
   484  		labelMap, err = metav1.LabelSelectorAsMap(selector)
   485  		if err == nil {
   486  			pods, err = ListPods(namespace, metav1.ListOptions{LabelSelector: labels.SelectorFromSet(labelMap).String()})
   487  		}
   488  	}
   489  	if err != nil {
   490  		return nil, err
   491  	}
   492  	return pods.Items, nil
   493  }
   494  
   495  // ListPodsInCluster returns the list of pods in a given namespace for the cluster
   496  func ListPodsInCluster(namespace string, clientset *kubernetes.Clientset) (*corev1.PodList, error) {
   497  	return clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{})
   498  }
   499  
   500  // ListPodsWithLabelsInCluster returns the list of pods in a given namespace that matches a specific label for the cluster
   501  func ListPodsWithLabelsInCluster(namespace, labels string, clientset *kubernetes.Clientset) (*corev1.PodList, error) {
   502  	return clientset.CoreV1().Pods(namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: labels})
   503  }
   504  
   505  // DoesPodExist returns whether a pod with the given name and namespace exists for the cluster
   506  func DoesPodExist(namespace string, name string) (bool, error) {
   507  	clientset, err := k8sutil.GetKubernetesClientset()
   508  	if err != nil {
   509  		return false, err
   510  	}
   511  	pods, err := ListPodsInCluster(namespace, clientset)
   512  	if err != nil {
   513  		Log(Error, fmt.Sprintf("Failed listing pods in cluster for namespace: %s: %v", namespace, err))
   514  		return false, err
   515  	}
   516  	for i := range pods.Items {
   517  		if strings.HasPrefix(pods.Items[i].Name, name) {
   518  			return true, nil
   519  		}
   520  	}
   521  	return false, nil
   522  }
   523  
   524  // GetKubernetesClientsetForCluster returns the Kubernetes clientset for the cluster whose
   525  // kubeconfig path is specified
   526  func GetKubernetesClientsetForCluster(kubeconfigPath string) (*kubernetes.Clientset, error) {
   527  	// use the current context in the kubeconfig
   528  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   529  	if err != nil {
   530  		return nil, err
   531  	}
   532  	return createClientset(config)
   533  }
   534  
   535  // createClientset Creates Kubernetes Clientset for a given kubeconfig
   536  func createClientset(config *restclient.Config) (*kubernetes.Clientset, error) {
   537  	return kubernetes.NewForConfig(config)
   538  }
   539  
   540  // GetClusterOperatorClientset returns the Kubernetes clientset for the Verrazzano Cluster Operator
   541  // for a given kubeconfig
   542  func GetClusterOperatorClientset(kubeconfigPath string) (*vcoClient.Clientset, error) {
   543  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   544  	if err != nil {
   545  		return nil, err
   546  	}
   547  	return vcoClient.NewForConfig(config)
   548  }
   549  
   550  // GetVerrazzanoClientset returns the Kubernetes clientset for the Verrazzano CRD
   551  func GetVerrazzanoClientset() (*vpoClient.Clientset, error) {
   552  	config, err := k8sutil.GetKubeConfig()
   553  	if err != nil {
   554  		return nil, err
   555  	}
   556  	return vpoClient.NewForConfig(config)
   557  }
   558  
   559  // GetVerrazzanoProjectClientsetInCluster returns the Kubernetes clientset for the VerrazzanoProject
   560  func GetVerrazzanoProjectClientsetInCluster(kubeconfigPath string) (*vaoClient.Clientset, error) {
   561  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   562  	if err != nil {
   563  		return nil, err
   564  	}
   565  	return vaoClient.NewForConfig(config)
   566  }
   567  
   568  // GetVerrazzanoApplicationOperatorClientSet returns the Kubernetes clientset for the Verrazzano Application Operator
   569  func GetVerrazzanoApplicationOperatorClientSet() (*vaoClient.Clientset, error) {
   570  	config, err := k8sutil.GetKubeConfig()
   571  	if err != nil {
   572  		return nil, err
   573  	}
   574  	return vaoClient.NewForConfig(config)
   575  }
   576  
   577  // GetDynamicClient returns a dynamic client needed to access Unstructured data
   578  func GetDynamicClient() (dynamic.Interface, error) {
   579  	config, err := k8sutil.GetKubeConfig()
   580  	if err != nil {
   581  		return nil, err
   582  	}
   583  	return dynamic.NewForConfig(config)
   584  }
   585  
   586  // GetDynamicClientInCluster returns a dynamic client needed to access Unstructured data
   587  func GetDynamicClientInCluster(kubeconfigPath string) (dynamic.Interface, error) {
   588  	return k8sutil.GetDynamicClientInCluster(kubeconfigPath)
   589  }
   590  
   591  // GetV1Beta1ControllerRuntimeClient, given a kubeconfig,
   592  // returns a controller runtime client with verrazzano v1beta1 as part of its scheme.
   593  func GetV1Beta1ControllerRuntimeClient(config *restclient.Config) (client.Client, error) {
   594  	scheme := runtime.NewScheme()
   595  	if err := v1beta1.AddToScheme(scheme); err != nil {
   596  		return nil, err
   597  	}
   598  	options := client.Options{
   599  		Scheme: scheme,
   600  		// The default SuppressWarnings=false will override whatever WarningHandler was used by the config.
   601  		// Set this to true to use whatever WarningHandler was passed into this function.
   602  		Opts: client.WarningHandlerOptions{SuppressWarnings: true},
   603  	}
   604  	vzClient, err := client.New(config, options)
   605  	if err != nil {
   606  		return nil, err
   607  	}
   608  	return vzClient, nil
   609  }
   610  
   611  // GetVerrazzanoInstallResourceInCluster returns the installed Verrazzano CR in the given cluster
   612  // (there should only be 1 per cluster)
   613  func GetVerrazzanoInstallResourceInCluster(kubeconfigPath string) (*v1alpha1.Verrazzano, error) {
   614  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   615  	if err != nil {
   616  		return nil, err
   617  	}
   618  	vzClient, err := GetV1Beta1ControllerRuntimeClient(config)
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  	vzList, err := verrazzano.ListV1Alpha1(context.TODO(), vzClient)
   623  
   624  	if err != nil {
   625  		return nil, fmt.Errorf("error listing out Verrazzano instances: %v", err)
   626  	}
   627  	numVzs := len(vzList.Items)
   628  	if numVzs == 0 {
   629  		return nil, fmt.Errorf("did not find installed Verrazzano instance")
   630  	}
   631  	vz := vzList.Items[0]
   632  	return &vz, nil
   633  }
   634  
   635  // GetVerrazzanoInstallResourceInClusterV1beta1 returns the installed Verrazzano CR in the given cluster
   636  // (there should only be 1 per cluster)
   637  func GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath string) (*v1beta1.Verrazzano, error) {
   638  	config, err := k8sutil.GetKubeConfigGivenPath(kubeconfigPath)
   639  	if err != nil {
   640  		return nil, err
   641  	}
   642  	client, err := vpoClient.NewForConfig(config)
   643  	if err != nil {
   644  		return nil, err
   645  	}
   646  	vzClient := client.VerrazzanoV1beta1().Verrazzanos("")
   647  	vzList, err := vzClient.List(context.TODO(), metav1.ListOptions{})
   648  
   649  	if err != nil {
   650  		return nil, fmt.Errorf("error listing out v1beta1 Verrazzano instances: %v", err)
   651  	}
   652  	numVzs := len(vzList.Items)
   653  	if numVzs == 0 {
   654  		return nil, fmt.Errorf("did not find installed Verrazzano instance")
   655  	}
   656  	vz := vzList.Items[0]
   657  	return &vz, nil
   658  }
   659  
   660  // IsDevProfile returns true if the deployed resource is a 'dev' profile
   661  func IsDevProfile() bool {
   662  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   663  	if err != nil {
   664  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   665  		return false
   666  	}
   667  
   668  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   669  	if err != nil {
   670  		return false
   671  	}
   672  	if vz.Spec.Profile == v1beta1.Dev {
   673  		return true
   674  	}
   675  	return false
   676  }
   677  
   678  // GetVerrazzano returns the installed Verrazzano
   679  func GetVerrazzano() (*v1alpha1.Verrazzano, error) {
   680  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   681  	if err != nil {
   682  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   683  		return nil, err
   684  	}
   685  	cr, err := GetVerrazzanoInstallResourceInCluster(kubeconfigPath)
   686  	if err != nil {
   687  		return nil, err
   688  	}
   689  	return cr, nil
   690  }
   691  
   692  // GetVerrazzanoV1beta1 returns the installed Verrazzano using v1beta1 API client
   693  func GetVerrazzanoV1beta1() (*v1beta1.Verrazzano, error) {
   694  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   695  	if err != nil {
   696  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   697  		return nil, err
   698  	}
   699  	cr, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   700  	if err != nil {
   701  		return nil, err
   702  	}
   703  	return cr, nil
   704  }
   705  
   706  // GetVerrazzanoVersion returns the Verrazzano Version
   707  func GetVerrazzanoVersion(kubeconfigPath string) (string, error) {
   708  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   709  	if err != nil {
   710  		return "", err
   711  	}
   712  	vzVer := vz.Spec.Version
   713  	if vzVer == "" {
   714  		vzVer = vz.Status.Version
   715  	}
   716  	return vzVer, nil
   717  }
   718  
   719  // IsVerrazzanoMinVersion returns true if the installed Verrazzano version >= minVersion
   720  func IsVerrazzanoMinVersion(minVersion string, kubeconfigPath string) (bool, error) {
   721  	vzVersion, err := GetVerrazzanoVersion(kubeconfigPath)
   722  	if err != nil {
   723  		return false, err
   724  	}
   725  	if len(vzVersion) == 0 {
   726  		return false, nil
   727  	}
   728  	return IsMinVersion(vzVersion, minVersion)
   729  }
   730  
   731  // IsMinVersion returns true if the given version >= minVersion
   732  func IsMinVersion(vzVersion, minVersion string) (bool, error) {
   733  	vzSemver, err := semver.NewSemVersion(vzVersion)
   734  	if err != nil {
   735  		return false, err
   736  	}
   737  	minSemver, err := semver.NewSemVersion(minVersion)
   738  	if err != nil {
   739  		return false, err
   740  	}
   741  	return !vzSemver.IsLessThan(minSemver), nil
   742  }
   743  
   744  // IsProdProfile returns true if the deployed resource is a 'prod' profile
   745  func IsProdProfile() bool {
   746  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   747  	if err != nil {
   748  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   749  		return false
   750  	}
   751  
   752  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   753  	if err != nil {
   754  		return false
   755  	}
   756  	if vz.Spec.Profile == v1beta1.Prod || vz.Spec.Profile == "" {
   757  		return true
   758  	}
   759  	return false
   760  }
   761  
   762  // IsManagedClusterProfile returns true if the deployed resource is a 'managed-cluster' profile
   763  func IsManagedClusterProfile() bool {
   764  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
   765  	if err != nil {
   766  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   767  		return false
   768  	}
   769  
   770  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   771  	if err != nil {
   772  		Log(Error, fmt.Sprintf("Error getting vz install resource: %v", err))
   773  		return false
   774  	}
   775  	if vz.Spec.Profile == v1beta1.ManagedCluster {
   776  		return true
   777  	}
   778  	return false
   779  }
   780  
   781  // GetACMEEnvironment returns true if
   782  func GetACMEEnvironment(kubeconfigPath string) (string, error) {
   783  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   784  	if err != nil {
   785  		return "", err
   786  	}
   787  
   788  	// first check if letsEncrypt configured in clusterIssuer component
   789  	clusterIssuer := vz.Spec.Components.ClusterIssuer
   790  	if clusterIssuer != nil && clusterIssuer.LetsEncrypt != nil {
   791  		Log(Info, fmt.Sprintf("Let's Encrypt env is %s", clusterIssuer.LetsEncrypt.Environment))
   792  		return clusterIssuer.LetsEncrypt.Environment, nil
   793  	}
   794  
   795  	// then check if letsEncrypt configured in cert-manager certificate field
   796  	certManager := vz.Spec.Components.CertManager
   797  	if certManager != nil && strings.ToLower(string(certManager.Certificate.Acme.Provider)) == strings.ToLower(string(v1beta1.LetsEncrypt)) {
   798  		return certManager.Certificate.Acme.Environment, nil
   799  	}
   800  	return "", nil
   801  }
   802  
   803  // IsCoherenceOperatorEnabled returns true if the COH operator component is not set, or the value of its Enabled field otherwise
   804  func IsCoherenceOperatorEnabled(kubeconfigPath string) bool {
   805  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   806  	if err != nil {
   807  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   808  		return true
   809  	}
   810  	if vz.Spec.Components.CoherenceOperator == nil || vz.Spec.Components.CoherenceOperator.Enabled == nil {
   811  		return true
   812  	}
   813  	return *vz.Spec.Components.CoherenceOperator.Enabled
   814  }
   815  
   816  // IsCertManagerEnabled returns true if the Cert Manager component is not set, or the value of its Enabled field otherwise
   817  func IsCertManagerEnabled(kubeconfigPath string) bool {
   818  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   819  	if err != nil {
   820  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   821  		return true
   822  	}
   823  	if vz.Spec.Components.CertManager == nil || vz.Spec.Components.CertManager.Enabled == nil {
   824  		return true
   825  	}
   826  	return *vz.Spec.Components.CertManager.Enabled
   827  }
   828  
   829  // IsOCIDNSEnabled returns true if OCI DNS is enabled in the configuration
   830  func IsOCIDNSEnabled(kubeconfigPath string) bool {
   831  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   832  	if err != nil {
   833  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   834  		return true
   835  	}
   836  	if vz.Spec.Components.DNS == nil || vz.Spec.Components.DNS.OCI == nil {
   837  		return false
   838  	}
   839  	return true
   840  }
   841  
   842  func IsCAIssuerConfig(certConfig v1beta1.Certificate) (isCAConfig bool, err error) {
   843  	// Check if Ca or Acme is empty
   844  	caNotEmpty := certConfig.CA != v1beta1.CA{}
   845  	acmeNotEmpty := certConfig.Acme != v1beta1.Acme{}
   846  	if caNotEmpty && acmeNotEmpty {
   847  		return false, errors.New("certificate object Acme and CA cannot be simultaneously populated")
   848  	} else if !caNotEmpty && !acmeNotEmpty {
   849  		return false, errors.New("Either Acme or CA certificate authorities must be configured")
   850  	}
   851  	return caNotEmpty, nil
   852  }
   853  
   854  // IsOCIDNSWebhookEnabled returns true if the Cert Manager component is not set, or the value of its Enabled field otherwise
   855  func IsOCIDNSWebhookEnabled(kubeconfigPath string) bool {
   856  	if !IsCertManagerEnabled(kubeconfigPath) || !IsOCIDNSEnabled(kubeconfigPath) {
   857  		return false
   858  	}
   859  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   860  	if err != nil {
   861  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
   862  		return true
   863  	}
   864  	certManager := vz.Spec.Components.CertManager
   865  	if certManager != nil {
   866  		isCAConfig, _ := IsCAIssuerConfig(certManager.Certificate)
   867  		return !isCAConfig
   868  	}
   869  	// CM is not defined, so the OCI DNS webhook won't be deployed
   870  	return false
   871  }
   872  
   873  // IsWebLogicOperatorEnabled returns true if the WKO operator component is not set, or the value of its Enabled field otherwise
   874  func IsWebLogicOperatorEnabled(kubeconfigPath string) bool {
   875  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   876  	if err != nil {
   877  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   878  		return true
   879  	}
   880  	if vz.Spec.Components.WebLogicOperator == nil || vz.Spec.Components.WebLogicOperator.Enabled == nil {
   881  		return true
   882  	}
   883  	return *vz.Spec.Components.WebLogicOperator.Enabled
   884  }
   885  
   886  // IsOpenSearchEnabled returns true if the OpenSearch component is not set, or the value of its Enabled field otherwise
   887  func IsOpenSearchEnabled(kubeconfigPath string) (bool, error) {
   888  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   889  	if err != nil {
   890  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
   891  		return false, err
   892  	}
   893  	if vz != nil && vz.Spec.Components.OpenSearch != nil && vz.Spec.Components.OpenSearch.Enabled != nil {
   894  		return *vz.Spec.Components.OpenSearch.Enabled, nil
   895  	}
   896  	return false, nil
   897  }
   898  
   899  // IsPrometheusAdapterEnabled returns false if the Prometheus Adapter component is not set, or the value of its Enabled field otherwise
   900  func IsPrometheusAdapterEnabled(kubeconfigPath string) bool {
   901  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   902  	if err != nil {
   903  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   904  		return false
   905  	}
   906  	if vz.Spec.Components.PrometheusAdapter == nil || vz.Spec.Components.PrometheusAdapter.Enabled == nil {
   907  		return false
   908  	}
   909  	return *vz.Spec.Components.PrometheusAdapter.Enabled
   910  }
   911  
   912  // IsPrometheusOperatorEnabled returns false if the Prometheus Operator component is not set, or the value of its Enabled field otherwise
   913  func IsPrometheusOperatorEnabled(kubeconfigPath string) bool {
   914  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   915  	if err != nil {
   916  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   917  		return true
   918  	}
   919  	if vz.Spec.Components.PrometheusOperator == nil || vz.Spec.Components.PrometheusOperator.Enabled == nil {
   920  		return vz.Spec.Profile != v1beta1.None
   921  	}
   922  	return *vz.Spec.Components.PrometheusOperator.Enabled
   923  }
   924  
   925  // IsPrometheusEnabled returns true if the Prometheus component is not set and the Prometheus Operator is enabled, or the value of its Enabled field otherwise
   926  func IsPrometheusEnabled(kubeconfigPath string) bool {
   927  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   928  	if err != nil {
   929  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   930  		return false
   931  	}
   932  	if vz.Spec.Components.Prometheus == nil || vz.Spec.Components.Prometheus.Enabled == nil {
   933  		return vz.Spec.Profile != v1beta1.None
   934  	}
   935  	return *vz.Spec.Components.Prometheus.Enabled
   936  }
   937  
   938  // IsIngressEnabled returns false if the IngressNGINX component is not set and the IngressNGINX is enabled, or the value of its Enabled field otherwise
   939  func IsIngressEnabled(kubeconfigPath string) bool {
   940  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   941  	if err != nil {
   942  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   943  		return false
   944  	}
   945  	if vz.Spec.Components.IngressNGINX == nil || vz.Spec.Components.IngressNGINX.Enabled == nil {
   946  		return false
   947  	}
   948  	return *vz.Spec.Components.IngressNGINX.Enabled
   949  }
   950  
   951  // IsKubeStateMetricsEnabled returns false if the Kube State Metrics component is not set, or the value of its Enabled field otherwise
   952  func IsKubeStateMetricsEnabled(kubeconfigPath string) bool {
   953  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   954  	if err != nil {
   955  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   956  		return false
   957  	}
   958  	if vz.Spec.Components.KubeStateMetrics == nil || vz.Spec.Components.KubeStateMetrics.Enabled == nil {
   959  		return vz.Spec.Profile != v1beta1.None
   960  	}
   961  	return *vz.Spec.Components.KubeStateMetrics.Enabled
   962  }
   963  
   964  // IsPrometheusPushgatewayEnabled returns false if the Prometheus Pushgateway component is not set, or the value of its Enabled field otherwise
   965  func IsPrometheusPushgatewayEnabled(kubeconfigPath string) bool {
   966  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   967  	if err != nil {
   968  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   969  		return false
   970  	}
   971  	if vz.Spec.Components.PrometheusPushgateway == nil || vz.Spec.Components.PrometheusPushgateway.Enabled == nil {
   972  		return false
   973  	}
   974  	return *vz.Spec.Components.PrometheusPushgateway.Enabled
   975  }
   976  
   977  // IsPrometheusNodeExporterEnabled returns false if the Prometheus Node Exporter component is not set, or the value of its Enabled field otherwise
   978  func IsPrometheusNodeExporterEnabled(kubeconfigPath string) bool {
   979  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   980  	if err != nil {
   981  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
   982  		return false
   983  	}
   984  	if vz.Spec.Components.PrometheusNodeExporter == nil || vz.Spec.Components.PrometheusNodeExporter.Enabled == nil {
   985  		return IsPrometheusEnabled(kubeconfigPath)
   986  	}
   987  	return *vz.Spec.Components.PrometheusNodeExporter.Enabled
   988  }
   989  
   990  // IsOpenSearchDashboardsEnabled returns true if the OpenSearchDashboards component is not set, or the value of its Enabled field otherwise
   991  func IsOpenSearchDashboardsEnabled(kubeconfigPath string) bool {
   992  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
   993  	if err != nil {
   994  		Log(Error, fmt.Sprintf(verrazzanoErrorTemplate, err))
   995  		return true
   996  	}
   997  	if vz != nil && vz.Spec.Components.OpenSearchDashboards != nil && vz.Spec.Components.OpenSearchDashboards.Enabled != nil {
   998  		return *vz.Spec.Components.OpenSearchDashboards.Enabled
   999  	}
  1000  	return true
  1001  }
  1002  
  1003  // IsJaegerOperatorEnabled returns false if the Jaeger Operator component is not set, or the value of its Enabled field otherwise
  1004  func IsJaegerOperatorEnabled(kubeconfigPath string) bool {
  1005  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1006  	if err != nil {
  1007  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1008  		return false
  1009  	}
  1010  	if vz == nil || vz.Spec.Components.JaegerOperator == nil || vz.Spec.Components.JaegerOperator.Enabled == nil {
  1011  		return false
  1012  	}
  1013  	return *vz.Spec.Components.JaegerOperator.Enabled
  1014  }
  1015  
  1016  // IsGrafanaEnabled returns false if the Grafana component is not set, or the value of its Enabled field otherwise
  1017  func IsGrafanaEnabled(kubeconfigPath string) bool {
  1018  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1019  	if err != nil {
  1020  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1021  		return false
  1022  	}
  1023  	if vz.Spec.Components.Grafana == nil || vz.Spec.Components.Grafana.Enabled == nil {
  1024  		// Grafana component is enabled by default
  1025  		return true
  1026  	}
  1027  	return *vz.Spec.Components.Grafana.Enabled
  1028  }
  1029  
  1030  // IsKeycloakEnabled returns false if the Keycloak component is not set, or the value of its Enabled field otherwise
  1031  func IsKeycloakEnabled(kubeconfigPath string) bool {
  1032  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1033  	if err != nil {
  1034  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1035  		return false
  1036  	}
  1037  	if vz.Spec.Components.Keycloak == nil || vz.Spec.Components.Keycloak.Enabled == nil {
  1038  		// Keycloak component is enabled by default
  1039  		return true
  1040  	}
  1041  	return *vz.Spec.Components.Keycloak.Enabled
  1042  }
  1043  
  1044  // IsMySQLOperatorEnabled returns false if the MySQLOperator component is not set, or the value of its Enabled field otherwise
  1045  func IsMySQLOperatorEnabled(kubeconfigPath string) bool {
  1046  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1047  	if err != nil {
  1048  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1049  		return false
  1050  	}
  1051  	if vz.Spec.Components.MySQLOperator == nil || vz.Spec.Components.MySQLOperator.Enabled == nil {
  1052  		// MySQLOperator component is enabled by default
  1053  		return true
  1054  	}
  1055  	return *vz.Spec.Components.MySQLOperator.Enabled
  1056  }
  1057  
  1058  // IsVeleroEnabled returns false if the Velero component is not set, or the value of its Enabled field otherwise
  1059  func IsVeleroEnabled(kubeconfigPath string) bool {
  1060  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1061  	if err != nil {
  1062  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1063  		return false
  1064  	}
  1065  	if vz.Spec.Components.Velero == nil || vz.Spec.Components.Velero.Enabled == nil {
  1066  		return false
  1067  	}
  1068  	return *vz.Spec.Components.Velero.Enabled
  1069  }
  1070  
  1071  // IsRancherEnabled returns false if the Rancher component is not set, or the value of its Enabled field otherwise
  1072  func IsRancherEnabled(kubeconfigPath string) bool {
  1073  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1074  	if err != nil {
  1075  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1076  		return false
  1077  	}
  1078  	if vz.Spec.Components.Rancher == nil || vz.Spec.Components.Rancher.Enabled == nil {
  1079  		// Rancher component is enabled by default
  1080  		return true
  1081  	}
  1082  	return *vz.Spec.Components.Rancher.Enabled
  1083  }
  1084  
  1085  // IsRancherBackupEnabled returns false if the Rancher Backup component is not set, or the value of its Enabled field otherwise
  1086  func IsRancherBackupEnabled(kubeconfigPath string) bool {
  1087  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1088  	if err != nil {
  1089  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1090  		return false
  1091  	}
  1092  	if vz.Spec.Components.RancherBackup == nil || vz.Spec.Components.RancherBackup.Enabled == nil {
  1093  		return false
  1094  	}
  1095  	return *vz.Spec.Components.RancherBackup.Enabled
  1096  }
  1097  
  1098  // IsClusterAPIEnabled returns true if the ClusterAPI component is not set, or the value of its Enabled field otherwise
  1099  func IsClusterAPIEnabled(kubeconfigPath string) bool {
  1100  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1101  	if err != nil {
  1102  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1103  		return false
  1104  	}
  1105  	return vz.Spec.Components.ClusterAPI == nil || vz.Spec.Components.ClusterAPI.Enabled == nil || *vz.Spec.Components.ClusterAPI.Enabled
  1106  }
  1107  
  1108  // IsArgoCDEnabled returns false if the Argocd component is not set, or the value of its Enabled field otherwise
  1109  func IsArgoCDEnabled(kubeconfigPath string) bool {
  1110  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1111  	if err != nil {
  1112  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1113  		return false
  1114  	}
  1115  	if vz.Spec.Components.ArgoCD == nil || vz.Spec.Components.ArgoCD.Enabled == nil {
  1116  		return false
  1117  	}
  1118  	return *vz.Spec.Components.ArgoCD.Enabled
  1119  }
  1120  
  1121  // IsClusterAgentEnabled returns true if the Cluster Agent component is not set, or the value of its Enabled field otherwise
  1122  func IsClusterAgentEnabled(kubeconfigPath string) bool {
  1123  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1124  	if err != nil {
  1125  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
  1126  		return true
  1127  	}
  1128  	if vz.Spec.Components.ClusterAgent == nil || vz.Spec.Components.ClusterAgent.Enabled == nil {
  1129  		return true
  1130  	}
  1131  	return *vz.Spec.Components.ClusterAgent.Enabled
  1132  }
  1133  
  1134  // IsIstioEnabled returns true if the Istio component is not set, or the value of its Enabled field otherwise
  1135  func IsIstioEnabled(kubeconfigPath string) bool {
  1136  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1137  	if err != nil {
  1138  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
  1139  		return true
  1140  	}
  1141  	return vz.Spec.Components.Istio == nil || vz.Spec.Components.Istio.Enabled == nil || *vz.Spec.Components.Istio.Enabled
  1142  }
  1143  
  1144  // APIExtensionsClientSet returns a Kubernetes ClientSet for this cluster.
  1145  func APIExtensionsClientSet() (*apiextv1.ApiextensionsV1Client, error) {
  1146  	config, err := k8sutil.GetKubeConfig()
  1147  	if err != nil {
  1148  		return nil, err
  1149  	}
  1150  	// create the clientset
  1151  	return apiextv1.NewForConfig(config)
  1152  }
  1153  
  1154  // ListServices returns the list of services in a given namespace for the cluster
  1155  func ListServices(namespace string) (*corev1.ServiceList, error) {
  1156  	// Get the Kubernetes clientset
  1157  	clientset, err := k8sutil.GetKubernetesClientset()
  1158  	if err != nil {
  1159  		return nil, err
  1160  	}
  1161  
  1162  	services, err := clientset.CoreV1().Services(namespace).List(context.TODO(), metav1.ListOptions{})
  1163  	if err != nil {
  1164  		Log(Error, fmt.Sprintf("Failed to list services in namespace %s: %v", namespace, err))
  1165  		return nil, err
  1166  	}
  1167  	return services, nil
  1168  }
  1169  
  1170  // GetNamespace returns a namespace
  1171  func GetNamespace(name string) (*corev1.Namespace, error) {
  1172  	// Get the Kubernetes clientset
  1173  	clientset, err := k8sutil.GetKubernetesClientset()
  1174  	if err != nil {
  1175  		return nil, err
  1176  	}
  1177  	return GetNamespaceWithClientSet(name, clientset)
  1178  }
  1179  
  1180  // GetNamespaceWithClientSet returns a namespace for the given Clientset
  1181  func GetNamespaceWithClientSet(name string, clientset *kubernetes.Clientset) (*corev1.Namespace, error) {
  1182  	return clientset.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
  1183  }
  1184  
  1185  // GenerateNamespace takes a string and combines that with a UUID to generate a namespace
  1186  func GenerateNamespace(name string) string {
  1187  	return name + "-" + uuid.NewString()[:7]
  1188  }
  1189  
  1190  // GetEffectiveKeyCloakPersistenceOverride returns the effective PVC override for Keycloak, if it exists
  1191  func GetEffectiveKeyCloakPersistenceOverride(kubeconfigPath string) (*v1beta1.VolumeClaimSpecTemplate, error) {
  1192  	verrazzano, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1193  	if err != nil {
  1194  		return nil, err
  1195  	}
  1196  
  1197  	mysqlVolSource := verrazzano.Spec.DefaultVolumeSource
  1198  	if verrazzano.Spec.Components.Keycloak != nil {
  1199  		mysqlVolSource = verrazzano.Spec.Components.Keycloak.MySQL.VolumeSource
  1200  	}
  1201  	if mysqlVolSource == nil || mysqlVolSource.EmptyDir != nil {
  1202  		// no override specified, or its an EmptyDir override
  1203  		return nil, nil
  1204  	}
  1205  	for _, template := range verrazzano.Spec.VolumeClaimSpecTemplates {
  1206  		if template.Name == mysqlVolSource.PersistentVolumeClaim.ClaimName {
  1207  			return &template, nil
  1208  		}
  1209  	}
  1210  	return nil, fmt.Errorf("did not find matching PVC template for %s", mysqlVolSource.PersistentVolumeClaim.ClaimName)
  1211  }
  1212  
  1213  // GetEffectiveVMIPersistenceOverride returns the effective PVC override for the VMI components, if it exists
  1214  func GetEffectiveVMIPersistenceOverride(kubeconfigPath string) (*v1beta1.VolumeClaimSpecTemplate, error) {
  1215  	verrazzano, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1216  	if err != nil {
  1217  		return nil, err
  1218  	}
  1219  
  1220  	volumeOverride := verrazzano.Spec.DefaultVolumeSource
  1221  	if volumeOverride == nil || volumeOverride.EmptyDir != nil {
  1222  		// no override specified, or its an EmptyDir override
  1223  		return nil, nil
  1224  	}
  1225  	for _, template := range verrazzano.Spec.VolumeClaimSpecTemplates {
  1226  		if template.Name == volumeOverride.PersistentVolumeClaim.ClaimName {
  1227  			return &template, nil
  1228  		}
  1229  	}
  1230  	return nil, fmt.Errorf("did not find matching PVC template for %s", volumeOverride.PersistentVolumeClaim.ClaimName)
  1231  }
  1232  
  1233  // GetNamespaceInCluster returns a namespace in the cluster whose kubeconfigPath is specified
  1234  func GetNamespaceInCluster(name string, kubeconfigPath string) (*corev1.Namespace, error) {
  1235  	// Get the Kubernetes clientset
  1236  	clientset, err := GetKubernetesClientsetForCluster(kubeconfigPath)
  1237  	if err != nil {
  1238  		return nil, err
  1239  	}
  1240  
  1241  	return clientset.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{})
  1242  }
  1243  
  1244  // CreateNamespace creates a namespace
  1245  func CreateNamespace(name string, labels map[string]string) (*corev1.Namespace, error) {
  1246  	return CreateNamespaceWithAnnotations(name, labels, nil)
  1247  }
  1248  
  1249  // CreateOrUpdateNamespace creates or updates a namespace
  1250  func CreateOrUpdateNamespace(name string, labels map[string]string, annotations map[string]string) (*corev1.Namespace, error) {
  1251  	// Get the Kubernetes clientset
  1252  	clientset, err := k8sutil.GetKubernetesClientset()
  1253  	if err != nil {
  1254  		return nil, err
  1255  	}
  1256  	var ns *corev1.Namespace
  1257  	if ns, err = clientset.CoreV1().Namespaces().Get(context.TODO(), name, metav1.GetOptions{}); err != nil {
  1258  		if !k8serrors.IsNotFound(err) {
  1259  			return nil, err
  1260  		}
  1261  		return clientset.CoreV1().Namespaces().Create(context.TODO(),
  1262  			&corev1.Namespace{
  1263  				ObjectMeta: metav1.ObjectMeta{
  1264  					Name:        name,
  1265  					Labels:      labels,
  1266  					Annotations: annotations,
  1267  				},
  1268  			}, metav1.CreateOptions{})
  1269  	}
  1270  	ns.Labels = mergeMaps(ns.Labels, labels)
  1271  	ns.Annotations = mergeMaps(ns.Annotations, annotations)
  1272  	return clientset.CoreV1().Namespaces().Update(context.TODO(), ns, metav1.UpdateOptions{})
  1273  }
  1274  
  1275  func mergeMaps(m1 map[string]string, m2 map[string]string) map[string]string {
  1276  	result := m1
  1277  	if result == nil {
  1278  		result = map[string]string{}
  1279  	}
  1280  	// merge keys from m2 into m1, overwriting existing keys of m1.
  1281  	for k, v := range m2 {
  1282  		result[k] = v
  1283  	}
  1284  	return result
  1285  }
  1286  
  1287  func CreateNamespaceWithAnnotations(name string, labels map[string]string, annotations map[string]string) (*corev1.Namespace, error) {
  1288  	// Get the Kubernetes clientset
  1289  	clientset, err := k8sutil.GetKubernetesClientset()
  1290  	if err != nil {
  1291  		return nil, err
  1292  	}
  1293  	return CreateNamespaceWithClientSet(name, labels, clientset, annotations)
  1294  }
  1295  
  1296  // CreateNamespaceWithClientSet creates a namespace using the given Clientset
  1297  func CreateNamespaceWithClientSet(name string, labels map[string]string, clientset *kubernetes.Clientset, annotations map[string]string) (*corev1.Namespace, error) {
  1298  	if len(os.Getenv(k8sutil.EnvVarTestKubeConfig)) > 0 {
  1299  		existingNamespace, err := GetNamespaceWithClientSet(name, clientset)
  1300  		if err != nil {
  1301  			Log(Error, fmt.Sprintf("CreateNamespace %s, error while getting existing namespace: %v", name, err))
  1302  			return nil, err
  1303  		}
  1304  
  1305  		if existingNamespace != nil && existingNamespace.Name == name {
  1306  			return existingNamespace, nil
  1307  		}
  1308  		return nil, fmt.Errorf("CreateNamespace %s, test is running with custom service account and namespace must be pre-created", name)
  1309  	}
  1310  	namespace := &corev1.Namespace{
  1311  		ObjectMeta: metav1.ObjectMeta{
  1312  			Name:        name,
  1313  			Labels:      labels,
  1314  			Annotations: annotations,
  1315  		},
  1316  	}
  1317  	ns, err := clientset.CoreV1().Namespaces().Create(context.TODO(), namespace, metav1.CreateOptions{})
  1318  	if err != nil {
  1319  		Log(Error, fmt.Sprintf("CreateNamespace %s error: %v", name, err))
  1320  		return nil, err
  1321  	}
  1322  	return ns, nil
  1323  }
  1324  
  1325  func RemoveNamespaceFinalizers(namespace *corev1.Namespace) error {
  1326  	clientset, err := k8sutil.GetKubernetesClientset()
  1327  	if err != nil {
  1328  		return err
  1329  	}
  1330  	namespace.ObjectMeta.Finalizers = nil
  1331  	_, err = clientset.CoreV1().Namespaces().Update(context.TODO(), namespace, metav1.UpdateOptions{})
  1332  	return err
  1333  }
  1334  
  1335  // DeleteNamespace deletes a namespace in the cluster specified in the environment
  1336  func DeleteNamespace(name string) error {
  1337  	if len(os.Getenv(k8sutil.EnvVarTestKubeConfig)) > 0 {
  1338  		Log(Info, fmt.Sprintf("DeleteNamespace %s, test is running with custom service account and therefore namespace won't be deleted by the test", name))
  1339  		return nil
  1340  	}
  1341  
  1342  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
  1343  	if err != nil {
  1344  		Log(Error, fmt.Sprintf("Error getting kubeconfig: %v", err))
  1345  		return err
  1346  	}
  1347  
  1348  	return DeleteNamespaceInCluster(name, kubeconfigPath)
  1349  }
  1350  
  1351  func DeleteNamespaceInCluster(name string, kubeconfigPath string) error {
  1352  	// Get the Kubernetes clientset
  1353  	clientset, err := GetKubernetesClientsetForCluster(kubeconfigPath)
  1354  	if err != nil {
  1355  		return err
  1356  	}
  1357  	return DeleteNamespaceWithClientSet(name, clientset)
  1358  }
  1359  
  1360  // DeleteNamespaceWithClientSet deletes the namespace using the given Clientset
  1361  func DeleteNamespaceWithClientSet(name string, clientset *kubernetes.Clientset) error {
  1362  	err := clientset.CoreV1().Namespaces().Delete(context.TODO(), name, metav1.DeleteOptions{})
  1363  	if err != nil {
  1364  		Log(Error, fmt.Sprintf("Failed to delete namespace %s: %v", name, err))
  1365  	}
  1366  	return err
  1367  }
  1368  
  1369  // DoesClusterRoleExist returns whether a cluster role with the given name exists in the cluster
  1370  func DoesClusterRoleExist(name string) (bool, error) {
  1371  	// Get the Kubernetes clientset
  1372  	clientset, err := k8sutil.GetKubernetesClientset()
  1373  	if err != nil {
  1374  		return false, err
  1375  	}
  1376  
  1377  	clusterrole, err := clientset.RbacV1().ClusterRoles().Get(context.TODO(), name, metav1.GetOptions{})
  1378  	if err != nil && !k8serrors.IsNotFound(err) {
  1379  		Log(Error, fmt.Sprintf("Failed to get cluster role %s: %v", name, err))
  1380  		return false, err
  1381  	}
  1382  
  1383  	return clusterrole != nil, nil
  1384  }
  1385  
  1386  // GetClusterRole returns the cluster role with the given name
  1387  func GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
  1388  	// Get the Kubernetes clientset
  1389  	clientset, err := k8sutil.GetKubernetesClientset()
  1390  	if err != nil {
  1391  		return nil, err
  1392  	}
  1393  
  1394  	clusterrole, err := clientset.RbacV1().ClusterRoles().Get(context.TODO(), name, metav1.GetOptions{})
  1395  	if err != nil {
  1396  		if !k8serrors.IsNotFound(err) {
  1397  			Log(Error, fmt.Sprintf("Failed to get cluster role %s: %v", name, err))
  1398  		}
  1399  		return nil, err
  1400  	}
  1401  
  1402  	return clusterrole, nil
  1403  }
  1404  
  1405  // DoesServiceAccountExist returns whether a service account with the given name and namespace exists in the cluster
  1406  func DoesServiceAccountExist(namespace, name string) (bool, error) {
  1407  	sa, err := GetServiceAccount(namespace, name)
  1408  	if err != nil {
  1409  		return false, err
  1410  	}
  1411  	return sa != nil, nil
  1412  }
  1413  
  1414  // DoesClusterRoleBindingExist returns whether a cluster role with the given name exists in the cluster
  1415  func DoesClusterRoleBindingExist(name string) (bool, error) {
  1416  	// Get the Kubernetes clientset
  1417  	clientset, err := k8sutil.GetKubernetesClientset()
  1418  	if err != nil {
  1419  		return false, err
  1420  	}
  1421  
  1422  	clusterrolebinding, err := clientset.RbacV1().ClusterRoleBindings().Get(context.TODO(), name, metav1.GetOptions{})
  1423  	if err != nil && !k8serrors.IsNotFound(err) {
  1424  		Log(Error, fmt.Sprintf("Failed to get cluster role binding %s: %v", name, err))
  1425  		return false, err
  1426  	}
  1427  
  1428  	return clusterrolebinding != nil && len(clusterrolebinding.Name) > 0, nil
  1429  }
  1430  
  1431  // GetClusterRoleBinding returns the cluster role with the given name
  1432  func GetClusterRoleBinding(name string) (*rbacv1.ClusterRoleBinding, error) {
  1433  	// Get the Kubernetes clientset
  1434  	clientset, err := k8sutil.GetKubernetesClientset()
  1435  	if err != nil {
  1436  		return nil, err
  1437  	}
  1438  
  1439  	crb, err := clientset.RbacV1().ClusterRoleBindings().Get(context.TODO(), name, metav1.GetOptions{})
  1440  	if err != nil {
  1441  		if !k8serrors.IsNotFound(err) {
  1442  			Log(Error, fmt.Sprintf("Failed to get cluster role binding %s: %v", name, err))
  1443  		}
  1444  		return nil, err
  1445  	}
  1446  
  1447  	return crb, err
  1448  }
  1449  
  1450  // ListClusterRoleBindings returns the list of cluster role bindings for the cluster
  1451  func ListClusterRoleBindings() (*rbacv1.ClusterRoleBindingList, error) {
  1452  	// Get the Kubernetes clientset
  1453  	clientset, err := k8sutil.GetKubernetesClientset()
  1454  	if err != nil {
  1455  		return nil, err
  1456  	}
  1457  
  1458  	bindings, err := clientset.RbacV1().ClusterRoleBindings().List(context.TODO(), metav1.ListOptions{})
  1459  	if err != nil {
  1460  		Log(Error, fmt.Sprintf("Failed to get cluster role bindings: %v", err))
  1461  		return nil, err
  1462  	}
  1463  
  1464  	return bindings, err
  1465  }
  1466  
  1467  // DoesRoleBindingContainSubject returns true if the RoleBinding exists and it contains the
  1468  // specified subject
  1469  func DoesRoleBindingContainSubject(namespace, name, subjectKind, subjectName string) (bool, error) {
  1470  	clientset, err := k8sutil.GetKubernetesClientset()
  1471  	if err != nil {
  1472  		return false, err
  1473  	}
  1474  
  1475  	rb, err := clientset.RbacV1().RoleBindings(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  1476  	if err != nil {
  1477  		if !k8serrors.IsNotFound(err) {
  1478  			Log(Error, fmt.Sprintf("Failed to get RoleBinding %s in namespace %s: %v", name, namespace, err))
  1479  			return false, err
  1480  		}
  1481  		return false, nil
  1482  	}
  1483  
  1484  	for _, s := range rb.Subjects {
  1485  		if s.Kind == subjectKind && s.Name == subjectName {
  1486  			return true, nil
  1487  		}
  1488  	}
  1489  	return false, nil
  1490  }
  1491  
  1492  func CreateRoleBinding(userOCID string, namespace string, rolebindingname string, clusterrolename string) error {
  1493  
  1494  	subject1 := rbacv1.Subject{
  1495  		Kind:      "User",
  1496  		APIGroup:  "rbac.authorization.k8s.io",
  1497  		Name:      userOCID,
  1498  		Namespace: "",
  1499  	}
  1500  	subjects := []rbacv1.Subject{0: subject1}
  1501  
  1502  	rb := rbacv1.RoleBinding{
  1503  		TypeMeta: metav1.TypeMeta{
  1504  			Kind:       "RoleBinding",
  1505  			APIVersion: "rbac.authorization.k8s.io/v1",
  1506  		},
  1507  		ObjectMeta: metav1.ObjectMeta{
  1508  			Name: rolebindingname,
  1509  		},
  1510  		Subjects: subjects,
  1511  		RoleRef: rbacv1.RoleRef{
  1512  			APIGroup: "rbac.authorization.k8s.io",
  1513  			Kind:     "ClusterRole",
  1514  			Name:     clusterrolename,
  1515  		},
  1516  	}
  1517  
  1518  	// Get the Kubernetes clientset
  1519  	clientset, err := k8sutil.GetKubernetesClientset()
  1520  	if err != nil {
  1521  		return err
  1522  	}
  1523  
  1524  	_, err = clientset.RbacV1().RoleBindings(namespace).Create(context.TODO(), &rb, metav1.CreateOptions{})
  1525  	if err != nil {
  1526  		Log(Info, fmt.Sprintf("Failed to create role binding: %v", err))
  1527  	}
  1528  
  1529  	return err
  1530  }
  1531  
  1532  // DoesRoleBindingExist returns whether a cluster role with the given name exists in the cluster
  1533  func DoesRoleBindingExist(name string, namespace string) (bool, error) {
  1534  	// Get the Kubernetes clientset
  1535  	clientset, err := k8sutil.GetKubernetesClientset()
  1536  	if err != nil {
  1537  		return false, err
  1538  	}
  1539  
  1540  	rolebinding, err := clientset.RbacV1().RoleBindings(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  1541  	if err != nil {
  1542  		Log(Info, fmt.Sprintf("Failed to verify role binding %s in namespace %s: %v", name, namespace, err))
  1543  		return false, err
  1544  	}
  1545  
  1546  	return rolebinding != nil, nil
  1547  }
  1548  
  1549  // Execute executes the given command on the pod and container identified by the given names and returns the
  1550  // resulting stdout and stderr
  1551  func Execute(podName, containerName, namespace string, command []string) (string, string, error) {
  1552  	clientset, err := k8sutil.GetKubernetesClientset()
  1553  	if err != nil {
  1554  		return "", "", err
  1555  	}
  1556  	request := clientset.CoreV1().RESTClient().Post().Resource("pods").Name(podName).
  1557  		Namespace(namespace).SubResource("exec")
  1558  	request.VersionedParams(
  1559  		&corev1.PodExecOptions{
  1560  			Command:   command,
  1561  			Container: containerName,
  1562  			Stdin:     false,
  1563  			Stdout:    true,
  1564  			Stderr:    true,
  1565  			TTY:       false,
  1566  		},
  1567  		scheme.ParameterCodec,
  1568  	)
  1569  	client, err := k8sutil.GetKubeConfig()
  1570  	if err != nil {
  1571  		return "", "", err
  1572  	}
  1573  	executor, err := remotecommand.NewSPDYExecutor(client, "POST", request.URL())
  1574  	if err != nil {
  1575  		return "", "", err
  1576  	}
  1577  	var stdout, stderr bytes.Buffer
  1578  	err = executor.Stream(remotecommand.StreamOptions{Stdout: &stdout, Stderr: &stderr})
  1579  
  1580  	return strings.TrimSpace(stdout.String()), strings.TrimSpace(stderr.String()), err
  1581  }
  1582  
  1583  // GetConfigMap returns the config map for the passed in ConfigMap Name and Namespace
  1584  func GetConfigMap(configMapName string, namespace string) (*corev1.ConfigMap, error) {
  1585  	// Get the Kubernetes clientset
  1586  	clientset, err := k8sutil.GetKubernetesClientset()
  1587  	if err != nil {
  1588  		return nil, err
  1589  	}
  1590  	cmi := clientset.CoreV1().ConfigMaps(namespace)
  1591  	configMap, err := cmi.Get(context.TODO(), configMapName, metav1.GetOptions{})
  1592  	if err != nil {
  1593  		if !k8serrors.IsNotFound(err) {
  1594  			Log(Error, fmt.Sprintf("Failed to get Config Map %s from namespace %s: %v ", configMapName, namespace, err))
  1595  		}
  1596  		return nil, err
  1597  	}
  1598  	return configMap, nil
  1599  }
  1600  
  1601  /*
  1602  The following code adds http headers to the kubernetes client invocations.  This is done to emulate the functionality of
  1603  kubectl auth can-i ...
  1604  
  1605  WrapTransport is configured to point to the function
  1606  WrapTransport will be invoked for custom HTTP behavior after the underlying transport is initialized
  1607  (either the transport created from TLSClientConfig, Transport, or http.DefaultTransport).
  1608  The config may layer other RoundTrippers on top of the returned RoundTripper.
  1609  
  1610  WrapperFunc wraps an http.RoundTripper when a new transport is created for a client, allowing per connection behavior to be injected.
  1611  
  1612  RoundTripper is an interface representing the ability to execute a single HTTP transaction, obtaining the Response for a given Request.
  1613  */
  1614  // headerAdder is an http.RoundTripper that adds additional headers to the request
  1615  type headerAdder struct {
  1616  	headers map[string][]string
  1617  
  1618  	rt http.RoundTripper
  1619  }
  1620  
  1621  func (h *headerAdder) RoundTrip(req *http.Request) (*http.Response, error) {
  1622  	for k, vv := range h.headers {
  1623  		for _, v := range vv {
  1624  			req.Header.Add(k, v)
  1625  		}
  1626  	}
  1627  	return h.rt.RoundTrip(req)
  1628  }
  1629  
  1630  func CanI(userOCID string, namespace string, verb string, resource string) (bool, string, error) {
  1631  	return CanIForAPIGroup(userOCID, namespace, verb, resource, "")
  1632  }
  1633  
  1634  func CanIForAPIGroup(userOCID string, namespace string, verb string, resource string, group string) (bool, string, error) {
  1635  	return CanIForAPIGroupForServiceAccountOrUser(userOCID, namespace, verb, resource, group, false, "")
  1636  }
  1637  
  1638  func CanIForAPIGroupForServiceAccountOrUser(saOrUserOCID string, namespace string, verb string, resource string, group string, isServiceAccount bool, saNamespace string) (bool, string, error) {
  1639  	canI := &v1.SelfSubjectAccessReview{
  1640  		TypeMeta: metav1.TypeMeta{
  1641  			Kind:       "SelfSubjectAccessReview",
  1642  			APIVersion: "authorization.k8s.io/v1",
  1643  		},
  1644  		Spec: v1.SelfSubjectAccessReviewSpec{
  1645  			ResourceAttributes: &v1.ResourceAttributes{
  1646  				Namespace:   namespace,
  1647  				Verb:        verb,
  1648  				Group:       group,
  1649  				Version:     "",
  1650  				Resource:    resource,
  1651  				Subresource: "",
  1652  				Name:        "",
  1653  			},
  1654  		},
  1655  	}
  1656  
  1657  	config, err := k8sutil.GetKubeConfig()
  1658  	if err != nil {
  1659  		return false, "", err
  1660  	}
  1661  
  1662  	wt := config.WrapTransport // Config might already have a transport wrapper
  1663  	if isServiceAccount {
  1664  		token, err := GetTokenForServiceAccount(saOrUserOCID, saNamespace)
  1665  		if err != nil {
  1666  			return false, "", err
  1667  		}
  1668  
  1669  		kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
  1670  		if err != nil {
  1671  			Log(Error, fmt.Sprintf("Error getting kubeconfig, error: %v", err))
  1672  			return false, "", err
  1673  		}
  1674  
  1675  		clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
  1676  			&clientcmd.ClientConfigLoadingRules{ExplicitPath: kubeconfigPath},
  1677  			&clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: ""}})
  1678  		rawConfig, err := clientConfig.RawConfig()
  1679  		if err != nil {
  1680  			return false, "", fmt.Errorf("could not get rawconfig: %v", err)
  1681  		}
  1682  
  1683  		rawConfig.AuthInfos["sa-token"] = &clientcmdapi.AuthInfo{Token: string(token)}
  1684  		cluster := ""
  1685  		if len(rawConfig.Clusters) > 0 {
  1686  			for k, v := range rawConfig.Clusters {
  1687  				if v != nil {
  1688  					cluster = k
  1689  					break
  1690  				}
  1691  			}
  1692  		}
  1693  
  1694  		rawConfig.Contexts["sa-context"] = &clientcmdapi.Context{Cluster: cluster, AuthInfo: "sa-token"}
  1695  		rawConfig.CurrentContext = "sa-context"
  1696  		config, err = clientcmd.NewNonInteractiveClientConfig(rawConfig, "sa-context", &clientcmd.ConfigOverrides{ClusterInfo: clientcmdapi.Cluster{Server: ""}}, clientConfig.ConfigAccess()).ClientConfig()
  1697  		if err != nil {
  1698  			return false, "", err
  1699  		}
  1700  
  1701  	} else {
  1702  		config.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
  1703  			if wt != nil {
  1704  				rt = wt(rt)
  1705  			}
  1706  			header := &headerAdder{
  1707  				rt:      rt,
  1708  				headers: map[string][]string{"Impersonate-User": {saOrUserOCID}},
  1709  			}
  1710  			return header
  1711  		}
  1712  	}
  1713  
  1714  	clientset, err := kubernetes.NewForConfig(config)
  1715  	if err != nil {
  1716  		return false, "", err
  1717  	}
  1718  
  1719  	auth, err := clientset.AuthorizationV1().SelfSubjectAccessReviews().Create(context.TODO(), canI, metav1.CreateOptions{})
  1720  	if err != nil {
  1721  		Log(Error, fmt.Sprintf("Failed to check perms: %v", err))
  1722  		return false, "", err
  1723  	}
  1724  
  1725  	return auth.Status.Allowed, auth.Status.Reason, nil
  1726  }
  1727  
  1728  // GetTokenForServiceAccount returns the token associated with service account
  1729  func GetTokenForServiceAccount(sa string, namespace string) ([]byte, error) {
  1730  	// In k8s 1.24 and later, secret is not created for service account. Create a service account token secret and get
  1731  	// the token from the same.
  1732  	secretName := sa + "-token"
  1733  	if err := createServiceAccountTokenSecret(sa, namespace); err != nil {
  1734  		msg := fmt.Sprintf("failed to create a service account token secret %s in namespace %s: %v", secretName,
  1735  			namespace, err)
  1736  		Log(Error, msg)
  1737  		return nil, errors.New(msg)
  1738  	}
  1739  
  1740  	clientset, err := k8sutil.GetKubernetesClientset()
  1741  	if err != nil {
  1742  		return nil, err
  1743  	}
  1744  	secret, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
  1745  	if err != nil {
  1746  		msg := fmt.Sprintf("failed to get secret %s for service account %s in namespace %s: %v", secretName, sa, namespace, err)
  1747  		Log(Error, msg)
  1748  		return nil, errors.New(msg)
  1749  	}
  1750  	// API token secret is populated asynchronously. As a work-around, wait for up to 10 seconds for the secret to be
  1751  	// populated.
  1752  	// https://github.com/kubernetes/kubernetes/pull/108309/files#diff-9037e55a81aefc2c9dc448fa4329772381d50ed1f270575be0ff48e0a949e12eR475
  1753  	err = wait.Poll(time.Second, 10*time.Second, func() (bool, error) {
  1754  		if len(secret.Data["token"]) != 0 {
  1755  			return true, nil
  1756  		}
  1757  		secret, err = clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
  1758  		if err != nil {
  1759  			return false, fmt.Errorf("failed to get secret %s for service account %s in namespace %s: %v", secretName,
  1760  				sa, namespace, err)
  1761  		}
  1762  		return false, nil
  1763  	})
  1764  	if err != nil {
  1765  		msg := fmt.Sprintf("unable to find token in secret %s for service account %s in namespace %s: %v", secretName, sa, namespace, err)
  1766  		Log(Error, msg)
  1767  		return nil, errors.New(msg)
  1768  	}
  1769  	return secret.Data["token"], nil
  1770  }
  1771  
  1772  func GetServiceAccount(namespace, name string) (*corev1.ServiceAccount, error) {
  1773  	clientset, err := k8sutil.GetKubernetesClientset()
  1774  	if err != nil {
  1775  		return nil, err
  1776  	}
  1777  	sa, err := clientset.CoreV1().ServiceAccounts(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  1778  	if err != nil {
  1779  		if !k8serrors.IsNotFound(err) {
  1780  			Log(Error, fmt.Sprintf("Failed to get service account %s in namespace %s: %v", name, namespace, err))
  1781  		}
  1782  		return nil, err
  1783  	}
  1784  	return sa, nil
  1785  }
  1786  
  1787  func GetPersistentVolumeClaims(namespace string) (map[string]*corev1.PersistentVolumeClaim, error) {
  1788  	clientset, err := k8sutil.GetKubernetesClientset()
  1789  	if err != nil {
  1790  		return nil, err
  1791  	}
  1792  	pvcs, err := clientset.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), metav1.ListOptions{})
  1793  	if err != nil {
  1794  		return nil, err
  1795  	}
  1796  
  1797  	volumeClaims := make(map[string]*corev1.PersistentVolumeClaim)
  1798  
  1799  	for i, pvc := range pvcs.Items {
  1800  		volumeClaims[pvc.Name] = &pvcs.Items[i]
  1801  	}
  1802  	return volumeClaims, nil
  1803  }
  1804  
  1805  func GetPersistentVolumes() (map[string]*corev1.PersistentVolume, error) {
  1806  	clientset, err := k8sutil.GetKubernetesClientset()
  1807  	if err != nil {
  1808  		return nil, err
  1809  	}
  1810  	pvList, err := clientset.CoreV1().PersistentVolumes().List(context.TODO(), metav1.ListOptions{})
  1811  	if err != nil {
  1812  		return nil, err
  1813  	}
  1814  
  1815  	pvs := make(map[string]*corev1.PersistentVolume)
  1816  
  1817  	for i, pvc := range pvList.Items {
  1818  		pvs[pvc.Name] = &pvList.Items[i]
  1819  	}
  1820  	return pvs, nil
  1821  }
  1822  
  1823  // DoesVerrazzanoProjectExistInCluster returns whether a VerrazzanoProject with the given name exists in the specified cluster
  1824  func DoesVerrazzanoProjectExistInCluster(name string, kubeconfigPath string) (bool, error) {
  1825  	// Get the clientset
  1826  	clientset, err := GetVerrazzanoProjectClientsetInCluster(kubeconfigPath)
  1827  	if err != nil {
  1828  		return false, err
  1829  	}
  1830  
  1831  	vp, err := clientset.ClustersV1alpha1().VerrazzanoProjects("verrazzano-mc").Get(context.TODO(), name, metav1.GetOptions{})
  1832  	if err != nil && !k8serrors.IsNotFound(err) {
  1833  		Log(Error, fmt.Sprintf("Failed to get VerrazzanoProject %s: %v", name, err))
  1834  		return false, err
  1835  	}
  1836  
  1837  	return vp != nil && len(vp.Name) > 0, nil
  1838  }
  1839  
  1840  // ContainerHasExpectedArgs returns true if each of the arguments matches a substring of one of the arguments found in the deployment
  1841  func ContainerHasExpectedArgs(namespace string, deploymentName string, containerName string, arguments []string) (bool, error) {
  1842  	deployment, err := GetDeployment(namespace, deploymentName)
  1843  	if err != nil {
  1844  		Log(Error, fmt.Sprintf("Deployment %v is not found in the namespace: %v, error: %v", deploymentName, namespace, err))
  1845  		return false, nil
  1846  	}
  1847  	for _, container := range deployment.Spec.Template.Spec.Containers {
  1848  		if container.Name == containerName {
  1849  			return SlicesContainSubsetSubstring(arguments, container.Args), nil
  1850  		}
  1851  	}
  1852  	return false, nil
  1853  }
  1854  
  1855  // UpdateConfigMap updates the config map
  1856  func UpdateConfigMap(configMap *corev1.ConfigMap) error {
  1857  	// Get the Kubernetes clientset
  1858  	clientset, err := k8sutil.GetKubernetesClientset()
  1859  	if err != nil {
  1860  		return err
  1861  	}
  1862  
  1863  	cmi := clientset.CoreV1().ConfigMaps(configMap.GetNamespace())
  1864  	_, err = cmi.Update(context.TODO(), configMap, metav1.UpdateOptions{})
  1865  	if err != nil {
  1866  		Log(Error, fmt.Sprintf("Failed to update Config Map %s from namespace %s: %v ", configMap.GetName(), configMap.GetNamespace(), err))
  1867  		return err
  1868  	}
  1869  	return nil
  1870  }
  1871  
  1872  // GetContainerEnv returns an array of environment variables in the specified container for the specified deployment
  1873  func GetContainerEnv(namespace string, deploymentName string, containerName string) ([]corev1.EnvVar, error) {
  1874  	deployment, err := GetDeployment(namespace, deploymentName)
  1875  	if err != nil {
  1876  		return nil, fmt.Errorf("deployment %s not found in the namespace: %s, error: %v", deploymentName, namespace, err)
  1877  	}
  1878  	for _, container := range deployment.Spec.Template.Spec.Containers {
  1879  		if container.Name == containerName {
  1880  			return container.Env, nil
  1881  		}
  1882  	}
  1883  	return nil, fmt.Errorf("container %s not found in the namespace: %s", containerName, namespace)
  1884  }
  1885  
  1886  func GetDeploymentLabelSelector(namespace, deploymentName string) (*metav1.LabelSelector, error) {
  1887  	deployment, err := GetDeployment(namespace, deploymentName)
  1888  	if err != nil {
  1889  		Log(Error, fmt.Sprintf("Deployment %v not found in the namespace: %v, error: %v", deploymentName, namespace, err))
  1890  		return nil, fmt.Errorf("deployment %s not found in the namespace: %s, error: %v", deploymentName, namespace, err)
  1891  	}
  1892  	return deployment.Spec.Selector, err
  1893  }
  1894  
  1895  // GetContainerImage returns the image used by the specified container for the specified deployment
  1896  func GetContainerImage(namespace string, deploymentName string, containerName string) (string, error) {
  1897  	deployment, err := GetDeployment(namespace, deploymentName)
  1898  	if err != nil {
  1899  		Log(Error, fmt.Sprintf("Deployment %v not found in the namespace: %v, error: %v", deploymentName, namespace, err))
  1900  		return "", nil
  1901  	}
  1902  	for _, container := range deployment.Spec.Template.Spec.Containers {
  1903  		if container.Name == containerName {
  1904  			return container.Image, nil
  1905  		}
  1906  	}
  1907  	return "", fmt.Errorf("container %v not found in the namespace: %v", containerName, namespace)
  1908  }
  1909  
  1910  // WaitForVZCondition waits till the VZ CR reaches the given condition
  1911  func WaitForVZCondition(conditionType v1beta1.ConditionType, pollingInterval, timeout time.Duration) {
  1912  	gomega.Eventually(func() bool {
  1913  		cr, err := GetVerrazzanoV1beta1()
  1914  		if err != nil {
  1915  			Log(Error, err.Error())
  1916  			return false
  1917  		}
  1918  		for _, condition := range cr.Status.Conditions {
  1919  			Log(Info, fmt.Sprintf("Evaluating condition: [%s - %s]", condition.Type, condition.Status))
  1920  			if condition.Type == conditionType && condition.Status == corev1.ConditionTrue {
  1921  				return true
  1922  			}
  1923  		}
  1924  		return false
  1925  	}).WithPolling(pollingInterval).WithTimeout(timeout).Should(gomega.BeTrue())
  1926  }
  1927  
  1928  // DeleteConfigMap to delete the ConfigMap with the given name and namespace
  1929  func DeleteConfigMap(namespace string, name string) error {
  1930  	clientset, err := k8sutil.GetKubernetesClientset()
  1931  	if err != nil {
  1932  		return err
  1933  	}
  1934  	return clientset.CoreV1().ConfigMaps(namespace).Delete(context.TODO(), name, metav1.DeleteOptions{})
  1935  }
  1936  
  1937  // CreateConfigMap creates the ConfigMap
  1938  func CreateConfigMap(configMap *corev1.ConfigMap) error {
  1939  	clientset, err := k8sutil.GetKubernetesClientset()
  1940  	if err != nil {
  1941  		return err
  1942  	}
  1943  	_, err = clientset.CoreV1().ConfigMaps(configMap.Namespace).Create(context.TODO(), configMap, metav1.CreateOptions{})
  1944  	if err != nil {
  1945  		return err
  1946  	}
  1947  	return nil
  1948  }
  1949  
  1950  func createServiceAccountTokenSecret(serviceAccount string, namespace string) error {
  1951  	var secret corev1.Secret
  1952  	secret.Name = serviceAccount + "-token"
  1953  	secret.Namespace = namespace
  1954  	secret.Type = corev1.SecretTypeServiceAccountToken
  1955  	secret.Annotations = map[string]string{
  1956  		corev1.ServiceAccountNameKey: serviceAccount,
  1957  	}
  1958  	clientset, err := k8sutil.GetKubernetesClientset()
  1959  	if err != nil {
  1960  		return err
  1961  	}
  1962  	_, err = clientset.CoreV1().Secrets(namespace).Create(context.TODO(), &secret, metav1.CreateOptions{})
  1963  	if err != nil && !k8serrors.IsAlreadyExists(err) {
  1964  		return err
  1965  	}
  1966  	return nil
  1967  }
  1968  
  1969  func VzReadyV1beta1() (bool, error) {
  1970  	cr, err := GetVerrazzanoV1beta1()
  1971  	if err != nil {
  1972  		return false, err
  1973  	}
  1974  	if cr.Status.State == v1beta1.VzStateReady {
  1975  		return true, nil
  1976  	}
  1977  	return false, fmt.Errorf("CR in state %s, not Ready yet", cr.Status.State)
  1978  }
  1979  
  1980  // IsDexEnabled returns true if the Dex component is enabled, false otherwise
  1981  func IsDexEnabled(kubeconfigPath string) bool {
  1982  	vz, err := GetVerrazzanoInstallResourceInClusterV1beta1(kubeconfigPath)
  1983  	if err != nil {
  1984  		Log(Error, fmt.Sprintf("Error Verrazzano Resource: %v", err))
  1985  		return false
  1986  	}
  1987  	if vz.Spec.Components.Dex == nil || vz.Spec.Components.Dex.Enabled == nil {
  1988  		return false
  1989  	}
  1990  	return *vz.Spec.Components.Dex.Enabled
  1991  }
  1992  
  1993  func ValidateDeploymentContainerImage(namespace, deploymentName, containerName, version string) (bool, error) {
  1994  	// Get the deployment
  1995  	deployment, err := GetDeployment(namespace, deploymentName)
  1996  	if err != nil {
  1997  		return false, fmt.Errorf("deployment %s not found in the namespace: %s, error: %v", deploymentName, namespace, err)
  1998  	}
  1999  
  2000  	for _, container := range deployment.Spec.Template.Spec.Containers {
  2001  		if containerName == container.Name {
  2002  			split := strings.Split(container.Image, ":")
  2003  			if !strings.HasPrefix(split[len(split)-1], version) {
  2004  				errStr := fmt.Sprintf("namespace %v deployment %v container %v image %v does not contain correct image version %v",
  2005  					namespace, deploymentName, containerName, container.Name, version)
  2006  				Log(Error, errStr)
  2007  			}
  2008  			break
  2009  		}
  2010  	}
  2011  	return true, nil
  2012  }