diff --git a/e2e/rbd.go b/e2e/rbd.go index c15cedbbb..5821f35d6 100644 --- a/e2e/rbd.go +++ b/e2e/rbd.go @@ -185,6 +185,20 @@ func createORDeleteRbdResources(action kubectlAction) { } } +func validateRBDSnapshotCount(f *framework.Framework, count int, pool, image string) error { + snapshotList, err := listRBDSnapshots(f, pool, image) + if err != nil { + return fmt.Errorf("failed to list RBD snapshots: %w", err) + } + if len(snapshotList) != count { + return fmt.Errorf("RBD snapshots count not matching, snapshot count for image %s/%s %d, expected %d"+ + "snapshots in cluster: %v", + pool, image, len(snapshotList), count, snapshotList) + } + + return nil +} + func validateRBDImageCount(f *framework.Framework, count int, pool string) { imageList, err := listRBDImages(f, pool) if err != nil { diff --git a/e2e/rbd_helper.go b/e2e/rbd_helper.go index 05b59979a..7744ac925 100644 --- a/e2e/rbd_helper.go +++ b/e2e/rbd_helper.go @@ -248,6 +248,17 @@ type imageInfoFromPVC struct { pvName string } +type snapInfo struct { + ID int `json:"id"` + Name string `json:"name"` + Size int64 `json:"size"` + Protected string `json:"protected"` +} + +func (s snapInfo) String() string { + return fmt.Sprintf("{id: %d, name: %s, protected: %s}", s.ID, s.Name, s.Protected) +} + // getImageInfoFromPVC reads volume handle of the bound PV to the passed in PVC, // and returns imageInfoFromPVC or error. func getImageInfoFromPVC(pvcNamespace, pvcName string, f *framework.Framework) (imageInfoFromPVC, error) { @@ -715,6 +726,25 @@ func librbdSupportsVolumeGroupSnapshot(f *framework.Framework) (bool, error) { return strings.TrimSpace(stdout) == "0", nil } +func listRBDSnapshots(f *framework.Framework, pool, image string) ([]snapInfo, error) { + var snapInfos []snapInfo + command := fmt.Sprintf("rbd snap ls --format=json %s %s", rbdOptions(pool), image) + stdout, stdErr, err := execCommandInToolBoxPod(f, command, rookNamespace) + if err != nil { + return snapInfos, err + } + if stdErr != "" { + return snapInfos, fmt.Errorf("failed to list RBD snapshots %v", stdErr) + } + + err = json.Unmarshal([]byte(stdout), &snapInfos) + if err != nil { + return snapInfos, err + } + + return snapInfos, nil +} + func listRBDImages(f *framework.Framework, pool string) ([]string, error) { var imgInfos []string diff --git a/e2e/utils.go b/e2e/utils.go index 04cc03f2b..bec691337 100644 --- a/e2e/utils.go +++ b/e2e/utils.go @@ -1003,6 +1003,16 @@ func validatePVCClone( if wgErrs[n] == nil && validatePVC != nil && kms != noKMS { wgErrs[n] = validatePVC(f, &p, &a) } + if wgErrs[n] == nil { + // validate RBD snapshot under temporary clone is not deleted. + imageData, imageInfoerr := getImageInfoFromPVC(p.Namespace, name, f) + if imageInfoerr != nil { + wgErrs[n] = imageInfoerr + } else { + tempRBDImageName := imageData.imageName + "-temp" + wgErrs[n] = validateRBDSnapshotCount(f, 1, defaultRBDPool, tempRBDImageName) + } + } wg.Done() }(i, *pvcClone, *appClone) }