rbd: replace cli with go-ceph for snapshot namespace

cephcsi uses cli for fetching snap list as well as to check the
snapshot namespace, replaced that with go-ceph calls.

Signed-off-by: Mudit Agarwal <muagarwa@redhat.com>
This commit is contained in:
Mudit Agarwal 2020-08-27 16:39:45 +05:30 committed by mergify[bot]
parent 06066cd153
commit e1237f348f
2 changed files with 82 additions and 49 deletions

View File

@ -347,7 +347,7 @@ func flattenParentImage(ctx context.Context, rbdVol *rbdVolume, cr *util.Credent
// If the snapshots are more than the `maxSnapshotsOnImage` Add a task to // If the snapshots are more than the `maxSnapshotsOnImage` Add a task to
// flatten all the temporary cloned images. // flatten all the temporary cloned images.
func flattenTemporaryClonedImages(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials) error { func flattenTemporaryClonedImages(ctx context.Context, rbdVol *rbdVolume, cr *util.Credentials) error {
snaps, err := rbdVol.listSnapshots(ctx, cr) snaps, err := rbdVol.listSnapshots()
if err != nil { if err != nil {
if errors.Is(err, ErrImageNotFound) { if errors.Is(err, ErrImageNotFound) {
return status.Error(codes.InvalidArgument, err.Error()) return status.Error(codes.InvalidArgument, err.Error())
@ -356,7 +356,13 @@ func flattenTemporaryClonedImages(ctx context.Context, rbdVol *rbdVolume, cr *ut
} }
if len(snaps) > int(maxSnapshotsOnImage) { if len(snaps) > int(maxSnapshotsOnImage) {
err = flattenClonedRbdImages(ctx, snaps, rbdVol.Pool, rbdVol.Monitors, cr) err = flattenClonedRbdImages(
ctx,
snaps,
rbdVol.Pool,
rbdVol.Monitors,
rbdVol.RbdImageName,
cr)
if err != nil { if err != nil {
return status.Error(codes.Internal, err.Error()) return status.Error(codes.Internal, err.Error())
} }

View File

@ -417,10 +417,15 @@ func (rv *rbdVolume) getCloneDepth(ctx context.Context) (uint, error) {
} }
} }
func flattenClonedRbdImages(ctx context.Context, snaps []snapshotInfo, pool, monitors string, cr *util.Credentials) error { type trashSnapInfo struct {
origSnapName string
}
func flattenClonedRbdImages(ctx context.Context, snaps []librbd.SnapInfo, pool, monitors, rbdImageName string, cr *util.Credentials) error {
rv := &rbdVolume{ rv := &rbdVolume{
Monitors: monitors, Monitors: monitors,
Pool: pool, Pool: pool,
RbdImageName: rbdImageName,
} }
defer rv.Destroy() defer rv.Destroy()
err := rv.Connect(cr) err := rv.Connect(cr)
@ -428,16 +433,32 @@ func flattenClonedRbdImages(ctx context.Context, snaps []snapshotInfo, pool, mon
util.ErrorLog(ctx, "failed to open connection %s; err %v", rv, err) util.ErrorLog(ctx, "failed to open connection %s; err %v", rv, err)
return err return err
} }
for _, s := range snaps { var origNameList []trashSnapInfo
if s.Namespace.Type == "trash" { for _, snapInfo := range snaps {
rv.RbdImageName = s.Namespace.OriginalName // check if the snapshot belongs to trash namespace.
isTrash, retErr := rv.isTrashSnap(snapInfo.Id)
if retErr != nil {
return retErr
}
if isTrash {
// get original snap name for the snapshot in trash namespace
origSnapName, retErr := rv.getOrigSnapName(snapInfo.Id)
if retErr != nil {
return retErr
}
origNameList = append(origNameList, trashSnapInfo{origSnapName})
}
}
for _, snapName := range origNameList {
rv.RbdImageName = snapName.origSnapName
err = rv.flattenRbdImage(ctx, cr, true, rbdHardMaxCloneDepth, rbdSoftMaxCloneDepth) err = rv.flattenRbdImage(ctx, cr, true, rbdHardMaxCloneDepth, rbdSoftMaxCloneDepth)
if err != nil { if err != nil {
util.ErrorLog(ctx, "failed to flatten %s; err %v", rv, err) util.ErrorLog(ctx, "failed to flatten %s; err %v", rv, err)
continue continue
} }
} }
}
return nil return nil
} }
@ -1129,47 +1150,53 @@ func (rv *rbdVolume) ensureEncryptionMetadataSet(status string) error {
return nil return nil
} }
// SnapshotInfo holds snapshots details. func (rv *rbdVolume) listSnapshots() ([]librbd.SnapInfo, error) {
type snapshotInfo struct { image, err := rv.open()
ID int `json:"id"` if err != nil {
Name string `json:"name"` return nil, err
Size int64 `json:"size"` }
Protected string `json:"protected"` defer image.Close()
Timestamp string `json:"timestamp"`
Namespace struct { snapInfoList, err := image.GetSnapshotNames()
Type string `json:"type"` if err != nil {
OriginalName string `json:"original_name"` return nil, err
} `json:"namespace"` }
return snapInfoList, nil
} }
// TODO: use go-ceph once https://github.com/ceph/go-ceph/issues/300 is available in a release. // isTrashSnap returns true if the snapshot belongs to trash namespace.
func (rv *rbdVolume) listSnapshots(ctx context.Context, cr *util.Credentials) ([]snapshotInfo, error) { func (rv *rbdVolume) isTrashSnap(snapID uint64) (bool, error) {
// rbd snap ls <image> --pool=<pool-name> --all --format=json image, err := rv.open()
var snapInfo []snapshotInfo
stdout, stderr, err := util.ExecCommand(
ctx,
"rbd",
"-m", rv.Monitors,
"--id", cr.ID,
"--keyfile="+cr.KeyFile,
"-c", util.CephConfigPath,
"--format="+"json",
"snap",
"ls",
"--all", rv.String())
if err != nil { if err != nil {
util.ErrorLog(ctx, "failed getting information for image (%s): (%s)", rv, err) return false, err
if strings.Contains(stderr, "rbd: error opening image "+rv.RbdImageName+
": (2) No such file or directory") {
return snapInfo, util.JoinErrors(ErrImageNotFound, err)
} }
return snapInfo, err defer image.Close()
// Get namespace type for the snapshot
nsType, err := image.GetSnapNamespaceType(snapID)
if err != nil {
return false, err
} }
err = json.Unmarshal([]byte(stdout), &snapInfo) if nsType == librbd.SnapNamespaceTypeTrash {
if err != nil { return true, nil
util.ErrorLog(ctx, "failed to parse JSON output of snapshot info (%s)", err)
return snapInfo, fmt.Errorf("unmarshal failed: %w. raw buffer response: %s", err, stdout)
} }
return snapInfo, nil return false, nil
}
// getOrigSnapName returns the original snap name for
// the snapshots in Trash Namespace.
func (rv *rbdVolume) getOrigSnapName(snapID uint64) (string, error) {
image, err := rv.open()
if err != nil {
return "", err
}
defer image.Close()
origSnapName, err := image.GetSnapTrashNamespace(snapID)
if err != nil {
return "", err
}
return origSnapName, nil
} }