mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-11-21 13:50:20 +00:00
rbd: add rbdVolume.NewSnapshotByID
to clone images by RBD snapshot-id
The NewSnapshotByID() function makes it possible to clone a new Snapshot from an existing RBD-image and the ID of an RBD-snapshot on that image. This will be used by the VolumeGroupSnapshot feature, where the ID of an RBD-snapshot is obtained for the RBD-snapshot on the RBD-images. Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
parent
9808408340
commit
20fadf2016
@ -20,9 +20,11 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
librbd "github.com/ceph/go-ceph/rbd"
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/ceph/ceph-csi/internal/rbd/types"
|
||||
"github.com/ceph/ceph-csi/internal/util"
|
||||
"github.com/ceph/ceph-csi/internal/util/log"
|
||||
)
|
||||
@ -176,3 +178,135 @@ func undoSnapshotCloning(
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewSnapshotByID creates a new rbdSnapshot from the rbdVolume.
|
||||
//
|
||||
// Parameters:
|
||||
// - name of the new rbd-image backing the snapshot
|
||||
// - id of the rbd-snapshot to clone
|
||||
//
|
||||
// FIXME: When resolving the Snapshot, the RbdImageName will be set to the name
|
||||
// of the parent image. This is can cause issues when not accounting for that
|
||||
// and the Snapshot is deleted; instead of deleting the snapshot image, the
|
||||
// parent image is removed.
|
||||
//
|
||||
//nolint:gocyclo,cyclop // TODO: reduce complexity.
|
||||
func (rv *rbdVolume) NewSnapshotByID(
|
||||
ctx context.Context,
|
||||
cr *util.Credentials,
|
||||
name string,
|
||||
id uint64,
|
||||
) (types.Snapshot, error) {
|
||||
snap := rv.toSnapshot()
|
||||
snap.RequestName = name
|
||||
|
||||
srcVolID, err := rv.GetID(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snap.SourceVolumeID = srcVolID
|
||||
|
||||
// reserveSnap sets snap.{RbdSnapName,ReservedID,VolID}
|
||||
err = reserveSnap(ctx, snap, rv, cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create a reservation in the journal for snapshot image %q: %w", snap, err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
undoErr := undoSnapReservation(ctx, snap, cr)
|
||||
if undoErr != nil {
|
||||
log.WarningLog(ctx, "failed undoing reservation of snapshot %q: %v", name, undoErr)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// a new snapshot image will be created, needs to have a unique name
|
||||
snap.RbdImageName = snap.RbdSnapName
|
||||
|
||||
err = rv.Connect(cr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = rv.openIoctx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
options, err := rv.constructImageOptions(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer options.Destroy()
|
||||
|
||||
err = options.SetUint64(librbd.ImageOptionCloneFormat, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// indicator to remove the snapshot after a failure
|
||||
removeSnap := true
|
||||
var snapImage *librbd.Snapshot
|
||||
|
||||
log.DebugLog(ctx, "going to clone snapshot image %q from image %q with snapshot ID %d", snap, rv, id)
|
||||
|
||||
err = librbd.CloneImageByID(rv.ioctx, rv.RbdImageName, id, rv.ioctx, snap.RbdImageName, options)
|
||||
if err != nil && !errors.Is(librbd.ErrExist, err) {
|
||||
log.ErrorLog(ctx, "failed to clone snapshot %q with id %d: %v", snap, id, err)
|
||||
|
||||
return nil, fmt.Errorf("failed to clone %q with snapshot id %d as new image %q: %w", rv.RbdImageName, id, snap, err)
|
||||
}
|
||||
defer func() {
|
||||
if !removeSnap {
|
||||
// success, no need to remove the snapshot image
|
||||
return
|
||||
}
|
||||
|
||||
if snapImage != nil {
|
||||
err = snapImage.Remove()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to remove snapshot of image %q after failure: %v", snap, err)
|
||||
}
|
||||
}
|
||||
|
||||
err = librbd.RemoveImage(rv.ioctx, snap.RbdImageName)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to remove snapshot image %q after failure: %v", snap, err)
|
||||
}
|
||||
}()
|
||||
|
||||
// update the snapshot image in the journal, after the image info is updated
|
||||
j, err := snapJournal.Connect(snap.Monitors, snap.RadosNamespace, cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("snapshot image %q failed to connect to journal: %w", snap, err)
|
||||
}
|
||||
defer j.Destroy()
|
||||
|
||||
err = snap.Connect(cr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to connect snapshot image %q: %w", snap, err)
|
||||
}
|
||||
defer snap.Destroy(ctx)
|
||||
|
||||
image, err := snap.open()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open snapshot image %q: %w", snap, err)
|
||||
}
|
||||
defer image.Close()
|
||||
|
||||
snapImage, err = image.CreateSnapshot(snap.RbdSnapName)
|
||||
if err != nil && !errors.Is(librbd.ErrExist, err) {
|
||||
return nil, fmt.Errorf("failed to create snapshot on image %q: %w", snap, err)
|
||||
}
|
||||
|
||||
err = snap.repairImageID(ctx, j, true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to repair image id for snapshot image %q: %w", snap, err)
|
||||
}
|
||||
|
||||
// all ok, don't remove the snapshot image in a defer statement
|
||||
removeSnap = false
|
||||
|
||||
return snap, nil
|
||||
}
|
||||
|
@ -21,6 +21,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
|
||||
"github.com/ceph/ceph-csi/internal/util"
|
||||
)
|
||||
|
||||
//nolint:interfacebloat // more than 10 methods are needed for the interface
|
||||
@ -59,4 +61,7 @@ type Volume interface {
|
||||
|
||||
// ToMirror converts the Volume to a Mirror.
|
||||
ToMirror() (Mirror, error)
|
||||
|
||||
// NewSnapshotByID creates a new Snapshot object based on the details of the Volume.
|
||||
NewSnapshotByID(ctx context.Context, cr *util.Credentials, name string, id uint64) (Snapshot, error)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user