diff --git a/e2e/resize.go b/e2e/resize.go new file mode 100644 index 000000000..c3dad4501 --- /dev/null +++ b/e2e/resize.go @@ -0,0 +1,177 @@ +package e2e + +import ( + "fmt" + "strings" + "time" + + . "github.com/onsi/gomega" // nolint + v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/cloud-provider/volume/helpers" + "k8s.io/kubernetes/test/e2e/framework" + e2elog "k8s.io/kubernetes/test/e2e/framework/log" + testutils "k8s.io/kubernetes/test/utils" +) + +func expandPVCSize(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, size string, t int) error { + pvcName := pvc.Name + updatedPVC := pvc.DeepCopy() + var err error + + updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvcName, metav1.GetOptions{}) + if err != nil { + return fmt.Errorf("error fetching pvc %q with %v", pvcName, err) + } + timeout := time.Duration(t) * time.Minute + + updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size) + _, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Update(updatedPVC) + Expect(err).Should(BeNil()) + + start := time.Now() + e2elog.Logf("Waiting up to %v to be in Resized state", pvc) + return wait.PollImmediate(poll, timeout, func() (bool, error) { + e2elog.Logf("waiting for PVC %s (%d seconds elapsed)", updatedPVC.Name, int(time.Since(start).Seconds())) + updatedPVC, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Get(pvcName, metav1.GetOptions{}) + if err != nil { + e2elog.Logf("Error getting pvc in namespace: '%s': %v", updatedPVC.Namespace, err) + if testutils.IsRetryableAPIError(err) { + return false, nil + } + return false, err + } + pvcConditions := updatedPVC.Status.Conditions + if len(pvcConditions) > 0 { + e2elog.Logf("pvc state %v", pvcConditions[0].Type) + if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing || pvcConditions[0].Type == v1.PersistentVolumeClaimFileSystemResizePending { + return false, nil + } + } + + if updatedPVC.Status.Capacity[v1.ResourceStorage] != resource.MustParse(size) { + e2elog.Logf("current size in status %v,expected size %v", updatedPVC.Status.Capacity[v1.ResourceStorage], resource.MustParse(size)) + return false, nil + } + return true, nil + }) +} + +func resizePVCAndValidateSize(pvcPath, appPath string, f *framework.Framework) error { + size := "1Gi" + expandSize := "10Gi" + pvc, err := loadPVC(pvcPath) + if pvc == nil { + return err + } + pvc.Namespace = f.UniqueName + + resizePvc, err := loadPVC(pvcPath) + if resizePvc == nil { + return err + } + resizePvc.Namespace = f.UniqueName + + app, err := loadApp(appPath) + if err != nil { + return err + } + pvc.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size) + app.Labels = map[string]string{"app": "resize-pvc"} + app.Namespace = f.UniqueName + + err = createPVCAndApp("", f, pvc, app) + if err != nil { + return err + } + + opt := metav1.ListOptions{ + LabelSelector: "app=resize-pvc", + } + + if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem { + err = checkDirSize(app, f, &opt, size) + if err != nil { + return err + } + } + + if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock { + err = checkDeviceSize(app, f, &opt, size) + if err != nil { + return err + } + } + // resize PVC + err = expandPVCSize(f.ClientSet, resizePvc, expandSize, deployTimeout) + if err != nil { + return err + } + // wait for application pod to come up after resize + err = waitForPodInRunningState(app.Name, app.Namespace, f.ClientSet, deployTimeout) + if err != nil { + return err + } + if *pvc.Spec.VolumeMode == v1.PersistentVolumeFilesystem { + err = checkDirSize(app, f, &opt, expandSize) + if err != nil { + return err + } + } + + if *pvc.Spec.VolumeMode == v1.PersistentVolumeBlock { + err = checkDeviceSize(app, f, &opt, expandSize) + if err != nil { + return err + } + } + err = deletePVCAndApp("", f, resizePvc, app) + return err +} + +func checkDirSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error { + cmd := getDirSizeCheckCmd(app.Spec.Containers[0].VolumeMounts[0].MountPath) + return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout) +} + +func checkDeviceSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string) error { + cmd := getDeviceSizeCheckCmd(app.Spec.Containers[0].VolumeDevices[0].DevicePath) + return checkAppMntSize(f, opt, size, cmd, app.Namespace, deployTimeout) + +} +func getDirSizeCheckCmd(dirPath string) string { + return fmt.Sprintf("df -h|grep %s |awk '{print $2}'", dirPath) +} + +func getDeviceSizeCheckCmd(devPath string) string { + return fmt.Sprintf("blockdev --getsize64 %s", devPath) +} + +func checkAppMntSize(f *framework.Framework, opt *metav1.ListOptions, size, cmd, ns string, t int) error { + timeout := time.Duration(t) * time.Minute + start := time.Now() + + return wait.PollImmediate(poll, timeout, func() (bool, error) { + e2elog.Logf("executing cmd %s (%d seconds elapsed)", cmd, int(time.Since(start).Seconds())) + output, stdErr := execCommandInPod(f, cmd, ns, opt) + + if stdErr != "" { + e2elog.Logf("failed to execute command in app pod %v", stdErr) + return false, nil + } + s := resource.MustParse(strings.TrimSpace(output)) + actualSize := helpers.RoundUpToGiB(s) + + s = resource.MustParse(size) + expectedSize := helpers.RoundUpToGiB(s) + + if actualSize != expectedSize { + e2elog.Logf("expected size %s found %s information", size, output) + return false, nil + } + return true, nil + }) +} diff --git a/e2e/utils.go b/e2e/utils.go index 5cdbbfb63..28801e4ff 100644 --- a/e2e/utils.go +++ b/e2e/utils.go @@ -19,14 +19,12 @@ import ( v1 "k8s.io/api/core/v1" scv1 "k8s.io/api/storage/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/util/wait" utilyaml "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes" clientset "k8s.io/client-go/kubernetes" - "k8s.io/cloud-provider/volume/helpers" "k8s.io/kubernetes/pkg/client/conditions" "k8s.io/kubernetes/test/e2e/framework" e2elog "k8s.io/kubernetes/test/e2e/framework/log" @@ -879,126 +877,3 @@ func checkDataPersist(pvcPath, appPath string, f *framework.Framework) error { err = deletePVCAndApp("", f, pvc, app) return err } - -func expandPVCSize(c kubernetes.Interface, pvc *v1.PersistentVolumeClaim, size string, t int) error { - pvcName := pvc.Name - updatedPVC := pvc.DeepCopy() - var err error - - updatedPVC, err = c.CoreV1().PersistentVolumeClaims(pvc.Namespace).Get(pvcName, metav1.GetOptions{}) - if err != nil { - return fmt.Errorf("error fetching pvc %q with %v", pvcName, err) - } - timeout := time.Duration(t) * time.Minute - - updatedPVC.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size) - _, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Update(updatedPVC) - Expect(err).Should(BeNil()) - - start := time.Now() - e2elog.Logf("Waiting up to %v to be in Resized state", pvc) - return wait.PollImmediate(poll, timeout, func() (bool, error) { - e2elog.Logf("waiting for PVC %s (%d seconds elapsed)", updatedPVC.Name, int(time.Since(start).Seconds())) - updatedPVC, err = c.CoreV1().PersistentVolumeClaims(updatedPVC.Namespace).Get(pvcName, metav1.GetOptions{}) - if err != nil { - e2elog.Logf("Error getting pvc in namespace: '%s': %v", updatedPVC.Namespace, err) - if testutils.IsRetryableAPIError(err) { - return false, nil - } - return false, err - } - pvcConditions := updatedPVC.Status.Conditions - if len(pvcConditions) > 0 { - e2elog.Logf("pvc state %v", pvcConditions[0].Type) - if pvcConditions[0].Type == v1.PersistentVolumeClaimResizing || pvcConditions[0].Type == v1.PersistentVolumeClaimFileSystemResizePending { - return false, nil - } - } - - if updatedPVC.Status.Capacity[v1.ResourceStorage] != resource.MustParse(size) { - e2elog.Logf("current size in status %v,expected size %v", updatedPVC.Status.Capacity[v1.ResourceStorage], resource.MustParse(size)) - return false, nil - } - return true, nil - }) -} - -func resizePVCAndValidateSize(pvcPath, appPath string, f *framework.Framework) error { - size := "1Gi" - expandSize := "10Gi" - pvc, err := loadPVC(pvcPath) - if pvc == nil { - return err - } - pvc.Namespace = f.UniqueName - - resizePvc, err := loadPVC(pvcPath) - if resizePvc == nil { - return err - } - resizePvc.Namespace = f.UniqueName - - app, err := loadApp(appPath) - if err != nil { - return err - } - pvc.Spec.Resources.Requests[v1.ResourceStorage] = resource.MustParse(size) - app.Labels = map[string]string{"app": "resize-pvc"} - app.Namespace = f.UniqueName - - err = createPVCAndApp("", f, pvc, app) - if err != nil { - return err - } - - opt := metav1.ListOptions{ - LabelSelector: "app=resize-pvc", - } - err = checkDirSize(app, f, &opt, size, deployTimeout) - if err != nil { - return err - } - // resize PVC - err = expandPVCSize(f.ClientSet, resizePvc, expandSize, deployTimeout) - if err != nil { - return err - } - // wait for application pod to come up after resize - err = waitForPodInRunningState(app.Name, app.Namespace, f.ClientSet, deployTimeout) - if err != nil { - return err - } - err = checkDirSize(app, f, &opt, expandSize, deployTimeout) - if err != nil { - return err - } - err = deletePVCAndApp("", f, resizePvc, app) - return err -} - -func checkDirSize(app *v1.Pod, f *framework.Framework, opt *metav1.ListOptions, size string, t int) error { - dirPath := app.Spec.Containers[0].VolumeMounts[0].MountPath - timeout := time.Duration(t) * time.Minute - start := time.Now() - - return wait.PollImmediate(poll, timeout, func() (bool, error) { - e2elog.Logf("checking directory size %s (%d seconds elapsed)", dirPath, int(time.Since(start).Seconds())) - output, stdErr := execCommandInPod(f, fmt.Sprintf("df -h|grep %s |awk '{print $2}'", dirPath), app.Namespace, opt) - - if stdErr != "" { - e2elog.Logf("failed to execute command in app pod %v", stdErr) - return false, nil - } - s := resource.MustParse(strings.TrimSpace(output)) - actualSize := helpers.RoundUpToGiB(s) - - s = resource.MustParse(size) - expectedSize := helpers.RoundUpToGiB(s) - - if actualSize != expectedSize { - e2elog.Logf("expected directory size %s found %s information", size, output) - return false, nil - } - return true, nil - }) -}