Skip to content

Commit 5adaa75

Browse files
fix: Enhanced cephfs enable workflow
Signed-off-by: Utkarsh Bhatt <utkarsh.bhatt@canonical.com>
1 parent d4fbae6 commit 5adaa75

4 files changed

Lines changed: 139 additions & 16 deletions

File tree

microceph/ceph/cephfs_volume.go

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,25 @@ func ListCephFSVolumes() ([]Volume, error) {
5656
response = append(response, Volume(volume.String()))
5757
}
5858

59-
return response, nil
59+
return parseListVolOutputJson(output)
60+
}
61+
62+
func ListRemoteCephFSVolumes(remote string, local string) ([]Volume, error) {
63+
if len(remote) == 0 || len(local) == 0 {
64+
return nil, fmt.Errorf("both remote(%s) and local(%s) names must be provided", remote, local)
65+
}
66+
67+
args := []string{"fs", "volume", "ls", "--format=json"}
68+
cmd := appendRemoteClusterArgs(args, remote, local)
69+
70+
output, err := cephRun(cmd...)
71+
if err != nil {
72+
return nil, err
73+
}
74+
75+
logger.Infof("FSVOL: listed %s as remote cluster (%s) cephfs volumes", output, remote)
76+
77+
return parseListVolOutputJson(output)
6078
}
6179

6280
// CephFsSubvolumePathDeconstruct deconstructs a CephFS subvolume path string into its subvolume and subvolumegroup names.
@@ -182,3 +200,20 @@ func GetCephFSSubvolumePath(subvolumegroup string, subvolume string) string {
182200

183201
return retval
184202
}
203+
204+
// ##### Helper Functions #####
205+
206+
func parseListVolOutputJson(output string) ([]Volume, error) {
207+
volumes := gjson.Get(output, "#.name")
208+
response := make([]Volume, 0, len(volumes.Array()))
209+
for _, volume := range volumes.Array() {
210+
if len(volume.String()) == 0 {
211+
continue
212+
}
213+
214+
logger.Debugf("FSVOL: found %s as cephfs volume", volume.String())
215+
response = append(response, Volume(volume.String()))
216+
}
217+
218+
return response, nil
219+
}

microceph/ceph/manager.go

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package ceph
22

33
import (
4+
"context"
45
"fmt"
56
"path/filepath"
7+
"strings"
68

79
"github.com/canonical/microceph/microceph/common"
10+
"github.com/canonical/microceph/microceph/constants"
811
"github.com/canonical/microceph/microceph/logger"
912
"github.com/tidwall/gjson"
1013
)
@@ -50,11 +53,46 @@ func getActiveMgrs() ([]string, error) {
5053
}
5154

5255
// Mgr Module Ops
53-
func enableMgrModule(module string) error {
54-
cmd := []string{
55-
"mgr", "module", "enable", module,
56-
}
56+
57+
// EnableMgrModule enabled a mgr module on specified ceph cluster and verifies if is comes up
58+
func EnableMgrModule(ctx context.Context, module string, remote string, local string) error {
59+
args := []string{"mgr", "module", "enable", module}
60+
61+
cmd := appendRemoteClusterArgs(args, remote, local)
5762

5863
_, err := cephRun(cmd...)
59-
return err
64+
if err != nil {
65+
logger.Errorf("Failed to enable remote cluster (%s) mgr module %s: %v", remote, module, err)
66+
return err
67+
}
68+
69+
return verifyMgrModuleEnabled(ctx, module, remote, local)
70+
}
71+
72+
func verifyMgrModuleEnabled(ctx context.Context, module string, remote string, local string) error {
73+
args := []string{"mgr", "module", "ls", "-f", "json"}
74+
75+
cmd := appendRemoteClusterArgs(args, remote, local)
76+
77+
output, err := cephRunContext(ctx, cmd...)
78+
if err != nil {
79+
logger.Errorf("Failed to list remote cluster (%s) mgr modules: %v", remote, err)
80+
return err
81+
}
82+
83+
result := gjson.Get(output, "enabled_modules")
84+
if !result.Exists() || !result.Bool() {
85+
return fmt.Errorf("mgr module %s not enabled", module)
86+
}
87+
88+
logger.Debugf("Enabled Mgr Modules:\n%+v", result.Array())
89+
90+
for _, module := range result.Array() {
91+
logger.Debugf("Mgr Module: %s", module.String())
92+
if strings.Compare(module.String(), constants.MgrModuleMirroring) == 0 {
93+
return nil
94+
}
95+
}
96+
97+
return fmt.Errorf("could not enable mgr module %s", module)
6098
}

microceph/ceph/rbd_mirror.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,19 @@ package ceph
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/canonical/microceph/microceph/common"
76
"os"
87
"path/filepath"
98
"strings"
109
"time"
1110

11+
"github.com/canonical/microceph/microceph/common"
12+
1213
"github.com/Rican7/retry"
1314
"github.com/Rican7/retry/backoff"
1415
"github.com/Rican7/retry/strategy"
15-
"github.com/canonical/microceph/microceph/logger"
1616
"github.com/canonical/microceph/microceph/api/types"
1717
"github.com/canonical/microceph/microceph/constants"
18+
"github.com/canonical/microceph/microceph/logger"
1819
"github.com/tidwall/gjson"
1920
)
2021

