diff --git a/tests/e2e/driver/driver.go b/tests/e2e/driver/driver.go index 4b54e6912c..7dc5a93303 100644 --- a/tests/e2e/driver/driver.go +++ b/tests/e2e/driver/driver.go @@ -35,7 +35,7 @@ type PVTestDriver interface { // DynamicPVTestDriver represents an interface for a CSI driver that supports DynamicPV type DynamicPVTestDriver interface { // GetDynamicProvisionStorageClass returns a StorageClass dynamic provision Persistent Volume - GetDynamicProvisionStorageClass(parameters map[string]string, mountOptions []string, reclaimPolicy *v1.PersistentVolumeReclaimPolicy, bindingMode *storagev1.VolumeBindingMode, allowedTopologyValues []string, namespace string) *storagev1.StorageClass + GetDynamicProvisionStorageClass(parameters map[string]string, mountOptions []string, reclaimPolicy *v1.PersistentVolumeReclaimPolicy, volumeExpansion *bool, bindingMode *storagev1.VolumeBindingMode, allowedTopologyValues []string, namespace string) *storagev1.StorageClass } // PreProvisionedVolumeTestDriver represents an interface for a CSI driver that supports pre-provisioned volume @@ -54,6 +54,7 @@ func getStorageClass( parameters map[string]string, mountOptions []string, reclaimPolicy *v1.PersistentVolumeReclaimPolicy, + volumeExpansion *bool, bindingMode *storagev1.VolumeBindingMode, allowedTopologies []v1.TopologySelectorTerm, ) *storagev1.StorageClass { @@ -75,6 +76,7 @@ func getStorageClass( ReclaimPolicy: reclaimPolicy, VolumeBindingMode: bindingMode, AllowedTopologies: allowedTopologies, + AllowVolumeExpansion: volumeExpansion, } } diff --git a/tests/e2e/driver/ebs_csi_driver.go b/tests/e2e/driver/ebs_csi_driver.go index 94260f1309..9a72392ed4 100644 --- a/tests/e2e/driver/ebs_csi_driver.go +++ b/tests/e2e/driver/ebs_csi_driver.go @@ -41,10 +41,11 @@ func InitEbsCSIDriver() PVTestDriver { } } -func (d *ebsCSIDriver) GetDynamicProvisionStorageClass(parameters map[string]string, mountOptions []string, reclaimPolicy *v1.PersistentVolumeReclaimPolicy, bindingMode *storagev1.VolumeBindingMode, allowedTopologyValues []string, namespace string) *storagev1.StorageClass { +func (d *ebsCSIDriver) GetDynamicProvisionStorageClass(parameters map[string]string, mountOptions []string, reclaimPolicy *v1.PersistentVolumeReclaimPolicy, volumeExpansion *bool, bindingMode *storagev1.VolumeBindingMode, allowedTopologyValues []string, namespace string) *storagev1.StorageClass { provisioner := d.driverName generateName := fmt.Sprintf("%s-%s-dynamic-sc-", namespace, provisioner) allowedTopologies := []v1.TopologySelectorTerm{} + if len(allowedTopologyValues) > 0 { allowedTopologies = []v1.TopologySelectorTerm{ { @@ -57,7 +58,7 @@ func (d *ebsCSIDriver) GetDynamicProvisionStorageClass(parameters map[string]str }, } } - return getStorageClass(generateName, provisioner, parameters, mountOptions, reclaimPolicy, bindingMode, allowedTopologies) + return getStorageClass(generateName, provisioner, parameters, mountOptions, reclaimPolicy, volumeExpansion, bindingMode, allowedTopologies) } func (d *ebsCSIDriver) GetVolumeSnapshotClass(namespace string) *v1beta1.VolumeSnapshotClass { diff --git a/tests/e2e/dynamic_provisioning.go b/tests/e2e/dynamic_provisioning.go index 104021d3ff..a5ab32d6b6 100644 --- a/tests/e2e/dynamic_provisioning.go +++ b/tests/e2e/dynamic_provisioning.go @@ -404,6 +404,30 @@ var _ = Describe("[ebs-csi-e2e] [single-az] Dynamic Provisioning", func() { } test.Run(cs, ns) }) + + It("should create a volume on demand and resize it ", func() { + allowVolumeExpansion := true + pod := testsuites.PodDetails{ + Cmd: "echo 'hello world' >> /mnt/test-1/data && grep 'hello world' /mnt/test-1/data && sync", + Volumes: []testsuites.VolumeDetails{ + { + VolumeType: awscloud.VolumeTypeGP2, + FSType: ebscsidriver.FSTypeExt4, + ClaimSize: driver.MinimumSizeForVolumeType(awscloud.VolumeTypeGP2), + VolumeMount: testsuites.VolumeMountDetails{ + NameGenerate: "test-volume-", + MountPathGenerate: "/mnt/test-", + }, + AllowVolumeExpansion: &allowVolumeExpansion, + }, + }, + } + test := testsuites.DynamicallyProvisionedResizeVolumeTest{ + CSIDriver: ebsDriver, + Pod: pod, + } + test.Run(cs, ns) + }) }) var _ = Describe("[ebs-csi-e2e] [single-az] Snapshot", func() { diff --git a/tests/e2e/pre_provsioning.go b/tests/e2e/pre_provsioning.go index 06ef2d86ab..7612279466 100644 --- a/tests/e2e/pre_provsioning.go +++ b/tests/e2e/pre_provsioning.go @@ -17,6 +17,7 @@ package e2e import ( "context" "fmt" + ebscsidriver "github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver" k8srestclient "k8s.io/client-go/rest" "math/rand" "os" @@ -29,8 +30,6 @@ import ( v1 "k8s.io/api/core/v1" clientset "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/test/e2e/framework" - - ebscsidriver "github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/driver" ) const ( diff --git a/tests/e2e/testsuites/dynamically_provisioned_resize_volume_tester.go b/tests/e2e/testsuites/dynamically_provisioned_resize_volume_tester.go new file mode 100644 index 0000000000..421f729179 --- /dev/null +++ b/tests/e2e/testsuites/dynamically_provisioned_resize_volume_tester.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 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 testsuites + +import ( + "fmt" + "github.com/kubernetes-sigs/aws-ebs-csi-driver/pkg/util" + "github.com/kubernetes-sigs/aws-ebs-csi-driver/tests/e2e/driver" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/kubernetes/test/e2e/framework" + "time" + + . "github.com/onsi/ginkgo" + "k8s.io/api/core/v1" + clientset "k8s.io/client-go/kubernetes" +) + +// DynamicallyProvisionedResizeVolumeTest will provision required StorageClass(es), PVC(s) and Pod(s) +// Waiting for the PV provisioner to create a new PV +// Update pvc storage size +// Waiting for new PVC and PV to be ready +// And finally attach pvc to the pod and wait for pod to be ready. +type DynamicallyProvisionedResizeVolumeTest struct { + CSIDriver driver.DynamicPVTestDriver + Pod PodDetails +} + +func (t *DynamicallyProvisionedResizeVolumeTest) Run(client clientset.Interface, namespace *v1.Namespace) { + volume := t.Pod.Volumes[0] + tpvc, _ := volume.SetupDynamicPersistentVolumeClaim(client, namespace, t.CSIDriver) + defer tpvc.Cleanup() + + pvcName := tpvc.persistentVolumeClaim.Name + pvc, err := client.CoreV1().PersistentVolumeClaims(namespace.Name).Get(pvcName, metav1.GetOptions{}) + By(fmt.Sprintf("Get pvc name: %v", pvc.Name)) + originalSize := pvc.Spec.Resources.Requests["storage"] + delta := resource.Quantity{} + delta.Set(util.GiBToBytes(1)) + originalSize.Add(delta) + pvc.Spec.Resources.Requests["storage"] = originalSize + + By("resizing the pvc") + updatedPvc, err := client.CoreV1().PersistentVolumeClaims(namespace.Name).Update(pvc) + if err != nil { + framework.ExpectNoError(err, fmt.Sprintf("fail to resize pvc(%s): %v", pvcName, err)) + } + updatedSize := updatedPvc.Spec.Resources.Requests["storage"] + + By("Wait for resize to complete") + time.Sleep(30 * time.Second) + + By("checking the resizing result") + newPvc, err := client.CoreV1().PersistentVolumeClaims(namespace.Name).Get(pvcName, metav1.GetOptions{}) + if err != nil { + framework.ExpectNoError(err, fmt.Sprintf("fail to get new pvc(%s): %v", pvcName, err)) + } + newSize := newPvc.Spec.Resources.Requests["storage"] + if !newSize.Equal(updatedSize) { + framework.Failf("newSize(%+v) is not equal to updatedSize(%+v)", newSize.String(), updatedSize.String()) + } + + By("checking the resizing PV result") + newPv, _ := client.CoreV1().PersistentVolumes().Get(newPvc.Spec.VolumeName, metav1.GetOptions{}) + newPvSize := newPv.Spec.Capacity["storage"] + if !newSize.Equal(newPvSize) { + By(fmt.Sprintf("newPVCSize(%+v) is not equal to newPVSize(%+v)", newSize.String(), newPvSize.String())) + } + + By("Validate volume can be attached") + tpod := NewTestPod(client, namespace, t.Pod.Cmd) + + tpod.SetupVolume(tpvc.persistentVolumeClaim, volume.VolumeMount.NameGenerate+"1", volume.VolumeMount.MountPathGenerate+"1", volume.VolumeMount.ReadOnly) + + By("deploying the pod") + tpod.Create() + By("checking that the pods is running") + tpod.WaitForSuccess() + + defer tpod.Cleanup() + +} diff --git a/tests/e2e/testsuites/specs.go b/tests/e2e/testsuites/specs.go index cbe30c507f..6c43d6cf01 100644 --- a/tests/e2e/testsuites/specs.go +++ b/tests/e2e/testsuites/specs.go @@ -39,6 +39,7 @@ type VolumeDetails struct { MountOptions []string ClaimSize string ReclaimPolicy *v1.PersistentVolumeReclaimPolicy + AllowVolumeExpansion *bool VolumeBindingMode *storagev1.VolumeBindingMode AllowedTopologyValues []string VolumeMode VolumeMode @@ -119,7 +120,8 @@ func (pod *PodDetails) SetupDeployment(client clientset.Interface, namespace *v1 cleanupFuncs := make([]func(), 0) volume := pod.Volumes[0] By("setting up the StorageClass") - storageClass := csiDriver.GetDynamicProvisionStorageClass(driver.GetParameters(volume.VolumeType, volume.FSType, volume.Encrypted), volume.MountOptions, volume.ReclaimPolicy, volume.VolumeBindingMode, volume.AllowedTopologyValues, namespace.Name) + + storageClass := csiDriver.GetDynamicProvisionStorageClass(driver.GetParameters(volume.VolumeType, volume.FSType, volume.Encrypted), volume.MountOptions, volume.ReclaimPolicy, volume.AllowVolumeExpansion, volume.VolumeBindingMode, volume.AllowedTopologyValues, namespace.Name) tsc := NewTestStorageClass(client, namespace, storageClass) createdStorageClass := tsc.Create() cleanupFuncs = append(cleanupFuncs, tsc.Cleanup) @@ -139,7 +141,7 @@ func (pod *PodDetails) SetupDeployment(client clientset.Interface, namespace *v1 func (volume *VolumeDetails) SetupDynamicPersistentVolumeClaim(client clientset.Interface, namespace *v1.Namespace, csiDriver driver.DynamicPVTestDriver) (*TestPersistentVolumeClaim, []func()) { cleanupFuncs := make([]func(), 0) By("setting up the StorageClass") - storageClass := csiDriver.GetDynamicProvisionStorageClass(driver.GetParameters(volume.VolumeType, volume.FSType, volume.Encrypted), volume.MountOptions, volume.ReclaimPolicy, volume.VolumeBindingMode, volume.AllowedTopologyValues, namespace.Name) + storageClass := csiDriver.GetDynamicProvisionStorageClass(driver.GetParameters(volume.VolumeType, volume.FSType, volume.Encrypted), volume.MountOptions, volume.ReclaimPolicy, volume.AllowVolumeExpansion, volume.VolumeBindingMode, volume.AllowedTopologyValues, namespace.Name) tsc := NewTestStorageClass(client, namespace, storageClass) createdStorageClass := tsc.Create() cleanupFuncs = append(cleanupFuncs, tsc.Cleanup)