From 79cb1b384924c24aeafab0cea19cde9f67196ef0 Mon Sep 17 00:00:00 2001 From: Robert Vasek Date: Wed, 6 Apr 2022 14:05:18 +0200 Subject: [PATCH] e2e: add test for cephfs snapshot-backed volumes Signed-off-by: Robert Vasek --- e2e/cephfs.go | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++ e2e/pod.go | 19 +++++++ e2e/utils.go | 5 +- 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/e2e/cephfs.go b/e2e/cephfs.go index aa3b0544f..332d55ea7 100644 --- a/e2e/cephfs.go +++ b/e2e/cephfs.go @@ -1209,6 +1209,142 @@ var _ = Describe(cephfsType, func() { validateSubvolumeCount(f, 0, fileSystemName, subvolumegroup) validateOmapCount(f, 0, cephfsType, metadataPool, volumesType) validateOmapCount(f, 0, cephfsType, metadataPool, snapsType) + + err = deleteResource(cephFSExamplePath + "snapshotclass.yaml") + if err != nil { + e2elog.Failf("failed to delete CephFS snapshotclass: %v", err) + } + }) + + By("checking snapshot-backed volume", func() { + err := createCephFSSnapshotClass(f) + if err != nil { + e2elog.Failf("failed to delete CephFS storageclass: %v", err) + } + + pvc, err := loadPVC(pvcPath) + if err != nil { + e2elog.Failf("failed to load PVC: %v", err) + } + pvc.Namespace = f.UniqueName + err = createPVCAndvalidatePV(f.ClientSet, pvc, deployTimeout) + if err != nil { + e2elog.Failf("failed to create PVC: %v", err) + } + + app, err := loadApp(appPath) + if err != nil { + e2elog.Failf("failed to load application: %v", err) + } + app.Namespace = f.UniqueName + app.Spec.Volumes[0].PersistentVolumeClaim.ClaimName = pvc.Name + appLabels := map[string]string{ + appKey: appLabel, + } + app.Labels = appLabels + optApp := metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", appKey, appLabels[appKey]), + } + err = writeDataInPod(app, &optApp, f) + if err != nil { + e2elog.Failf("failed to write data: %v", err) + } + + appTestFilePath := app.Spec.Containers[0].VolumeMounts[0].MountPath + "/test" + + snap := getSnapshot(snapshotPath) + snap.Namespace = f.UniqueName + snap.Spec.Source.PersistentVolumeClaimName = &pvc.Name + err = createSnapshot(&snap, deployTimeout) + if err != nil { + e2elog.Failf("failed to create snapshot: %v", err) + } + + err = appendToFileInContainer(f, app, appTestFilePath, "hello", &optApp) + if err != nil { + e2elog.Failf("failed to append data: %v", err) + } + + parentFileSum, err := calculateSHA512sum(f, app, appTestFilePath, &optApp) + if err != nil { + e2elog.Failf("failed to get SHA512 sum for file: %v", err) + } + + err = deleteResource(cephFSExamplePath + "storageclass.yaml") + if err != nil { + e2elog.Failf("failed to delete CephFS storageclass: %v", err) + } + err = createCephfsStorageClass(f.ClientSet, f, false, map[string]string{ + "backingSnapshot": "true", + }) + if err != nil { + e2elog.Failf("failed to create CephFS storageclass: %v", err) + } + + pvcClone, err := loadPVC(pvcClonePath) + if err != nil { + e2elog.Failf("failed to load PVC: %v", err) + } + // Snapshot-backed volumes support read-only access modes only. + pvcClone.Spec.AccessModes = []v1.PersistentVolumeAccessMode{v1.ReadOnlyMany} + appClone, err := loadApp(appClonePath) + if err != nil { + e2elog.Failf("failed to load application: %v", err) + } + appCloneLabels := map[string]string{ + appKey: appCloneLabel, + } + appClone.Labels = appCloneLabels + optAppClone := metav1.ListOptions{ + LabelSelector: fmt.Sprintf("%s=%s", appKey, appCloneLabels[appKey]), + } + pvcClone.Namespace = f.UniqueName + appClone.Namespace = f.UniqueName + err = createPVCAndApp("", f, pvcClone, appClone, deployTimeout) + if err != nil { + e2elog.Failf("failed to create PVC and app: %v", err) + } + + // Snapshot-backed volume shouldn't contribute to total subvolume count. + validateSubvolumeCount(f, 1, fileSystemName, subvolumegroup) + + // Deleting snapshot before deleting pvcClone should succeed. It will be + // deleted once all volumes that are backed by this snapshot are gone. + err = deleteSnapshot(&snap, deployTimeout) + if err != nil { + e2elog.Failf("failed to delete snapshot: %v", err) + } + + appCloneTestFilePath := appClone.Spec.Containers[0].VolumeMounts[0].MountPath + "/test" + + snapFileSum, err := calculateSHA512sum(f, appClone, appCloneTestFilePath, &optAppClone) + if err != nil { + e2elog.Failf("failed to get SHA512 sum for file: %v", err) + } + + if parentFileSum == snapFileSum { + e2elog.Failf("SHA512 sums of files in parent subvol and snapshot should differ") + } + + err = deletePVCAndApp("", f, pvcClone, appClone) + if err != nil { + e2elog.Failf("failed to delete PVC or application: %v", err) + } + + err = deletePVCAndApp("", f, pvc, app) + if err != nil { + e2elog.Failf("failed to delete PVC or application: %v", err) + } + + err = deleteResource(cephFSExamplePath + "storageclass.yaml") + if err != nil { + e2elog.Failf("failed to delete CephFS storageclass: %v", err) + } + + err = createCephfsStorageClass(f.ClientSet, f, false, nil) + if err != nil { + e2elog.Failf("failed to create CephFS storageclass: %v", err) + } }) By("create a PVC-PVC clone and bind it to an app", func() { diff --git a/e2e/pod.go b/e2e/pod.go index 58e762f8a..cf281caa3 100644 --- a/e2e/pod.go +++ b/e2e/pod.go @@ -428,6 +428,25 @@ func calculateSHA512sum(f *framework.Framework, app *v1.Pod, filePath string, op return checkSum, nil } +func appendToFileInContainer( + f *framework.Framework, + app *v1.Pod, + filePath, + toAppend string, + opt *metav1.ListOptions, +) error { + cmd := fmt.Sprintf("echo %q >> %s", toAppend, filePath) + _, stdErr, err := execCommandInPod(f, cmd, app.Namespace, opt) + if err != nil { + return fmt.Errorf("could not append to file %s: %w ; stderr: %s", filePath, err, stdErr) + } + if stdErr != "" { + return fmt.Errorf("could not append to file %s: %v", filePath, stdErr) + } + + return nil +} + // getKernelVersionFromDaemonset gets the kernel version from the specified container. func getKernelVersionFromDaemonset(f *framework.Framework, ns, dsn, cn string) (string, error) { selector, err := getDaemonSetLabelSelector(f, ns, dsn) diff --git a/e2e/utils.go b/e2e/utils.go index 62ff0f948..a97afa299 100644 --- a/e2e/utils.go +++ b/e2e/utils.go @@ -62,8 +62,9 @@ const ( // deletePolicy is the default policy in E2E. deletePolicy = v1.PersistentVolumeReclaimDelete // Default key and label for Listoptions. - appKey = "app" - appLabel = "write-data-in-pod" + appKey = "app" + appLabel = "write-data-in-pod" + appCloneLabel = "app-clone" noError = "" // labels/selector used to list/delete rbd pods.