diff --git a/internal/rbd/group/volume_group.go b/internal/rbd/group/volume_group.go index 9f7e2644c..b1857570a 100644 --- a/internal/rbd/group/volume_group.go +++ b/internal/rbd/group/volume_group.go @@ -311,7 +311,37 @@ func (vg *volumeGroup) ListVolumes(ctx context.Context) ([]types.Volume, error) return vg.volumes, nil } -func (vg *volumeGroup) CreateSnapshot(ctx context.Context, name string) (types.VolumeGroupSnapshot, error) { - // TODO: return the VolumeGroupSnapshot +func (vg *volumeGroup) CreateSnapshots(ctx context.Context, name string) ([]types.Snapshot, error) { + group, err := vg.GetName(ctx) + if err != nil { + return nil, err + } + + ioctx, err := vg.GetIOContext(ctx) + if err != nil { + return nil, err + } + + err = librbd.GroupSnapCreate(ioctx, group, name) + if err != nil { + if !errors.Is(rados.ErrObjectExists, err) && !strings.Contains(err.Error(), "rbd: ret=-17, File exists") { + return nil, fmt.Errorf("failed to create volume group snapshot %q: %w", name, err) + } + + log.DebugLog(ctx, "ignoring error while creating volume group snapshot %q: %v", vg, err) + } + + info, err := librbd.GroupSnapGetInfo(ioctx, group, name) + if err != nil { + return nil, fmt.Errorf("failed to get info for volume group snapshot %q: %w", vg.String()+"@"+name, err) + } + + fmt.Printf("volume group snapshot %q has %d snapshots:\n", vg.String()+"@"+name, len(info.Snapshots)) + for _, snap := range info.Snapshots { + // TODO: clone snapshot and create a rbdSnapshot object + // "first-volume@.group.1_c35f5de69170_c35fa08d2b61" from {Name:first-volume PoolID:1 SnapID:29} + fmt.Printf(" - %q in pool %d with ID %d\n", snap.Name + "@" + info.Name, snap.PoolID, snap.SnapID) + } + return nil, nil } diff --git a/internal/rbd/manager.go b/internal/rbd/manager.go index 6393a5494..cbd96ca51 100644 --- a/internal/rbd/manager.go +++ b/internal/rbd/manager.go @@ -320,76 +320,82 @@ func (mgr *rbdManager) DeleteVolumeGroup(ctx context.Context, vg types.VolumeGro return nil } -func (mgr *rbdManager) CreateSnapshot(ctx context.Context, vg *volumeGroup, name) (types.VolumeGroupSnapshot, error) { - group, err := vg.GetName(ctx) - if err != nil { - return nil, err - } - - ioctx, err := vg.GetIOContext(ctx) - if err != nil { - return nil, err - } - +func (mgr *rbdManager) CreateVolumeGroupSnapshot(ctx context.Context, vg types.VolumeGroup, name string) (types.VolumeGroupSnapshot, error) { // TODO: reserve a unique name for the snapshot pool, err := vg.GetPool(ctx) if err != nil { - return err + return nil, err } - // journalPool is an optional parameter, use pool if it is not set - journalPool, ok := mgr.parameters["journalPool"] - if !ok || journalPool == "" { - journalPool = pool - } + // volumeNamePrefix is an optional parameter, can be an empty string + prefix := mgr.parameters["volumeNamePrefix"] - vgsData, err := vg.journal.CheckReservation(ctx, journalPool, name, prefix) - if err != nil { - return nil, fmt.Errorf("failed to reserve volume group snapshot for name %q: %w", name, err) - } + // journalPool is an optional parameter, use pool if it is not set + journalPool, ok := mgr.parameters["journalPool"] + if !ok || journalPool == "" { + journalPool = pool + } - var uuid string - if vgsData != nil && vgsData.GroupUUID != "" { - uuid = vgsData.GroupUUID - } else { - log.DebugLog(ctx, "the journal does not contain a reservation for a volume group snapshot with name %q yet", name) - - var vgsName string - uuid, vgsName, err = vg.journal.ReserveName(ctx, journalPool, name, prefix) - if err != nil { - return nil, fmt.Errorf("failed to reserve volume group snapshot for name %q: %w", name, err) - } - defer func() { - if err != nil { - err = vg.journal.UndoReservation(ctx, journalPool, vgName, name) - if err != nil { - log.ErrorLog(ctx, "failed to undo the reservation for volume group %q: %w", name, err) - } - } - }() - } - - _ /*journalPoolID*/, poolID, err := util.GetPoolIDs(ctx, vg.monitors, journalPool, pool, vg.creds) - if err != nil { - return nil, fmt.Errorf("failed to generate a unique CSI volume group with uuid for %q: %w", uuid, err) - } - - csiID, err := util.GenerateVolID(ctx, vg.monitors, vg.creds, poolID, pool, clusterID, uuid) - if err != nil { - return nil, fmt.Errorf("failed to generate a unique CSI volume group with uuid for %q: %w", uuid, err) - } - - err = librbd.GroupSnapCreate(ioctx, group, name) + clusterID, err := vg.GetClusterID(ctx) if err != nil { - if !errors.Is(rados.ErrObjectExists, err) && !strings.Contains(err.Error(), "rbd: ret=-17, File exists") { - return nil, fmt.Errorf("failed to create volume group snapshot %q: %w", name, err) - } - - log.DebugLog(ctx, "ignoring error while creating volume group snapshot %q: %v", vg, err) + return nil, fmt.Errorf("failed to get cluster id for volume group %q: %w", vg, err) } - log.DebugLog(ctx, "volume group %q has been created", vg) + vgJournal, err := mgr.getVolumeGroupJournal(clusterID) + if err != nil { + return nil, err + } - // TODO: return the VolumeGroupSnapshot - return nil, nil + vgsData, err := vgJournal.CheckReservation(ctx, journalPool, name, prefix) + if err != nil { + return nil, fmt.Errorf("failed to reserve volume group snapshot for name %q: %w", name, err) + } + + var uuid string + if vgsData != nil && vgsData.GroupUUID != "" { + uuid = vgsData.GroupUUID + } else { + log.DebugLog(ctx, "the journal does not contain a reservation for a volume group snapshot with name %q yet", name) + + uuid, _ /*vgsName*/, err = vgJournal.ReserveName(ctx, journalPool, name, prefix) + if err != nil { + return nil, fmt.Errorf("failed to reserve volume group snapshot for name %q: %w", name, err) + } + defer func() { + if err != nil { + err = vgJournal.UndoReservation(ctx, journalPool, uuid, name) + if err != nil { + log.ErrorLog(ctx, "failed to undo the reservation for volume group %q: %w", name, err) + } + } + }() + } + + monitors, err := util.Mons(util.CsiConfigFile, clusterID) + if err != nil { + return nil, fmt.Errorf("failed to find MONs for cluster %q: %w", clusterID, err) + } + + _ /*journalPoolID*/, poolID, err := util.GetPoolIDs(ctx, monitors, journalPool, pool, mgr.creds) + if err != nil { + return nil, fmt.Errorf("failed to generate a unique CSI volume group with uuid for %q: %w", uuid, err) + } + + csiID, err := util.GenerateVolID(ctx, monitors, mgr.creds, poolID, pool, clusterID, uuid) + if err != nil { + return nil, fmt.Errorf("failed to generate a unique CSI volume group with uuid for %q: %w", uuid, err) + } + + snapshots, err := vg.CreateSnapshots(ctx, csiID) + if err != nil { + return nil, fmt.Errorf("failed to create volume group snapshot %q: %w", name, err) + } + + log.DebugLog(ctx, "volume group snapshot %q contains snapshots: %v", name, snapshots) + + // TODO: create the VolumeGroupSnapshot + var vgs types.VolumeGroupSnapshot + log.DebugLog(ctx, "volume group snapshot %q has been created", vgs) + + return vgs, nil } diff --git a/internal/rbd/types/group.go b/internal/rbd/types/group.go index 07dd2d09b..02a1bc7ea 100644 --- a/internal/rbd/types/group.go +++ b/internal/rbd/types/group.go @@ -67,5 +67,5 @@ type VolumeGroup interface { // ListVolumes returns a slice with all Volumes in the VolumeGroup. ListVolumes(ctx context.Context) ([]Volume, error) - CreateSnapshot(ctx context.Context, name string) (VolumeGroupSnapshot, error) + CreateSnapshots(ctx context.Context, name string) ([]Snapshot, error) }