mirror of
https://github.com/kubevirt/containerized-data-importer.git
synced 2025-06-03 06:30:22 +00:00

* Move "isOpenshift" to utils and make public. No functional change. Signed-off-by: Maya Rashish <mrashish@redhat.com> * Skip malformed too large qcow2 on openshift. Whether this test fails depends on the qemu-img version. The way we build and test it in this repo is fine, but external builds may fail. Skipping only on OpenShift means we will continue testing it and finding regressions. Signed-off-by: Maya Rashish <mrashish@redhat.com>
203 lines
6.0 KiB
Go
203 lines
6.0 KiB
Go
package tests
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"time"
|
|
|
|
sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/api"
|
|
|
|
"github.com/onsi/ginkgo"
|
|
|
|
v1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/kubernetes"
|
|
|
|
"kubevirt.io/containerized-data-importer/tests/framework"
|
|
)
|
|
|
|
const (
|
|
defaultTimeout = 270 * time.Second
|
|
testNamespacePrefix = "cdi-test-"
|
|
)
|
|
|
|
var (
|
|
versionRegex = regexp.MustCompile(`ubernetes .*v(\d+\.\d+\.\d+)`)
|
|
versionRegexServer = regexp.MustCompile(`Server Version: .*({.*})`)
|
|
versionRegexGitVersion = regexp.MustCompile(`GitVersion:"v(\d+\.\d+\.\d+)\+?\S*"`)
|
|
nodeSelectorTestValue = map[string]string{"kubernetes.io/arch": runtime.GOARCH}
|
|
tolerationsTestValue = []v1.Toleration{{Key: "test", Value: "123"}}
|
|
affinityTestValue = &v1.Affinity{}
|
|
)
|
|
|
|
// CDIFailHandler call ginkgo.Fail with printing the additional information
|
|
func CDIFailHandler(message string, callerSkip ...int) {
|
|
if len(callerSkip) > 0 {
|
|
callerSkip[0]++
|
|
}
|
|
ginkgo.Fail(message, callerSkip...)
|
|
}
|
|
|
|
//RunKubectlCommand ...
|
|
func RunKubectlCommand(f *framework.Framework, args ...string) (string, error) {
|
|
var errb bytes.Buffer
|
|
cmd := CreateKubectlCommand(f, args...)
|
|
|
|
cmd.Stderr = &errb
|
|
stdOutBytes, err := cmd.Output()
|
|
if err != nil {
|
|
if len(errb.String()) > 0 {
|
|
return errb.String(), err
|
|
}
|
|
// err will not always be nil calling kubectl, this is expected on no results for instance.
|
|
// still return the value and let the called decide what to do.
|
|
return string(stdOutBytes), err
|
|
}
|
|
return string(stdOutBytes), nil
|
|
}
|
|
|
|
// CreateKubectlCommand returns the Cmd to execute kubectl
|
|
func CreateKubectlCommand(f *framework.Framework, args ...string) *exec.Cmd {
|
|
kubeconfig := f.KubeConfig
|
|
path := f.KubectlPath
|
|
|
|
cmd := exec.Command(path, args...)
|
|
kubeconfEnv := fmt.Sprintf("KUBECONFIG=%s", kubeconfig)
|
|
cmd.Env = append(os.Environ(), kubeconfEnv)
|
|
|
|
return cmd
|
|
}
|
|
|
|
//PrintControllerLog ...
|
|
func PrintControllerLog(f *framework.Framework) {
|
|
PrintPodLog(f, f.ControllerPod.Name, f.CdiInstallNs)
|
|
}
|
|
|
|
//PrintPodLog ...
|
|
func PrintPodLog(f *framework.Framework, podName, namespace string) {
|
|
log, err := RunKubectlCommand(f, "logs", podName, "-n", namespace)
|
|
if err == nil {
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, "INFO: Pod log\n%s\n", log)
|
|
} else {
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, "INFO: Unable to get pod log, %s\n", err.Error())
|
|
}
|
|
}
|
|
|
|
//PanicOnError ...
|
|
func PanicOnError(err error) {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// GetKubeVersion returns the version returned by the kubectl version command as a semver compatible string
|
|
func GetKubeVersion(f *framework.Framework) string {
|
|
// Check non json version output.
|
|
out, err := RunKubectlCommand(f, "version")
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, "INFO: Output from kubectl: %s\n", out)
|
|
matches := versionRegex.FindStringSubmatch(out)
|
|
if len(matches) > 1 {
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, "INFO: kubectl version: %s\n", matches[1])
|
|
return matches[1]
|
|
}
|
|
// Didn't match, maybe its the newer version
|
|
matches = versionRegexServer.FindStringSubmatch(out)
|
|
if len(matches) > 1 {
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, "INFO: kubectl version output: %s\n", matches[1])
|
|
// Would love to use json.Unmarshal, but keys aren't quoted
|
|
gitVersion := versionRegexGitVersion.FindStringSubmatch(matches[1])
|
|
if len(gitVersion) > 1 {
|
|
return gitVersion[1]
|
|
}
|
|
return ""
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// TestNodePlacementValues returns a pre-defined set of node placement values for testing purposes.
|
|
// The values chosen are valid, but the pod will likely not be schedulable.
|
|
func TestNodePlacementValues(f *framework.Framework) sdkapi.NodePlacement {
|
|
nodes, _ := f.K8sClient.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
|
|
affinityTestValue = &v1.Affinity{
|
|
NodeAffinity: &v1.NodeAffinity{
|
|
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
|
|
NodeSelectorTerms: []v1.NodeSelectorTerm{
|
|
{
|
|
MatchExpressions: []v1.NodeSelectorRequirement{
|
|
{Key: "kubernetes.io/hostname", Operator: v1.NodeSelectorOpIn, Values: []string{nodes.Items[0].Name}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
return sdkapi.NodePlacement{
|
|
NodeSelector: nodeSelectorTestValue,
|
|
Affinity: affinityTestValue,
|
|
Tolerations: tolerationsTestValue,
|
|
}
|
|
}
|
|
|
|
// PodSpecHasTestNodePlacementValues compares if the pod spec has the set of node placement values defined for testing purposes
|
|
func PodSpecHasTestNodePlacementValues(f *framework.Framework, podSpec v1.PodSpec) bool {
|
|
if !reflect.DeepEqual(podSpec.NodeSelector, nodeSelectorTestValue) {
|
|
fmt.Printf("mismatched nodeSelectors, podSpec:\n%v\nExpected:\n%v\n", podSpec.NodeSelector, nodeSelectorTestValue)
|
|
return false
|
|
}
|
|
if !reflect.DeepEqual(podSpec.Affinity, affinityTestValue) {
|
|
fmt.Printf("mismatched affinity, podSpec:\n%v\nExpected:\n%v\n", *podSpec.Affinity, affinityTestValue)
|
|
return false
|
|
}
|
|
foundMatchingTolerations := false
|
|
for _, toleration := range podSpec.Tolerations {
|
|
if toleration == tolerationsTestValue[0] {
|
|
foundMatchingTolerations = true
|
|
}
|
|
}
|
|
if foundMatchingTolerations != true {
|
|
fmt.Printf("no matching tolerations found. podSpec:\n%v\nExpected:\n%v\n", podSpec.Tolerations, tolerationsTestValue)
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
//IsOpenshift checks if we are on OpenShift platform
|
|
func IsOpenshift(client kubernetes.Interface) bool {
|
|
//OpenShift 3.X check
|
|
result := client.Discovery().RESTClient().Get().AbsPath("/oapi/v1").Do(context.TODO())
|
|
var statusCode int
|
|
result.StatusCode(&statusCode)
|
|
|
|
if result.Error() == nil {
|
|
// It is OpenShift
|
|
if statusCode == http.StatusOK {
|
|
return true
|
|
}
|
|
} else {
|
|
// Got 404 so this is not Openshift 3.X, let's check OpenShift 4
|
|
result = client.Discovery().RESTClient().Get().AbsPath("/apis/route.openshift.io").Do(context.TODO())
|
|
var statusCode int
|
|
result.StatusCode(&statusCode)
|
|
|
|
if result.Error() == nil {
|
|
// It is OpenShift
|
|
if statusCode == http.StatusOK {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|