ceph-csi/internal/cephfs/core/quiesce.go
Madhu Rajanna 6a4c45deeb cephfs: add helper for quiesce api
added helper function which calls
the go-ceph API for the quiesce
operations.

Signed-off-by: Madhu Rajanna <madhupr007@gmail.com>
2024-03-21 06:16:42 +00:00

251 lines
6.3 KiB
Go

/*
Copyright 2024 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.
*/
package core
import (
"context"
"github.com/ceph/ceph-csi/internal/util"
"github.com/ceph/ceph-csi/internal/util/log"
"github.com/ceph/go-ceph/cephfs/admin"
)
type QuiesceState string
const (
Released QuiesceState = "RELEASED"
Quiescing QuiesceState = "QUIESCING"
Quiesced QuiesceState = "QUIESCED"
)
// GetQuiesceState returns the quiesce state of the filesystem.
func GetQuiesceState(set admin.QuiesceState) QuiesceState {
var state QuiesceState
switch set.Name {
case "RELEASED":
state = Released
case "QUIESCING":
state = Quiescing
case "QUIESCED":
state = Quiesced
default:
state = QuiesceState(set.Name)
}
return state
}
type FSQuiesceClient interface {
// Destroy destroys the connection used for FSAdmin.
Destroy()
// FSQuiesce quiesces the subvolumes in the filesystem.
FSQuiesce(
ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error)
// GetVolumes returns the list of volumes in the filesystem that are to be
// quiesced.
GetVolumes() []Volume
// FSQuiesceWithExpireTimeout quiesces the subvolumes in the filesystem
// with an expiration timeout. it should be used after FSQuiesce to reset
// the expire timeout. This helps in keeping the subvolumes in the
// filesystem in quiesced state until all snapshots are taken.
FSQuiesceWithExpireTimeout(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error)
// ResetFSQuiesce resets the quiesce timeout for the subvolumes in
// the filesystem.
ResetFSQuiesce(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error)
// ReleaseFSQuiesce releases the quiesce on the subvolumes in the
// filesystem.
ReleaseFSQuiesce(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error)
}
type Volume struct {
VolumeID string
ClusterID string
}
type fsQuiesce struct {
connection *util.ClusterConnection
fsName string
volumes []Volume
// subVolumeGroupMapping is a map of subvolumes to groups.
subVolumeGroupMapping map[string][]string
fsa *admin.FSAdmin
}
// NewFSQuiesce returns a new instance of fsQuiesce. It
// take the filesystem name, the list of volumes to be quiesced, the mapping of
// subvolumes to groups and the cluster connection as input.
func NewFSQuiesce(
fsName string,
volumes []Volume,
mapping map[string][]string,
conn *util.ClusterConnection,
) (FSQuiesceClient, error) {
fsa, err := conn.GetFSAdmin()
if err != nil {
return nil, err
}
return &fsQuiesce{
connection: conn,
fsName: fsName,
volumes: volumes,
subVolumeGroupMapping: mapping,
fsa: fsa,
}, nil
}
// Destroy destroys the connection used for FSAdmin.
func (fq *fsQuiesce) Destroy() {
if fq.connection != nil {
fq.connection.Destroy()
}
}
// GetVolumes returns the list of volumes in the filesystem that are to be
// quiesced.
func (fq *fsQuiesce) GetVolumes() []Volume {
return fq.volumes
}
// getMembers returns the list of names in the format
// group/subvolume that are to be quiesced. This is the format that the
// ceph fs quiesce expects.
// Example: ["group1/subvolume1", "group1/subvolume2", "group2/subvolume1"].
func (fq *fsQuiesce) getMembers() []string {
volName := []string{}
for svg, sb := range fq.subVolumeGroupMapping {
for _, s := range sb {
name := svg + "/" + s
volName = append(volName, name)
}
}
return volName
}
func (fq *fsQuiesce) FSQuiesce(
ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error) {
opt := &admin.FSQuiesceOptions{
Timeout: 180,
AwaitFor: 0,
Expiration: 180,
}
log.DebugLog(ctx,
"FSQuiesce for reserveName %s: members:%v options:%v",
reserveName,
fq.getMembers(),
opt)
resp, err := fq.fsa.FSQuiesce(fq.fsName, admin.NoGroup, fq.getMembers(), reserveName, opt)
if resp != nil {
qInfo := resp.Sets[reserveName]
return &qInfo, nil
}
log.ErrorLog(ctx, "failed to quiesce filesystem %s", err)
return nil, err
}
func (fq *fsQuiesce) FSQuiesceWithExpireTimeout(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error) {
opt := &admin.FSQuiesceOptions{
Timeout: 180,
AwaitFor: 0,
Expiration: 180,
}
log.DebugLog(ctx,
"FSQuiesceWithExpireTimeout for reserveName %s: members:%v options:%v",
reserveName,
fq.getMembers(),
opt)
resp, err := fq.fsa.FSQuiesce(fq.fsName, admin.NoGroup, fq.getMembers(), reserveName, opt)
if resp != nil {
qInfo := resp.Sets[reserveName]
return &qInfo, nil
}
log.ErrorLog(ctx, "failed to quiesce filesystem with expire timeout %s", err)
return nil, err
}
func (fq *fsQuiesce) ResetFSQuiesce(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error) {
opt := &admin.FSQuiesceOptions{
Reset: true,
AwaitFor: 0,
Timeout: 180,
Expiration: 180,
}
// Reset the filesystem quiesce so that the timer will be reset, and we can
// reuse the same reservation if it has already failed or timed out.
log.DebugLog(ctx,
"ResetFSQuiesce for reserveName %s: members:%v options:%v",
reserveName,
fq.getMembers(),
opt)
resp, err := fq.fsa.FSQuiesce(fq.fsName, admin.NoGroup, fq.getMembers(), reserveName, opt)
if resp != nil {
qInfo := resp.Sets[reserveName]
return &qInfo, nil
}
log.ErrorLog(ctx, "failed to reset timeout for quiesce filesystem %s", err)
return nil, err
}
func (fq *fsQuiesce) ReleaseFSQuiesce(ctx context.Context,
reserveName string,
) (*admin.QuiesceInfo, error) {
opt := &admin.FSQuiesceOptions{
AwaitFor: 0,
Release: true,
}
log.DebugLog(ctx,
"ReleaseFSQuiesce for reserveName %s: members:%v options:%v",
reserveName,
fq.getMembers(),
opt)
resp, err := fq.fsa.FSQuiesce(fq.fsName, admin.NoGroup, []string{}, reserveName, opt)
if resp != nil {
qInfo := resp.Sets[reserveName]
return &qInfo, nil
}
log.ErrorLog(ctx, "failed to release quiesce of filesystem %s", err)
return nil, err
}