2019-05-28 19:03:18 +00:00
|
|
|
/*
|
|
|
|
Copyright 2019 The Ceph-CSI Authors.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
package store
|
2019-05-28 19:03:18 +00:00
|
|
|
|
|
|
|
import (
|
2019-08-22 17:19:06 +00:00
|
|
|
"context"
|
2020-06-25 08:35:19 +00:00
|
|
|
"errors"
|
2020-08-07 07:07:36 +00:00
|
|
|
"fmt"
|
2019-08-22 17:19:06 +00:00
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
"github.com/ceph/ceph-csi/internal/cephfs/core"
|
2021-08-25 06:46:03 +00:00
|
|
|
cerrors "github.com/ceph/ceph-csi/internal/cephfs/errors"
|
2021-09-16 13:47:57 +00:00
|
|
|
"github.com/ceph/ceph-csi/internal/journal"
|
2020-04-17 09:23:49 +00:00
|
|
|
"github.com/ceph/ceph-csi/internal/util"
|
2021-08-24 15:03:25 +00:00
|
|
|
"github.com/ceph/ceph-csi/internal/util/log"
|
2020-08-07 07:07:36 +00:00
|
|
|
|
|
|
|
"github.com/golang/protobuf/ptypes/timestamp"
|
2022-11-11 10:40:24 +00:00
|
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
2019-05-28 19:03:18 +00:00
|
|
|
)
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
var (
|
|
|
|
// VolJournal is used to maintain RADOS based journals for CO generated.
|
|
|
|
// VolumeName to backing CephFS subvolumes.
|
|
|
|
VolJournal *journal.Config
|
|
|
|
|
|
|
|
// SnapJournal is used to maintain RADOS based journals for CO generated.
|
|
|
|
// SnapshotName to backing CephFS subvolumes.
|
|
|
|
SnapJournal *journal.Config
|
2024-02-05 12:21:26 +00:00
|
|
|
|
|
|
|
// VolumeGroupJournal is used to maintain RADOS based journals for CO
|
|
|
|
// generate request name to CephFS snapshot group attributes.
|
|
|
|
VolumeGroupJournal journal.VolumeGroupJournalConfig
|
2021-09-16 13:47:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// VolumeIdentifier structure contains an association between the CSI VolumeID to its subvolume
|
2020-07-19 12:21:03 +00:00
|
|
|
// name on the backing CephFS instance.
|
2021-09-16 13:47:57 +00:00
|
|
|
type VolumeIdentifier struct {
|
2019-05-28 19:03:18 +00:00
|
|
|
FsSubvolName string
|
|
|
|
VolumeID string
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
type SnapshotIdentifier struct {
|
2020-08-07 07:07:36 +00:00
|
|
|
FsSnapshotName string
|
|
|
|
SnapshotID string
|
|
|
|
RequestName string
|
|
|
|
CreationTime *timestamp.Timestamp
|
|
|
|
FsSubvolName string
|
|
|
|
}
|
|
|
|
|
2019-05-28 19:03:18 +00:00
|
|
|
/*
|
2021-09-16 13:47:57 +00:00
|
|
|
CheckVolExists checks to determine if passed in RequestName in volOptions exists on the backend.
|
2019-05-28 19:03:18 +00:00
|
|
|
|
|
|
|
**NOTE:** These functions manipulate the rados omaps that hold information regarding
|
|
|
|
volume names as requested by the CSI drivers. Hence, these need to be invoked only when the
|
|
|
|
respective CSI driver generated volume name based locks are held, as otherwise racy
|
|
|
|
access to these omaps may end up leaving them in an inconsistent state.
|
|
|
|
|
|
|
|
These functions also cleanup omap reservations that are stale. I.e when omap entries exist and
|
|
|
|
backing subvolumes are missing, or one of the omaps exist and the next is missing. This is
|
|
|
|
because, the order of omap creation and deletion are inverse of each other, and protected by the
|
|
|
|
request name lock, and hence any stale omaps are leftovers from incomplete transactions and are
|
|
|
|
hence safe to garbage collect.
|
|
|
|
*/
|
2023-06-02 08:59:52 +00:00
|
|
|
//nolint:gocognit,gocyclo,nestif,cyclop // TODO: reduce complexity
|
2021-09-16 13:47:57 +00:00
|
|
|
func CheckVolExists(ctx context.Context,
|
2020-08-07 07:07:36 +00:00
|
|
|
volOptions,
|
2021-09-16 13:47:57 +00:00
|
|
|
parentVolOpt *VolumeOptions,
|
2020-08-07 07:07:36 +00:00
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
pvID *VolumeIdentifier,
|
|
|
|
sID *SnapshotIdentifier,
|
2022-06-01 10:17:19 +00:00
|
|
|
cr *util.Credentials,
|
2022-06-14 13:23:29 +00:00
|
|
|
clusterName string,
|
2022-07-28 12:05:33 +00:00
|
|
|
setMetadata bool,
|
2022-06-01 10:17:19 +00:00
|
|
|
) (*VolumeIdentifier, error) {
|
2021-09-16 13:47:57 +00:00
|
|
|
var vid VolumeIdentifier
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := VolJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-05-12 21:05:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
2022-08-12 14:31:08 +00:00
|
|
|
kmsID, encryptionType := getEncryptionConfig(volOptions)
|
|
|
|
|
2020-05-12 21:05:55 +00:00
|
|
|
imageData, err := j.CheckReservation(
|
2022-08-12 14:31:08 +00:00
|
|
|
ctx, volOptions.MetadataPool, volOptions.RequestName, volOptions.NamePrefix, "", kmsID, encryptionType)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-01-24 16:26:56 +00:00
|
|
|
if imageData == nil {
|
2019-05-28 19:03:18 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
2020-01-24 16:26:56 +00:00
|
|
|
imageUUID := imageData.ImageUUID
|
|
|
|
vid.FsSubvolName = imageData.ImageAttributes.ImageName
|
2022-02-15 12:11:09 +00:00
|
|
|
volOptions.VolID = vid.FsSubvolName
|
2019-05-28 19:03:18 +00:00
|
|
|
|
2022-07-28 12:05:33 +00:00
|
|
|
vol := core.NewSubVolume(volOptions.conn, &volOptions.SubVolume, volOptions.ClusterID, clusterName, setMetadata)
|
2022-04-06 12:39:40 +00:00
|
|
|
if (sID != nil || pvID != nil) && imageData.ImageAttributes.BackingSnapshotID == "" {
|
2022-02-15 12:11:09 +00:00
|
|
|
cloneState, cloneStateErr := vol.GetCloneState(ctx)
|
2020-11-04 08:10:39 +00:00
|
|
|
if cloneStateErr != nil {
|
2021-08-25 06:46:03 +00:00
|
|
|
if errors.Is(cloneStateErr, cerrors.ErrVolumeNotFound) {
|
2020-08-07 07:07:36 +00:00
|
|
|
if pvID != nil {
|
2022-02-15 12:11:09 +00:00
|
|
|
err = vol.CleanupSnapshotFromSubvolume(
|
|
|
|
ctx, &parentVolOpt.SubVolume)
|
2020-08-07 07:07:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
|
|
|
volOptions.MetadataPool, vid.FsSubvolName, volOptions.RequestName)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:07:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:07:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2022-06-21 11:49:13 +00:00
|
|
|
err = cloneState.ToError()
|
|
|
|
if errors.Is(err, cerrors.ErrCloneInProgress) {
|
2024-10-28 06:09:13 +00:00
|
|
|
progressReport := cloneState.GetProgressReport()
|
|
|
|
// append progress report only if the progress report parameters are present.
|
|
|
|
if progressReport.PercentageCloned != "" {
|
|
|
|
err = fmt.Errorf("%w. progress report: percentage cloned=%s, amount cloned=%s, files cloned=%s",
|
|
|
|
err,
|
|
|
|
progressReport.PercentageCloned,
|
|
|
|
progressReport.AmountCloned,
|
|
|
|
progressReport.FilesCloned)
|
|
|
|
log.ErrorLog(ctx, err.Error())
|
|
|
|
}
|
|
|
|
|
2022-06-21 11:49:13 +00:00
|
|
|
return nil, err
|
2020-08-07 07:07:36 +00:00
|
|
|
}
|
2022-06-21 11:49:13 +00:00
|
|
|
if errors.Is(err, cerrors.ErrClonePending) {
|
|
|
|
return nil, err
|
2020-11-09 06:00:18 +00:00
|
|
|
}
|
2022-06-21 11:49:13 +00:00
|
|
|
if errors.Is(err, cerrors.ErrCloneFailed) {
|
2022-01-11 07:14:22 +00:00
|
|
|
log.ErrorLog(ctx,
|
2022-06-21 11:49:13 +00:00
|
|
|
"clone failed (%v), deleting subvolume clone. vol=%s, subvol=%s subvolgroup=%s",
|
|
|
|
err,
|
2022-01-11 07:14:22 +00:00
|
|
|
volOptions.FsName,
|
|
|
|
vid.FsSubvolName,
|
|
|
|
volOptions.SubvolumeGroup)
|
2022-02-15 12:11:09 +00:00
|
|
|
err = vol.PurgeVolume(ctx, true)
|
2020-08-07 07:07:36 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "failed to delete volume %s: %v", vid.FsSubvolName, err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:07:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if pvID != nil {
|
2022-02-15 12:11:09 +00:00
|
|
|
err = vol.CleanupSnapshotFromSubvolume(
|
|
|
|
ctx, &parentVolOpt.SubVolume)
|
2020-08-07 07:07:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2020-05-12 21:05:55 +00:00
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
2020-01-24 16:26:56 +00:00
|
|
|
volOptions.MetadataPool, vid.FsSubvolName, volOptions.RequestName)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-02-24 05:29:08 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2022-06-21 11:49:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("clone is not in complete state for %s: %w", vid.FsSubvolName, err)
|
2020-08-07 07:07:36 +00:00
|
|
|
}
|
2021-02-08 07:15:23 +00:00
|
|
|
}
|
2022-04-06 12:39:40 +00:00
|
|
|
|
|
|
|
if imageData.ImageAttributes.BackingSnapshotID == "" {
|
|
|
|
volOptions.RootPath, err = vol.GetVolumeRootPathCeph(ctx)
|
|
|
|
if err != nil {
|
|
|
|
if errors.Is(err, cerrors.ErrVolumeNotFound) {
|
|
|
|
// If the subvolume is not present, cleanup the stale snapshot
|
|
|
|
// created for clone.
|
|
|
|
if parentVolOpt != nil && pvID != nil {
|
|
|
|
err = vol.CleanupSnapshotFromSubvolume(
|
|
|
|
ctx, &parentVolOpt.SubVolume)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-08 07:15:23 +00:00
|
|
|
}
|
2022-04-06 12:39:40 +00:00
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
|
|
|
volOptions.MetadataPool, vid.FsSubvolName, volOptions.RequestName)
|
|
|
|
|
|
|
|
return nil, err
|
2020-08-07 07:07:36 +00:00
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:07:36 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2020-02-24 05:29:08 +00:00
|
|
|
}
|
2020-01-24 16:26:56 +00:00
|
|
|
|
|
|
|
// check if topology constraints match what is found
|
|
|
|
// TODO: we need an API to fetch subvolume attributes (size/datapool and others), based
|
|
|
|
// on which we can evaluate which topology this belongs to.
|
|
|
|
// TODO: CephFS topology support is postponed till we get the same
|
2019-05-28 19:03:18 +00:00
|
|
|
// TODO: size checks
|
|
|
|
|
|
|
|
// found a volume already available, process and return it!
|
2020-01-24 16:26:56 +00:00
|
|
|
vid.VolumeID, err = util.GenerateVolID(ctx, volOptions.Monitors, cr, volOptions.FscID,
|
2024-03-14 09:40:49 +00:00
|
|
|
"", volOptions.ClusterID, imageUUID)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-08-24 15:03:25 +00:00
|
|
|
log.DebugLog(ctx, "Found existing volume (%s) with subvolume name (%s) for request (%s)",
|
2019-05-28 19:03:18 +00:00
|
|
|
vid.VolumeID, vid.FsSubvolName, volOptions.RequestName)
|
|
|
|
|
2020-08-07 07:07:36 +00:00
|
|
|
if parentVolOpt != nil && pvID != nil {
|
2022-02-15 12:11:09 +00:00
|
|
|
err = vol.CleanupSnapshotFromSubvolume(
|
|
|
|
ctx, &parentVolOpt.SubVolume)
|
2020-08-07 07:07:36 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-28 19:03:18 +00:00
|
|
|
return &vid, nil
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
// UndoVolReservation is a helper routine to undo a name reservation for a CSI VolumeName.
|
|
|
|
func UndoVolReservation(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx context.Context,
|
2021-09-16 13:47:57 +00:00
|
|
|
volOptions *VolumeOptions,
|
|
|
|
vid VolumeIdentifier,
|
2022-06-01 10:17:19 +00:00
|
|
|
secret map[string]string,
|
|
|
|
) error {
|
2019-06-25 19:29:17 +00:00
|
|
|
cr, err := util.NewAdminCredentials(secret)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-25 19:29:17 +00:00
|
|
|
defer cr.DeleteCredentials()
|
2019-05-28 19:03:18 +00:00
|
|
|
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := VolJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-05-12 21:05:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
2020-01-24 16:26:56 +00:00
|
|
|
volOptions.MetadataPool, vid.FsSubvolName, volOptions.RequestName)
|
2019-05-28 19:03:18 +00:00
|
|
|
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
func updateTopologyConstraints(volOpts *VolumeOptions) error {
|
2020-01-24 16:26:56 +00:00
|
|
|
// update request based on topology constrained parameters (if present)
|
2020-04-06 20:19:13 +00:00
|
|
|
poolName, _, topology, err := util.FindPoolAndTopology(volOpts.TopologyPools, volOpts.TopologyRequirement)
|
2020-01-24 16:26:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if poolName != "" {
|
|
|
|
volOpts.Pool = poolName
|
|
|
|
volOpts.Topology = topology
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-08-12 14:31:08 +00:00
|
|
|
func getEncryptionConfig(volOptions *VolumeOptions) (string, util.EncryptionType) {
|
|
|
|
if volOptions.IsEncrypted() {
|
|
|
|
return volOptions.Encryption.GetID(), util.EncryptionTypeFile
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", util.EncryptionTypeNone
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
// ReserveVol is a helper routine to request a UUID reservation for the CSI VolumeName and,
|
2020-07-19 12:21:03 +00:00
|
|
|
// to generate the volume identifier for the reserved UUID.
|
2021-09-16 13:47:57 +00:00
|
|
|
func ReserveVol(ctx context.Context, volOptions *VolumeOptions, secret map[string]string) (*VolumeIdentifier, error) {
|
2019-05-28 19:03:18 +00:00
|
|
|
var (
|
2021-09-16 13:47:57 +00:00
|
|
|
vid VolumeIdentifier
|
2020-02-24 13:19:42 +00:00
|
|
|
imageUUID string
|
|
|
|
err error
|
2019-05-28 19:03:18 +00:00
|
|
|
)
|
|
|
|
|
2019-06-25 19:29:17 +00:00
|
|
|
cr, err := util.NewAdminCredentials(secret)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-06-25 19:29:17 +00:00
|
|
|
defer cr.DeleteCredentials()
|
2019-05-28 19:03:18 +00:00
|
|
|
|
2020-01-24 16:26:56 +00:00
|
|
|
err = updateTopologyConstraints(volOptions)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := VolJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-05-12 21:05:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
2022-08-12 14:31:08 +00:00
|
|
|
kmsID, encryptionType := getEncryptionConfig(volOptions)
|
|
|
|
|
2020-05-12 21:05:55 +00:00
|
|
|
imageUUID, vid.FsSubvolName, err = j.ReserveName(
|
|
|
|
ctx, volOptions.MetadataPool, util.InvalidPoolID,
|
|
|
|
volOptions.MetadataPool, util.InvalidPoolID, volOptions.RequestName,
|
2022-08-12 14:31:08 +00:00
|
|
|
volOptions.NamePrefix, "", kmsID, volOptions.ReservedID, volOptions.Owner,
|
|
|
|
volOptions.BackingSnapshotID, encryptionType)
|
2020-01-24 16:26:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2019-05-28 19:03:18 +00:00
|
|
|
}
|
2022-02-15 12:11:09 +00:00
|
|
|
volOptions.VolID = vid.FsSubvolName
|
2020-01-24 16:26:56 +00:00
|
|
|
// generate the volume ID to return to the CO system
|
|
|
|
vid.VolumeID, err = util.GenerateVolID(ctx, volOptions.Monitors, cr, volOptions.FscID,
|
2024-03-14 09:40:49 +00:00
|
|
|
"", volOptions.ClusterID, imageUUID)
|
2019-05-28 19:03:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-08-24 15:03:25 +00:00
|
|
|
log.DebugLog(ctx, "Generated Volume ID (%s) and subvolume name (%s) for request name (%s)",
|
2019-05-28 19:03:18 +00:00
|
|
|
vid.VolumeID, vid.FsSubvolName, volOptions.RequestName)
|
|
|
|
|
|
|
|
return &vid, nil
|
|
|
|
}
|
2020-08-04 04:14:56 +00:00
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
// ReserveSnap is a helper routine to request a UUID reservation for the CSI SnapName and,
|
2020-08-04 04:14:56 +00:00
|
|
|
// to generate the snapshot identifier for the reserved UUID.
|
2021-09-16 13:47:57 +00:00
|
|
|
func ReserveSnap(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx context.Context,
|
2021-09-16 13:47:57 +00:00
|
|
|
volOptions *VolumeOptions,
|
2021-06-25 10:18:59 +00:00
|
|
|
parentSubVolName string,
|
2022-02-15 12:11:09 +00:00
|
|
|
snap *SnapshotOption,
|
2022-06-01 10:17:19 +00:00
|
|
|
cr *util.Credentials,
|
|
|
|
) (*SnapshotIdentifier, error) {
|
2020-08-04 04:14:56 +00:00
|
|
|
var (
|
2021-09-16 13:47:57 +00:00
|
|
|
vid SnapshotIdentifier
|
2020-08-04 04:14:56 +00:00
|
|
|
imageUUID string
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := SnapJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
2022-08-12 14:31:08 +00:00
|
|
|
kmsID, encryptionType := getEncryptionConfig(volOptions)
|
|
|
|
|
2020-08-04 04:14:56 +00:00
|
|
|
imageUUID, vid.FsSnapshotName, err = j.ReserveName(
|
|
|
|
ctx, volOptions.MetadataPool, util.InvalidPoolID,
|
|
|
|
volOptions.MetadataPool, util.InvalidPoolID, snap.RequestName,
|
2022-08-12 14:31:08 +00:00
|
|
|
snap.NamePrefix, parentSubVolName, kmsID, snap.ReservedID, "",
|
|
|
|
volOptions.Owner, encryptionType)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate the snapshot ID to return to the CO system
|
|
|
|
vid.SnapshotID, err = util.GenerateVolID(ctx, volOptions.Monitors, cr, volOptions.FscID,
|
2024-03-14 09:40:49 +00:00
|
|
|
"", volOptions.ClusterID, imageUUID)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-08-24 15:03:25 +00:00
|
|
|
log.DebugLog(ctx, "Generated Snapshot ID (%s) for request name (%s)",
|
2020-08-04 04:14:56 +00:00
|
|
|
vid.SnapshotID, snap.RequestName)
|
|
|
|
|
|
|
|
return &vid, nil
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
// UndoSnapReservation is a helper routine to undo a name reservation for a CSI SnapshotName.
|
|
|
|
func UndoSnapReservation(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx context.Context,
|
2021-09-16 13:47:57 +00:00
|
|
|
volOptions *VolumeOptions,
|
|
|
|
vid SnapshotIdentifier,
|
2021-06-25 10:18:59 +00:00
|
|
|
snapName string,
|
2022-06-01 10:17:19 +00:00
|
|
|
cr *util.Credentials,
|
|
|
|
) error {
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := SnapJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
|
|
|
volOptions.MetadataPool, vid.FsSnapshotName, snapName)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-04 04:14:56 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2021-09-16 13:47:57 +00:00
|
|
|
CheckSnapExists checks to determine if passed in RequestName in volOptions exists on the backend.
|
2020-08-04 04:14:56 +00:00
|
|
|
|
|
|
|
**NOTE:** These functions manipulate the rados omaps that hold information regarding
|
|
|
|
volume names as requested by the CSI drivers. Hence, these need to be invoked only when the
|
|
|
|
respective CSI driver generated volume name based locks are held, as otherwise racy
|
|
|
|
access to these omaps may end up leaving them in an inconsistent state.
|
|
|
|
|
2021-08-17 10:56:55 +00:00
|
|
|
These functions also cleanup omap reservations that are stale. I.e. when omap entries exist and
|
2020-08-04 04:14:56 +00:00
|
|
|
backing subvolumes are missing, or one of the omaps exist and the next is missing. This is
|
|
|
|
because, the order of omap creation and deletion are inverse of each other, and protected by the
|
|
|
|
request name lock, and hence any stale omaps are leftovers from incomplete transactions and are
|
|
|
|
hence safe to garbage collect.
|
|
|
|
*/
|
2021-09-16 13:47:57 +00:00
|
|
|
func CheckSnapExists(
|
2020-08-04 04:14:56 +00:00
|
|
|
ctx context.Context,
|
2021-09-16 13:47:57 +00:00
|
|
|
volOptions *VolumeOptions,
|
2022-02-15 12:11:09 +00:00
|
|
|
snap *SnapshotOption,
|
2022-07-28 08:44:52 +00:00
|
|
|
clusterName string,
|
2022-07-28 12:26:55 +00:00
|
|
|
setMetadata bool,
|
2022-06-01 10:17:19 +00:00
|
|
|
cr *util.Credentials,
|
2023-10-30 08:45:18 +00:00
|
|
|
) (*SnapshotIdentifier, error) {
|
2024-10-03 10:34:22 +00:00
|
|
|
j, err := SnapJournal.Connect(volOptions.Monitors, volOptions.RadosNamespace, cr)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, err
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
|
|
|
defer j.Destroy()
|
|
|
|
|
2022-08-12 14:31:08 +00:00
|
|
|
kmsID, encryptionType := getEncryptionConfig(volOptions)
|
|
|
|
|
2020-08-04 04:14:56 +00:00
|
|
|
snapData, err := j.CheckReservation(
|
2022-08-12 14:31:08 +00:00
|
|
|
ctx, volOptions.MetadataPool, snap.RequestName, snap.NamePrefix, volOptions.VolID, kmsID, encryptionType)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, err
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
|
|
|
if snapData == nil {
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, nil
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
2021-09-16 13:47:57 +00:00
|
|
|
sid := &SnapshotIdentifier{}
|
2020-08-04 04:14:56 +00:00
|
|
|
snapUUID := snapData.ImageUUID
|
|
|
|
snapID := snapData.ImageAttributes.ImageName
|
|
|
|
sid.FsSnapshotName = snapData.ImageAttributes.ImageName
|
2022-07-28 12:26:55 +00:00
|
|
|
snapClient := core.NewSnapshot(volOptions.conn, snapID,
|
|
|
|
volOptions.ClusterID, clusterName, setMetadata, &volOptions.SubVolume)
|
2022-02-15 12:11:09 +00:00
|
|
|
snapInfo, err := snapClient.GetSnapshotInfo(ctx)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
2021-08-25 06:46:03 +00:00
|
|
|
if errors.Is(err, cerrors.ErrSnapNotFound) {
|
2020-08-04 04:14:56 +00:00
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
|
|
|
volOptions.MetadataPool, snapID, snap.RequestName)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, err
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, err
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if err != nil {
|
2022-02-15 12:11:09 +00:00
|
|
|
err = snapClient.DeleteSnapshot(ctx)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "failed to delete snapshot %s: %v", snapID, err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-04 04:14:56 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
err = j.UndoReservation(ctx, volOptions.MetadataPool,
|
|
|
|
volOptions.MetadataPool, snapID, snap.RequestName)
|
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "removing reservation failed for snapshot %s: %v", snapID, err)
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
2022-11-11 10:40:24 +00:00
|
|
|
sid.CreationTime = timestamppb.New(snapInfo.CreatedAt)
|
2020-08-04 04:14:56 +00:00
|
|
|
|
|
|
|
// found a snapshot already available, process and return it!
|
|
|
|
sid.SnapshotID, err = util.GenerateVolID(ctx, volOptions.Monitors, cr, volOptions.FscID,
|
2024-03-14 09:40:49 +00:00
|
|
|
"", volOptions.ClusterID, snapUUID)
|
2020-08-04 04:14:56 +00:00
|
|
|
if err != nil {
|
2023-10-30 08:45:18 +00:00
|
|
|
return nil, err
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|
2021-08-24 15:03:25 +00:00
|
|
|
log.DebugLog(ctx, "Found existing snapshot (%s) with subvolume name (%s) for request (%s)",
|
2022-02-15 12:11:09 +00:00
|
|
|
snapData.ImageAttributes.RequestName, volOptions.VolID, sid.FsSnapshotName)
|
2020-08-04 04:14:56 +00:00
|
|
|
|
2023-10-30 08:45:18 +00:00
|
|
|
return sid, nil
|
2020-08-04 04:14:56 +00:00
|
|
|
}
|