Skip to content

Commit c137b63

Browse files
committed
incusd/storage/drivers: refactor ceph discovery
Previously during Ceph storage mounting Incus would try and parse the `ceph.conf` files itself. While this approach works in the majority of cases it failed to cover more then a few common setups and was fragile. This commit changes that to instead makes calls to the Ceph admin tool `ceph` which provides easy to parse JSON output and is by definition "correct". I also introduce a `CephBuildMount` function that essentially takes the output of `CephMonitors`, `CephFsid`, `CephKeyring`, and the CephFS path to produce a source path and options list suitable for passing to `mount`. This also uses the new mount syntax stlye enabling support for (sub)volumes. With this the `cephfs.getConfig` function is made redundant and `cephfs` driver is tweaked to use the modified discovery functions as well as `CephBuildMount`. Signed-off-by: Michael 'ASAP' Weinrich <[email protected]>
1 parent cd19568 commit c137b63

File tree

4 files changed

+244
-218
lines changed

4 files changed

+244
-218
lines changed

internal/server/device/device_utils_disk.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ again:
239239

240240
// diskCephfsOptions returns the mntSrcPath and fsOptions to use for mounting a cephfs share.
241241
func diskCephfsOptions(clusterName string, userName string, fsName string, fsPath string) (string, []string, error) {
242+
// Get the FSID
243+
fsid, err := storageDrivers.CephFsid(clusterName)
244+
if err != nil {
245+
return "", nil, err
246+
}
247+
242248
// Get the monitor list.
243249
monAddresses, err := storageDrivers.CephMonitors(clusterName)
244250
if err != nil {
@@ -251,14 +257,15 @@ func diskCephfsOptions(clusterName string, userName string, fsName string, fsPat
251257
return "", nil, err
252258
}
253259

254-
// Prepare mount entry.
255-
fsOptions := []string{
256-
fmt.Sprintf("name=%v", userName),
257-
fmt.Sprintf("secret=%v", secret),
258-
fmt.Sprintf("mds_namespace=%v", fsName),
259-
}
260+
srcPath, fsOptions := storageDrivers.CephBuildMount(
261+
userName,
262+
secret,
263+
fsid,
264+
monAddresses,
265+
fsName,
266+
fsPath,
267+
)
260268

261-
srcPath := strings.Join(monAddresses, ",") + ":/" + fsPath
262269
return srcPath, fsOptions, nil
263270
}
264271

internal/server/storage/drivers/driver_cephfs.go

Lines changed: 76 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,8 @@ func (d *cephfs) Create() error {
133133
d.config["cephfs.path"] = d.config["source"]
134134

135135
// Parse the namespace / path.
136-
fields := strings.SplitN(d.config["cephfs.path"], "/", 2)
137-
fsName := fields[0]
138-
fsPath := "/"
139-
if len(fields) > 1 {
140-
fsPath = fields[1]
141-
}
136+
fsName, fsPath, _ := strings.Cut(d.config["cephfs.path"], "/")
137+
fsPath = "/" + fsPath
142138

143139
// If the filesystem already exists, disallow keys associated to creating the filesystem.
144140
fsExists, err := d.fsExists(d.config["cephfs.cluster_name"], d.config["cephfs.user.name"], fsName)
@@ -265,15 +261,35 @@ func (d *cephfs) Create() error {
265261
return fmt.Errorf("Failed to create directory '%s': %w", mountPoint, err)
266262
}
267263

268-
// Get the credentials and host.
269-
monAddresses, userSecret, err := d.getConfig(d.config["cephfs.cluster_name"], d.config["cephfs.user.name"])
264+
// Collect Ceph information
265+
clusterName := d.config["cephfs.cluster_name"]
266+
userName := d.config["cephfs.user.name"]
267+
268+
fsid, err := CephFsid(clusterName)
269+
if err != nil {
270+
return err
271+
}
272+
273+
monitors, err := CephMonitors(clusterName)
270274
if err != nil {
271275
return err
272276
}
273277

278+
key, err := CephKeyring(clusterName, userName)
279+
if err != nil {
280+
return err
281+
}
282+
283+
srcPath, options := CephBuildMount(
284+
userName,
285+
key,
286+
fsid,
287+
monitors,
288+
fsName, "/",
289+
)
290+
274291
// Mount the pool.
275-
srcPath := strings.Join(monAddresses, ",") + ":/"
276-
err = TryMount(srcPath, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", d.config["cephfs.user.name"], userSecret, fsName))
292+
err = TryMount(srcPath, mountPoint, "ceph", 0, strings.Join(options, ","))
277293
if err != nil {
278294
return err
279295
}
@@ -300,12 +316,8 @@ func (d *cephfs) Create() error {
300316
// Delete clears any local and remote data related to this driver instance.
301317
func (d *cephfs) Delete(op *operations.Operation) error {
302318
// Parse the namespace / path.
303-
fields := strings.SplitN(d.config["cephfs.path"], "/", 2)
304-
fsName := fields[0]
305-
fsPath := "/"
306-
if len(fields) > 1 {
307-
fsPath = fields[1]
308-
}
319+
fsName, fsPath, _ := strings.Cut(d.config["cephfs.path"], "/")
320+
fsPath = "/" + fsPath
309321

310322
// Create a temporary mountpoint.
311323
mountPath, err := os.MkdirTemp("", "incus_cephfs_")
@@ -326,15 +338,35 @@ func (d *cephfs) Delete(op *operations.Operation) error {
326338
return fmt.Errorf("Failed to create directory '%s': %w", mountPoint, err)
327339
}
328340

329-
// Get the credentials and host.
330-
monAddresses, userSecret, err := d.getConfig(d.config["cephfs.cluster_name"], d.config["cephfs.user.name"])
341+
// Collect Ceph information
342+
clusterName := d.config["cephfs.cluster_name"]
343+
userName := d.config["cephfs.user.name"]
344+
345+
fsid, err := CephFsid(clusterName)
331346
if err != nil {
332347
return err
333348
}
334349

350+
monitors, err := CephMonitors(clusterName)
351+
if err != nil {
352+
return err
353+
}
354+
355+
key, err := CephKeyring(clusterName, userName)
356+
if err != nil {
357+
return err
358+
}
359+
360+
srcPath, options := CephBuildMount(
361+
userName,
362+
key,
363+
fsid,
364+
monitors,
365+
fsName, "/",
366+
)
367+
335368
// Mount the pool.
336-
srcPath := strings.Join(monAddresses, ",") + ":/"
337-
err = TryMount(srcPath, mountPoint, "ceph", 0, fmt.Sprintf("name=%v,secret=%v,mds_namespace=%v", d.config["cephfs.user.name"], userSecret, fsName))
369+
err = TryMount(srcPath, mountPoint, "ceph", 0, strings.Join(options, ","))
338370
if err != nil {
339371
return err
340372
}
@@ -397,28 +429,39 @@ func (d *cephfs) Mount() (bool, error) {
397429
}
398430

399431
// Parse the namespace / path.
400-
fields := strings.SplitN(d.config["cephfs.path"], "/", 2)
401-
fsName := fields[0]
402-
fsPath := ""
403-
if len(fields) > 1 {
404-
fsPath = fields[1]
432+
fsName, fsPath, _ := strings.Cut(d.config["cephfs.path"], "/")
433+
fsPath = "/" + fsPath
434+
435+
// Collect Ceph information
436+
clusterName := d.config["cephfs.cluster_name"]
437+
userName := d.config["cephfs.user.name"]
438+
439+
fsid, err := CephFsid(clusterName)
440+
if err != nil {
441+
return false, err
405442
}
406443

407-
// Get the credentials and host.
408-
monAddresses, userSecret, err := d.getConfig(d.config["cephfs.cluster_name"], d.config["cephfs.user.name"])
444+
monitors, err := CephMonitors(clusterName)
409445
if err != nil {
410446
return false, err
411447
}
412448

413-
// Mount options.
414-
options := fmt.Sprintf("name=%s,secret=%s,mds_namespace=%s", d.config["cephfs.user.name"], userSecret, fsName)
415-
if util.IsTrue(d.config["cephfs.fscache"]) {
416-
options += ",fsc"
449+
key, err := CephKeyring(clusterName, userName)
450+
if err != nil {
451+
return false, err
417452
}
418453

454+
srcPath, options := CephBuildMount(
455+
userName,
456+
key,
457+
fsid,
458+
monitors,
459+
fsName,
460+
fsPath,
461+
)
462+
419463
// Mount the pool.
420-
srcPath := strings.Join(monAddresses, ",") + ":/" + fsPath
421-
err = TryMount(srcPath, GetPoolMountPath(d.name), "ceph", 0, options)
464+
err = TryMount(srcPath, GetPoolMountPath(d.name), "ceph", 0, strings.Join(options, ","))
422465
if err != nil {
423466
return false, err
424467
}

internal/server/storage/drivers/driver_cephfs_utils.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,3 @@ func (d *cephfs) osdPoolExists(clusterName string, userName string, osdPoolName
4444

4545
return true, nil
4646
}
47-
48-
// getConfig parses the Ceph configuration file and returns the list of monitors and secret key.
49-
func (d *cephfs) getConfig(clusterName string, userName string) ([]string, string, error) {
50-
// Get the monitor list.
51-
monitors, err := CephMonitors(clusterName)
52-
if err != nil {
53-
return nil, "", err
54-
}
55-
56-
// Get the keyring entry.
57-
secret, err := CephKeyring(clusterName, userName)
58-
if err != nil {
59-
return nil, "", err
60-
}
61-
62-
return monitors, secret, nil
63-
}

0 commit comments

Comments
 (0)