...

Source file src/github.com/redhat-developer/odo/tests/helper/helper_oc.go

Documentation: github.com/redhat-developer/odo/tests/helper

     1  package helper
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"regexp"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	"github.com/onsi/gomega/gexec"
    15  
    16  	"github.com/redhat-developer/odo/pkg/labels"
    17  )
    18  
    19  type OcRunner struct {
    20  	// path to oc binary
    21  	path string
    22  }
    23  
    24  // NewOcRunner initializes new OcRunner
    25  func NewOcRunner(ocPath string) OcRunner {
    26  	return OcRunner{
    27  		path: ocPath,
    28  	}
    29  }
    30  
    31  // Run oc with given arguments
    32  func (oc OcRunner) Run(args ...string) *gexec.Session {
    33  	session := CmdRunner(oc.path, args...)
    34  	Eventually(session).Should(gexec.Exit(0))
    35  	return session
    36  }
    37  
    38  // GetCurrentProject get currently active project in oc
    39  // returns empty string if there no active project, or no access to the project
    40  func (oc OcRunner) GetCurrentProject() string {
    41  	session := CmdRunner(oc.path, "project", "-q")
    42  	session.Wait()
    43  	if session.ExitCode() == 0 {
    44  		return strings.TrimSpace(string(session.Out.Contents()))
    45  	}
    46  	return ""
    47  }
    48  
    49  // GetCurrentServerURL retrieves the URL of the server we're currently connected to
    50  // returns empty if not connected or an error occurred
    51  func (oc OcRunner) GetCurrentServerURL() string {
    52  	session := CmdRunner(oc.path, "project")
    53  	session.Wait()
    54  	if session.ExitCode() == 0 {
    55  		output := strings.TrimSpace(string(session.Out.Contents()))
    56  		// format is: Using project "<namespace>" on server "<url>".
    57  		a := strings.Split(output, "\"")
    58  		return a[len(a)-2] // last entry is ".", we need the one before that
    59  	}
    60  	return ""
    61  }
    62  
    63  // ExecListDir returns dir list in specified location of pod
    64  func (oc OcRunner) ExecListDir(podName string, projectName string, dir string) string {
    65  	stdOut := Cmd(oc.path, "exec", podName, "--namespace", projectName,
    66  		"--", "ls", "-lai", dir).ShouldPass().Out()
    67  	return stdOut
    68  }
    69  
    70  // Exec allows generic execution of commands, returning the contents of stdout
    71  func (oc OcRunner) Exec(podName string, projectName string, args []string, expectedSuccess *bool) (string, string) {
    72  	cmd := []string{"exec", podName, "--namespace", projectName}
    73  	cmd = append(cmd, args...)
    74  
    75  	cmdWrapper := Cmd(oc.path, cmd...)
    76  	if expectedSuccess == nil {
    77  		cmdWrapper = cmdWrapper.ShouldRun()
    78  	} else if *expectedSuccess {
    79  		cmdWrapper = cmdWrapper.ShouldPass()
    80  	} else {
    81  		cmdWrapper = cmdWrapper.ShouldFail()
    82  	}
    83  	return cmdWrapper.OutAndErr()
    84  }
    85  
    86  // CheckCmdOpInRemoteCmpPod runs the provided command on remote component pod and returns the return value of command output handler function passed to it
    87  func (oc OcRunner) CheckCmdOpInRemoteCmpPod(cmpName string, appName string, prjName string, cmd []string, checkOp func(cmdOp string, err error) bool) bool {
    88  	cmpDCName := fmt.Sprintf("%s-%s", cmpName, appName)
    89  	outPodName := Cmd(oc.path, "get", "pods", "--namespace", prjName,
    90  		"--selector=deploymentconfig="+cmpDCName,
    91  		"-o", "jsonpath='{.items[0].metadata.name}'").ShouldPass().Out()
    92  	podName := strings.Replace(outPodName, "'", "", -1)
    93  	session := CmdRunner(oc.path, append([]string{"exec", podName, "--namespace", prjName,
    94  		"-c", cmpDCName, "--"}, cmd...)...)
    95  	stdOut := string(session.Wait().Out.Contents())
    96  	stdErr := string(session.Wait().Err.Contents())
    97  	if stdErr != "" && session.ExitCode() != 0 {
    98  		return checkOp(stdOut, fmt.Errorf("cmd %s failed with error %s on pod %s", cmd, stdErr, podName))
    99  	}
   100  	return checkOp(stdOut, nil)
   101  }
   102  
   103  // CheckCmdOpInRemoteDevfilePod runs the provided command on remote component pod and returns the return value of command output handler function passed to it
   104  func (oc OcRunner) CheckCmdOpInRemoteDevfilePod(podName string, containerName string, prjName string, cmd []string, checkOp func(cmdOp string, err error) bool) bool {
   105  	var execOptions []string
   106  	execOptions = []string{"exec", podName, "--namespace", prjName, "--"}
   107  	if containerName != "" {
   108  		execOptions = []string{"exec", podName, "-c", containerName, "--namespace", prjName, "--"}
   109  	}
   110  	args := append(execOptions, cmd...)
   111  	session := CmdRunner(oc.path, args...)
   112  	stdOut := string(session.Wait().Out.Contents())
   113  	stdErr := string(session.Wait().Err.Contents())
   114  	if stdErr != "" && session.ExitCode() != 0 {
   115  		return checkOp(stdOut, fmt.Errorf("cmd %s failed with error %s on pod %s", cmd, stdErr, podName))
   116  	}
   117  	return checkOp(stdOut, nil)
   118  }
   119  
   120  // GetRunningPodNameOfComp executes oc command and returns the running pod name of a deployed
   121  // component by passing component name as a argument
   122  func (oc OcRunner) GetRunningPodNameOfComp(compName string, namespace string) string {
   123  	stdOut := Cmd(oc.path, "get", "pods", "--namespace", namespace, "--show-labels").ShouldPass().Out()
   124  	re := regexp.MustCompile(`(` + compName + `-\S+)\s+\S+\s+Running.*deploymentconfig=` + compName)
   125  	podName := re.FindStringSubmatch(stdOut)[1]
   126  	return strings.TrimSpace(podName)
   127  }
   128  
   129  // GetRunningPodNameByComponent executes oc command and returns the running pod name of a deployed
   130  // devfile component by passing component name as a argument
   131  func (oc OcRunner) GetRunningPodNameByComponent(compName string, namespace string) string {
   132  	selector := fmt.Sprintf("--selector=component=%s", compName)
   133  	stdOut := Cmd(oc.path, "get", "pods", "--namespace", namespace, selector, "-o", "jsonpath={.items[*].metadata.name}").ShouldPass().Out()
   134  	return strings.TrimSpace(stdOut)
   135  }
   136  
   137  // GetJobNameByComponent executes kubectl command and returns the running job name
   138  func (oc OcRunner) GetJobNameByComponent(compName string, namespace string) string {
   139  	selector := fmt.Sprintf("--selector=app.kubernetes.io/instance=%s", compName)
   140  	stdOut := Cmd(oc.path, "get", ResourceTypeJob, "--namespace", namespace, selector, "-o", "jsonpath={.items[*].metadata.name}").ShouldPass().Out()
   141  	return strings.TrimSpace(stdOut)
   142  }
   143  
   144  // GetPVCSize executes oc command and returns the bound storage size
   145  func (oc OcRunner) GetPVCSize(compName, storageName, namespace string) string {
   146  	selector := fmt.Sprintf("--selector=app.kubernetes.io/storage-name=%s,app.kubernetes.io/instance=%s", storageName, compName)
   147  	stdOut := Cmd(oc.path, "get", "pvc", "--namespace", namespace, selector, "-o", "jsonpath={.items[*].spec.resources.requests.storage}").ShouldPass().Out()
   148  	return strings.TrimSpace(stdOut)
   149  }
   150  
   151  // GetPodInitContainers executes oc command and returns the init containers of the pod
   152  func (oc OcRunner) GetPodInitContainers(compName string, namespace string) []string {
   153  	selector := fmt.Sprintf("--selector=component=%s", compName)
   154  	stdOut := Cmd(oc.path, "get", "pods", "--namespace", namespace, selector, "-o", "jsonpath={.items[*].spec.initContainers[*].name}").ShouldPass().Out()
   155  	return strings.Split(stdOut, " ")
   156  }
   157  
   158  // GetRoute returns route URL
   159  func (oc OcRunner) GetRoute(urlName string, appName string) string {
   160  	session := CmdRunner(oc.path, "get", "routes", urlName+"-"+appName,
   161  		"-o jsonpath={.spec.host}")
   162  	Eventually(session).Should(gexec.Exit(0))
   163  	return strings.TrimSpace(string(session.Wait().Out.Contents()))
   164  }
   165  
   166  // GetToken returns current user token
   167  func (oc OcRunner) GetToken() string {
   168  	session := CmdRunner(oc.path, "whoami", "-t")
   169  	Eventually(session).Should(gexec.Exit(0))
   170  	return strings.TrimSpace(string(session.Wait().Out.Contents()))
   171  }
   172  
   173  // LoginUsingToken returns output after successful login
   174  func (oc OcRunner) LoginUsingToken(token string) string {
   175  	session := CmdRunner(oc.path, "login", "--token", token)
   176  	Eventually(session).Should(gexec.Exit(0))
   177  	return strings.TrimSpace(string(session.Wait().Out.Contents()))
   178  }
   179  
   180  // GetLoginUser returns current user name
   181  func (oc OcRunner) GetLoginUser() string {
   182  	user := Cmd(oc.path, "whoami").ShouldPass().Out()
   183  	return strings.TrimSpace(user)
   184  }
   185  
   186  // ServiceInstanceStatus returns service instance
   187  func (oc OcRunner) ServiceInstanceStatus(serviceInstanceName string) string {
   188  	serviceinstance := Cmd(oc.path, "get", "serviceinstance", serviceInstanceName,
   189  		"-o", "go-template='{{ (index .status.conditions 0).reason}}'").ShouldPass().Out()
   190  	return strings.TrimSpace(serviceinstance)
   191  }
   192  
   193  // GetVolumeMountNamesandPathsFromContainer returns the volume name and mount path in the format name:path\n
   194  func (oc OcRunner) GetVolumeMountNamesandPathsFromContainer(deployName string, containerName, namespace string) string {
   195  	volumeName := Cmd(oc.path, "get", "deploy", deployName, "--namespace", namespace,
   196  		"-o", "go-template="+
   197  			"{{range .spec.template.spec.containers}}{{if eq .name \""+containerName+
   198  			"\"}}{{range .volumeMounts}}{{.name}}{{\":\"}}{{.mountPath}}{{\"\\n\"}}{{end}}{{end}}{{end}}").ShouldPass().Out()
   199  
   200  	return strings.TrimSpace(volumeName)
   201  }
   202  
   203  // GetContainerEnv returns the container env in the format name:value\n
   204  func (oc OcRunner) GetContainerEnv(podName, containerName, namespace string) string {
   205  	containerEnv := Cmd(oc.path, "get", "po", podName, "--namespace", namespace,
   206  		"-o", "go-template="+
   207  			"{{range .spec.containers}}{{if eq .name \""+containerName+
   208  			"\"}}{{range .env}}{{.name}}{{\":\"}}{{.value}}{{\"\\n\"}}{{end}}{{end}}{{end}}").ShouldPass().Out()
   209  
   210  	return strings.TrimSpace(containerEnv)
   211  }
   212  
   213  // GetEnvFromEntry returns envFrom entry of the deployment
   214  func (oc OcRunner) GetEnvFromEntry(componentName string, appName string, projectName string) string {
   215  	return GetEnvFromEntry(oc.path, componentName, appName, projectName)
   216  }
   217  
   218  func (oc OcRunner) GetEnvsDevFileDeployment(componentName, appName, projectName string) map[string]string {
   219  	var mapOutput = make(map[string]string)
   220  
   221  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag()
   222  	output := Cmd(oc.path, "get", "deployment", selector, "--namespace", projectName,
   223  		"-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].env[*]}{.name}:{.value}{\"\\n\"}{end}'").ShouldPass().Out()
   224  
   225  	for _, line := range strings.Split(output, "\n") {
   226  		line = strings.TrimPrefix(line, "'")
   227  		splits := strings.Split(line, ":")
   228  		name := splits[0]
   229  		value := strings.Join(splits[1:], ":")
   230  		mapOutput[name] = value
   231  	}
   232  	return mapOutput
   233  }
   234  
   235  // GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data
   236  func (oc OcRunner) GetEnvRefNames(componentName, appName, projectName string) []string {
   237  	return GetEnvRefNames(oc.path, componentName, appName, projectName)
   238  }
   239  
   240  // WaitAndCheckForExistence wait for the given and checks if the given resource type gets deleted on the cluster
   241  func (oc OcRunner) WaitAndCheckForExistence(resourceType, namespace string, timeoutMinutes int) bool {
   242  	pingTimeout := time.After(time.Duration(timeoutMinutes) * time.Minute)
   243  	// this is a test package so time.Tick() is acceptable
   244  	// nolint
   245  	tick := time.Tick(time.Second)
   246  	for {
   247  		select {
   248  		case <-pingTimeout:
   249  			Fail(fmt.Sprintf("Timeout after %d minutes", timeoutMinutes))
   250  
   251  		case <-tick:
   252  			session := CmdRunner(oc.path, "get", resourceType, "--namespace", namespace)
   253  			Eventually(session).Should(gexec.Exit(0))
   254  			// https://github.com/kubernetes/kubectl/issues/847
   255  			output := string(session.Wait().Err.Contents())
   256  
   257  			if strings.Contains(strings.ToLower(output), "no resources found") {
   258  				return true
   259  			}
   260  		}
   261  	}
   262  }
   263  
   264  // GetServices gets services on the cluster
   265  func (oc OcRunner) GetServices(namespace string) string {
   266  	session := CmdRunner(oc.path, "get", "services", "--namespace", namespace)
   267  	Eventually(session).Should(gexec.Exit(0))
   268  	output := string(session.Wait().Out.Contents())
   269  	return output
   270  }
   271  
   272  // VerifyResourceDeleted verifies if the given resource is deleted from cluster
   273  func (oc OcRunner) VerifyResourceDeleted(ri ResourceInfo) {
   274  	session := CmdRunner(oc.path, "get", ri.ResourceType, "--namespace", ri.Namespace)
   275  	Eventually(session).Should(gexec.Exit(0))
   276  	output := string(session.Wait().Out.Contents())
   277  	Expect(output).NotTo(ContainSubstring(ri.ResourceName))
   278  }
   279  
   280  func (oc OcRunner) VerifyResourceToBeDeleted(ri ResourceInfo) {
   281  	deletedOrMarkedToDelete := func() bool {
   282  		session := CmdRunner(oc.path, "get", ri.ResourceType, ri.ResourceName, "--namespace", ri.Namespace, "-o", "jsonpath='{.metadata.deletionTimestamp}'")
   283  		exit := session.Wait().ExitCode()
   284  		if exit == 1 {
   285  			// resources does not exist
   286  			return true
   287  		}
   288  		content := session.Wait().Out.Contents()
   289  		// resource is marked for deletion
   290  		return len(content) > 0
   291  	}
   292  	Expect(deletedOrMarkedToDelete()).To(BeTrue())
   293  }
   294  
   295  // CreateAndSetRandNamespaceProject create and set new project
   296  func (oc OcRunner) CreateAndSetRandNamespaceProject() string {
   297  	projectName := GenerateProjectName()
   298  	oc.createAndSetRandNamespaceProject(projectName)
   299  	return projectName
   300  }
   301  
   302  // CreateAndSetRandNamespaceProjectOfLength creates a new project with name of length i and sets it to the current context
   303  func (oc OcRunner) CreateAndSetRandNamespaceProjectOfLength(i int) string {
   304  	projectName := RandString(i)
   305  	oc.createAndSetRandNamespaceProject(projectName)
   306  	return projectName
   307  }
   308  
   309  func (oc OcRunner) createAndSetRandNamespaceProject(projectName string) string {
   310  	if oc.HasNamespaceProject(projectName) {
   311  		fmt.Fprintf(GinkgoWriter, "Project %q already exists\n", projectName)
   312  	} else {
   313  		fmt.Fprintf(GinkgoWriter, "Creating a new project: %s\n", projectName)
   314  		session := Cmd(oc.path, "new-project", projectName).ShouldPass().Out()
   315  		Expect(session).To(ContainSubstring(projectName))
   316  	}
   317  	// ListNamespaceProject makes sure that project eventually appears in the list of all namespaces/projects.
   318  	oc.ListNamespaceProject(projectName)
   319  	oc.addConfigMapForCleanup(projectName)
   320  	return projectName
   321  }
   322  
   323  func (oc OcRunner) SetProject(namespace string) string {
   324  	fmt.Fprintf(GinkgoWriter, "Setting project: %s\n", namespace)
   325  	Cmd("odo", "set", "project", namespace).ShouldPass()
   326  	return namespace
   327  }
   328  
   329  // DeleteNamespaceProject deletes a specified project in oc cluster
   330  func (oc OcRunner) DeleteNamespaceProject(projectName string, wait bool) {
   331  	fmt.Fprintf(GinkgoWriter, "Deleting project: %s\n", projectName)
   332  	Cmd(oc.path, "delete", "project", projectName, "--wait="+strconv.FormatBool(wait)).ShouldPass()
   333  }
   334  
   335  func (oc OcRunner) GetAllPVCNames(namespace string) []string {
   336  	session := CmdRunner(oc.path, "get", "pvc", "--namespace", namespace, "-o", "jsonpath={.items[*].metadata.name}")
   337  	Eventually(session).Should(gexec.Exit(0))
   338  	output := string(session.Wait().Out.Contents())
   339  	if output == "" {
   340  		return []string{}
   341  	}
   342  	return strings.Split(output, " ")
   343  }
   344  
   345  // DeletePod deletes a specified pod in the namespace
   346  func (oc OcRunner) DeletePod(podName string, namespace string) {
   347  	Cmd(oc.path, "delete", "pod", "--namespace", namespace, podName).ShouldPass()
   348  }
   349  
   350  // GetAllPodsInNs gets the list of pods in given namespace. It waits for reasonable amount of time for pods to come up
   351  func (oc OcRunner) GetAllPodsInNs(namespace string) string {
   352  	args := []string{"get", "pods", "-n", namespace}
   353  	noResourcesMsg := fmt.Sprintf("No resources found in %s namespace", namespace)
   354  	oc.WaitForRunnerCmdOut(args, 1, true, func(output string) bool {
   355  		return !strings.Contains(output, noResourcesMsg)
   356  	}, true)
   357  	return Cmd(oc.path, args...).ShouldPass().Out()
   358  }
   359  
   360  // GetAllPodNames gets the names of pods in given namespace
   361  func (oc OcRunner) GetAllPodNames(namespace string) []string {
   362  	session := CmdRunner(oc.path, "get", "pods", "--namespace", namespace, "-o", "jsonpath={.items[*].metadata.name}")
   363  	Eventually(session).Should(gexec.Exit(0))
   364  	output := string(session.Wait().Out.Contents())
   365  	if output == "" {
   366  		return []string{}
   367  	}
   368  	return strings.Split(output, " ")
   369  }
   370  
   371  // StatFileInPod returns stat result of filepath in pod of given component, in a given app, in a given project.
   372  // It also strips access time information as it vaires accross file systems/kernel configs, and we are not interested
   373  // in it anyway
   374  func (oc OcRunner) StatFileInPod(cmpName, appName, project, filepath string) string {
   375  	var result string
   376  	oc.CheckCmdOpInRemoteCmpPod(
   377  		cmpName,
   378  		appName,
   379  		project,
   380  		[]string{"stat", filepath},
   381  		func(cmdOp string, err error) bool {
   382  			// strip out access info as
   383  			// 1. Touching a file (such as running it in a script) modifies access times. This gives wrong value on mounts without noatime
   384  			// 2. We are not interested in Access info anyway.
   385  			re := regexp.MustCompile("(?m)[\r\n]+^.*Access.*$")
   386  			result = re.ReplaceAllString(cmdOp, "")
   387  			return true
   388  		},
   389  	)
   390  	return result
   391  }
   392  
   393  // WaitAndCheckForTerminatingState waits for the given interval
   394  // and checks if the given resource type has been deleted on the cluster or is in the terminating state
   395  func (oc OcRunner) WaitAndCheckForTerminatingState(resourceType, namespace string, timeoutMinutes int) bool {
   396  	return WaitAndCheckForTerminatingState(oc.path, resourceType, namespace, timeoutMinutes)
   397  }
   398  
   399  // GetAnnotationsDeployment gets the annotations from the deployment
   400  // belonging to the given component, app and project
   401  func (oc OcRunner) GetAnnotationsDeployment(componentName, appName, projectName string) map[string]string {
   402  	return GetAnnotationsDeployment(oc.path, componentName, appName, projectName)
   403  }
   404  
   405  func (oc OcRunner) PodsShouldBeRunning(project string, regex string) {
   406  	// now verify if the pods for the operator have started
   407  	pods := oc.GetAllPodsInNs(project)
   408  	// Look for pods with specified regex
   409  	pod := regexp.MustCompile(regex).FindString(pods)
   410  	args := []string{"get", "pods", pod, "-o", "template=\"{{.status.phase}}\"", "-n", project}
   411  	oc.WaitForRunnerCmdOut(args, 8, true, func(output string) bool {
   412  		return strings.Contains(output, "Running")
   413  	})
   414  }
   415  
   416  // WaitForRunnerCmdOut runs "oc" command until it gets
   417  // the expected output.
   418  // It accepts 4 arguments
   419  // args (arguments to the program)
   420  // timeout (the time to wait for the output)
   421  // errOnFail (flag to set if test should fail if command fails)
   422  // check (function with output check logic)
   423  // It times out if the command doesn't fetch the
   424  // expected output  within the timeout period.
   425  func (oc OcRunner) WaitForRunnerCmdOut(args []string, timeout int, errOnFail bool, check func(output string) bool, includeStdErr ...bool) bool {
   426  	pingTimeout := time.After(time.Duration(timeout) * time.Minute)
   427  	// this is a test package so time.Tick() is acceptable
   428  	// nolint
   429  	tick := time.Tick(time.Second)
   430  	for {
   431  		select {
   432  		case <-pingTimeout:
   433  			Fail(fmt.Sprintf("Timeout after %v minutes", timeout))
   434  
   435  		case <-tick:
   436  			session := CmdRunner(oc.path, args...)
   437  			if errOnFail {
   438  				Eventually(session).Should(gexec.Exit(0), runningCmd(session.Command))
   439  			} else {
   440  				Eventually(session).Should(gexec.Exit(), runningCmd(session.Command))
   441  			}
   442  			session.Wait()
   443  			output := string(session.Out.Contents())
   444  
   445  			if len(includeStdErr) > 0 && includeStdErr[0] {
   446  				output += "\n"
   447  				output += string(session.Err.Contents())
   448  			}
   449  			if check(strings.TrimSpace(output)) {
   450  				return true
   451  			}
   452  		}
   453  	}
   454  }
   455  
   456  // CreateSecret takes secret name, password and the namespace where we want to create the specific secret into the cluster
   457  func (oc OcRunner) CreateSecret(secretName, secretPass, project string) {
   458  	Cmd(oc.path, "create", "secret", "generic", secretName, "--from-literal=password="+secretPass, "-n", project).ShouldPass()
   459  }
   460  
   461  // GetSecrets gets all the secrets belonging to the project
   462  func (oc OcRunner) GetSecrets(project string) string {
   463  	return GetSecrets(oc.path, project)
   464  }
   465  
   466  // GetVolumeNamesFromDeployment gets the volumes from the deployment belonging to the given data
   467  func (oc OcRunner) GetVolumeNamesFromDeployment(componentName, appName, projectName string) map[string]string {
   468  	return GetVolumeNamesFromDeployment(oc.path, componentName, appName, projectName)
   469  }
   470  
   471  // AddSecret adds pull-secret to the namespace, for e2e-test
   472  func (oc OcRunner) AddSecret(comvar CommonVar) {
   473  
   474  	clusterType := os.Getenv("CLUSTER_TYPE")
   475  	if clusterType == "PSI" || clusterType == "IBM" {
   476  
   477  		token := oc.doAsAdmin(clusterType)
   478  
   479  		yaml := Cmd(oc.path, "get", "secret", "pull-secret", "-n", "openshift-config", "-o", "yaml").ShouldPass().Out()
   480  		newYaml := strings.Replace(yaml, "openshift-config", comvar.Project, -1)
   481  		filename := fmt.Sprint(RandString(4), ".yaml")
   482  		newYamlinByte := []byte(newYaml)
   483  		err := os.WriteFile(filename, newYamlinByte, 0600)
   484  		if err != nil {
   485  			fmt.Println(err)
   486  		}
   487  		Cmd(oc.path, "apply", "-f", filename).ShouldPass()
   488  		os.Remove(filename)
   489  		oc.doAsDeveloper(token, clusterType)
   490  	}
   491  
   492  }
   493  
   494  // doAsAdmin logins as admin to perform some task that requires admin privileges
   495  func (oc OcRunner) doAsAdmin(clusterType string) string {
   496  	// save token for developer
   497  	token := oc.GetToken()
   498  	if clusterType == "PSI" || clusterType == "IBM" {
   499  
   500  		adminToken := os.Getenv("IBMC_OCLOGIN_APIKEY")
   501  		if adminToken != "" {
   502  			ibmcloudAdminToken := os.Getenv("IBMC_ADMIN_LOGIN_APIKEY")
   503  			cluster := os.Getenv("IBMC_OCP47_SERVER")
   504  			// login ibmcloud
   505  			Cmd("ibmcloud", "login", "--apikey", ibmcloudAdminToken, "-r", "eu-de", "-g", "Developer-CI-and-QE")
   506  			// login as admin in cluster
   507  			Cmd(oc.path, "login", "--token=", adminToken, "--server=", cluster)
   508  		} else {
   509  			pass := os.Getenv("OCP4X_KUBEADMIN_PASSWORD")
   510  			cluster := os.Getenv("OCP4X_API_URL")
   511  			// login as kubeadmin
   512  			Cmd(oc.path, "login", "-u", "kubeadmin", "-p", pass, cluster).ShouldPass()
   513  		}
   514  	}
   515  	return token
   516  }
   517  
   518  // doAsDeveloper logins as developer to perform some task
   519  func (oc OcRunner) doAsDeveloper(token, clusterType string) {
   520  
   521  	if clusterType == "IBM" {
   522  		ibmcloudDeveloperToken := os.Getenv("IBMC_DEVELOPER_LOGIN_APIKEY")
   523  		Cmd("ibmcloud", "login", "--apikey", ibmcloudDeveloperToken, "-r", "eu-de", "-g", "Developer-CI-and-QE")
   524  		// login as developer using token
   525  	}
   526  	oc.LoginUsingToken(token)
   527  }
   528  
   529  // add config map to the project for cleanup
   530  func (oc OcRunner) addConfigMapForCleanup(projectName string) {
   531  	Cmd(oc.path, "create", "configmap", "config-map-for-cleanup", "--from-literal", "type=testing", "--from-literal", "team=odo", "-n", projectName).ShouldPass()
   532  }
   533  
   534  func (oc OcRunner) Logout() {
   535  	Cmd(oc.path, "logout")
   536  }
   537  
   538  // ScalePodToZero scales the pod of the deployment to zero.
   539  // It waits for the pod to get deleted from the cluster before returning
   540  func (oc OcRunner) ScalePodToZero(componentName, appName, projectName string) {
   541  	podName := oc.GetRunningPodNameByComponent(componentName, projectName)
   542  	Cmd(oc.path, "scale", "deploy", strings.Join([]string{componentName, appName}, "-"), "--replicas=0").ShouldPass()
   543  	oc.WaitForRunnerCmdOut([]string{"get", "-n", projectName, "pod", podName}, 1, false, func(output string) bool {
   544  		return !strings.Contains(output, podName)
   545  	})
   546  }
   547  
   548  func (oc OcRunner) GetBindableKinds() (string, string) {
   549  	return Cmd(oc.path, "get", "bindablekinds", "bindable-kinds", "-ojsonpath={.status[*].kind}").ShouldRun().OutAndErr()
   550  }
   551  
   552  func (oc OcRunner) GetServiceBinding(name, projectName string) (string, string) {
   553  	return Cmd(oc.path, "get", "servicebinding", name, "-n", projectName).ShouldRun().OutAndErr()
   554  }
   555  
   556  func (oc OcRunner) EnsureOperatorIsInstalled(partialOperatorName string) {
   557  	WaitForCmdOut(oc.path, []string{"get", "csv", "-o", "jsonpath={.items[?(@.status.phase==\"Succeeded\")].metadata.name}"}, 4, true, func(output string) bool {
   558  		return strings.Contains(output, partialOperatorName)
   559  	})
   560  }
   561  
   562  func (oc OcRunner) GetNamespaceProject() string {
   563  	return Cmd(oc.path, "get", "project").ShouldPass().Out()
   564  }
   565  
   566  func (oc OcRunner) HasNamespaceProject(name string) bool {
   567  	out := Cmd(oc.path, "get", "project", name, "-o", "jsonpath={.metadata.name}").
   568  		ShouldRun().Out()
   569  	return strings.Contains(out, name)
   570  }
   571  
   572  func (oc OcRunner) ListNamespaceProject(name string) {
   573  	Eventually(func() string {
   574  		return Cmd(oc.path, "get", "project").ShouldRun().Out()
   575  	}, 30, 1).Should(ContainSubstring(name))
   576  }
   577  
   578  func (oc OcRunner) GetActiveNamespace() string {
   579  	return Cmd(oc.path, "config", "view", "--minify", "-ojsonpath={..namespace}").ShouldPass().Out()
   580  }
   581  
   582  func (oc OcRunner) GetAllNamespaceProjects() []string {
   583  	output := Cmd(oc.path, "get", "projects",
   584  		"-o", "custom-columns=NAME:.metadata.name",
   585  		"--no-headers").ShouldPass().Out()
   586  	result, err := ExtractLines(output)
   587  	Expect(err).ShouldNot(HaveOccurred())
   588  	return result
   589  }
   590  
   591  func (oc OcRunner) GetLogs(podName string) string {
   592  	output := Cmd(oc.path, "logs", podName).ShouldPass().Out()
   593  	return output
   594  }
   595  
   596  func (oc OcRunner) AssertContainsLabel(kind, namespace, componentName, appName, mode, key, value string) {
   597  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).WithMode(mode).SelectorFlag()
   598  	all := Cmd(oc.path, "get", kind, selector, "-n", namespace, "-o", "jsonpath={.items[0].metadata.labels}").ShouldPass().Out()
   599  	Expect(all).To(ContainSubstring(fmt.Sprintf(`"%s":"%s"`, key, value)))
   600  }
   601  
   602  func (oc OcRunner) AssertNoContainsLabel(kind, namespace, componentName, appName, mode, key string) {
   603  	selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).WithMode(mode).SelectorFlag()
   604  	all := Cmd(oc.path, "get", kind, selector, "-n", namespace, "-o", "jsonpath={.items[0].metadata.labels}").ShouldPass().Out()
   605  	Expect(all).ToNot(ContainSubstring(fmt.Sprintf(`"%s"`, key)))
   606  }
   607  
   608  func (oc OcRunner) EnsurePodIsUp(namespace, podName string) {
   609  	WaitForCmdOut(oc.path, []string{"get", "pods", "-n", namespace, "-o", "jsonpath='{range .items[*]}{.metadata.name}'"}, 4, true, func(output string) bool {
   610  		return strings.Contains(output, podName)
   611  	})
   612  }
   613  
   614  func (oc OcRunner) AssertNonAuthenticated() {
   615  	Cmd(oc.path, "whoami").ShouldFail()
   616  }
   617  
   618  func (oc OcRunner) GetVersion() string {
   619  	res := Cmd(oc.path, "version", "--output=json").ShouldPass().Out()
   620  	var js map[string]interface{}
   621  	err := json.Unmarshal([]byte(res), &js)
   622  	Expect(err).ShouldNot(HaveOccurred())
   623  	val, ok := js["openshiftVersion"].(string)
   624  	if !ok {
   625  		return ""
   626  	}
   627  	return val
   628  }
   629  
   630  func (oc OcRunner) SetLabelsOnNamespace(ns string, labelValues ...string) {
   631  	args := []string{"label", "namespaces"}
   632  	args = append(args, labelValues...)
   633  	Cmd(oc.path, args...)
   634  }
   635  

View as plain text