Refactor TestVolumeClient and InjectContent into common function

These two functions do almost the same thing - one writes data to volumes
in a pod, the second reads them. Let them share the code.
This commit is contained in:
Jan Safranek 2019-07-10 15:17:09 +02:00
parent a29243775a
commit a2c9052716
2 changed files with 45 additions and 68 deletions

View File

@ -42,14 +42,13 @@ package volume
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv" "strconv"
"time" "time"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors" apierrs "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/labels"
clientset "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/framework"
e2elog "k8s.io/kubernetes/test/e2e/framework/log" e2elog "k8s.io/kubernetes/test/e2e/framework/log"
@ -424,19 +423,15 @@ func TestCleanup(f *framework.Framework, config TestConfig) {
} }
} }
// TestVolumeClient start a client pod using given VolumeSource (exported by startVolumeServer()) func runVolumeTesterPod(client clientset.Interface, config TestConfig, podSuffix string, fsGroup *int64, tests []Test) (*v1.Pod, error) {
// and check that the pod sees expected data, e.g. from the server pod. ginkgo.By(fmt.Sprint("starting ", config.Prefix, "-", podSuffix))
// Multiple Tests can be specified to mount multiple volumes to a single
// pod.
func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *int64, fsType string, tests []Test) {
ginkgo.By(fmt.Sprint("starting ", config.Prefix, "-client"))
var gracePeriod int64 = 1 var gracePeriod int64 = 1
var command string var command string
if !framework.NodeOSDistroIs("windows") { if !framework.NodeOSDistroIs("windows") {
command = "while true ; do cat /opt/0/index.html ; sleep 2 ; ls -altrh /opt/ ; sleep 2 ; done " command = "while true ; do sleep 2; done "
} else { } else {
command = "while(1) {cat /opt/0/index.html ; sleep 2 ; ls /opt/; sleep 2}" command = "while(1) {sleep 2}"
} }
seLinuxOptions := &v1.SELinuxOptions{Level: "s0:c0,c1"} seLinuxOptions := &v1.SELinuxOptions{Level: "s0:c0,c1"}
clientPod := &v1.Pod{ clientPod := &v1.Pod{
@ -445,18 +440,18 @@ func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *in
APIVersion: "v1", APIVersion: "v1",
}, },
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: config.Prefix + "-client", Name: config.Prefix + "-" + podSuffix,
Labels: map[string]string{ Labels: map[string]string{
"role": config.Prefix + "-client", "role": config.Prefix + "-" + podSuffix,
}, },
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{ Containers: []v1.Container{
{ {
Name: config.Prefix + "-client", Name: config.Prefix + "-" + podSuffix,
Image: GetTestImage(framework.BusyBoxImage), Image: GetTestImage(framework.BusyBoxImage),
WorkingDir: "/opt", WorkingDir: "/opt",
// An imperative and easily debuggable container which reads vol contents for // An imperative and easily debuggable container which reads/writes vol contents for
// us to scan in the tests or by eye. // us to scan in the tests or by eye.
// We expect that /opt is empty in the minimal containers which we use in this test. // We expect that /opt is empty in the minimal containers which we use in this test.
Command: GenerateScriptCmd(command), Command: GenerateScriptCmd(command),
@ -470,7 +465,6 @@ func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *in
NodeSelector: config.NodeSelector, NodeSelector: config.NodeSelector,
}, },
} }
podsNamespacer := client.CoreV1().Pods(config.Namespace)
for i, test := range tests { for i, test := range tests {
volumeName := fmt.Sprintf("%s-%s-%d", config.Prefix, "volume", i) volumeName := fmt.Sprintf("%s-%s-%d", config.Prefix, "volume", i)
@ -483,9 +477,27 @@ func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *in
VolumeSource: test.Volume, VolumeSource: test.Volume,
}) })
} }
podsNamespacer := client.CoreV1().Pods(config.Namespace)
clientPod, err := podsNamespacer.Create(clientPod) clientPod, err := podsNamespacer.Create(clientPod)
if err != nil { if err != nil {
e2elog.Failf("Failed to create %s pod: %v", clientPod.Name, err) return nil, err
}
err = e2epod.WaitForPodRunningInNamespace(client, clientPod)
if err != nil {
e2epod.WaitForPodToDisappear(client, clientPod.Namespace, clientPod.Name, labels.Everything(), framework.Poll, framework.PodDeleteTimeout)
return nil, err
}
return clientPod, nil
}
// TestVolumeClient start a client pod using given VolumeSource (exported by startVolumeServer())
// and check that the pod sees expected data, e.g. from the server pod.
// Multiple Tests can be specified to mount multiple volumes to a single
// pod.
func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *int64, fsType string, tests []Test) {
clientPod, err := runVolumeTesterPod(client, config, "client", fsGroup, tests)
if err != nil {
e2elog.Failf("Failed to create client pod: %v", err)
} }
framework.ExpectNoError(e2epod.WaitForPodRunningInNamespace(client, clientPod)) framework.ExpectNoError(e2epod.WaitForPodRunningInNamespace(client, clientPod))
@ -512,63 +524,28 @@ func TestVolumeClient(client clientset.Interface, config TestConfig, fsGroup *in
} }
} }
// InjectHTML inserts index.html with given content into given volume. It does so by // InjectContent inserts index.html with given content into given volume. It does so by
// starting and auxiliary pod which writes the file there. // starting and auxiliary pod which writes the file there.
// The volume must be writable. // The volume must be writable.
func InjectHTML(client clientset.Interface, config TestConfig, fsGroup *int64, volume v1.VolumeSource, content string) { func InjectContent(client clientset.Interface, config TestConfig, fsGroup *int64, tests []Test) {
ginkgo.By(fmt.Sprint("starting ", config.Prefix, " injector")) injectorPod, err := runVolumeTesterPod(client, config, "injector", fsGroup, tests)
podClient := client.CoreV1().Pods(config.Namespace) if err != nil {
podName := fmt.Sprintf("%s-injector-%s", config.Prefix, rand.String(4)) e2elog.Failf("Failed to create injector pod: %v", err)
volMountName := fmt.Sprintf("%s-volume-%s", config.Prefix, rand.String(4)) return
fileName := "/mnt/index.html"
injectPod := &v1.Pod{
TypeMeta: metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Labels: map[string]string{
"role": config.Prefix + "-injector",
},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: config.Prefix + "-injector",
Image: GetTestImage(framework.BusyBoxImage),
Command: GenerateWriteFileCmd(content, fileName),
VolumeMounts: []v1.VolumeMount{
{
Name: volMountName,
MountPath: "/mnt",
},
},
SecurityContext: GenerateSecurityContext(true),
},
},
SecurityContext: GeneratePodSecurityContext(fsGroup, nil),
RestartPolicy: v1.RestartPolicyNever,
Volumes: []v1.Volume{
{
Name: volMountName,
VolumeSource: volume,
},
},
NodeName: config.ClientNodeName,
NodeSelector: config.NodeSelector,
},
} }
defer func() { defer func() {
podClient.Delete(podName, nil) e2epod.DeletePodOrFail(client, injectorPod.Namespace, injectorPod.Name)
e2epod.WaitForPodToDisappear(client, injectorPod.Namespace, injectorPod.Name, labels.Everything(), framework.Poll, framework.PodDeleteTimeout)
}() }()
injectPod, err := podClient.Create(injectPod) ginkgo.By("Writing text file contents in the container.")
framework.ExpectNoError(err, "Failed to create injector pod: %v", err) for i, test := range tests {
err = e2epod.WaitForPodSuccessInNamespace(client, injectPod.Name, injectPod.Namespace) fileName := fmt.Sprintf("/opt/%d/%s", i, test.File)
framework.ExpectNoError(err) commands := []string{"exec", injectorPod.Name, fmt.Sprintf("--namespace=%v", injectorPod.Namespace), "--"}
commands = append(commands, GenerateWriteFileCmd(test.ExpectedContent, fileName)...)
out, err := framework.RunKubectl(commands...)
framework.ExpectNoError(err, "failed: writing the contents of the mounted file %s: %s", fileName, out)
}
} }
// CreateGCEVolume creates PersistentVolumeSource for GCEVolume. // CreateGCEVolume creates PersistentVolumeSource for GCEVolume.

View File

@ -166,7 +166,7 @@ func (t *volumesTestSuite) defineTests(driver TestDriver, pattern testpatterns.T
// local), plugin skips setting fsGroup if volume is already mounted // local), plugin skips setting fsGroup if volume is already mounted
// and we don't have reliable way to detect volumes are unmounted or // and we don't have reliable way to detect volumes are unmounted or
// not before starting the second pod. // not before starting the second pod.
volume.InjectHTML(f.ClientSet, config, fsGroup, tests[0].Volume, tests[0].ExpectedContent) volume.InjectContent(f.ClientSet, config, fsGroup, tests)
volume.TestVolumeClient(f.ClientSet, config, fsGroup, pattern.FsType, tests) volume.TestVolumeClient(f.ClientSet, config, fsGroup, pattern.FsType, tests)
}) })