@@ -680,7 +681,7 @@ func IsRemoteConfiguredForRbdMirror(remoteName string) bool {
680681

681682
// appendRemoteClusterArgs appends the cluster and client arguments to ceph commands
682683
func appendRemoteClusterArgs(args []string, cluster string, client string) []string {
683-
logger.Debugf("RBD Replication: old args are %v", args)
684+
logger.Debugf("REP: old args are %v", args)
684685
// check if appendage is needed
685686
if len(cluster) == 0 && len(client) == 0 {
686687
// return as is
@@ -697,7 +698,7 @@ func appendRemoteClusterArgs(args []string, cluster string, client string) []str
697698
args = append(args, client)
698699
}
699700

700-
logger.Debugf("RBD Replication: new args are %v", args)
701+
logger.Debugf("REP: new args are %v", args)
701702

702703
// return modified args
703704
return args

microceph/ceph/replication_cephfs.go

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,22 @@ func (rh *CephfsReplicationHandler) EnableHandler(ctx context.Context, args ...a
131131
return err
132132
}
133133

134-
err = enableMgrModule(constants.MgrModuleMirroring)
134+
dbRec, err := database.GetRemoteDb(ctx, st.ClusterState(), rh.Request.RemoteName)
135+
if err != nil {
136+
err := fmt.Errorf("remote (%s) does not exist: %w", rh.Request.RemoteName, err)
137+
logger.Error(err.Error())
138+
return err
139+
}
140+
141+
logger.Infof("REPCFS: LocalName(%s) RemoteName(%s)", dbRec[0].LocalName, dbRec[0].Name)
142+
143+
err = verifyRemoteCephFSVolumeExists(rh.Request.Volume, dbRec[0].Name, dbRec[0].LocalName)
144+
if err != nil {
145+
logger.Errorf("Failed to verify if remote cephfs volume %s: %v", rh.Request.Volume, err)
146+
return err
147+
}
148+
149+
err = enableCephFSMgrModules(ctx, dbRec[0].Name, dbRec[0].LocalName)
135150
if err != nil {
136151
return err
137152
}
@@ -237,7 +252,7 @@ func (rh *CephfsReplicationHandler) StatusHandler(ctx context.Context, args ...a
237252

238253
// cannot directly modify struct fields in a map, so retrieve, modify and reassign
239254
for _, peer := range fs.Peers {
240-
responsePeer, _ := response.Peers[peer.UUID]
255+
responsePeer := response.Peers[peer.UUID]
241256
responsePeer.Name = peer.Remote.ClusterName
242257
response.Peers[peer.UUID] = responsePeer
243258
}
@@ -279,9 +294,9 @@ func (rh *CephfsReplicationHandler) GetCephFSMirrorStatus(ctx context.Context) e
279294
return fmt.Errorf("%s is not %s", rh.Request.RequestType, types.StatusReplicationRequest)
280295
}
281296

282-
volumeId, peers := GetCephFsMirrorVolumeAndPeersId(rh)
283-
if volumeId < 0 || len(peers) == 0 {
284-
return fmt.Errorf("no CephFS volume (%d) or peers (%v) found for mirroring status", volumeId, peers)
297+
volumeID, peers := GetCephFsMirrorVolumeAndPeersId(rh)
298+
if volumeID < 0 || len(peers) == 0 {
299+
return fmt.Errorf("no CephFS volume (%d) or peers (%v) found for mirroring status", volumeID, peers)
285300
}
286301

287302
// TODO: (utkarshbhatthere):
@@ -297,7 +312,7 @@ func (rh *CephfsReplicationHandler) GetCephFSMirrorStatus(ctx context.Context) e
297312
response := MirrorStatus{}
298313
for _, peer := range peers {
299314
// Get the mirror status for each peer
300-
response[peer], err = GetCephFsMirrorPeerStatus(ctx, cephfsMirrorAdminSock, volumeId, peer)
315+
response[peer], err = GetCephFsMirrorPeerStatus(ctx, cephfsMirrorAdminSock, volumeID, peer)
301316
if err != nil {
302317
return fmt.Errorf("failed to get CephFS mirror status for peer %s: %w", peer, err)
303318
}
@@ -368,6 +383,40 @@ func verifyEnableRequestData(ctx context.Context, s interfaces.CephState, reques
368383
return nil
369384
}
370385

386+
func enableCephFSMgrModules(ctx context.Context, remote string, local string) error {
387+
err := EnableMgrModule(ctx, constants.MgrModuleMirroring, "", "")
388+
if err != nil {
389+
err := fmt.Errorf("failed to enable mgr module %s on local cluster: %w", constants.MgrModuleMirroring, err)
390+
logger.Error(err.Error())
391+
return err
392+
}
393+
394+
err = EnableMgrModule(ctx, constants.MgrModuleMirroring, remote, local)
395+
if err != nil {
396+
err := fmt.Errorf("failed to enable mgr module %s on remote cluster %s: %w", constants.MgrModuleMirroring, remote, err)
397+
logger.Error(err.Error())
398+
return err
399+
}
400+
401+
return nil
402+
}
403+
404+
func verifyRemoteCephFSVolumeExists(vol string, remote string, local string) error {
405+
volumes, err := ListRemoteCephFSVolumes(remote, local)
406+
if err != nil {
407+
logger.Errorf("Failed to list remote cephfs volumes for remote %s: %v", remote, err)
408+
return err
409+
}
410+
411+
for _, volume := range volumes {
412+
if strings.Compare(string(volume), vol) == 0 {
413+
return nil
414+
}
415+
}
416+
417+
return fmt.Errorf("cephfs volume %s not found on remote %s", vol, remote)
418+
}
419+
371420
func enableCephFSVolumeMirror(ctx context.Context, request types.CephfsReplicationRequest) error {
372421
peerExists, err := cephFSSnapshotMirrorPeerExists(ctx, request.Volume, request.RemoteName)
373422
if err != nil {

0 commit comments

Comments
 (0)