k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/common/storage/empty_dir.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 "path" 23 24 "github.com/onsi/ginkgo/v2" 25 "github.com/onsi/gomega" 26 27 v1 "k8s.io/api/core/v1" 28 "k8s.io/apimachinery/pkg/api/resource" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/util/uuid" 31 "k8s.io/kubernetes/test/e2e/framework" 32 e2epod "k8s.io/kubernetes/test/e2e/framework/pod" 33 e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" 34 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" 35 "k8s.io/kubernetes/test/e2e/nodefeature" 36 imageutils "k8s.io/kubernetes/test/utils/image" 37 admissionapi "k8s.io/pod-security-admission/api" 38 ) 39 40 const ( 41 volumePath = "/test-volume" 42 ) 43 44 var ( 45 nonRootUID = int64(1001) 46 ) 47 48 var _ = SIGDescribe("EmptyDir volumes", func() { 49 f := framework.NewDefaultFramework("emptydir") 50 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline 51 52 f.Context("when FSGroup is specified [LinuxOnly]", nodefeature.FSGroup, func() { 53 54 ginkgo.BeforeEach(func() { 55 // Windows does not support the FSGroup SecurityContext option. 56 e2eskipper.SkipIfNodeOSDistroIs("windows") 57 }) 58 59 ginkgo.It("new files should be created with FSGroup ownership when container is root", func(ctx context.Context) { 60 doTestSetgidFSGroup(ctx, f, 0, v1.StorageMediumMemory) 61 }) 62 63 ginkgo.It("new files should be created with FSGroup ownership when container is non-root", func(ctx context.Context) { 64 doTestSetgidFSGroup(ctx, f, nonRootUID, v1.StorageMediumMemory) 65 }) 66 67 ginkgo.It("nonexistent volume subPath should have the correct mode and owner using FSGroup", func(ctx context.Context) { 68 doTestSubPathFSGroup(ctx, f, nonRootUID, v1.StorageMediumMemory) 69 }) 70 71 ginkgo.It("files with FSGroup ownership should support (root,0644,tmpfs)", func(ctx context.Context) { 72 doTest0644FSGroup(ctx, f, 0, v1.StorageMediumMemory) 73 }) 74 75 ginkgo.It("volume on default medium should have the correct mode using FSGroup", func(ctx context.Context) { 76 doTestVolumeModeFSGroup(ctx, f, 0, v1.StorageMediumDefault) 77 }) 78 79 ginkgo.It("volume on tmpfs should have the correct mode using FSGroup", func(ctx context.Context) { 80 doTestVolumeModeFSGroup(ctx, f, 0, v1.StorageMediumMemory) 81 }) 82 }) 83 84 /* 85 Release: v1.9 86 Testname: EmptyDir, medium memory, volume mode default 87 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs. 88 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or the medium = 'Memory'. 89 */ 90 framework.ConformanceIt("volume on tmpfs should have the correct mode [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 91 doTestVolumeMode(ctx, f, 0, v1.StorageMediumMemory) 92 }) 93 94 /* 95 Release: v1.9 96 Testname: EmptyDir, medium memory, volume mode 0644 97 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0644. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable. 98 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 99 */ 100 framework.ConformanceIt("should support (root,0644,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 101 doTest0644(ctx, f, 0, v1.StorageMediumMemory) 102 }) 103 104 /* 105 Release: v1.9 106 Testname: EmptyDir, medium memory, volume mode 0666 107 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0666. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable. 108 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 109 */ 110 framework.ConformanceIt("should support (root,0666,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 111 doTest0666(ctx, f, 0, v1.StorageMediumMemory) 112 }) 113 114 /* 115 Release: v1.9 116 Testname: EmptyDir, medium memory, volume mode 0777 117 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0777. The volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable. 118 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 119 */ 120 framework.ConformanceIt("should support (root,0777,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 121 doTest0777(ctx, f, 0, v1.StorageMediumMemory) 122 }) 123 124 /* 125 Release: v1.9 126 Testname: EmptyDir, medium memory, volume mode 0644, non-root user 127 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0644. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable. 128 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 129 */ 130 framework.ConformanceIt("should support (non-root,0644,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 131 doTest0644(ctx, f, nonRootUID, v1.StorageMediumMemory) 132 }) 133 134 /* 135 Release: v1.9 136 Testname: EmptyDir, medium memory, volume mode 0666,, non-root user 137 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0666. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable. 138 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 139 */ 140 framework.ConformanceIt("should support (non-root,0666,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 141 doTest0666(ctx, f, nonRootUID, v1.StorageMediumMemory) 142 }) 143 144 /* 145 Release: v1.9 146 Testname: EmptyDir, medium memory, volume mode 0777, non-root user 147 Description: A Pod created with an 'emptyDir' Volume and 'medium' as 'Memory', the volume mode set to 0777. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable. 148 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID, or the medium = 'Memory'. 149 */ 150 framework.ConformanceIt("should support (non-root,0777,tmpfs) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 151 doTest0777(ctx, f, nonRootUID, v1.StorageMediumMemory) 152 }) 153 154 /* 155 Release: v1.9 156 Testname: EmptyDir, medium default, volume mode default 157 Description: A Pod created with an 'emptyDir' Volume, the volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs. 158 This test is marked LinuxOnly since Windows does not support setting specific file permissions. 159 */ 160 framework.ConformanceIt("volume on default medium should have the correct mode [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 161 doTestVolumeMode(ctx, f, 0, v1.StorageMediumDefault) 162 }) 163 164 /* 165 Release: v1.9 166 Testname: EmptyDir, medium default, volume mode 0644 167 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0644. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable. 168 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 169 */ 170 framework.ConformanceIt("should support (root,0644,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 171 doTest0644(ctx, f, 0, v1.StorageMediumDefault) 172 }) 173 174 /* 175 Release: v1.9 176 Testname: EmptyDir, medium default, volume mode 0666 177 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0666. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable. 178 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 179 */ 180 framework.ConformanceIt("should support (root,0666,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 181 doTest0666(ctx, f, 0, v1.StorageMediumDefault) 182 }) 183 184 /* 185 Release: v1.9 186 Testname: EmptyDir, medium default, volume mode 0777 187 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0777. The volume MUST have mode set as -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable. 188 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 189 */ 190 framework.ConformanceIt("should support (root,0777,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 191 doTest0777(ctx, f, 0, v1.StorageMediumDefault) 192 }) 193 194 /* 195 Release: v1.9 196 Testname: EmptyDir, medium default, volume mode 0644 197 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0644. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-r--r-- and mount type set to tmpfs and the contents MUST be readable. 198 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 199 */ 200 framework.ConformanceIt("should support (non-root,0644,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 201 doTest0644(ctx, f, nonRootUID, v1.StorageMediumDefault) 202 }) 203 204 /* 205 Release: v1.9 206 Testname: EmptyDir, medium default, volume mode 0666 207 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0666. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rw-rw-rw- and mount type set to tmpfs and the contents MUST be readable. 208 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 209 */ 210 framework.ConformanceIt("should support (non-root,0666,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 211 doTest0666(ctx, f, nonRootUID, v1.StorageMediumDefault) 212 }) 213 214 /* 215 Release: v1.9 216 Testname: EmptyDir, medium default, volume mode 0777 217 Description: A Pod created with an 'emptyDir' Volume, the volume mode set to 0777. Volume is mounted into the container where container is run as a non-root user. The volume MUST have mode -rwxrwxrwx and mount type set to tmpfs and the contents MUST be readable. 218 This test is marked LinuxOnly since Windows does not support setting specific file permissions, or running as UID / GID. 219 */ 220 framework.ConformanceIt("should support (non-root,0777,default) [LinuxOnly]", f.WithNodeConformance(), func(ctx context.Context) { 221 doTest0777(ctx, f, nonRootUID, v1.StorageMediumDefault) 222 }) 223 224 /* 225 Release: v1.15 226 Testname: EmptyDir, Shared volumes between containers 227 Description: A Pod created with an 'emptyDir' Volume, should share volumes between the containeres in the pod. The two busybox image containers should share the volumes mounted to the pod. 228 The main container should wait until the sub container drops a file, and main container access the shared data. 229 */ 230 framework.ConformanceIt("pod should support shared volumes between containers", func(ctx context.Context) { 231 var ( 232 volumeName = "shared-data" 233 busyBoxMainVolumeMountPath = "/usr/share/volumeshare" 234 busyBoxSubVolumeMountPath = "/pod-data" 235 busyBoxMainVolumeFilePath = fmt.Sprintf("%s/shareddata.txt", busyBoxMainVolumeMountPath) 236 busyBoxSubVolumeFilePath = fmt.Sprintf("%s/shareddata.txt", busyBoxSubVolumeMountPath) 237 message = "Hello from the busy-box sub-container" 238 busyBoxMainContainerName = "busybox-main-container" 239 busyBoxSubContainerName = "busybox-sub-container" 240 resultString = "" 241 deletionGracePeriod = int64(0) 242 ) 243 244 pod := &v1.Pod{ 245 ObjectMeta: metav1.ObjectMeta{ 246 Name: "pod-sharedvolume-" + string(uuid.NewUUID()), 247 }, 248 Spec: v1.PodSpec{ 249 Volumes: []v1.Volume{ 250 { 251 Name: volumeName, 252 VolumeSource: v1.VolumeSource{ 253 EmptyDir: new(v1.EmptyDirVolumeSource), 254 }, 255 }, 256 }, 257 Containers: []v1.Container{ 258 { 259 Name: busyBoxMainContainerName, 260 Image: imageutils.GetE2EImage(imageutils.BusyBox), 261 Command: []string{"/bin/sh"}, 262 Args: []string{"-c", "sleep 100000"}, 263 VolumeMounts: []v1.VolumeMount{ 264 { 265 Name: volumeName, 266 MountPath: busyBoxMainVolumeMountPath, 267 }, 268 }, 269 }, 270 { 271 Name: busyBoxSubContainerName, 272 Image: imageutils.GetE2EImage(imageutils.BusyBox), 273 Command: []string{"/bin/sh"}, 274 Args: []string{"-c", fmt.Sprintf("echo %s > %s", message, busyBoxSubVolumeFilePath)}, 275 VolumeMounts: []v1.VolumeMount{ 276 { 277 Name: volumeName, 278 MountPath: busyBoxSubVolumeMountPath, 279 }, 280 }, 281 }, 282 }, 283 TerminationGracePeriodSeconds: &deletionGracePeriod, 284 RestartPolicy: v1.RestartPolicyNever, 285 }, 286 } 287 288 ginkgo.By("Creating Pod") 289 e2epod.NewPodClient(f).Create(ctx, pod) 290 framework.ExpectNoError(e2epod.WaitForPodNameRunningInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name)) 291 292 ginkgo.By("Reading file content from the nginx-container") 293 result := e2epod.ExecShellInContainer(f, pod.Name, busyBoxMainContainerName, fmt.Sprintf("cat %s", busyBoxMainVolumeFilePath)) 294 gomega.Expect(result).To(gomega.Equal(message), "failed to match expected string %s with %s", message, resultString) 295 }) 296 297 /* 298 Release: v1.20 299 Testname: EmptyDir, Memory backed volume is sized to specified limit 300 Description: A Pod created with an 'emptyDir' Volume backed by memory should be sized to user provided value. 301 */ 302 ginkgo.It("pod should support memory backed volumes of specified size", func(ctx context.Context) { 303 var ( 304 volumeName = "shared-data" 305 busyBoxMainVolumeMountPath = "/usr/share/volumeshare" 306 busyBoxMainContainerName = "busybox-main-container" 307 expectedResult = "10240" // equal to 10Mi 308 deletionGracePeriod = int64(0) 309 sizeLimit = resource.MustParse("10Mi") 310 ) 311 312 pod := &v1.Pod{ 313 ObjectMeta: metav1.ObjectMeta{ 314 Name: "pod-size-memory-volume-" + string(uuid.NewUUID()), 315 }, 316 Spec: v1.PodSpec{ 317 Volumes: []v1.Volume{ 318 { 319 Name: volumeName, 320 VolumeSource: v1.VolumeSource{ 321 EmptyDir: &v1.EmptyDirVolumeSource{ 322 Medium: v1.StorageMediumMemory, 323 SizeLimit: &sizeLimit, 324 }, 325 }, 326 }, 327 }, 328 Containers: []v1.Container{ 329 { 330 Name: busyBoxMainContainerName, 331 Image: imageutils.GetE2EImage(imageutils.BusyBox), 332 Command: []string{"/bin/sh"}, 333 Args: []string{"-c", "sleep 100000"}, 334 VolumeMounts: []v1.VolumeMount{ 335 { 336 Name: volumeName, 337 MountPath: busyBoxMainVolumeMountPath, 338 }, 339 }, 340 }, 341 }, 342 TerminationGracePeriodSeconds: &deletionGracePeriod, 343 RestartPolicy: v1.RestartPolicyNever, 344 }, 345 } 346 347 var err error 348 ginkgo.By("Creating Pod") 349 pod = e2epod.NewPodClient(f).CreateSync(ctx, pod) 350 351 ginkgo.By("Waiting for the pod running") 352 err = e2epod.WaitForPodNameRunningInNamespace(ctx, f.ClientSet, pod.Name, f.Namespace.Name) 353 framework.ExpectNoError(err, "failed to deploy pod %s", pod.Name) 354 355 ginkgo.By("Getting the pod") 356 pod, err = e2epod.NewPodClient(f).Get(ctx, pod.Name, metav1.GetOptions{}) 357 framework.ExpectNoError(err, "failed to get pod %s", pod.Name) 358 359 ginkgo.By("Reading empty dir size") 360 result := e2epod.ExecShellInContainer(f, pod.Name, busyBoxMainContainerName, fmt.Sprintf("df | grep %s | awk '{print $2}'", busyBoxMainVolumeMountPath)) 361 gomega.Expect(result).To(gomega.Equal(expectedResult), "failed to match expected string %s with %s", expectedResult, result) 362 }) 363 }) 364 365 const ( 366 containerName = "test-container" 367 volumeName = "test-volume" 368 ) 369 370 func doTestSetgidFSGroup(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 371 var ( 372 filePath = path.Join(volumePath, "test-file") 373 source = &v1.EmptyDirVolumeSource{Medium: medium} 374 pod = testPodWithVolume(uid, volumePath, source) 375 ) 376 377 pod.Spec.Containers[0].Args = []string{ 378 "mounttest", 379 fmt.Sprintf("--fs_type=%v", volumePath), 380 fmt.Sprintf("--new_file_0660=%v", filePath), 381 fmt.Sprintf("--file_perm=%v", filePath), 382 fmt.Sprintf("--file_owner=%v", filePath), 383 } 384 385 fsGroup := int64(123) 386 pod.Spec.SecurityContext.FSGroup = &fsGroup 387 388 msg := fmt.Sprintf("emptydir 0644 on %v", formatMedium(medium)) 389 out := []string{ 390 "perms of file \"/test-volume/test-file\": -rw-rw----", 391 "content of file \"/test-volume/test-file\": mount-tester new file", 392 "owner GID of \"/test-volume/test-file\": 123", 393 } 394 if medium == v1.StorageMediumMemory { 395 out = append(out, "mount type of \"/test-volume\": tmpfs") 396 } 397 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 398 } 399 400 func doTestSubPathFSGroup(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 401 var ( 402 subPath = "test-sub" 403 source = &v1.EmptyDirVolumeSource{Medium: medium} 404 pod = testPodWithVolume(uid, volumePath, source) 405 ) 406 407 pod.Spec.Containers[0].Args = []string{ 408 "mounttest", 409 fmt.Sprintf("--fs_type=%v", volumePath), 410 fmt.Sprintf("--file_perm=%v", volumePath), 411 fmt.Sprintf("--file_owner=%v", volumePath), 412 fmt.Sprintf("--file_mode=%v", volumePath), 413 } 414 415 pod.Spec.Containers[0].VolumeMounts[0].SubPath = subPath 416 417 fsGroup := int64(123) 418 pod.Spec.SecurityContext.FSGroup = &fsGroup 419 420 msg := fmt.Sprintf("emptydir subpath on %v", formatMedium(medium)) 421 out := []string{ 422 "perms of file \"/test-volume\": -rwxrwxrwx", 423 "owner UID of \"/test-volume\": 0", 424 "owner GID of \"/test-volume\": 123", 425 "mode of file \"/test-volume\": dgtrwxrwxrwx", 426 } 427 if medium == v1.StorageMediumMemory { 428 out = append(out, "mount type of \"/test-volume\": tmpfs") 429 } 430 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 431 } 432 433 func doTestVolumeModeFSGroup(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 434 var ( 435 source = &v1.EmptyDirVolumeSource{Medium: medium} 436 pod = testPodWithVolume(uid, volumePath, source) 437 ) 438 439 pod.Spec.Containers[0].Args = []string{ 440 "mounttest", 441 fmt.Sprintf("--fs_type=%v", volumePath), 442 fmt.Sprintf("--file_perm=%v", volumePath), 443 } 444 445 fsGroup := int64(1001) 446 pod.Spec.SecurityContext.FSGroup = &fsGroup 447 448 msg := fmt.Sprintf("emptydir volume type on %v", formatMedium(medium)) 449 out := []string{ 450 "perms of file \"/test-volume\": -rwxrwxrwx", 451 } 452 if medium == v1.StorageMediumMemory { 453 out = append(out, "mount type of \"/test-volume\": tmpfs") 454 } 455 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 456 } 457 458 func doTest0644FSGroup(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 459 var ( 460 filePath = path.Join(volumePath, "test-file") 461 source = &v1.EmptyDirVolumeSource{Medium: medium} 462 pod = testPodWithVolume(uid, volumePath, source) 463 ) 464 465 pod.Spec.Containers[0].Args = []string{ 466 "mounttest", 467 fmt.Sprintf("--fs_type=%v", volumePath), 468 fmt.Sprintf("--new_file_0644=%v", filePath), 469 fmt.Sprintf("--file_perm=%v", filePath), 470 } 471 472 fsGroup := int64(123) 473 pod.Spec.SecurityContext.FSGroup = &fsGroup 474 475 msg := fmt.Sprintf("emptydir 0644 on %v", formatMedium(medium)) 476 out := []string{ 477 "perms of file \"/test-volume/test-file\": -rw-r--r--", 478 "content of file \"/test-volume/test-file\": mount-tester new file", 479 } 480 if medium == v1.StorageMediumMemory { 481 out = append(out, "mount type of \"/test-volume\": tmpfs") 482 } 483 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 484 } 485 486 func doTestVolumeMode(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 487 var ( 488 source = &v1.EmptyDirVolumeSource{Medium: medium} 489 pod = testPodWithVolume(uid, volumePath, source) 490 ) 491 492 pod.Spec.Containers[0].Args = []string{ 493 "mounttest", 494 fmt.Sprintf("--fs_type=%v", volumePath), 495 fmt.Sprintf("--file_perm=%v", volumePath), 496 } 497 498 msg := fmt.Sprintf("emptydir volume type on %v", formatMedium(medium)) 499 out := []string{ 500 "perms of file \"/test-volume\": -rwxrwxrwx", 501 } 502 if medium == v1.StorageMediumMemory { 503 out = append(out, "mount type of \"/test-volume\": tmpfs") 504 } 505 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 506 } 507 508 func doTest0644(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 509 var ( 510 filePath = path.Join(volumePath, "test-file") 511 source = &v1.EmptyDirVolumeSource{Medium: medium} 512 pod = testPodWithVolume(uid, volumePath, source) 513 ) 514 515 pod.Spec.Containers[0].Args = []string{ 516 "mounttest", 517 fmt.Sprintf("--fs_type=%v", volumePath), 518 fmt.Sprintf("--new_file_0644=%v", filePath), 519 fmt.Sprintf("--file_perm=%v", filePath), 520 } 521 522 msg := fmt.Sprintf("emptydir 0644 on %v", formatMedium(medium)) 523 out := []string{ 524 "perms of file \"/test-volume/test-file\": -rw-r--r--", 525 "content of file \"/test-volume/test-file\": mount-tester new file", 526 } 527 if medium == v1.StorageMediumMemory { 528 out = append(out, "mount type of \"/test-volume\": tmpfs") 529 } 530 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 531 } 532 533 func doTest0666(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 534 var ( 535 filePath = path.Join(volumePath, "test-file") 536 source = &v1.EmptyDirVolumeSource{Medium: medium} 537 pod = testPodWithVolume(uid, volumePath, source) 538 ) 539 540 pod.Spec.Containers[0].Args = []string{ 541 "mounttest", 542 fmt.Sprintf("--fs_type=%v", volumePath), 543 fmt.Sprintf("--new_file_0666=%v", filePath), 544 fmt.Sprintf("--file_perm=%v", filePath), 545 } 546 547 msg := fmt.Sprintf("emptydir 0666 on %v", formatMedium(medium)) 548 out := []string{ 549 "perms of file \"/test-volume/test-file\": -rw-rw-rw-", 550 "content of file \"/test-volume/test-file\": mount-tester new file", 551 } 552 if medium == v1.StorageMediumMemory { 553 out = append(out, "mount type of \"/test-volume\": tmpfs") 554 } 555 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 556 } 557 558 func doTest0777(ctx context.Context, f *framework.Framework, uid int64, medium v1.StorageMedium) { 559 var ( 560 filePath = path.Join(volumePath, "test-file") 561 source = &v1.EmptyDirVolumeSource{Medium: medium} 562 pod = testPodWithVolume(uid, volumePath, source) 563 ) 564 565 pod.Spec.Containers[0].Args = []string{ 566 "mounttest", 567 fmt.Sprintf("--fs_type=%v", volumePath), 568 fmt.Sprintf("--new_file_0777=%v", filePath), 569 fmt.Sprintf("--file_perm=%v", filePath), 570 } 571 572 msg := fmt.Sprintf("emptydir 0777 on %v", formatMedium(medium)) 573 out := []string{ 574 "perms of file \"/test-volume/test-file\": -rwxrwxrwx", 575 "content of file \"/test-volume/test-file\": mount-tester new file", 576 } 577 if medium == v1.StorageMediumMemory { 578 out = append(out, "mount type of \"/test-volume\": tmpfs") 579 } 580 e2epodoutput.TestContainerOutput(ctx, f, msg, pod, 0, out) 581 } 582 583 func formatMedium(medium v1.StorageMedium) string { 584 if medium == v1.StorageMediumMemory { 585 return "tmpfs" 586 } 587 588 return "node default medium" 589 } 590 591 // testPodWithVolume creates a Pod that runs as the given UID and with the given empty dir source mounted at the given path. 592 // If the uid is 0, the Pod will run as its default user (root). 593 func testPodWithVolume(uid int64, path string, source *v1.EmptyDirVolumeSource) *v1.Pod { 594 podName := "pod-" + string(uuid.NewUUID()) 595 pod := &v1.Pod{ 596 TypeMeta: metav1.TypeMeta{ 597 Kind: "Pod", 598 APIVersion: "v1", 599 }, 600 ObjectMeta: metav1.ObjectMeta{ 601 Name: podName, 602 }, 603 Spec: v1.PodSpec{ 604 Containers: []v1.Container{ 605 { 606 Name: containerName, 607 Image: imageutils.GetE2EImage(imageutils.Agnhost), 608 VolumeMounts: []v1.VolumeMount{ 609 { 610 Name: volumeName, 611 MountPath: path, 612 }, 613 }, 614 }, 615 }, 616 SecurityContext: &v1.PodSecurityContext{ 617 SELinuxOptions: &v1.SELinuxOptions{ 618 Level: "s0", 619 }, 620 }, 621 RestartPolicy: v1.RestartPolicyNever, 622 Volumes: []v1.Volume{ 623 { 624 Name: volumeName, 625 VolumeSource: v1.VolumeSource{ 626 EmptyDir: source, 627 }, 628 }, 629 }, 630 }, 631 } 632 633 if uid != 0 { 634 pod.Spec.SecurityContext.RunAsUser = &uid 635 } 636 637 return pod 638 }