2020-08-07 07:06:45 +00:00
|
|
|
/*
|
|
|
|
Copyright 2020 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.
|
|
|
|
*/
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
package core
|
2020-08-07 07:06:45 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2020-12-02 10:28:31 +00:00
|
|
|
"errors"
|
2020-12-02 08:27:03 +00:00
|
|
|
"time"
|
2020-08-07 07:06:45 +00:00
|
|
|
|
2021-08-25 06:46:03 +00:00
|
|
|
cerrors "github.com/ceph/ceph-csi/internal/cephfs/errors"
|
2022-02-15 12:11:09 +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:06:45 +00:00
|
|
|
|
2020-12-02 10:42:56 +00:00
|
|
|
"github.com/ceph/go-ceph/cephfs/admin"
|
|
|
|
"github.com/ceph/go-ceph/rados"
|
2020-08-07 07:06:45 +00:00
|
|
|
"github.com/golang/protobuf/ptypes/timestamp"
|
|
|
|
)
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
// SnapshotClient is the interface that holds the signature of snapshot methods
|
|
|
|
// that interacts with CephFS snapshot API's.
|
|
|
|
type SnapshotClient interface {
|
|
|
|
// CreateSnapshot creates a snapshot of the subvolume.
|
|
|
|
CreateSnapshot(ctx context.Context) error
|
|
|
|
// DeleteSnapshot deletes the snapshot of the subvolume.
|
|
|
|
DeleteSnapshot(ctx context.Context) error
|
|
|
|
// GetSnapshotInfo returns the snapshot info of the subvolume.
|
|
|
|
GetSnapshotInfo(ctx context.Context) (SnapshotInfo, error)
|
|
|
|
// CloneSnapshot clones the snapshot of the subvolume.
|
|
|
|
CloneSnapshot(ctx context.Context, cloneVolOptions *SubVolume) error
|
2022-06-07 07:55:30 +00:00
|
|
|
// SetAllSnapshotMetadata set all the metadata from arg parameters on
|
|
|
|
// subvolume snapshot.
|
|
|
|
SetAllSnapshotMetadata(parameters map[string]string) error
|
|
|
|
// UnsetAllSnapshotMetadata unset all the metadata from arg keys on
|
|
|
|
// subvolume snapshot.
|
|
|
|
UnsetAllSnapshotMetadata(keys []string) error
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
// snapshotClient is the implementation of SnapshotClient interface.
|
|
|
|
type snapshotClient struct {
|
2022-07-28 12:26:55 +00:00
|
|
|
*Snapshot // Embedded snapshot struct.
|
|
|
|
clusterID string // Cluster ID.
|
|
|
|
clusterName string // Cluster Name.
|
|
|
|
enableMetadata bool // Set metadata on volume
|
|
|
|
conn *util.ClusterConnection // Cluster connection.
|
2022-02-15 12:11:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Snapshot represents a subvolume snapshot and its cluster information.
|
|
|
|
type Snapshot struct {
|
|
|
|
SnapshotID string // subvolume snapshot id.
|
|
|
|
*SubVolume // parent subvolume information.
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewSnapshot creates a new snapshot client.
|
2022-07-28 08:44:52 +00:00
|
|
|
func NewSnapshot(
|
|
|
|
conn *util.ClusterConnection,
|
|
|
|
snapshotID,
|
|
|
|
clusterID,
|
|
|
|
clusterName string,
|
2022-07-28 12:26:55 +00:00
|
|
|
setMetadata bool,
|
2022-07-28 08:44:52 +00:00
|
|
|
vol *SubVolume,
|
|
|
|
) SnapshotClient {
|
2022-02-15 12:11:09 +00:00
|
|
|
return &snapshotClient{
|
|
|
|
Snapshot: &Snapshot{
|
|
|
|
SnapshotID: snapshotID,
|
|
|
|
SubVolume: vol,
|
|
|
|
},
|
2022-07-28 12:26:55 +00:00
|
|
|
clusterID: clusterID,
|
|
|
|
clusterName: clusterName,
|
|
|
|
enableMetadata: setMetadata,
|
|
|
|
conn: conn,
|
2022-02-15 12:11:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateSnapshot creates a snapshot of the subvolume.
|
|
|
|
func (s *snapshotClient) CreateSnapshot(ctx context.Context) error {
|
|
|
|
fsa, err := s.conn.GetFSAdmin()
|
2020-11-04 12:56:49 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "could not get FSAdmin: %s", err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-11-04 12:56:49 +00:00
|
|
|
return err
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
err = fsa.CreateSubVolumeSnapshot(s.FsName, s.SubvolumeGroup, s.VolID, s.SnapshotID)
|
2020-08-07 07:06:45 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "failed to create subvolume snapshot %s %s in fs %s: %s",
|
2022-02-15 12:11:09 +00:00
|
|
|
s.SnapshotID, s.VolID, s.FsName, err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
// DeleteSnapshot deletes the snapshot of the subvolume.
|
|
|
|
func (s *snapshotClient) DeleteSnapshot(ctx context.Context) error {
|
|
|
|
fsa, err := s.conn.GetFSAdmin()
|
2020-11-04 13:19:36 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "could not get FSAdmin: %s", err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-11-04 13:19:36 +00:00
|
|
|
return err
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
err = fsa.ForceRemoveSubVolumeSnapshot(s.FsName, s.SubvolumeGroup, s.VolID, s.SnapshotID)
|
2020-08-07 07:06:45 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "failed to delete subvolume snapshot %s %s in fs %s: %s",
|
2022-02-15 12:11:09 +00:00
|
|
|
s.SnapshotID, s.VolID, s.FsName, err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-09-16 13:47:57 +00:00
|
|
|
type SnapshotInfo struct {
|
2020-12-02 08:27:03 +00:00
|
|
|
CreatedAt time.Time
|
2020-08-07 07:06:45 +00:00
|
|
|
CreationTime *timestamp.Timestamp
|
2020-12-02 08:27:03 +00:00
|
|
|
HasPendingClones string
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
// GetSnapshotInfo returns the snapshot info of the subvolume.
|
|
|
|
func (s *snapshotClient) GetSnapshotInfo(ctx context.Context) (SnapshotInfo, error) {
|
2021-09-16 13:47:57 +00:00
|
|
|
snap := SnapshotInfo{}
|
2022-02-15 12:11:09 +00:00
|
|
|
fsa, err := s.conn.GetFSAdmin()
|
2020-12-02 08:27:03 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "could not get FSAdmin: %s", err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-12-02 08:27:03 +00:00
|
|
|
return snap, err
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
2020-12-02 08:27:03 +00:00
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
info, err := fsa.SubVolumeSnapshotInfo(s.FsName, s.SubvolumeGroup, s.VolID, s.SnapshotID)
|
2020-08-07 07:06:45 +00:00
|
|
|
if err != nil {
|
2020-12-02 08:27:03 +00:00
|
|
|
if errors.Is(err, rados.ErrNotFound) {
|
2021-08-25 06:46:03 +00:00
|
|
|
return snap, cerrors.ErrSnapNotFound
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx,
|
|
|
|
"failed to get subvolume snapshot info %s %s in fs %s with error %s",
|
2022-02-15 12:11:09 +00:00
|
|
|
s.VolID,
|
|
|
|
s.SnapshotID,
|
|
|
|
s.FsName,
|
2021-06-25 10:18:59 +00:00
|
|
|
err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-12-02 08:27:03 +00:00
|
|
|
return snap, err
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
2020-12-02 08:27:03 +00:00
|
|
|
snap.CreatedAt = info.CreatedAt.Time
|
|
|
|
snap.HasPendingClones = info.HasPendingClones
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return snap, nil
|
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
// CloneSnapshot clones the snapshot of the subvolume.
|
|
|
|
func (s *snapshotClient) CloneSnapshot(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx context.Context,
|
2022-02-15 12:11:09 +00:00
|
|
|
cloneSubVol *SubVolume,
|
2021-06-25 10:18:59 +00:00
|
|
|
) error {
|
2022-02-15 12:11:09 +00:00
|
|
|
fsa, err := s.conn.GetFSAdmin()
|
2020-12-02 10:42:56 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(ctx, "could not get FSAdmin: %s", err)
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-12-02 10:42:56 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
co := &admin.CloneOptions{
|
2022-02-15 12:11:09 +00:00
|
|
|
TargetGroup: cloneSubVol.SubvolumeGroup,
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
2022-02-15 12:11:09 +00:00
|
|
|
if cloneSubVol.Pool != "" {
|
|
|
|
co.PoolLayout = cloneSubVol.Pool
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
|
|
|
|
2022-02-15 12:11:09 +00:00
|
|
|
err = fsa.CloneSubVolumeSnapshot(s.FsName, s.SubvolumeGroup, s.VolID, s.SnapshotID, cloneSubVol.VolID, co)
|
2020-08-07 07:06:45 +00:00
|
|
|
if err != nil {
|
2021-08-24 15:03:25 +00:00
|
|
|
log.ErrorLog(
|
2021-06-25 10:18:59 +00:00
|
|
|
ctx,
|
|
|
|
"failed to clone subvolume snapshot %s %s in fs %s with error: %s",
|
2022-02-15 12:11:09 +00:00
|
|
|
s.VolID,
|
|
|
|
s.SnapshotID,
|
|
|
|
cloneSubVol.VolID,
|
|
|
|
s.FsName,
|
2021-06-25 10:18:59 +00:00
|
|
|
err)
|
2020-12-02 10:42:56 +00:00
|
|
|
if errors.Is(err, rados.ErrNotFound) {
|
2021-08-25 06:46:03 +00:00
|
|
|
return cerrors.ErrVolumeNotFound
|
2020-08-07 07:06:45 +00:00
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return err
|
|
|
|
}
|
2021-07-22 05:45:17 +00:00
|
|
|
|
2020-08-07 07:06:45 +00:00
|
|
|
return nil
|
|
|
|
}
|