...

Source file src/k8s.io/kubernetes/test/e2e/windows/volumes.go

Documentation: k8s.io/kubernetes/test/e2e/windows

     1  /*
     2  Copyright 2018 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 windows
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	"k8s.io/apimachinery/pkg/util/uuid"
    26  	"k8s.io/kubernetes/test/e2e/feature"
    27  	"k8s.io/kubernetes/test/e2e/framework"
    28  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    29  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    30  	imageutils "k8s.io/kubernetes/test/utils/image"
    31  	admissionapi "k8s.io/pod-security-admission/api"
    32  
    33  	"github.com/onsi/ginkgo/v2"
    34  	"github.com/onsi/gomega"
    35  )
    36  
    37  const (
    38  	emptyDirVolumePath = "C:\\test-volume"
    39  	hostMapPath        = "C:\\tmp"
    40  	containerName      = "test-container"
    41  	volumeName         = "test-volume"
    42  )
    43  
    44  var (
    45  	image = imageutils.GetE2EImage(imageutils.Pause)
    46  )
    47  
    48  var _ = sigDescribe(feature.Windows, "Windows volume mounts", skipUnlessWindows(func() {
    49  	f := framework.NewDefaultFramework("windows-volumes")
    50  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    51  	var (
    52  		emptyDirSource = v1.VolumeSource{
    53  			EmptyDir: &v1.EmptyDirVolumeSource{
    54  				Medium: v1.StorageMediumDefault,
    55  			},
    56  		}
    57  		hostPathDirectoryOrCreate = v1.HostPathDirectoryOrCreate
    58  		hostMapSource             = v1.VolumeSource{
    59  			HostPath: &v1.HostPathVolumeSource{
    60  				Path: hostMapPath,
    61  				Type: &hostPathDirectoryOrCreate,
    62  			},
    63  		}
    64  	)
    65  	ginkgo.BeforeEach(func() {
    66  		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
    67  	})
    68  
    69  	ginkgo.Context("check volume mount permissions", func() {
    70  
    71  		ginkgo.It("container should have readOnly permissions on emptyDir", func(ctx context.Context) {
    72  
    73  			ginkgo.By("creating a container with readOnly permissions on emptyDir volume")
    74  			doReadOnlyTest(ctx, f, emptyDirSource, emptyDirVolumePath)
    75  
    76  			ginkgo.By("creating two containers, one with readOnly permissions the other with read-write permissions on emptyDir volume")
    77  			doReadWriteReadOnlyTest(ctx, f, emptyDirSource, emptyDirVolumePath)
    78  		})
    79  
    80  		ginkgo.It("container should have readOnly permissions on hostMapPath", func(ctx context.Context) {
    81  
    82  			ginkgo.By("creating a container with readOnly permissions on hostMap volume")
    83  			doReadOnlyTest(ctx, f, hostMapSource, hostMapPath)
    84  
    85  			ginkgo.By("creating two containers, one with readOnly permissions the other with read-write permissions on hostMap volume")
    86  			doReadWriteReadOnlyTest(ctx, f, hostMapSource, hostMapPath)
    87  		})
    88  
    89  	})
    90  }))
    91  
    92  func doReadOnlyTest(ctx context.Context, f *framework.Framework, source v1.VolumeSource, volumePath string) {
    93  	var (
    94  		filePath = volumePath + "\\test-file.txt"
    95  		podName  = "pod-" + string(uuid.NewUUID())
    96  		pod      = testPodWithROVolume(podName, source, volumePath)
    97  	)
    98  	pod.Spec.NodeSelector = map[string]string{
    99  		"kubernetes.io/os": "windows",
   100  	}
   101  
   102  	pod = e2epod.NewPodClient(f).CreateSync(ctx, pod)
   103  	ginkgo.By("verifying that pod has the correct nodeSelector")
   104  	gomega.Expect(pod.Spec.NodeSelector).To(gomega.HaveKeyWithValue("kubernetes.io/os", "windows"), "pod.spec.nodeSelector")
   105  
   106  	cmd := []string{"cmd", "/c", "echo windows-volume-test", ">", filePath}
   107  
   108  	ginkgo.By("verifying that pod will get an error when writing to a volume that is readonly")
   109  	_, stderr, _ := e2epod.ExecCommandInContainerWithFullOutput(f, podName, containerName, cmd...)
   110  	gomega.Expect(stderr).To(gomega.Equal("Access is denied."))
   111  }
   112  
   113  func doReadWriteReadOnlyTest(ctx context.Context, f *framework.Framework, source v1.VolumeSource, volumePath string) {
   114  	var (
   115  		filePath        = volumePath + "\\test-file" + string(uuid.NewUUID())
   116  		podName         = "pod-" + string(uuid.NewUUID())
   117  		pod             = testPodWithROVolume(podName, source, volumePath)
   118  		rwcontainerName = containerName + "-rw"
   119  	)
   120  	pod.Spec.NodeSelector = map[string]string{
   121  		"kubernetes.io/os": "windows",
   122  	}
   123  
   124  	rwcontainer := v1.Container{
   125  		Name:  containerName + "-rw",
   126  		Image: image,
   127  		VolumeMounts: []v1.VolumeMount{
   128  			{
   129  				Name:      volumeName,
   130  				MountPath: volumePath,
   131  			},
   132  		},
   133  	}
   134  
   135  	pod.Spec.Containers = append(pod.Spec.Containers, rwcontainer)
   136  	pod = e2epod.NewPodClient(f).CreateSync(ctx, pod)
   137  
   138  	ginkgo.By("verifying that pod has the correct nodeSelector")
   139  	gomega.Expect(pod.Spec.NodeSelector).To(gomega.HaveKeyWithValue("kubernetes.io/os", "windows"), "pod.spec.nodeSelector")
   140  
   141  	ginkgo.By("verifying that pod can write to a volume with read/write access")
   142  	writecmd := []string{"cmd", "/c", "echo windows-volume-test", ">", filePath}
   143  	stdoutRW, stderrRW, errRW := e2epod.ExecCommandInContainerWithFullOutput(f, podName, rwcontainerName, writecmd...)
   144  	msg := fmt.Sprintf("cmd: %v, stdout: %q, stderr: %q", writecmd, stdoutRW, stderrRW)
   145  	framework.ExpectNoError(errRW, msg)
   146  
   147  	ginkgo.By("verifying that pod will get an error when writing to a volume that is readonly")
   148  	_, stderr, _ := e2epod.ExecCommandInContainerWithFullOutput(f, podName, containerName, writecmd...)
   149  	gomega.Expect(stderr).To(gomega.Equal("Access is denied."))
   150  
   151  	ginkgo.By("verifying that pod can read from a volume that is readonly")
   152  	readcmd := []string{"cmd", "/c", "type", filePath}
   153  	readout, readerr, err := e2epod.ExecCommandInContainerWithFullOutput(f, podName, containerName, readcmd...)
   154  	readmsg := fmt.Sprintf("cmd: %v, stdout: %q, stderr: %q", readcmd, readout, readerr)
   155  	gomega.Expect(readout).To(gomega.Equal("windows-volume-test"))
   156  	framework.ExpectNoError(err, readmsg)
   157  }
   158  
   159  // testPodWithROVolume makes a minimal pod defining a volume input source. Similarly to
   160  // other tests for sig-windows this should append a nodeSelector for windows.
   161  func testPodWithROVolume(podName string, source v1.VolumeSource, path string) *v1.Pod {
   162  	return &v1.Pod{
   163  		TypeMeta: metav1.TypeMeta{
   164  			Kind:       "Pod",
   165  			APIVersion: "v1",
   166  		},
   167  		ObjectMeta: metav1.ObjectMeta{
   168  			Name: podName,
   169  		},
   170  		Spec: v1.PodSpec{
   171  			Containers: []v1.Container{
   172  				{
   173  					Name:  containerName,
   174  					Image: image,
   175  					VolumeMounts: []v1.VolumeMount{
   176  						{
   177  							Name:      volumeName,
   178  							MountPath: path,
   179  							ReadOnly:  true,
   180  						},
   181  					},
   182  				},
   183  			},
   184  			RestartPolicy: v1.RestartPolicyNever,
   185  			Volumes: []v1.Volume{
   186  				{
   187  					Name:         volumeName,
   188  					VolumeSource: source,
   189  				},
   190  			},
   191  		},
   192  	}
   193  }
   194  

View as plain text