Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for mismatched usage of filesystem/block volumes #79796

Merged
merged 2 commits into from Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions test/e2e/storage/testsuites/BUILD
Expand Up @@ -20,12 +20,14 @@ go_library(
importpath = "k8s.io/kubernetes/test/e2e/storage/testsuites",
visibility = ["//visibility:public"],
deps = [
"//pkg/kubelet/events:go_default_library",
"//staging/src/k8s.io/api/core/v1:go_default_library",
"//staging/src/k8s.io/api/storage/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/api/resource:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/fields:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/errors:go_default_library",
Expand Down
86 changes: 82 additions & 4 deletions test/e2e/storage/testsuites/volumemode.go
Expand Up @@ -24,9 +24,12 @@ import (
v1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/fields"
clientset "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/kubelet/events"
"k8s.io/kubernetes/test/e2e/framework"
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
"k8s.io/kubernetes/test/e2e/storage/testpatterns"
)

Expand Down Expand Up @@ -94,6 +97,11 @@ func (t *volumeModeTestSuite) defineTests(driver TestDriver, pattern testpattern
// Now do the more expensive test initialization.
l.config, l.testCleanup = driver.PrepareTest(f)
l.intreeOps, l.migratedOps = getMigrationVolumeOpCounts(f.ClientSet, dInfo.InTreePluginName)
}

// manualInit initializes l.genericVolumeTestResource without creating the PV & PVC objects.
manualInit := func() {
init()

fsType := pattern.FsType
volBindMode := storagev1.VolumeBindingImmediate
Expand Down Expand Up @@ -167,7 +175,7 @@ func (t *volumeModeTestSuite) defineTests(driver TestDriver, pattern testpattern
case testpatterns.PreprovisionedPV:
if pattern.VolMode == v1.PersistentVolumeBlock && !isBlockSupported {
ginkgo.It("should fail to create pod by failing to mount volume [Slow]", func() {
init()
manualInit()
defer cleanup()

var err error
Expand Down Expand Up @@ -196,13 +204,12 @@ func (t *volumeModeTestSuite) defineTests(driver TestDriver, pattern testpattern
}()
framework.ExpectError(err)
})
// TODO(mkimuram): Add more tests
}

case testpatterns.DynamicPV:
if pattern.VolMode == v1.PersistentVolumeBlock && !isBlockSupported {
ginkgo.It("should fail in binding dynamic provisioned PV to PVC [Slow]", func() {
init()
manualInit()
defer cleanup()

var err error
Expand All @@ -218,12 +225,57 @@ func (t *volumeModeTestSuite) defineTests(driver TestDriver, pattern testpattern
err = framework.WaitForPersistentVolumeClaimPhase(v1.ClaimBound, l.cs, l.pvc.Namespace, l.pvc.Name, framework.Poll, framework.ClaimProvisionTimeout)
framework.ExpectError(err)
})
// TODO(mkimuram): Add more tests
}
default:
e2elog.Failf("Volume mode test doesn't support volType: %v", pattern.VolType)
}

ginkgo.It("should fail to use a volume in a pod with mismatched mode [Slow]", func() {
skipBlockTest(driver)
init()
l.genericVolumeTestResource = *createGenericVolumeTestResource(driver, l.config, pattern)
defer cleanup()

ginkgo.By("Creating pod")
var err error
pod := framework.MakeSecPod(l.ns.Name, []*v1.PersistentVolumeClaim{l.pvc}, nil, false, "", false, false, framework.SELinuxLabel, nil)
// Change volumeMounts to volumeDevices and the other way around
pod = swapVolumeMode(pod)

// Run the pod
pod, err = l.cs.CoreV1().Pods(l.ns.Name).Create(pod)
framework.ExpectNoError(err)
defer func() {
framework.ExpectNoError(framework.DeletePodWithWait(f, l.cs, pod))
}()

ginkgo.By("Waiting for pod to fail")
// Wait for an event that the pod is invalid.
eventSelector := fields.Set{
"involvedObject.kind": "Pod",
"involvedObject.name": pod.Name,
"involvedObject.namespace": l.ns.Name,
"reason": events.FailedMountVolume,
}.AsSelector().String()

var msg string
if pattern.VolMode == v1.PersistentVolumeBlock {
msg = "has volumeMode Block, but is specified in volumeMounts"
} else {
msg = "has volumeMode Filesystem, but is specified in volumeDevices"
}
err = e2epod.WaitTimeoutForPodEvent(l.cs, pod.Name, l.ns.Name, eventSelector, msg, framework.PodStartTimeout)
// Events are unreliable, don't depend on them. They're used only to speed up the test.
if err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good idea to speed up tests without any risks of flake! Let's apply similar way to other places to speed up tests later in another commit.

e2elog.Logf("Warning: did not get event about mismatched volume use")
}

// Check the pod is still not running
p, err := l.cs.CoreV1().Pods(l.ns.Name).Get(pod.Name, metav1.GetOptions{})
framework.ExpectNoError(err, "could not re-read the pod after event (or timeout)")
framework.ExpectEqual(p.Status.Phase, v1.PodPending)
})

}

func generateConfigsForPreprovisionedPVTest(scName string, volBindMode storagev1.VolumeBindingMode,
Expand Down Expand Up @@ -254,3 +306,29 @@ func generateConfigsForPreprovisionedPVTest(scName string, volBindMode storagev1

return scConfig, pvConfig, pvcConfig
}

// swapVolumeMode changes volumeMounts to volumeDevices and the other way around
func swapVolumeMode(podTemplate *v1.Pod) *v1.Pod {
pod := podTemplate.DeepCopy()
for c := range pod.Spec.Containers {
container := &pod.Spec.Containers[c]
container.VolumeDevices = []v1.VolumeDevice{}
container.VolumeMounts = []v1.VolumeMount{}

// Change VolumeMounts to VolumeDevices
for _, volumeMount := range podTemplate.Spec.Containers[c].VolumeMounts {
container.VolumeDevices = append(container.VolumeDevices, v1.VolumeDevice{
Name: volumeMount.Name,
DevicePath: volumeMount.MountPath,
})
}
// Change VolumeDevices to VolumeMounts
for _, volumeDevice := range podTemplate.Spec.Containers[c].VolumeDevices {
container.VolumeMounts = append(container.VolumeMounts, v1.VolumeMount{
Name: volumeDevice.Name,
MountPath: volumeDevice.DevicePath,
})
}
}
return pod
}