diff --git a/e2e/rbd.go b/e2e/rbd.go index c44a6441afa..33e9b839015 100644 --- a/e2e/rbd.go +++ b/e2e/rbd.go @@ -4745,6 +4745,27 @@ var _ = Describe("RBD", func() { } }) + By("test volumeGroupSnapshot", func() { + supported, err := librbdSupportsVolumeGroupSnapshot(f) + if err != nil { + framework.Failf("failed to check for VolumeGroupSnapshot support: %v", err) + } + if !supported { + Skip("librbd does not support required VolumeGroupSnapshot function(s)") + } + + scName := "csi-rbd-sc" + snapshotter, err := newRBDVolumeGroupSnapshot(f, f.UniqueName, scName, false, deployTimeout, 3) + if err != nil { + framework.Failf("failed to create RBDVolumeGroupSnapshot: %v", err) + } + + err = snapshotter.TestVolumeGroupSnapshot() + if err != nil { + framework.Failf("failed to test volumeGroupSnapshot: %v", err) + } + }) + // delete RBD provisioner secret err := deleteCephUser(f, keyringRBDProvisionerUsername) if err != nil { diff --git a/e2e/rbd_helper.go b/e2e/rbd_helper.go index b35e38a432c..2da60f68da0 100644 --- a/e2e/rbd_helper.go +++ b/e2e/rbd_helper.go @@ -693,6 +693,28 @@ func validateEncryptedFilesystem(f *framework.Framework, rbdImageSpec, pvName, a return nil } +// librbdSupportsVolumeGroupSnapshot checks for the rbd_group_snap_get_info in +// librbd.so.* in a ceph-csi container. If this function is available, +// VolumeGroupSnapshot support is available. +func librbdSupportsVolumeGroupSnapshot(f *framework.Framework) (bool, error) { + selector, err := getDaemonSetLabelSelector(f, cephCSINamespace, rbdDaemonsetName) + if err != nil { + return false, fmt.Errorf("failed to get labels: %w", err) + } + opt := metav1.ListOptions{ + LabelSelector: selector, + } + + // run a shell command (to expand the * in the filename), return 0 on stdout when successful + cmd := "sh -c '/grep -q rbd_group_snap_get_info /lib64/librbd.so.*; echo $?'" + stdout, _, err := execCommandInContainer(f, cmd, cephCSINamespace, "csi-rbdplugin", &opt) + if err != nil { + return false, fmt.Errorf("error checking for rbd_group_snap_get_info in /lib64/librbd.so.*: %w", err) + } + + return strings.TrimSpace(stdout) == "0", nil +} + func listRBDImages(f *framework.Framework, pool string) ([]string, error) { var imgInfos []string diff --git a/e2e/volumegroupsnapshot.go b/e2e/volumegroupsnapshot.go index a204bab9eff..8a41aef57ef 100644 --- a/e2e/volumegroupsnapshot.go +++ b/e2e/volumegroupsnapshot.go @@ -117,3 +117,65 @@ func (c *cephFSVolumeGroupSnapshot) ValidateResourcesForDelete() error { return nil } + +type rbdVolumeGroupSnapshot struct { + *volumeGroupSnapshotterBase +} + +var _ VolumeGroupSnapshotter = &rbdVolumeGroupSnapshot{} + +func newRBDVolumeGroupSnapshot(f *framework.Framework, namespace, + storageClass string, + blockPVC bool, + timeout, totalPVCCount int, +) (VolumeGroupSnapshotter, error) { + base, err := newVolumeGroupSnapshotBase(f, namespace, storageClass, blockPVC, timeout, totalPVCCount) + if err != nil { + return nil, fmt.Errorf("failed to create volumeGroupSnapshotterBase: %w", err) + } + + return &rbdVolumeGroupSnapshot{ + volumeGroupSnapshotterBase: base, + }, nil +} + +func (rvgs *rbdVolumeGroupSnapshot) TestVolumeGroupSnapshot() error { + return rvgs.volumeGroupSnapshotterBase.testVolumeGroupSnapshot(rvgs) +} + +func (rvgs *rbdVolumeGroupSnapshot) GetVolumeGroupSnapshotClass() (*groupsnapapi.VolumeGroupSnapshotClass, error) { + vgscPath := fmt.Sprintf("%s/%s", rbdExamplePath, "groupsnapshotclass.yaml") + vgsc := &groupsnapapi.VolumeGroupSnapshotClass{} + err := unmarshal(vgscPath, vgsc) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal VolumeGroupSnapshotClass: %w", err) + } + + vgsc.Parameters["csi.storage.k8s.io/group-snapshotter-secret-namespace"] = cephCSINamespace + vgsc.Parameters["csi.storage.k8s.io/group-snapshotter-secret-name"] = rbdProvisionerSecretName + vgsc.Parameters["pool"] = defaultRBDPool + + fsID, err := getClusterID(rvgs.framework) + if err != nil { + return nil, fmt.Errorf("failed to get clusterID: %w", err) + } + vgsc.Parameters["clusterID"] = fsID + + return vgsc, nil +} + +func (rvgs *rbdVolumeGroupSnapshot) ValidateResourcesForCreate(vgs *groupsnapapi.VolumeGroupSnapshot) error { + sourcePVCCount := len(vgs.Status.PVCVolumeSnapshotRefList) + clonePVCCount := len(vgs.Status.PVCVolumeSnapshotRefList) + totalPVCCount := sourcePVCCount + clonePVCCount + + validateOmapCount(rvgs.framework, totalPVCCount, rbdType, defaultRBDPool, volumesType) + + return nil +} + +func (rvgs *rbdVolumeGroupSnapshot) ValidateResourcesForDelete() error { + validateOmapCount(rvgs.framework, 0, rbdType, defaultRBDPool, volumesType) + + return nil +}