diff --git a/internal/rbd/controllerserver.go b/internal/rbd/controllerserver.go index eb37a8063..5ccec05f9 100644 --- a/internal/rbd/controllerserver.go +++ b/internal/rbd/controllerserver.go @@ -1157,7 +1157,7 @@ func (cs *ControllerServer) CreateSnapshot( return cloneFromSnapshot(ctx, rbdVol, rbdSnap, cr, req.GetParameters()) } - err = flattenTemporaryClonedImages(ctx, rbdVol, cr) + err = rbdVol.PrepareVolumeForSnapshot(ctx, cr) if err != nil { return nil, err } @@ -1376,11 +1376,6 @@ func (cs *ControllerServer) doSnapshotClone( return cloneRbd, err } - err = cloneRbd.flattenRbdImage(ctx, false, rbdHardMaxCloneDepth, rbdSoftMaxCloneDepth) - if err != nil { - return cloneRbd, err - } - return cloneRbd, nil } diff --git a/internal/rbd/group_controllerserver.go b/internal/rbd/group_controllerserver.go index 4e4d3c408..8b447b921 100644 --- a/internal/rbd/group_controllerserver.go +++ b/internal/rbd/group_controllerserver.go @@ -37,6 +37,8 @@ import ( // group snapshot and remove all images from the group again. This leaves the // group and its snapshot around, the group snapshot can be inspected to list // the snapshots of the images. +// +//nolint:gocyclo,cyclop // TODO: reduce complexity. func (cs *ControllerServer) CreateVolumeGroupSnapshot( ctx context.Context, req *csi.CreateVolumeGroupSnapshotRequest, @@ -130,6 +132,27 @@ func (cs *ControllerServer) CreateVolumeGroupSnapshot( "failed to get existing one with name %q: %v", vgsName, err) } + creds, err := util.NewUserCredentials(req.GetSecrets()) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + defer creds.DeleteCredentials() + + errList := make([]error, 0) + for _, volume := range volumes { + err = volume.PrepareVolumeForSnapshot(ctx, creds) + if err != nil { + errList = append(errList, err) + } + } + if len(errList) > 0 { + // FIXME: we should probably choose a error code that has more priority. + return nil, status.Errorf( + status.Code(errList[0]), + "failed to prepare volumes for snapshot: %v", + errList) + } + // create a temporary VolumeGroup with a different name vg, err = mgr.CreateVolumeGroup(ctx, vgName) if err != nil { diff --git a/internal/rbd/rbd_util.go b/internal/rbd/rbd_util.go index 343d63708..6dc4d139a 100644 --- a/internal/rbd/rbd_util.go +++ b/internal/rbd/rbd_util.go @@ -2277,3 +2277,28 @@ func (ri *rbdImage) GetClusterID(ctx context.Context) (string, error) { return ri.ClusterID, nil } + +func (rv *rbdVolume) PrepareVolumeForSnapshot(ctx context.Context, cr *util.Credentials) error { + hardLimit := rbdHardMaxCloneDepth + softLimit := rbdSoftMaxCloneDepth + err := flattenTemporaryClonedImages(ctx, rv, cr) + if err != nil { + return err + } + + // choosing 2, since snapshot adds one depth and we'll be flattening the parent. + const depthToAvoidFlatten = 2 + if rbdHardMaxCloneDepth > depthToAvoidFlatten { + hardLimit = rbdHardMaxCloneDepth - depthToAvoidFlatten + } + if rbdSoftMaxCloneDepth > depthToAvoidFlatten { + softLimit = rbdSoftMaxCloneDepth - depthToAvoidFlatten + } + + err = rv.flattenParent(ctx, hardLimit, softLimit) + if err != nil { + return getGRPCErrorForCreateVolume(err) + } + + return nil +} diff --git a/internal/rbd/types/volume.go b/internal/rbd/types/volume.go index 1f235bf16..fde0125b1 100644 --- a/internal/rbd/types/volume.go +++ b/internal/rbd/types/volume.go @@ -58,6 +58,10 @@ type Volume interface { // if the parent image is in trash, it returns an error. // if the parent image exists and is not enabled for mirroring, it returns an error. HandleParentImageExistence(ctx context.Context, flattenMode FlattenMode) error + // PrepareVolumeForSnapshot prepares the volume for snapshot by + // checking snapshots limit and clone depth limit and flatten it + // if required. + PrepareVolumeForSnapshot(ctx context.Context, cr *util.Credentials) error // ToMirror converts the Volume to a Mirror. ToMirror() (Mirror, error)