mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
cephfs: refactor cephfs core functions
This commits refactors the cephfs core functions with interfaces. This helps in better code structuring and writing the unit test cases. update #852 Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
This commit is contained in:
committed by
mergify[bot]
parent
f19ca4a473
commit
e9802c4940
@ -53,20 +53,75 @@ type Subvolume struct {
|
||||
Features []string
|
||||
}
|
||||
|
||||
// SubVolumeClient is the interface that holds the signature of subvolume methods
|
||||
// that interacts with CephFS subvolume API's.
|
||||
type SubVolumeClient interface {
|
||||
// GetVolumeRootPathCeph returns the root path of the subvolume.
|
||||
GetVolumeRootPathCeph(ctx context.Context) (string, error)
|
||||
// CreateVolume creates a subvolume.
|
||||
CreateVolume(ctx context.Context) error
|
||||
// GetSubVolumeInfo returns the subvolume information.
|
||||
GetSubVolumeInfo(ctx context.Context) (*Subvolume, error)
|
||||
// ExpandVolume expands the volume if the requested size is greater than
|
||||
// the subvolume size.
|
||||
ExpandVolume(ctx context.Context, bytesQuota int64) error
|
||||
// ResizeVolume resizes the volume.
|
||||
ResizeVolume(ctx context.Context, bytesQuota int64) error
|
||||
// PurgSubVolume removes the subvolume.
|
||||
PurgeVolume(ctx context.Context, force bool) error
|
||||
|
||||
// CreateCloneFromSubVolume creates a clone from the subvolume.
|
||||
CreateCloneFromSubvolume(ctx context.Context, parentvolOpt *SubVolume) error
|
||||
// GetCloneState returns the clone state of the subvolume.
|
||||
GetCloneState(ctx context.Context) (cephFSCloneState, error)
|
||||
// CreateCloneFromSnapshot creates a clone from the subvolume snapshot.
|
||||
CreateCloneFromSnapshot(ctx context.Context, snap Snapshot) error
|
||||
// CleanupSnapshotFromSubvolume removes the snapshot from the subvolume.
|
||||
CleanupSnapshotFromSubvolume(ctx context.Context, parentVol *SubVolume) error
|
||||
}
|
||||
|
||||
// subVolumeClient implements SubVolumeClient interface.
|
||||
type subVolumeClient struct {
|
||||
*SubVolume // Embedded SubVolume struct.
|
||||
clusterID string // Cluster ID to check subvolumegroup and resize functionality.
|
||||
conn *util.ClusterConnection // Cluster connection.
|
||||
}
|
||||
|
||||
// SubVolume holds the information about the subvolume.
|
||||
type SubVolume struct {
|
||||
VolID string // subvolume id.
|
||||
FsName string // filesystem name.
|
||||
SubvolumeGroup string // subvolume group name where subvolume will be created.
|
||||
Pool string // pool name where subvolume will be created.
|
||||
Features []string // subvolume features.
|
||||
Size int64 // subvolume size.
|
||||
}
|
||||
|
||||
// NewSubVolume returns a new subvolume client.
|
||||
func NewSubVolume(conn *util.ClusterConnection, vol *SubVolume, clusterID string) SubVolumeClient {
|
||||
return &subVolumeClient{
|
||||
SubVolume: vol,
|
||||
clusterID: clusterID,
|
||||
conn: conn,
|
||||
}
|
||||
}
|
||||
|
||||
// GetVolumeRootPathCephDeprecated returns the root path of the subvolume.
|
||||
func GetVolumeRootPathCephDeprecated(volID fsutil.VolumeID) string {
|
||||
return path.Join("/", "csi-volumes", string(volID))
|
||||
}
|
||||
|
||||
func (vo *VolumeOptions) GetVolumeRootPathCeph(ctx context.Context, volID fsutil.VolumeID) (string, error) {
|
||||
fsa, err := vo.conn.GetFSAdmin()
|
||||
// GetVolumeRootPathCeph returns the root path of the subvolume.
|
||||
func (s *subVolumeClient) GetVolumeRootPathCeph(ctx context.Context) (string, error) {
|
||||
fsa, err := s.conn.GetFSAdmin()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "could not get FSAdmin err %s", err)
|
||||
|
||||
return "", err
|
||||
}
|
||||
svPath, err := fsa.SubVolumePath(vo.FsName, vo.SubvolumeGroup, string(volID))
|
||||
svPath, err := fsa.SubVolumePath(s.FsName, s.SubvolumeGroup, s.VolID)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to get the rootpath for the vol %s: %s", string(volID), err)
|
||||
log.ErrorLog(ctx, "failed to get the rootpath for the vol %s: %s", s.VolID, err)
|
||||
if errors.Is(err, rados.ErrNotFound) {
|
||||
return "", util.JoinErrors(cerrors.ErrVolumeNotFound, err)
|
||||
}
|
||||
@ -77,17 +132,18 @@ func (vo *VolumeOptions) GetVolumeRootPathCeph(ctx context.Context, volID fsutil
|
||||
return svPath, nil
|
||||
}
|
||||
|
||||
func (vo *VolumeOptions) GetSubVolumeInfo(ctx context.Context, volID fsutil.VolumeID) (*Subvolume, error) {
|
||||
fsa, err := vo.conn.GetFSAdmin()
|
||||
// GetSubVolumeInfo returns the subvolume information.
|
||||
func (s *subVolumeClient) GetSubVolumeInfo(ctx context.Context) (*Subvolume, error) {
|
||||
fsa, err := s.conn.GetFSAdmin()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not fetch metadata pool for %s:", vo.FsName, err)
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not fetch metadata pool for %s:", s.FsName, err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := fsa.SubVolumeInfo(vo.FsName, vo.SubvolumeGroup, string(volID))
|
||||
info, err := fsa.SubVolumeInfo(s.FsName, s.SubvolumeGroup, s.VolID)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to get subvolume info for the vol %s: %s", string(volID), err)
|
||||
log.ErrorLog(ctx, "failed to get subvolume info for the vol %s: %s", s.VolID, err)
|
||||
if errors.Is(err, rados.ErrNotFound) {
|
||||
return nil, cerrors.ErrVolumeNotFound
|
||||
}
|
||||
@ -111,7 +167,7 @@ func (vo *VolumeOptions) GetSubVolumeInfo(ctx context.Context, volID fsutil.Volu
|
||||
// or nil (in case the subvolume is in snapshot-retained state),
|
||||
// just continue without returning quota information.
|
||||
if !(info.BytesQuota == fsAdmin.Infinite || info.State == fsAdmin.StateSnapRetained) {
|
||||
return nil, fmt.Errorf("subvolume %s has unsupported quota: %v", string(volID), info.BytesQuota)
|
||||
return nil, fmt.Errorf("subvolume %s has unsupported quota: %v", s.VolID, info.BytesQuota)
|
||||
}
|
||||
} else {
|
||||
subvol.BytesQuota = int64(bc)
|
||||
@ -140,50 +196,52 @@ type localClusterState struct {
|
||||
subVolumeGroupCreated bool
|
||||
}
|
||||
|
||||
func CreateVolume(ctx context.Context, volOptions *VolumeOptions, volID fsutil.VolumeID, bytesQuota int64) error {
|
||||
// verify if corresponding ClusterID key is present in the map,
|
||||
// CreateVolume creates a subvolume.
|
||||
func (s *subVolumeClient) CreateVolume(ctx context.Context) error {
|
||||
// verify if corresponding clusterID key is present in the map,
|
||||
// and if not, initialize with default values(false).
|
||||
if _, keyPresent := clusterAdditionalInfo[volOptions.ClusterID]; !keyPresent {
|
||||
clusterAdditionalInfo[volOptions.ClusterID] = &localClusterState{}
|
||||
if _, keyPresent := clusterAdditionalInfo[s.clusterID]; !keyPresent {
|
||||
clusterAdditionalInfo[s.clusterID] = &localClusterState{}
|
||||
}
|
||||
|
||||
ca, err := volOptions.conn.GetFSAdmin()
|
||||
ca, err := s.conn.GetFSAdmin()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not create subvolume %s: %s", string(volID), err)
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not create subvolume %s: %s", s.VolID, err)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// create subvolumegroup if not already created for the cluster.
|
||||
if !clusterAdditionalInfo[volOptions.ClusterID].subVolumeGroupCreated {
|
||||
if !clusterAdditionalInfo[s.clusterID].subVolumeGroupCreated {
|
||||
opts := fsAdmin.SubVolumeGroupOptions{}
|
||||
err = ca.CreateSubVolumeGroup(volOptions.FsName, volOptions.SubvolumeGroup, &opts)
|
||||
err = ca.CreateSubVolumeGroup(s.FsName, s.SubvolumeGroup, &opts)
|
||||
if err != nil {
|
||||
log.ErrorLog(
|
||||
ctx,
|
||||
"failed to create subvolume group %s, for the vol %s: %s",
|
||||
volOptions.SubvolumeGroup,
|
||||
string(volID),
|
||||
s.SubvolumeGroup,
|
||||
s.VolID,
|
||||
err)
|
||||
|
||||
return err
|
||||
}
|
||||
log.DebugLog(ctx, "cephfs: created subvolume group %s", volOptions.SubvolumeGroup)
|
||||
clusterAdditionalInfo[volOptions.ClusterID].subVolumeGroupCreated = true
|
||||
log.DebugLog(ctx, "cephfs: created subvolume group %s", s.SubvolumeGroup)
|
||||
clusterAdditionalInfo[s.clusterID].subVolumeGroupCreated = true
|
||||
}
|
||||
|
||||
opts := fsAdmin.SubVolumeOptions{
|
||||
Size: fsAdmin.ByteCount(bytesQuota),
|
||||
Size: fsAdmin.ByteCount(s.Size),
|
||||
Mode: modeAllRWX,
|
||||
}
|
||||
if volOptions.Pool != "" {
|
||||
opts.PoolLayout = volOptions.Pool
|
||||
if s.Pool != "" {
|
||||
opts.PoolLayout = s.Pool
|
||||
}
|
||||
|
||||
fmt.Println("this is for debugging ")
|
||||
// FIXME: check if the right credentials are used ("-n", cephEntityClientPrefix + cr.ID)
|
||||
err = ca.CreateSubVolume(volOptions.FsName, volOptions.SubvolumeGroup, string(volID), &opts)
|
||||
err = ca.CreateSubVolume(s.FsName, s.SubvolumeGroup, s.VolID, &opts)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to create subvolume %s in fs %s: %s", string(volID), volOptions.FsName, err)
|
||||
log.ErrorLog(ctx, "failed to create subvolume %s in fs %s: %s", s.VolID, s.FsName, err)
|
||||
|
||||
return err
|
||||
}
|
||||
@ -193,16 +251,16 @@ func CreateVolume(ctx context.Context, volOptions *VolumeOptions, volID fsutil.V
|
||||
|
||||
// ExpandVolume will expand the volume if the requested size is greater than
|
||||
// the subvolume size.
|
||||
func (vo *VolumeOptions) ExpandVolume(ctx context.Context, volID fsutil.VolumeID, bytesQuota int64) error {
|
||||
func (s *subVolumeClient) ExpandVolume(ctx context.Context, bytesQuota int64) error {
|
||||
// get the subvolume size for comparison with the requested size.
|
||||
info, err := vo.GetSubVolumeInfo(ctx, volID)
|
||||
info, err := s.GetSubVolumeInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// resize if the requested size is greater than the current size.
|
||||
if vo.Size > info.BytesQuota {
|
||||
log.DebugLog(ctx, "clone %s size %d is greater than requested size %d", volID, info.BytesQuota, bytesQuota)
|
||||
err = vo.ResizeVolume(ctx, volID, bytesQuota)
|
||||
if s.Size > info.BytesQuota {
|
||||
log.DebugLog(ctx, "clone %s size %d is greater than requested size %d", s.VolID, info.BytesQuota, bytesQuota)
|
||||
err = s.ResizeVolume(ctx, bytesQuota)
|
||||
}
|
||||
|
||||
return err
|
||||
@ -211,45 +269,47 @@ func (vo *VolumeOptions) ExpandVolume(ctx context.Context, volID fsutil.VolumeID
|
||||
// ResizeVolume will try to use ceph fs subvolume resize command to resize the
|
||||
// subvolume. If the command is not available as a fallback it will use
|
||||
// CreateVolume to resize the subvolume.
|
||||
func (vo *VolumeOptions) ResizeVolume(ctx context.Context, volID fsutil.VolumeID, bytesQuota int64) error {
|
||||
func (s *subVolumeClient) ResizeVolume(ctx context.Context, bytesQuota int64) error {
|
||||
// keyPresent checks whether corresponding clusterID key is present in clusterAdditionalInfo
|
||||
var keyPresent bool
|
||||
// verify if corresponding ClusterID key is present in the map,
|
||||
// verify if corresponding clusterID key is present in the map,
|
||||
// and if not, initialize with default values(false).
|
||||
if _, keyPresent = clusterAdditionalInfo[vo.ClusterID]; !keyPresent {
|
||||
clusterAdditionalInfo[vo.ClusterID] = &localClusterState{}
|
||||
if _, keyPresent = clusterAdditionalInfo[s.clusterID]; !keyPresent {
|
||||
clusterAdditionalInfo[s.clusterID] = &localClusterState{}
|
||||
}
|
||||
// resize subvolume when either it's supported, or when corresponding
|
||||
// clusterID key was not present.
|
||||
if clusterAdditionalInfo[vo.ClusterID].resizeState == unknown ||
|
||||
clusterAdditionalInfo[vo.ClusterID].resizeState == supported {
|
||||
fsa, err := vo.conn.GetFSAdmin()
|
||||
if clusterAdditionalInfo[s.clusterID].resizeState == unknown ||
|
||||
clusterAdditionalInfo[s.clusterID].resizeState == supported {
|
||||
fsa, err := s.conn.GetFSAdmin()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not resize volume %s:", vo.FsName, err)
|
||||
log.ErrorLog(ctx, "could not get FSAdmin, can not resize volume %s:", s.FsName, err)
|
||||
|
||||
return err
|
||||
}
|
||||
_, err = fsa.ResizeSubVolume(vo.FsName, vo.SubvolumeGroup, string(volID), fsAdmin.ByteCount(bytesQuota), true)
|
||||
_, err = fsa.ResizeSubVolume(s.FsName, s.SubvolumeGroup, s.VolID, fsAdmin.ByteCount(bytesQuota), true)
|
||||
if err == nil {
|
||||
clusterAdditionalInfo[vo.ClusterID].resizeState = supported
|
||||
clusterAdditionalInfo[s.clusterID].resizeState = supported
|
||||
|
||||
return nil
|
||||
}
|
||||
var invalid fsAdmin.NotImplementedError
|
||||
// In case the error is other than invalid command return error to the caller.
|
||||
if !errors.As(err, &invalid) {
|
||||
log.ErrorLog(ctx, "failed to resize subvolume %s in fs %s: %s", string(volID), vo.FsName, err)
|
||||
log.ErrorLog(ctx, "failed to resize subvolume %s in fs %s: %s", s.VolID, s.FsName, err)
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
clusterAdditionalInfo[vo.ClusterID].resizeState = unsupported
|
||||
clusterAdditionalInfo[s.clusterID].resizeState = unsupported
|
||||
s.Size = bytesQuota
|
||||
|
||||
return CreateVolume(ctx, vo, volID, bytesQuota)
|
||||
return s.CreateVolume(ctx)
|
||||
}
|
||||
|
||||
func (vo *VolumeOptions) PurgeVolume(ctx context.Context, volID fsutil.VolumeID, force bool) error {
|
||||
fsa, err := vo.conn.GetFSAdmin()
|
||||
// PurgSubVolume removes the subvolume.
|
||||
func (s *subVolumeClient) PurgeVolume(ctx context.Context, force bool) error {
|
||||
fsa, err := s.conn.GetFSAdmin()
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "could not get FSAdmin %s:", err)
|
||||
|
||||
@ -259,13 +319,13 @@ func (vo *VolumeOptions) PurgeVolume(ctx context.Context, volID fsutil.VolumeID,
|
||||
opt := fsAdmin.SubVolRmFlags{}
|
||||
opt.Force = force
|
||||
|
||||
if checkSubvolumeHasFeature("snapshot-retention", vo.Features) {
|
||||
if checkSubvolumeHasFeature("snapshot-retention", s.Features) {
|
||||
opt.RetainSnapshots = true
|
||||
}
|
||||
|
||||
err = fsa.RemoveSubVolumeWithFlags(vo.FsName, vo.SubvolumeGroup, string(volID), opt)
|
||||
err = fsa.RemoveSubVolumeWithFlags(s.FsName, s.SubvolumeGroup, s.VolID, opt)
|
||||
if err != nil {
|
||||
log.ErrorLog(ctx, "failed to purge subvolume %s in fs %s: %s", string(volID), vo.FsName, err)
|
||||
log.ErrorLog(ctx, "failed to purge subvolume %s in fs %s: %s", s.VolID, s.FsName, err)
|
||||
if strings.Contains(err.Error(), cerrors.VolumeNotEmpty) {
|
||||
return util.JoinErrors(cerrors.ErrVolumeHasSnapshots, err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user