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  }