/* Copyright 2020 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package e2e import ( "fmt" "github.com/kubernetes-csi/csi-driver-nfs/test/e2e/driver" "github.com/kubernetes-csi/csi-driver-nfs/test/e2e/testsuites" "github.com/onsi/ginkgo/v2" v1 "k8s.io/api/core/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/test/e2e/framework" admissionapi "k8s.io/pod-security-admission/api" ) var _ = ginkgo.Describe("Dynamic Provisioning", func() { f := framework.NewDefaultFramework("nfs") f.NamespacePodSecurityEnforceLevel = admissionapi.LevelPrivileged var ( cs clientset.Interface ns *v1.Namespace testDriver driver.PVTestDriver ) ginkgo.BeforeEach(func(_ ginkgo.SpecContext) { checkPodsRestart := testCmd{ command: "sh", args: []string{"test/utils/check_driver_pods_restart.sh"}, startLog: "Check driver pods for restarts", endLog: "Check successful", } execTestCmd([]testCmd{checkPodsRestart}) cs = f.ClientSet ns = f.Namespace }) testDriver = driver.InitNFSDriver() ginkgo.It("should create a volume on demand with mount options [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCmdVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a volume on demand with zero mountPermissions [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCmdVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: storageClassParametersWithZeroMountPermisssions, } test.Run(ctx, cs, ns) }) ginkgo.It("should create multiple PV objects, bind to PVCs and attach all to different pods on the same node [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, { Cmd: "while true; do echo $(date -u) >> /mnt/test-1/data; sleep 100; done", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCollocatedPodTest{ CSIDriver: testDriver, Pods: pods, ColocatePods: true, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) // Track issue https://github.com/kubernetes/kubernetes/issues/70505 ginkgo.It("should create a volume on demand and mount it as readOnly in a pod [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "touch /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", ReadOnly: true, }, }, }, }, } test := testsuites.DynamicallyProvisionedReadOnlyVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a deployment object, write and read to it, delete the pod and write and read to it again [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pod := testsuites.PodDetails{ Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, } podCheckCmd := []string{"cat", "/mnt/test-1/data"} expectedString := "hello world\n" test := testsuites.DynamicallyProvisionedDeletePodTest{ CSIDriver: testDriver, Pod: pod, PodCheck: &testsuites.PodExecCheck{ Cmd: podCheckCmd, ExpectedString: expectedString, // pod will be restarted so expect to see 2 instances of string }, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("[subDir]should create a deployment object, write and read to it, delete the pod and write and read to it again [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pod := testsuites.PodDetails{ Cmd: "echo 'hello world' >> /mnt/test-1/data && while true; do sleep 100; done", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, } podCheckCmd := []string{"cat", "/mnt/test-1/data"} expectedString := "hello world\n" test := testsuites.DynamicallyProvisionedDeletePodTest{ CSIDriver: testDriver, Pod: pod, PodCheck: &testsuites.PodExecCheck{ Cmd: podCheckCmd, ExpectedString: expectedString, // pod will be restarted so expect to see 2 instances of string }, StorageClassParameters: subDirStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It(fmt.Sprintf("should delete PV with reclaimPolicy %q [nfs.csi.k8s.io]", v1.PersistentVolumeReclaimDelete), func(ctx ginkgo.SpecContext) { reclaimPolicy := v1.PersistentVolumeReclaimDelete volumes := []testsuites.VolumeDetails{ { ClaimSize: "10Gi", ReclaimPolicy: &reclaimPolicy, }, } test := testsuites.DynamicallyProvisionedReclaimPolicyTest{ CSIDriver: testDriver, Volumes: volumes, StorageClassParameters: defaultStorageClassParameters, ControllerServer: *controllerServer, } test.Run(ctx, cs, ns) }) ginkgo.It(fmt.Sprintf("should retain PV with reclaimPolicy %q [nfs.csi.k8s.io]", v1.PersistentVolumeReclaimRetain), func(ctx ginkgo.SpecContext) { reclaimPolicy := v1.PersistentVolumeReclaimRetain volumes := []testsuites.VolumeDetails{ { ClaimSize: "10Gi", ReclaimPolicy: &reclaimPolicy, }, } test := testsuites.DynamicallyProvisionedReclaimPolicyTest{ CSIDriver: testDriver, Volumes: volumes, ControllerServer: *controllerServer, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a pod with multiple volumes [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { volumes := []testsuites.VolumeDetails{} for i := 1; i <= 6; i++ { volume := testsuites.VolumeDetails{ ClaimSize: "100Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, } volumes = append(volumes, volume) } pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: volumes, }, } test := testsuites.DynamicallyProvisionedPodWithMultiplePVsTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: subDirStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a pod with volume mount subpath [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: convertToPowershellCommandIfNecessary("echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data"), Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedVolumeSubpathTester{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: defaultStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a CSI inline volume [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: convertToPowershellCommandIfNecessary("echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data"), Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedInlineVolumeTest{ CSIDriver: testDriver, Pods: pods, Server: nfsServerAddress, Share: nfsShare, MountOptions: "nconnect=8,nfsvers=4.1,sec=sys", ReadOnly: false, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a volume on demand with retaining subdir on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCmdVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: retainStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a volume on demand with archive on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCmdVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: archiveStorageClassParameters, } test.Run(ctx, cs, ns) }) ginkgo.It("should create a volume on demand with archive subdir on delete [nfs.csi.k8s.io]", func(ctx ginkgo.SpecContext) { pods := []testsuites.PodDetails{ { Cmd: "echo 'hello world' > /mnt/test-1/data && grep 'hello world' /mnt/test-1/data", Volumes: []testsuites.VolumeDetails{ { ClaimSize: "10Gi", VolumeMount: testsuites.VolumeMountDetails{ NameGenerate: "test-volume-", MountPathGenerate: "/mnt/test-", }, }, }, }, } test := testsuites.DynamicallyProvisionedCmdVolumeTest{ CSIDriver: testDriver, Pods: pods, StorageClassParameters: archiveSubDirStorageClassParameters, } test.Run(ctx, cs, ns) }) })