containerized-data-importer/tests/utils.go
Marcelo Carneiro do Amaral 8d1721db0a
Add support for proxy in the CDI import pod, reconciling the info from OpenShift cluster wide proxy when available (#1507)
* api: Add new ImportProxy structure to CDIConfig in v1beta1 core api

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* common: Add constants related to configure Import proxy in Import pod and controller reconcile

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* config controller: Add import proxy reconcile, monitoring OCP proxy updates

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* config controller: Add unit test for import proxy reconcile, monitoring OCP proxy updates and creating Secret and ConfigMap

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* import controller: Add unit support of ImportProxy in the tests

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller util: Add support to retrieve an OpenShift cluster wide proxy object as well as its needed configurations

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller util:  Add unit test for the get cluster wide proxy functionality

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller: moved isOpenshift function to utils common and export it

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* importer: Clone http transport to keep the default proxy config such as the usage of environment variables and add support for proxy CA

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* operator: Update CDIConfigCRD with import proxy info

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* operator: Update CDIListCRD with import proxy info

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* operator: Add service account rights to CDI for accessing OpenShift proxy obj

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* operator: Add OpenShift proxy obj scheme support

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: Add new forwarding proxy for testing things that require a proxy

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: Add test to verify the importer pod with proxy

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* doc: Update cdi config doc with the ImportProxy info

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* add support to build the new proxy docker image

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: remove unwanted F parameter from test

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller: fix error handling

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: update the used method to get the pod of the importer pod and proxy

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* fixed comments from the revision

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller config: update the methods to use the log object from the reconcile object

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller: update function GetImportProxyConfig to return errors and include a new unit test

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* controller: add back a test that was removed by mistake

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* update updateCDIConfigByUpdatingTheClusterWideProxy function

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: decrease the import pod log pooling interval and increase the image size to be able to verify the import pod before it is deleted

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: update the pvc and proxied requests verification

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* tools: add X-Forwarded-For header in the proxy requests  used for testing

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: reset cluster wide proxy with the original values

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* test: fix proxy update to change spec instead of status and other minor updates

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* doc: update import proxy description

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>

* update generated files

Signed-off-by: Marcelo Amaral <marcelo.amaral1@ibm.com>
2021-02-16 13:43:01 +01:00

172 lines
5.2 KiB
Go

package tests
import (
"bytes"
"context"
"fmt"
"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"
"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
}