Code change:
<ins> /* Copyright 2020 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package storage import ( "context" "fmt" "path" "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/kubernetes/pkg/kubelet/events" "k8s.io/kubernetes/test/e2e/framework" e2eevents "k8s.io/kubernetes/test/e2e/framework/events" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" "k8s.io/kubernetes/test/e2e/storage/utils" imageutils "k8s.io/kubernetes/test/utils/image" "github.com/onsi/ginkgo" ) var _ = utils.SIGDescribe("HostPathType Directory [Slow]", func() { f := framework.NewDefaultFramework("host-path-type-directory") var ( ns           string hostBaseDir  string mountBaseDir string basePod      *v1.Pod targetDir    string hostPathUnset             = v1.HostPathUnset hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate hostPathDirectory         = v1.HostPathDirectory hostPathFile              = v1.HostPathFile hostPathSocket            = v1.HostPathSocket hostPathCharDev           = v1.HostPathCharDev hostPathBlockDev          = v1.HostPathBlockDev ) ginkgo.BeforeEach(func() { ns = f.Namespace.Name ginkgo.By("Create a pod for further testing") hostBaseDir = path.Join("/tmp", ns) mountBaseDir = "/mnt/test" basePod = f.PodClient().CreateSync(newHostPathTypeTestPod(map[string]string{}, hostBaseDir, mountBaseDir, &hostPathDirectoryOrCreate)) ginkgo.By(fmt.Sprintf("running on node %s", basePod.Spec.NodeName)) targetDir = path.Join(hostBaseDir, "adir") ginkgo.By("Should automatically create a new directory 'adir' when HostPathType is HostPathDirectoryOrCreate") verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, &hostPathDirectoryOrCreate) }) ginkgo.It("Should fail on mounting non-existent directory 'does-not-exist-dir' when HostPathType is HostPathDirectory", func() { dirPath := path.Join(hostBaseDir, "does-not-exist-dir") verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, dirPath, fmt.Sprintf("%s is not a directory", dirPath), &hostPathDirectory) }) ginkgo.It("Should be able to mount directory 'adir' successfully when HostPathType is HostPathDirectory", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, &hostPathDirectory) }) ginkgo.It("Should be able to mount directory 'adir' successfully when HostPathType is HostPathUnset", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, &hostPathUnset) }) ginkgo.It("Should fail on mounting directory 'adir' when HostPathType is HostPathFile", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, fmt.Sprintf("%s is not a file", targetDir), &hostPathFile) }) ginkgo.It("Should fail on mounting directory 'adir' when HostPathType is HostPathSocket", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, fmt.Sprintf("%s is not a socket", targetDir), &hostPathSocket) }) ginkgo.It("Should fail on mounting directory 'adir' when HostPathType is HostPathCharDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, fmt.Sprintf("%s is not a character device", targetDir), &hostPathCharDev) }) ginkgo.It("Should fail on mounting directory 'adir' when HostPathType is HostPathBlockDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetDir, fmt.Sprintf("%s is not a block device", targetDir), &hostPathBlockDev) }) }) var _ = utils.SIGDescribe("HostPathType File [Slow]", func() { f := framework.NewDefaultFramework("host-path-type-file") var ( ns           string hostBaseDir  string mountBaseDir string basePod      *v1.Pod targetFile   string hostPathUnset             = v1.HostPathUnset hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate hostPathDirectory         = v1.HostPathDirectory hostPathFileOrCreate      = v1.HostPathFileOrCreate hostPathFile              = v1.HostPathFile hostPathSocket            = v1.HostPathSocket hostPathCharDev           = v1.HostPathCharDev hostPathBlockDev          = v1.HostPathBlockDev ) ginkgo.BeforeEach(func() { ns = f.Namespace.Name ginkgo.By("Create a pod for further testing") hostBaseDir = path.Join("/tmp", ns) mountBaseDir = "/mnt/test" basePod = f.PodClient().CreateSync(newHostPathTypeTestPod(map[string]string{}, hostBaseDir, mountBaseDir, &hostPathDirectoryOrCreate)) ginkgo.By(fmt.Sprintf("running on node %s", basePod.Spec.NodeName)) targetFile = path.Join(hostBaseDir, "afile") ginkgo.By("Should automatically create a new file 'afile' when HostPathType is HostPathFileOrCreate") verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, &hostPathFileOrCreate) }) ginkgo.It("Should fail on mounting non-existent file 'does-not-exist-file' when HostPathType is HostPathFile", func() { filePath := path.Join(hostBaseDir, "does-not-exist-file") verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, filePath, fmt.Sprintf("%s is not a file", filePath), &hostPathFile) }) ginkgo.It("Should be able to mount file 'afile' successfully when HostPathType is HostPathFile", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, &hostPathFile) }) ginkgo.It("Should be able to mount file 'afile' successfully when HostPathType is HostPathUnset", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, &hostPathUnset) }) ginkgo.It("Should fail on mounting file 'afile' when HostPathType is HostPathDirectory", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, fmt.Sprintf("%s is not a directory", targetFile), &hostPathDirectory) }) ginkgo.It("Should fail on mounting file 'afile' when HostPathType is HostPathSocket", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, fmt.Sprintf("%s is not a socket", targetFile), &hostPathSocket) }) ginkgo.It("Should fail on mounting file 'afile' when HostPathType is HostPathCharDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, fmt.Sprintf("%s is not a character device", targetFile), &hostPathCharDev) }) ginkgo.It("Should fail on mounting file 'afile' when HostPathType is HostPathBlockDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetFile, fmt.Sprintf("%s is not a block device", targetFile), &hostPathBlockDev) }) }) var _ = utils.SIGDescribe("HostPathType Socket [Slow]", func() { f := framework.NewDefaultFramework("host-path-type-socket") var ( ns           string hostBaseDir  string mountBaseDir string basePod      *v1.Pod targetSocket string hostPathUnset             = v1.HostPathUnset hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate hostPathDirectory         = v1.HostPathDirectory hostPathFile              = v1.HostPathFile hostPathSocket            = v1.HostPathSocket hostPathCharDev           = v1.HostPathCharDev hostPathBlockDev          = v1.HostPathBlockDev ) ginkgo.BeforeEach(func() { ns = f.Namespace.Name ginkgo.By("Create a pod for further testing") hostBaseDir = path.Join("/tmp", ns) mountBaseDir = "/mnt/test" basePod = f.PodClient().CreateSync(newHostPathTypeTestPod(map[string]string{}, hostBaseDir, mountBaseDir, &hostPathDirectoryOrCreate)) ginkgo.By(fmt.Sprintf("running on node %s", basePod.Spec.NodeName)) targetSocket = path.Join(hostBaseDir, "asocket") ginkgo.By("Create a socket for further testing") _, err := utils.PodExec(f, basePod, fmt.Sprintf("nc -lU %s &", path.Join(mountBaseDir, "asocket"))) framework.ExpectNoError(err) }) ginkgo.It("Should fail on mounting non-existent socket 'does-not-exist-socket' when HostPathType is HostPathSocket", func() { socketPath := path.Join(hostBaseDir, "does-not-exist-socket") verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, socketPath, fmt.Sprintf("%s is not a socket", socketPath), &hostPathSocket) }) ginkgo.It("Should be able to mount socket 'asocket' successfully when HostPathType is HostPathSocket", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, &hostPathSocket) }) ginkgo.It("Should be able to mount socket 'asocket' successfully when HostPathType is HostPathUnset", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, &hostPathUnset) }) ginkgo.It("Should fail on mounting socket 'asocket' when HostPathType is HostPathDirectory", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, fmt.Sprintf("%s is not a directory", targetSocket), &hostPathDirectory) }) ginkgo.It("Should fail on mounting socket 'asocket' when HostPathType is HostPathFile", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, fmt.Sprintf("%s is not a file", targetSocket), &hostPathFile) }) ginkgo.It("Should fail on mounting socket 'asocket' when HostPathType is HostPathCharDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, fmt.Sprintf("%s is not a character device", targetSocket), &hostPathCharDev) }) ginkgo.It("Should fail on mounting socket 'asocket' when HostPathType is HostPathBlockDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetSocket, fmt.Sprintf("%s is not a block device", targetSocket), &hostPathBlockDev) }) }) var _ = utils.SIGDescribe("HostPathType Character Device [Slow]", func() { f := framework.NewDefaultFramework("host-path-type-char-dev") var ( ns            string hostBaseDir   string mountBaseDir  string basePod       *v1.Pod targetCharDev string hostPathUnset             = v1.HostPathUnset hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate hostPathDirectory         = v1.HostPathDirectory hostPathFile              = v1.HostPathFile hostPathSocket            = v1.HostPathSocket hostPathCharDev           = v1.HostPathCharDev hostPathBlockDev          = v1.HostPathBlockDev ) ginkgo.BeforeEach(func() { ns = f.Namespace.Name ginkgo.By("Create a pod for further testing") hostBaseDir = path.Join("/tmp", ns) mountBaseDir = "/mnt/test" basePod = f.PodClient().CreateSync(newHostPathTypeTestPod(map[string]string{}, hostBaseDir, mountBaseDir, &hostPathDirectoryOrCreate)) ginkgo.By(fmt.Sprintf("running on node %s", basePod.Spec.NodeName)) targetCharDev = path.Join(hostBaseDir, "achardev") ginkgo.By("Create a character device for further testing") _, err := utils.PodExec(f, basePod, fmt.Sprintf("mknod %s c 89 1", path.Join(mountBaseDir, "achardev"))) framework.ExpectNoError(err) }) ginkgo.It("Should fail on mounting non-existent character device 'does-not-exist-char-dev' when HostPathType is HostPathCharDev", func() { charDevPath := path.Join(hostBaseDir, "does-not-exist-char-dev") verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, charDevPath, fmt.Sprintf("%s is not a character device", charDevPath), &hostPathCharDev) }) ginkgo.It("Should be able to mount character device 'achardev' successfully when HostPathType is HostPathCharDev", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, &hostPathCharDev) }) ginkgo.It("Should be able to mount character device 'achardev' successfully when HostPathType is HostPathUnset", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, &hostPathUnset) }) ginkgo.It("Should fail on mounting character device 'achardev' when HostPathType is HostPathDirectory", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, fmt.Sprintf("%s is not a directory", targetCharDev), &hostPathDirectory) }) ginkgo.It("Should fail on mounting character device 'achardev' when HostPathType is HostPathFile", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, fmt.Sprintf("%s is not a file", targetCharDev), &hostPathFile) }) ginkgo.It("Should fail on mounting character device 'achardev' when HostPathType is HostPathSocket", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, fmt.Sprintf("%s is not a socket", targetCharDev), &hostPathSocket) }) ginkgo.It("Should fail on mounting character device 'achardev' when HostPathType is HostPathBlockDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetCharDev, fmt.Sprintf("%s is not a block device", targetCharDev), &hostPathBlockDev) }) }) var _ = utils.SIGDescribe("HostPathType Block Device [Slow]", func() { f := framework.NewDefaultFramework("host-path-type-block-dev") var ( ns             string hostBaseDir    string mountBaseDir   string basePod        *v1.Pod targetBlockDev string hostPathUnset             = v1.HostPathUnset hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate hostPathDirectory         = v1.HostPathDirectory hostPathFile              = v1.HostPathFile hostPathSocket            = v1.HostPathSocket hostPathCharDev           = v1.HostPathCharDev hostPathBlockDev          = v1.HostPathBlockDev ) ginkgo.BeforeEach(func() { ns = f.Namespace.Name ginkgo.By("Create a pod for further testing") hostBaseDir = path.Join("/tmp", ns) mountBaseDir = "/mnt/test" basePod = f.PodClient().CreateSync(newHostPathTypeTestPod(map[string]string{}, hostBaseDir, mountBaseDir, &hostPathDirectoryOrCreate)) ginkgo.By(fmt.Sprintf("running on node %s", basePod.Spec.NodeName)) targetBlockDev = path.Join(hostBaseDir, "ablkdev") ginkgo.By("Create a block device for further testing") _, err := utils.PodExec(f, basePod, fmt.Sprintf("mknod %s b 89 1", path.Join(mountBaseDir, "ablkdev"))) framework.ExpectNoError(err) }) ginkgo.It("Should fail on mounting non-existent block device 'does-not-exist-blk-dev' when HostPathType is HostPathBlockDev", func() { blkDevPath := path.Join(hostBaseDir, "does-not-exist-blk-dev") verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, blkDevPath, fmt.Sprintf("%s is not a block device", blkDevPath), &hostPathBlockDev) }) ginkgo.It("Should be able to mount block device 'ablkdev' successfully when HostPathType is HostPathBlockDev", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, &hostPathBlockDev) }) ginkgo.It("Should be able to mount block device 'ablkdev' successfully when HostPathType is HostPathUnset", func() { verifyPodHostPathType(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, &hostPathUnset) }) ginkgo.It("Should fail on mounting block device 'ablkdev' when HostPathType is HostPathDirectory", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, fmt.Sprintf("%s is not a directory", targetBlockDev), &hostPathDirectory) }) ginkgo.It("Should fail on mounting block device 'ablkdev' when HostPathType is HostPathFile", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, fmt.Sprintf("%s is not a file", targetBlockDev), &hostPathFile) }) ginkgo.It("Should fail on mounting block device 'ablkdev' when HostPathType is HostPathSocket", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, fmt.Sprintf("%s is not a socket", targetBlockDev), &hostPathSocket) }) ginkgo.It("Should fail on mounting block device 'ablkdev' when HostPathType is HostPathCharDev", func() { verifyPodHostPathTypeFailure(f, map[string]string{"kubernetes.io/hostname": basePod.Spec.NodeName}, targetBlockDev, fmt.Sprintf("%s is not a character device", targetBlockDev), &hostPathCharDev) }) }) func newHostPathTypeTestPod(nodeSelector map[string]string, hostDir, mountDir string, hostPathType *v1.HostPathType) *v1.Pod { pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-hostpath-type-", }, Spec: v1.PodSpec{ NodeSelector:  nodeSelector, RestartPolicy: v1.RestartPolicyNever, Containers: []v1.Container{ { Name:  "host-path-testing", Image: imageutils.GetE2EImage(imageutils.Agnhost), VolumeMounts: []v1.VolumeMount{ { Name:      "host", MountPath: mountDir, ReadOnly:  false, }, }, }, }, Volumes: []v1.Volume{ { Name: "host", VolumeSource: v1.VolumeSource{ HostPath: &v1.HostPathVolumeSource{ Path: hostDir, Type: hostPathType, }, }, }, }, }, } return pod } func verifyPodHostPathTypeFailure(f *framework.Framework, nodeSelector map[string]string, hostDir, pattern string, hostPathType *v1.HostPathType) { pod := newHostPathTypeTestPod(nodeSelector, hostDir, "/mnt/test", hostPathType) ginkgo.By(fmt.Sprintf("Creating pod %s", pod.Name)) pod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(), pod, metav1.CreateOptions{}) framework.ExpectNoError(err) ginkgo.By("Checking for HostPathType error event") eventSelector := fields.Set{ "involvedObject.kind":      "Pod", "involvedObject.name":      pod.Name, "involvedObject.namespace": f.Namespace.Name, "reason":                   events.FailedMountVolume, }.AsSelector().String() msg := "hostPath type check failed" err = e2eevents.WaitTimeoutForEvent(f.ClientSet, f.Namespace.Name, eventSelector, msg, framework.PodStartTimeout) // Events are unreliable, don't depend on the event. It's used only to speed up the test. if err != nil { framework.Logf("Warning: did not get event about FailedMountVolume") } // Check the pod is still not running p, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(context.TODO(), pod.Name, metav1.GetOptions{}) framework.ExpectNoError(err, "could not re-read the pod after event (or timeout)") framework.ExpectEqual(p.Status.Phase, v1.PodPending, "Pod phase isn't pending") f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(context.TODO(), pod.Name, *metav1.NewDeleteOptions(0)) } func verifyPodHostPathType(f *framework.Framework, nodeSelector map[string]string, hostDir string, hostPathType *v1.HostPathType) { newPod, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Create(context.TODO(), newHostPathTypeTestPod(nodeSelector, hostDir, "/mnt/test", hostPathType), metav1.CreateOptions{}) framework.ExpectNoError(err) framework.ExpectNoError(e2epod.WaitTimeoutForPodRunningInNamespace(f.ClientSet, newPod.Name, newPod.Namespace, framework.PodStartShortTimeout)) f.ClientSet.CoreV1().Pods(f.Namespace.Name).Delete(context.TODO(), newPod.Name, *metav1.NewDeleteOptions(0)) } </ins>

Related discussion:
text: <!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . If this may be security issue, please disclose it privately via --Is this a BUG REPORT or FEATURE REQUEST?: What happened: This feature is lacking coverage, especially for containerized kubelet environments.
/assign since I'm the owner of this feature.
And just fixes a bug for containerized kubelet when the mount file is an empty file.
Are we going to enable these tests in v1.11? We're getting code freeze soon.
There is a local containerized cluster pull and CI job that we can probably leverage. Right now it only runs conformance tests, we may be able to add new suites to enable other tests. Cc who can point us to the owner for the containerized testing effort
yes, seems to be holding up pretty well - https://k8s-,%20master%20(dev)
In I made pull-kubernetes-local-e2e-containerized to run also all test with string. I'm enabling some tests (subpath!) in , feel free to suggest more tests.
Ref
IIUC, the default host path type is . And when host path type is , we expect container runtime to create the host path if it doesn't exist (docker is doing that today). Is that true? If that is, we should revert part of , because container runtime should still create host path if it does not exist. /cc I tried to enforce , and got a lot of errors , e.g.:
Correct. This is mainly for backwards compatibility.
I see. If so, I'll remove the CRI definition "If the hostPath doesn't exist (e.g. hostPath volume), runtimes should report errors". Thanks!
SGTM. Refer to .
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
/remove-lifecycle stale will help fix this.
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close.