diff --git a/test/e2e/storage/testsuites/subpath.go b/test/e2e/storage/testsuites/subpath.go index f7343b680c5..1ddc967a74c 100644 --- a/test/e2e/storage/testsuites/subpath.go +++ b/test/e2e/storage/testsuites/subpath.go @@ -208,8 +208,8 @@ type subPathTestInput struct { func testSubPath(input *subPathTestInput) { It("should support non-existent path", func() { - // Write the file in the subPath from container 0 - setWriteCommand(input.filePathInSubpath, &input.pod.Spec.Containers[0]) + // Write the file in the subPath from init container 1 + setWriteCommand(input.filePathInSubpath, &input.pod.Spec.InitContainers[1]) // Read it from outside the subPath from container 1 testReadFile(input.f, input.filePathInVolume, input.pod, 1) @@ -219,8 +219,8 @@ func testSubPath(input *subPathTestInput) { // Create the directory setInitCommand(input.pod, fmt.Sprintf("mkdir -p %s", input.subPathDir)) - // Write the file in the subPath from container 0 - setWriteCommand(input.filePathInSubpath, &input.pod.Spec.Containers[0]) + // Write the file in the subPath from init container 1 + setWriteCommand(input.filePathInSubpath, &input.pod.Spec.InitContainers[1]) // Read it from outside the subPath from container 1 testReadFile(input.f, input.filePathInVolume, input.pod, 1) @@ -291,7 +291,7 @@ func testSubPath(input *subPathTestInput) { SubPath: "subpath2", }) - addMultipleWrites(&input.pod.Spec.Containers[0], filepath1, filepath2) + addMultipleWrites(&input.pod.Spec.InitContainers[1], filepath1, filepath2) testMultipleReads(input.f, input.pod, 0, filepath1, filepath2) }) @@ -325,8 +325,8 @@ func testSubPath(input *subPathTestInput) { // Create the directory setInitCommand(input.pod, fmt.Sprintf("mkdir -p %s", input.subPathDir)) - // Write the file in the volume from container 1 - setWriteCommand(input.filePathInVolume, &input.pod.Spec.Containers[1]) + // Write the file in the volume from init container 2 + setWriteCommand(input.filePathInVolume, &input.pod.Spec.InitContainers[2]) // Read it from inside the subPath from container 0 input.pod.Spec.Containers[0].VolumeMounts[0].ReadOnly = true @@ -337,8 +337,8 @@ func testSubPath(input *subPathTestInput) { // Create the file setInitCommand(input.pod, fmt.Sprintf("touch %s", input.subPathDir)) - // Write the file in the volume from container 1 - setWriteCommand(input.subPathDir, &input.pod.Spec.Containers[1]) + // Write the file in the volume from init container 2 + setWriteCommand(input.subPathDir, &input.pod.Spec.InitContainers[2]) // Read it from inside the subPath from container 0 input.pod.Spec.Containers[0].VolumeMounts[0].ReadOnly = true @@ -350,8 +350,19 @@ func testSubPath(input *subPathTestInput) { framework.Skipf("Volume type %v doesn't support readOnly source", input.volType) } - // Initialize content in the volume while it's writable - initVolumeContent(input.f, input.pod, input.filePathInVolume, input.filePathInSubpath) + pod := input.pod.DeepCopy() + + // Create the directory + setInitCommand(input.pod, fmt.Sprintf("mkdir -p %s", input.subPathDir)) + + // Write the file in the subPath from init container 1 + setWriteCommand(input.filePathInSubpath, &input.pod.Spec.InitContainers[1]) + + // Read it from inside the subPath from container 0 + testReadFile(input.f, input.filePathInSubpath, input.pod, 0) + + // Reset the pod + input.pod = pod // Set volume source to read only input.pod.Spec.Volumes[0].VolumeSource = *input.roVol @@ -384,6 +395,7 @@ func testSubPath(input *subPathTestInput) { input.pod.Spec.Containers[1].Command = []string{"/bin/sh", "-ec", "sleep 100000"} By(fmt.Sprintf("Creating pod %s", input.pod.Name)) + removeUnusedContainers(input.pod) pod, err := input.f.ClientSet.CoreV1().Pods(input.f.Namespace.Name).Create(input.pod) Expect(err).ToNot(HaveOccurred(), "while creating pod") defer func() { @@ -416,6 +428,7 @@ func TestBasicSubpathFile(f *framework.Framework, contents string, pod *v1.Pod, setReadCommand(filepath, &pod.Spec.Containers[0]) By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) f.TestContainerOutput("atomic-volume-subpath", pod, 0, []string{contents}) By(fmt.Sprintf("Deleting pod %s", pod.Name)) @@ -467,6 +480,41 @@ func SubpathTestPod(f *framework.Framework, subpath, volumeType string, source * Privileged: &privilegedSecurityContext, }, }, + { + Name: fmt.Sprintf("test-init-subpath-%s", suffix), + Image: mountImage, + VolumeMounts: []v1.VolumeMount{ + { + Name: volumeName, + MountPath: volumePath, + SubPath: subpath, + }, + { + Name: probeVolumeName, + MountPath: probeVolumePath, + }, + }, + SecurityContext: &v1.SecurityContext{ + Privileged: &privilegedSecurityContext, + }, + }, + { + Name: fmt.Sprintf("test-init-volume-%s", suffix), + Image: mountImage, + VolumeMounts: []v1.VolumeMount{ + { + Name: volumeName, + MountPath: volumePath, + }, + { + Name: probeVolumeName, + MountPath: probeVolumePath, + }, + }, + SecurityContext: &v1.SecurityContext{ + Privileged: &privilegedSecurityContext, + }, + }, }, Containers: []v1.Container{ { @@ -528,6 +576,33 @@ func SubpathTestPod(f *framework.Framework, subpath, volumeType string, source * } } +func containerIsUnused(container *v1.Container) bool { + // mountImage with nil Args does nothing. Leave everything else + return container.Image == mountImage && container.Args == nil +} + +// removeUnusedContainers removes containers from a SubpathTestPod that aren't +// needed for a test. e.g. to test for subpath mount failure, only one +// container needs to run and get its status checked. +func removeUnusedContainers(pod *v1.Pod) { + initContainers := []v1.Container{} + containers := []v1.Container{} + if pod.Spec.InitContainers[0].Command != nil { + initContainers = append(initContainers, pod.Spec.InitContainers[0]) + } + for _, ic := range pod.Spec.InitContainers[1:] { + if !containerIsUnused(&ic) { + initContainers = append(initContainers, ic) + } + } + containers = append(containers, pod.Spec.Containers[0]) + if !containerIsUnused(&pod.Spec.Containers[1]) { + containers = append(containers, pod.Spec.Containers[1]) + } + pod.Spec.InitContainers = initContainers + pod.Spec.Containers = containers +} + // volumeFormatPod returns a Pod that does nothing but will cause the plugin to format a filesystem // on first use func volumeFormatPod(f *framework.Framework, volumeSource *v1.VolumeSource) *v1.Pod { @@ -562,6 +637,8 @@ func volumeFormatPod(f *framework.Framework, volumeSource *v1.VolumeSource) *v1. func clearSubpathPodCommands(pod *v1.Pod) { pod.Spec.InitContainers[0].Command = nil + pod.Spec.InitContainers[1].Args = nil + pod.Spec.InitContainers[2].Args = nil pod.Spec.Containers[0].Args = nil pod.Spec.Containers[1].Args = nil } @@ -591,6 +668,7 @@ func addMultipleWrites(container *v1.Container, file1 string, file2 string) { func testMultipleReads(f *framework.Framework, pod *v1.Pod, containerIndex int, file1 string, file2 string) { By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) f.TestContainerOutput("multi_subpath", pod, containerIndex, []string{ "content of file \"" + file1 + "\": mount-tester new file", "content of file \"" + file2 + "\": mount-tester new file", @@ -608,6 +686,7 @@ func testReadFile(f *framework.Framework, file string, pod *v1.Pod, containerInd setReadCommand(file, &pod.Spec.Containers[containerIndex]) By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) f.TestContainerOutput("subpath", pod, containerIndex, []string{ "content of file \"" + file + "\": mount-tester new file", }) @@ -623,6 +702,7 @@ func testPodFailSubpath(f *framework.Framework, pod *v1.Pod, allowContainerTermi func testPodFailSubpathError(f *framework.Framework, pod *v1.Pod, errorMsg string, allowContainerTerminationError bool) { By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) Expect(err).ToNot(HaveOccurred(), "while creating pod") defer func() { @@ -704,6 +784,7 @@ func testPodContainerRestart(f *framework.Framework, pod *v1.Pod) { // Start pod By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) Expect(err).ToNot(HaveOccurred(), "while creating pod") defer func() { @@ -791,6 +872,7 @@ func testSubpathReconstruction(f *framework.Framework, pod *v1.Pod, forceDelete pod.Spec.TerminationGracePeriodSeconds = &gracePeriod By(fmt.Sprintf("Creating pod %s", pod.Name)) + removeUnusedContainers(pod) pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(pod) Expect(err).ToNot(HaveOccurred(), "while creating pod") @@ -815,23 +897,6 @@ func formatVolume(f *framework.Framework, pod *v1.Pod) { Expect(err).ToNot(HaveOccurred(), "while deleting volume init pod") } -func initVolumeContent(f *framework.Framework, pod *v1.Pod, volumeFilepath, subpathFilepath string) { - setWriteCommand(volumeFilepath, &pod.Spec.Containers[1]) - setReadCommand(subpathFilepath, &pod.Spec.Containers[0]) - - By(fmt.Sprintf("Creating pod to write volume content %s", pod.Name)) - f.TestContainerOutput("subpath", pod, 0, []string{ - "content of file \"" + subpathFilepath + "\": mount-tester new file", - }) - - By(fmt.Sprintf("Deleting pod %s", pod.Name)) - err := framework.DeletePodWithWait(f, f.ClientSet, pod) - Expect(err).NotTo(HaveOccurred(), "while deleting pod") - - // This pod spec is going to be reused; reset all the commands - clearSubpathPodCommands(pod) -} - func podContainerExec(pod *v1.Pod, containerIndex int, bashExec string) (string, error) { return framework.RunKubectl("exec", fmt.Sprintf("--namespace=%s", pod.Namespace), pod.Name, "--container", pod.Spec.Containers[containerIndex].Name, "--", "/bin/sh", "-c", bashExec) }