k8s.io/kubernetes@v1.29.3/test/e2e/common/storage/host_path.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package storage 18 19 import ( 20 "context" 21 "fmt" 22 "os" 23 "path" 24 25 v1 "k8s.io/api/core/v1" 26 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 27 "k8s.io/kubernetes/test/e2e/framework" 28 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 29 imageutils "k8s.io/kubernetes/test/utils/image" 30 admissionapi "k8s.io/pod-security-admission/api" 31 32 "github.com/onsi/ginkgo/v2" 33 ) 34 35 // TODO : Consolidate this code with the code for emptyDir. 36 // This will require some smart. 37 var _ = SIGDescribe("HostPath", func() { 38 f := framework.NewDefaultFramework("hostpath") 39 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 40 41 ginkgo.BeforeEach(func() { 42 // TODO permission denied cleanup failures 43 //cleanup before running the test. 44 _ = os.Remove("/tmp/test-file") 45 }) 46 47 /* 48 Host path, volume mode default 49 Create a Pod with host volume mounted. The volume mounted MUST be a directory with permissions mode -rwxrwxrwx and that is has the sticky bit (mode flag t) set. 50 This test is marked LinuxOnly since Windows does not support setting the sticky bit (mode flag t). 51 */ 52 f.It("should give a volume the correct mode [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 53 source := &v1.HostPathVolumeSource{ 54 Path: "/tmp", 55 } 56 pod := testPodWithHostVol(volumePath, source, false) 57 58 pod.Spec.Containers[0].Args = []string{ 59 "mounttest", 60 fmt.Sprintf("--fs_type=%v", volumePath), 61 fmt.Sprintf("--file_mode=%v", volumePath), 62 } 63 e2epodoutput.TestContainerOutputRegexp(ctx, f, "hostPath mode", pod, 0, []string{ 64 "mode of file \"/test-volume\": dg?trwxrwx", // we expect the sticky bit (mode flag t) to be set for the dir 65 }) 66 }) 67 68 // This test requires mounting a folder into a container with write privileges. 69 f.It("should support r/w", f.WithNodeConformance(), func(ctx context.Context) { 70 filePath := path.Join(volumePath, "test-file") 71 retryDuration := 180 72 source := &v1.HostPathVolumeSource{ 73 Path: "/tmp", 74 } 75 // we can't spawn privileged containers on Windows, nor do we need to. 76 privileged := !framework.NodeOSDistroIs("windows") 77 pod := testPodWithHostVol(volumePath, source, privileged) 78 79 pod.Spec.Containers[0].Args = []string{ 80 "mounttest", 81 fmt.Sprintf("--new_file_0644=%v", filePath), 82 fmt.Sprintf("--file_mode=%v", filePath), 83 } 84 85 pod.Spec.Containers[1].Args = []string{ 86 "mounttest", 87 fmt.Sprintf("--file_content_in_loop=%v", filePath), 88 fmt.Sprintf("--retry_time=%d", retryDuration), 89 } 90 //Read the content of the file with the second container to 91 //verify volumes being shared properly among containers within the pod. 92 e2epodoutput.TestContainerOutput(ctx, f, "hostPath r/w", pod, 1, []string{ 93 "content of file \"/test-volume/test-file\": mount-tester new file", 94 }) 95 }) 96 97 f.It("should support subPath", f.WithNodeConformance(), func(ctx context.Context) { 98 subPath := "sub-path" 99 fileName := "test-file" 100 retryDuration := 180 101 102 filePathInWriter := path.Join(volumePath, fileName) 103 filePathInReader := path.Join(volumePath, subPath, fileName) 104 105 source := &v1.HostPathVolumeSource{ 106 Path: "/tmp", 107 } 108 109 // we can't spawn privileged containers on Windows, nor do we need to. 110 privileged := !framework.NodeOSDistroIs("windows") 111 pod := testPodWithHostVol(volumePath, source, privileged) 112 113 // Write the file in the subPath from container 0 114 container := &pod.Spec.Containers[0] 115 container.VolumeMounts[0].SubPath = subPath 116 container.Args = []string{ 117 "mounttest", 118 fmt.Sprintf("--new_file_0644=%v", filePathInWriter), 119 fmt.Sprintf("--file_mode=%v", filePathInWriter), 120 } 121 122 // Read it from outside the subPath from container 1 123 pod.Spec.Containers[1].Args = []string{ 124 "mounttest", 125 fmt.Sprintf("--file_content_in_loop=%v", filePathInReader), 126 fmt.Sprintf("--retry_time=%d", retryDuration), 127 } 128 129 e2epodoutput.TestContainerOutput(ctx, f, "hostPath subPath", pod, 1, []string{ 130 "content of file \"" + filePathInReader + "\": mount-tester new file", 131 }) 132 }) 133 }) 134 135 // These constants are borrowed from the other test. 136 // const volumeName = "test-volume" 137 const containerName1 = "test-container-1" 138 const containerName2 = "test-container-2" 139 140 func mount(source *v1.HostPathVolumeSource) []v1.Volume { 141 return []v1.Volume{ 142 { 143 Name: volumeName, 144 VolumeSource: v1.VolumeSource{ 145 HostPath: source, 146 }, 147 }, 148 } 149 } 150 151 // TODO: To merge this with the emptyDir tests, we can make source a lambda. 152 func testPodWithHostVol(path string, source *v1.HostPathVolumeSource, privileged bool) *v1.Pod { 153 podName := "pod-host-path-test" 154 155 return &v1.Pod{ 156 TypeMeta: metav1.TypeMeta{ 157 Kind: "Pod", 158 APIVersion: "v1", 159 }, 160 ObjectMeta: metav1.ObjectMeta{ 161 Name: podName, 162 }, 163 Spec: v1.PodSpec{ 164 Containers: []v1.Container{ 165 { 166 Name: containerName1, 167 Image: imageutils.GetE2EImage(imageutils.Agnhost), 168 Args: []string{"mounttest"}, 169 VolumeMounts: []v1.VolumeMount{ 170 { 171 Name: volumeName, 172 MountPath: path, 173 }, 174 }, 175 SecurityContext: &v1.SecurityContext{ 176 Privileged: &privileged, 177 }, 178 }, 179 { 180 Name: containerName2, 181 Image: imageutils.GetE2EImage(imageutils.Agnhost), 182 Args: []string{"mounttest"}, 183 VolumeMounts: []v1.VolumeMount{ 184 { 185 Name: volumeName, 186 MountPath: path, 187 }, 188 }, 189 SecurityContext: &v1.SecurityContext{ 190 Privileged: &privileged, 191 }, 192 }, 193 }, 194 RestartPolicy: v1.RestartPolicyNever, 195 Volumes: mount(source), 196 }, 197 } 198 }