diff --git a/.github/workflows/branch_preparation.yml b/.github/workflows/branch_preparation.yml index 929fab7b..ca50322d 100644 --- a/.github/workflows/branch_preparation.yml +++ b/.github/workflows/branch_preparation.yml @@ -9,7 +9,7 @@ on: jobs: update_release_branch_after_release: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores if: ${{ github.ref_type == 'tag' }} steps: - uses: actions/checkout@v4 @@ -49,7 +49,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} update_develop_branch_on_release_branch_creation: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores if: ${{ github.ref_type == 'branch' }} steps: - uses: actions/checkout@v4 @@ -92,7 +92,7 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} prepare_release_branch_on_creation: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores if: ${{ github.ref_type == 'branch' }} steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build_and_push.yml b/.github/workflows/build_and_push.yml index 264f5cc6..b153dc95 100644 --- a/.github/workflows/build_and_push.yml +++ b/.github/workflows/build_and_push.yml @@ -14,7 +14,7 @@ on: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores steps: - name: Checkout uses: actions/checkout@v4 @@ -38,7 +38,7 @@ jobs: run: make golint unit-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["lint"] steps: - name: Checkout @@ -67,7 +67,7 @@ jobs: flags: unittests bdd-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["unit-tests"] strategy: fail-fast: true @@ -130,7 +130,7 @@ jobs: flags: bddtests csi-driver: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["bdd-tests"] steps: - name: Checkout @@ -217,7 +217,7 @@ jobs: BRANCH=${{ env.BRANCH }} release-chart: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["csi-driver"] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index ca67ed05..8db8346b 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -14,7 +14,7 @@ on: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores steps: - name: Checkout uses: actions/checkout@v4 @@ -46,7 +46,7 @@ jobs: run: make golint validate_codegen: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores env: GOPATH: ${{ github.workspace }}/go GOBIN: ${{ github.workspace }}/go/bin @@ -77,7 +77,7 @@ jobs: make verify-manifests unit-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["lint", "validate_codegen"] steps: - name: Checkout @@ -106,7 +106,7 @@ jobs: flags: unittests bdd-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["unit-tests"] strategy: fail-fast: true @@ -169,7 +169,7 @@ jobs: flags: bddtests csi-driver: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["bdd-tests"] steps: - name: Checkout diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3b44cfb3..d9b6e50f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: jobs: lint: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores steps: - name: Checkout uses: actions/checkout@v4 @@ -29,7 +29,7 @@ jobs: ct lint --config ct.yaml unit-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["lint"] steps: - name: Checkout @@ -53,7 +53,7 @@ jobs: flags: unittests bdd-tests: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["unit-tests"] strategy: fail-fast: true @@ -111,7 +111,7 @@ jobs: flags: bddtests csi-driver: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["bdd-tests"] steps: - name: Checkout @@ -210,7 +210,7 @@ jobs: BRANCH=${{ env.BRANCH }} release-chart: - runs-on: ubuntu-22.04 + runs-on: ubuntu-22.04-8-cores needs: ["csi-driver"] steps: - uses: actions/checkout@v4 diff --git a/ci/ci-test.sh b/ci/ci-test.sh index 4f6bef00..d518c166 100755 --- a/ci/ci-test.sh +++ b/ci/ci-test.sh @@ -107,7 +107,7 @@ runTestSuite() { echo "running ginkgo test case with coverage ${coverageFile}" - if ! ginkgo -v -coverprofile="${coverageFile}" --label-filter="${labelFilter}" -covermode=atomic; then + if ! ginkgo -p -v -coverprofile="${coverageFile}" --label-filter="${labelFilter}" -covermode=atomic; then sudo zpool status diff --git a/pkg/driver/controller.go b/pkg/driver/controller.go index 990eee45..3abefba5 100644 --- a/pkg/driver/controller.go +++ b/pkg/driver/controller.go @@ -502,6 +502,18 @@ func (cs *controller) DeleteVolume( unlock := cs.volumeLock.LockVolume(volumeID) defer unlock() + // Fetch the list of snapshot for the given volume + snapList, err := zfs.GetSnapshotForVolume(volumeID) + if err != nil { + return nil, status.Errorf( + codes.NotFound, + "failed to handle delete volume request for {%s}, "+ + "validation failed checking for snapshots. Error: %s", + req.VolumeId, + err.Error(), + ) + } + // verify if the volume has already been deleted vol, err := zfs.GetVolume(volumeID) if vol != nil && vol.DeletionTimestamp != nil { @@ -524,14 +536,17 @@ func (cs *controller) DeleteVolume( return nil, status.Error(codes.Internal, "can not delete, volume creation is in progress") } - // Delete the corresponding ZV CR - err = zfs.DeleteVolume(volumeID) - if err != nil { - return nil, errors.Wrapf( - err, - "failed to handle delete volume request for {%s}", - volumeID, - ) + // Delete the corresponding ZV CR only if there are no snapshots present for the volume + + if len(snapList.Items) == 0 { + err = zfs.DeleteVolume(volumeID) + if err != nil { + return nil, errors.Wrapf( + err, + "failed to handle delete volume request for {%s}", + volumeID, + ) + } } sendEventOrIgnore("", volumeID, vol.Spec.Capacity, analytics.VolumeDeprovision) diff --git a/pkg/zfs/volume.go b/pkg/zfs/volume.go index 446e4a66..b4da2cd2 100644 --- a/pkg/zfs/volume.go +++ b/pkg/zfs/volume.go @@ -441,3 +441,12 @@ func IsVolumeReady(vol *apis.ZFSVolume) bool { return false } + +// GetSnapshotForVolume fetches all the snapshots for the given volume +func GetSnapshotForVolume(volumeID string) (*apis.ZFSSnapshotList, error) { + listOptions := metav1.ListOptions{ + LabelSelector: ZFSVolKey + "=" + volumeID, + } + snapList, err := snapbuilder.NewKubeclient().WithNamespace(OpenEBSNamespace).List(listOptions) + return snapList, err +} diff --git a/tests/provision_test.go b/tests/provision_test.go index 35246080..c1750f3a 100644 --- a/tests/provision_test.go +++ b/tests/provision_test.go @@ -24,6 +24,7 @@ var _ = Describe("[zfspv] TEST VOLUME PROVISIONING", func() { Context("App is deployed with zfs driver", func() { It("Running zfs volume Creation Test", volumeCreationTest) It("Running zfs volume Creation Test with custom node id", Label("custom-node-id"), volumeCreationTest) + It("Running zfs volume Deletion Test", volumeDeletionTest) }) }) @@ -41,7 +42,7 @@ func exhaustiveVolumeTests(parameters map[string]string) { snapshotAndCloneCreate() // btrfs does not support online resize if fstype != "btrfs" { - By("Resizing the PVC", resizeAndVerifyPVC) + By("Resizing the PVC", func() { resizeAndVerifyPVC(pvcNameFS) }) } snapshotAndCloneCleanUp() cleanUp() @@ -51,8 +52,8 @@ func exhaustiveVolumeTests(parameters map[string]string) { func create(parameters map[string]string) { By("####### Creating the storage class : " + parameters["fstype"] + " #######") createFstypeStorageClass(parameters) - By("creating and verifying PVC bound status", createAndVerifyPVC) - By("Creating and deploying app pod", createDeployVerifyApp) + By("creating and verifying PVC bound status", func() { createAndVerifyPVC(pvcNameFS) }) + By("Creating and deploying app pod", func() { createDeployVerifyApp(appNameFS, pvcNameFS) }) By("verifying ZFSVolume object", VerifyZFSVolume) By("verifying storage class parameters") VerifyStorageClassParams(parameters) @@ -60,48 +61,78 @@ func create(parameters map[string]string) { // Creates the snapshot/clone resources func snapshotAndCloneCreate() { - createSnapshot(pvcName, snapName) - verifySnapshotCreated(snapName) - createClone(clonePvcName, snapName, scObj.Name) - By("Creating and deploying clone app pod", createDeployVerifyCloneApp) + createSnapshot(pvcNameFS, snapNameFS) + verifySnapshotCreated(snapNameFS) + createClone(clonePvcNameFS, snapNameFS, scObj.Name) + By("Creating and deploying clone app pod", func() { createDeployVerifyCloneApp(cloneAppNameFS, clonePvcNameFS) }) } // Removes the snapshot/clone resources func snapshotAndCloneCleanUp() { - deleteAppDeployment(cloneAppName) - deletePVC(clonePvcName) - deleteSnapshot(pvcName, snapName) + deleteAppDeployment(cloneAppNameFS) + deletePVC(clonePvcNameFS) + deleteSnapshot(pvcNameFS, snapNameFS) } // Removes the resources func cleanUp() { - deleteAppDeployment(appName) - deletePVC(pvcName) + deleteAppDeployment(appNameFS) + deletePVC(pvcNameFS) By("Deleting storage class", deleteStorageClass) } func blockVolCreationTest() { By("Creating default storage class", createStorageClass) - By("creating and verifying PVC bound status", createAndVerifyBlockPVC) + By("creating and verifying PVC bound status", func() { createAndVerifyPVC(pvcNameBlock) }) - By("Creating and deploying app pod", createDeployVerifyBlockApp) + By("Creating and deploying app pod", func() { createDeployVerifyApp(appNameBlock, pvcNameBlock) }) By("verifying ZFSVolume object", VerifyZFSVolume) By("verifying ZFSVolume property change", VerifyZFSVolumePropEdit) - By("Deleting application deployment") - createSnapshot(pvcName, snapName) - verifySnapshotCreated(snapName) - createClone(clonePvcName, snapName, scObj.Name) - By("Creating and deploying clone app pod", createDeployVerifyCloneApp) + createSnapshot(pvcNameBlock, snapNameBlock) + verifySnapshotCreated(snapNameBlock) + createClone(clonePvcNameBlock, snapNameBlock, scObj.Name) + By("Creating and deploying clone app pod", func() { createDeployVerifyCloneApp(cloneAppNameBlock, clonePvcNameBlock) }) By("Deleting clone and main application deployment") - deleteAppDeployment(cloneAppName) - deleteAppDeployment(appName) + deleteAppDeployment(cloneAppNameBlock) + deleteAppDeployment(appNameBlock) By("Deleting snapshot, main pvc and clone pvc") - deletePVC(clonePvcName) - deleteSnapshot(pvcName, snapName) - deletePVC(pvcName) + deletePVC(clonePvcNameBlock) + deleteSnapshot(pvcNameBlock, snapNameBlock) + deletePVC(pvcNameBlock) + + By("Deleting storage class", deleteStorageClass) +} + +func blockVolDeletionTest() { + By("Creating default storage class", createStorageClass) + By("creating and verifying PVC bound status", func() { createAndVerifyPVC(pvcNameAplha) }) + + By("Creating and deploying app pod", func() { createDeployVerifyApp(appNameAlpha, pvcNameAplha) }) + By("verifying ZFSVolume object", VerifyZFSVolume) + + createSnapshot(pvcNameAplha, snapNameAlpha) + verifySnapshotCreated(snapNameAlpha) + + By("Deleting main application deployment") + deleteAppDeployment(appNameAlpha) + + By("Deleting main pvc") + deletePVC(pvcNameAplha) + + By("Verifying ZFSVolume object after pvc deletion when snapshot is present", VerifyZFSVolume) + + By("Creating clone from the snapshot") + createClone(clonePvcNameAlpha, snapNameAlpha, scObj.Name) + By("Creating and deploying clone app pod", func() { createDeployVerifyCloneApp(cloneAppNameAlpha, clonePvcNameAlpha) }) + + By("Deleting clone application deployment, clone pvc") + deleteAppDeployment(cloneAppNameAlpha) + + deletePVC(clonePvcNameAlpha) + deleteSnapshot(pvcNameAplha, snapNameAlpha) By("Deleting storage class", deleteStorageClass) } @@ -109,4 +140,9 @@ func blockVolCreationTest() { func volumeCreationTest() { By("Running volume creation test", fsVolCreationTest) By("Running block volume creation test", blockVolCreationTest) + +} + +func volumeDeletionTest() { + By("Running volume deletion test", blockVolDeletionTest) } diff --git a/tests/suite_test.go b/tests/suite_test.go index b20d46b5..139685e1 100644 --- a/tests/suite_test.go +++ b/tests/suite_test.go @@ -48,11 +48,33 @@ var ( PodClient *pod.KubeClient scName = "zfspv-sc" ZFSProvisioner = "zfs.csi.openebs.io" - pvcName = "zfspv-pvc" - snapName = "zfspv-snap" - appName = "busybox-zfspv" - clonePvcName = "zfspv-pvc-clone" - cloneAppName = "busybox-zfspv-clone" + + pvcName = "zfspv-pvc-fs" + snapName = "zfspv-snap" + appName = "busybox-zfspv" + + clonePvcName = "zfspv-pvc-clone" + cloneAppName = "busybox-zfspv-clone" + + pvcNameFS = "zfspv-pvc-fs" + pvcNameBlock = "zfspv-pvc-block" + pvcNameAplha = "zfspv-pvc-alpha" + + appNameFS = "busybox-zfspv-fs" + appNameBlock = "busybox-zfspv-block" + appNameAlpha = "busybox-zfspv-alpha" + + snapNameFS = "zfspv-snap-fs" + snapNameBlock = "zfspv-snap-block" + snapNameAlpha = "zfspv-snap-alpha" + + clonePvcNameFS = "zfspv-pvc-clone-fs" + clonePvcNameBlock = "zfspv-pvc-clone-block" + clonePvcNameAlpha = "zfspv-pvc-clone-alpha" + + cloneAppNameFS = "busybox-zfspv-clone-fs" + cloneAppNameBlock = "busybox-zfspv-clone-block" + cloneAppNameAlpha = "busybox-zfspv-clone-alpha" scObj *storagev1.StorageClass deployObj *appsv1.Deployment diff --git a/tests/utils.go b/tests/utils.go index a8102a0b..1578b180 100644 --- a/tests/utils.go +++ b/tests/utils.go @@ -18,10 +18,11 @@ package tests import ( "fmt" - "k8s.io/klog/v2" "os/exec" "time" + "k8s.io/klog/v2" + "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" @@ -349,11 +350,11 @@ func deleteStorageClass() { "while deleting zfs storageclass {%s}", scObj.Name) } -func createAndVerifyPVC() { +func createAndVerifyPVC(pvcName string) { var ( - err error - pvcName = "zfspv-pvc" + err error ) + ginkgo.By("building a pvc") pvcObj, err = pvc.NewBuilder(). WithName(pvcName). @@ -361,53 +362,12 @@ func createAndVerifyPVC() { WithStorageClass(scObj.Name). WithAccessModes(accessModes). WithCapacity(capacity).Build() - gomega.Expect(err).ShouldNot( - gomega.HaveOccurred(), - "while building pvc {%s} in namespace {%s}", - pvcName, - OpenEBSNamespace, - ) - - ginkgo.By("creating above pvc") - pvcObj, err = PVCClient.WithNamespace(OpenEBSNamespace).Create(pvcObj) - gomega.Expect(err).To( - gomega.BeNil(), - "while creating pvc {%s} in namespace {%s}", - pvcName, - OpenEBSNamespace, - ) - - ginkgo.By("verifying pvc status as bound") - - status := IsPVCBoundEventually(pvcName) - gomega.Expect(status).To(gomega.Equal(true), - "while checking status equal to bound") - - pvcObj, err = PVCClient.WithNamespace(OpenEBSNamespace).Get(pvcObj.Name, metav1.GetOptions{}) - gomega.Expect(err).To( - gomega.BeNil(), - "while retrieving pvc {%s} in namespace {%s}", - pvcName, - OpenEBSNamespace, - ) -} -func createAndVerifyBlockPVC() { - var ( - err error - pvcName = "zfspv-pvc" - ) - - volmode := corev1.PersistentVolumeBlock + if pvcName == "zfspv-pvc-block" { + volmode := corev1.PersistentVolumeBlock + pvcObj.Spec.VolumeMode = &volmode + } - ginkgo.By("building a pvc") - pvcObj, err = pvc.NewBuilder(). - WithName(pvcName). - WithNamespace(OpenEBSNamespace). - WithStorageClass(scObj.Name). - WithAccessModes(accessModes). - WithVolumeMode(&volmode). - WithCapacity(capacity).Build() gomega.Expect(err).ShouldNot( gomega.HaveOccurred(), "while building pvc {%s} in namespace {%s}", @@ -439,10 +399,9 @@ func createAndVerifyBlockPVC() { ) } -func resizeAndVerifyPVC() { +func resizeAndVerifyPVC(pvcName string) { var ( - err error - pvcName = "zfspv-pvc" + err error ) ginkgo.By("updating the pvc with new size") pvcObj, err = PVCClient.WithNamespace(OpenEBSNamespace).Get(pvcObj.Name, metav1.GetOptions{}) @@ -476,25 +435,30 @@ func resizeAndVerifyPVC() { OpenEBSNamespace, ) } -func createDeployVerifyApp() { +func createDeployVerifyApp(appName, pvcName string) { ginkgo.By("creating and deploying app pod") - createAndDeployAppPod(appName) + if pvcName == "zfspv-pvc-block" || pvcName == "pvc-name-for-del-test" { + createAndDeployBlockAppPod(appName, pvcName) + } else { + createAndDeployAppPod(appName, pvcName) + } + time.Sleep(30 * time.Second) ginkgo.By("verifying app pod is running", verifyAppPodRunning) } -func createDeployVerifyCloneApp() { +func createDeployVerifyCloneApp(cloneAppName, clonePvcName string) { ginkgo.By("creating and deploying app pod") - createAndDeployAppPod(cloneAppName) - time.Sleep(30 * time.Second) + createAndDeployAppPod(cloneAppName, clonePvcName) + time.Sleep(60 * time.Second) ginkgo.By("verifying app pod is running", verifyAppPodRunning) } -func createAndDeployAppPod(appname string) { +func createAndDeployAppPod(appName, pvcName string) { var err error ginkgo.By("building a busybox app pod deployment using above zfs volume") deployObj, err = deploy.NewBuilder(). - WithName(appname). + WithName(appName). WithNamespace(OpenEBSNamespace). WithLabelsNew( map[string]string{ @@ -537,7 +501,7 @@ func createAndDeployAppPod(appname string) { WithVolumeBuilders( k8svolume.NewBuilder(). WithName("datavol1"). - WithPVCSource(pvcObj.Name), + WithPVCSource(pvcName), ), ). Build() @@ -553,7 +517,7 @@ func createAndDeployAppPod(appname string) { ) } -func createAndDeployBlockAppPod() { +func createAndDeployBlockAppPod(appName, pvcName string) { var err error ginkgo.By("building a busybox app pod deployment using above zfs volume") deployObj, err = deploy.NewBuilder(). @@ -600,7 +564,7 @@ func createAndDeployBlockAppPod() { WithVolumeBuilders( k8svolume.NewBuilder(). WithName("datavol1"). - WithPVCSource(pvcObj.Name), + WithPVCSource(pvcName), ), ). Build() @@ -616,12 +580,6 @@ func createAndDeployBlockAppPod() { ) } -func createDeployVerifyBlockApp() { - ginkgo.By("creating and deploying app pod", createAndDeployBlockAppPod) - time.Sleep(30 * time.Second) - ginkgo.By("verifying app pod is running", verifyAppPodRunning) -} - func verifyAppPodRunning() { var err error appPod, err = PodClient.WithNamespace(OpenEBSNamespace).