...

Source file src/k8s.io/kubernetes/test/e2e/common/storage/empty_dir.go

Documentation: k8s.io/kubernetes/test/e2e/common/storage

     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  }
   639  

View as plain text