Skip to content

Commit 0e8e519

Browse files
MadnessASAPstgraber
authored andcommitted
incusd/instance/drivers: Let QEMU handle Ceph itself
QEMU interfaces with librados for providing Ceph RBD support and as such already has quite robust cluster discovery abilities. Instead of telling QEMU everything it could possibly want to know and risking telling it something wrong, tell it what it needs to know (user, pool, image). Then QEMU can almost certainly do a better and faster job of collecting the necessary information for initiating a cluster connection. Signed-off-by: Michael 'ASAP' Weinrich <[email protected]>
1 parent b753a33 commit 0e8e519

File tree

2 files changed

+34
-73
lines changed

2 files changed

+34
-73
lines changed

internal/server/device/device_utils_disk.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,35 @@ const RBDFormatPrefix = "rbd"
3030
// RBDFormatSeparator is the field separate used in disk paths for RBD devices.
3131
const RBDFormatSeparator = " "
3232

33-
// DiskParseRBDFormat parses an rbd formatted string, and returns the pool name, volume name, and list of options.
34-
func DiskParseRBDFormat(rbd string) (string, string, []string, error) {
35-
if !strings.HasPrefix(rbd, fmt.Sprintf("%s%s", RBDFormatPrefix, RBDFormatSeparator)) {
36-
return "", "", nil, fmt.Errorf("Invalid rbd format, missing prefix")
33+
// DiskParseRBDFormat parses an rbd formatted string, and returns the pool name, volume name, and map of options.
34+
func DiskParseRBDFormat(rbd string) (string, string, map[string]string, error) {
35+
// Remove and check the prefix.
36+
prefix, rbd, _ := strings.Cut(rbd, RBDFormatSeparator)
37+
if prefix != RBDFormatPrefix {
38+
return "", "", nil, fmt.Errorf("Invalid rbd format, wrong prefix: %q", prefix)
3739
}
3840

39-
fields := strings.SplitN(rbd, RBDFormatSeparator, 3)
40-
if len(fields) != 3 {
41-
return "", "", nil, fmt.Errorf("Invalid rbd format, invalid number of fields")
41+
// Split the path and options.
42+
path, rawOpts, _ := strings.Cut(rbd, RBDFormatSeparator)
43+
44+
// Check for valid RBD path.
45+
pool, volume, validPath := strings.Cut(path, "/")
46+
if !validPath {
47+
return "", "", nil, fmt.Errorf("Invalid rbd format, missing pool and/or volume: %q", path)
4248
}
4349

44-
opts := fields[2]
50+
// Parse options.
51+
opts := make(map[string]string)
52+
for _, o := range strings.Split(rawOpts, ":") {
53+
k, v, isValid := strings.Cut(o, "=")
54+
if !isValid {
55+
return "", "", nil, fmt.Errorf("Invalid rbd format, bad option: %q", o)
56+
}
4557

46-
fields = strings.SplitN(fields[1], "/", 2)
47-
if len(fields) != 2 {
48-
return "", "", nil, fmt.Errorf("Invalid rbd format, invalid pool or volume")
58+
opts[k] = v
4959
}
5060

51-
return fields[0], fields[1], strings.Split(opts, ":"), nil
61+
return pool, volume, opts, nil
5262
}
5363

5464
// DiskGetRBDFormat returns a rbd formatted string with the given values.
@@ -59,7 +69,6 @@ func DiskGetRBDFormat(clusterName string, userName string, poolName string, volu
5969
opts := []string{
6070
fmt.Sprintf("id=%s", optEscaper.Replace(userName)),
6171
fmt.Sprintf("pool=%s", optEscaper.Replace(poolName)),
62-
fmt.Sprintf("conf=/etc/ceph/%s.conf", optEscaper.Replace(clusterName)),
6372
}
6473

6574
return fmt.Sprintf("%s%s%s/%s%s%s", RBDFormatPrefix, RBDFormatSeparator, optEscaper.Replace(poolName), optEscaper.Replace(volumeName), RBDFormatSeparator, strings.Join(opts, ":"))
@@ -77,7 +86,7 @@ func BlockFsDetect(dev string) (string, error) {
7786

7887
// IsBlockdev returns boolean indicating whether device is block type.
7988
func IsBlockdev(path string) bool {
80-
// Get a stat struct from the provided path
89+
// Get a stat struct from the provided path.
8190
stat := unix.Stat_t{}
8291
err := unix.Stat(path, &stat)
8392
if err != nil {
@@ -240,7 +249,7 @@ again:
240249

241250
// diskCephfsOptions returns the mntSrcPath and fsOptions to use for mounting a cephfs share.
242251
func diskCephfsOptions(clusterName string, userName string, fsName string, fsPath string) (string, []string, error) {
243-
// Get the FSID
252+
// Get the FSID.
244253
fsid, err := storageDrivers.CephFsid(clusterName)
245254
if err != nil {
246255
return "", nil, err

internal/server/instance/drivers/driver_qemu.go

Lines changed: 10 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -4200,7 +4200,7 @@ func (d *qemu) addDriveConfig(qemuDev map[string]any, bootIndexes map[string]int
42004200
} else if isRBDImage {
42014201
blockDev["driver"] = "rbd"
42024202

4203-
_, volName, opts, err := device.DiskParseRBDFormat(driveConf.DevPath)
4203+
poolName, volName, opts, err := device.DiskParseRBDFormat(driveConf.DevPath)
42044204
if err != nil {
42054205
return nil, fmt.Errorf("Failed parsing rbd string: %w", err)
42064206
}
@@ -4225,68 +4225,20 @@ func (d *qemu) addDriveConfig(qemuDev map[string]any, bootIndexes map[string]int
42254225
vol := storageDrivers.NewVolume(nil, "", volumeType, rbdContentType, volumeName, nil, nil)
42264226
rbdImageName := storageDrivers.CephGetRBDImageName(vol, "", false)
42274227

4228-
// Parse the options (ceph credentials).
4229-
userName := storageDrivers.CephDefaultUser
4230-
clusterName := storageDrivers.CephDefaultCluster
4231-
poolName := ""
4232-
4233-
for _, option := range opts {
4234-
fields := strings.Split(option, "=")
4235-
if len(fields) != 2 {
4236-
return nil, fmt.Errorf("Unexpected volume rbd option %q", option)
4237-
}
4238-
4239-
if fields[0] == "id" {
4240-
userName = fields[1]
4241-
} else if fields[0] == "pool" {
4242-
poolName = fields[1]
4243-
} else if fields[0] == "conf" {
4244-
baseName := filepath.Base(fields[1])
4245-
clusterName = strings.TrimSuffix(baseName, ".conf")
4228+
// Scan & pass through options.
4229+
blockDev["pool"] = poolName
4230+
blockDev["image"] = rbdImageName
4231+
for key, val := range opts {
4232+
// We use 'id' where qemu uses 'user'.
4233+
if key == "id" {
4234+
blockDev["user"] = val
4235+
} else {
4236+
blockDev[key] = val
42464237
}
42474238
}
42484239

4249-
if poolName == "" {
4250-
return nil, fmt.Errorf("Missing pool name")
4251-
}
4252-
42534240
// The aio option isn't available when using the rbd driver.
42544241
delete(blockDev, "aio")
4255-
blockDev["pool"] = poolName
4256-
blockDev["image"] = rbdImageName
4257-
blockDev["user"] = userName
4258-
blockDev["server"] = []map[string]string{}
4259-
4260-
// Derference ceph config path.
4261-
cephConfPath := fmt.Sprintf("/etc/ceph/%s.conf", clusterName)
4262-
target, err := filepath.EvalSymlinks(cephConfPath)
4263-
if err == nil {
4264-
cephConfPath = target
4265-
}
4266-
4267-
blockDev["conf"] = cephConfPath
4268-
4269-
// Setup the Ceph cluster config (monitors and keyring).
4270-
monitors, err := storageDrivers.CephMonitors(clusterName)
4271-
if err != nil {
4272-
return nil, err
4273-
}
4274-
4275-
for _, monitor := range monitors {
4276-
idx := strings.LastIndex(monitor, ":")
4277-
host := monitor[:idx]
4278-
port := monitor[idx+1:]
4279-
4280-
blockDev["server"] = append(blockDev["server"].([]map[string]string), map[string]string{
4281-
"host": strings.Trim(host, "[]"),
4282-
"port": port,
4283-
})
4284-
}
4285-
4286-
rbdSecret, err = storageDrivers.CephKeyring(clusterName, userName)
4287-
if err != nil {
4288-
return nil, err
4289-
}
42904242
}
42914243

42924244
readonly := slices.Contains(driveConf.Opts, "ro")

0 commit comments

Comments
 (0)