cleanup: simplify rbdGetDeviceList()

The `rbdGetDeviceList()` function uses two very similar types for
converting krbd and NBD device information from JSON. There is no need
to use this distinction, and callers of `rbdGetDeviceList()` should not
need to care about it either.

By introducing a `deviceInfo` interface with Get-functions, the
`rbdGetDeviceList()` function becomes a little simpler, with a clearly
defined API for the returned list.

Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
Niels de Vos 2024-01-05 11:02:55 +01:00 committed by mergify[bot]
parent 2dab8f2b74
commit 3bf5c0e478

View File

@ -21,7 +21,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
@ -91,25 +90,43 @@ var (
} }
) )
type deviceInfo interface {
GetName() string
GetPool() string
GetRadosNamespace() string
GetDevice() string
}
// rbdDeviceInfo strongly typed JSON spec for rbd device list output (of type krbd). // rbdDeviceInfo strongly typed JSON spec for rbd device list output (of type krbd).
type rbdDeviceInfo struct { type rbdDeviceInfo struct {
ID string `json:"id"` // Name will only be set for krbd devices (NBD uses Image)
Name string `json:"name"`
// Image will only be set for NBD devices (krbd uses Name)
Image string `json:"image"`
Pool string `json:"pool"` Pool string `json:"pool"`
RadosNamespace string `json:"namespace"` RadosNamespace string `json:"namespace"`
Name string `json:"name"`
Device string `json:"device"` Device string `json:"device"`
} }
// nbdDeviceInfo strongly typed JSON spec for rbd-nbd device list output (of type nbd) func (rdi *rbdDeviceInfo) GetName() string {
// NOTE: There is a bug in rbd output that returns id as number for nbd, and string for krbd, thus if rdi.Name != "" {
// requiring 2 different JSON structures to unmarshal the output. return rdi.Name
// NOTE: image key is "name" in krbd output and "image" in nbd output, which is another difference. }
type nbdDeviceInfo struct {
ID int64 `json:"id"` return rdi.Image
Pool string `json:"pool"` }
RadosNamespace string `json:"namespace"`
Name string `json:"image"` func (rdi *rbdDeviceInfo) GetPool() string {
Device string `json:"device"` return rdi.Pool
}
func (rdi *rbdDeviceInfo) GetRadosNamespace() string {
return rdi.RadosNamespace
}
func (rdi *rbdDeviceInfo) GetDevice() string {
return rdi.Device
} }
type detachRBDImageArgs struct { type detachRBDImageArgs struct {
@ -123,25 +140,17 @@ type detachRBDImageArgs struct {
logStrategy string logStrategy string
} }
// rbdGetDeviceList queries rbd about mapped devices and returns a list of rbdDeviceInfo // getDeviceList queries rbd about mapped devices and returns a list of deviceInfo
// It will selectively list devices mapped using krbd or nbd as specified by accessType. // It will selectively list devices mapped using krbd or nbd as specified by accessType.
func rbdGetDeviceList(ctx context.Context, accessType string) ([]rbdDeviceInfo, error) { func getDeviceList(ctx context.Context, accessType string) ([]deviceInfo, error) {
// rbd device list --format json --device-type [krbd|nbd] // rbd device list --format json --device-type [krbd|nbd]
var (
rbdDeviceList []rbdDeviceInfo
nbdDeviceList []nbdDeviceInfo
)
stdout, _, err := util.ExecCommand(ctx, rbd, "device", "list", "--format="+"json", "--device-type", accessType) stdout, _, err := util.ExecCommand(ctx, rbd, "device", "list", "--format="+"json", "--device-type", accessType)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting device list from rbd for devices of type (%s): %w", accessType, err) return nil, fmt.Errorf("error getting device list from rbd for devices of type (%s): %w", accessType, err)
} }
if accessType == accessTypeKRbd { var devices []*rbdDeviceInfo
err = json.Unmarshal([]byte(stdout), &rbdDeviceList) err = json.Unmarshal([]byte(stdout), &devices)
} else {
err = json.Unmarshal([]byte(stdout), &nbdDeviceList)
}
if err != nil { if err != nil {
return nil, fmt.Errorf( return nil, fmt.Errorf(
"error to parse JSON output of device list for devices of type (%s): %w", "error to parse JSON output of device list for devices of type (%s): %w",
@ -149,22 +158,13 @@ func rbdGetDeviceList(ctx context.Context, accessType string) ([]rbdDeviceInfo,
err) err)
} }
// convert output to a rbdDeviceInfo list for consumers // convert []rbdDeviceInfo to []deviceInfo
if accessType == accessTypeNbd { deviceList := make([]deviceInfo, len(devices))
for _, device := range nbdDeviceList { for i := range devices {
rbdDeviceList = append( deviceList[i] = devices[i]
rbdDeviceList,
rbdDeviceInfo{
ID: strconv.FormatInt(device.ID, 10),
Pool: device.Pool,
RadosNamespace: device.RadosNamespace,
Name: device.Name,
Device: device.Device,
})
}
} }
return rbdDeviceList, nil return deviceList, nil
} }
// findDeviceMappingImage finds a devicePath, if available, based on image spec (pool/{namespace/}image) on the node. // findDeviceMappingImage finds a devicePath, if available, based on image spec (pool/{namespace/}image) on the node.
@ -179,16 +179,16 @@ func findDeviceMappingImage(ctx context.Context, pool, namespace, image string,
imageSpec = fmt.Sprintf("%s/%s/%s", pool, namespace, image) imageSpec = fmt.Sprintf("%s/%s/%s", pool, namespace, image)
} }
rbdDeviceList, err := rbdGetDeviceList(ctx, accessType) deviceList, err := getDeviceList(ctx, accessType)
if err != nil { if err != nil {
log.WarningLog(ctx, "failed to determine if image (%s) is mapped to a device (%v)", imageSpec, err) log.WarningLog(ctx, "failed to determine if image (%s) is mapped to a device (%v)", imageSpec, err)
return "", false return "", false
} }
for _, device := range rbdDeviceList { for _, device := range deviceList {
if device.Name == image && device.Pool == pool && device.RadosNamespace == namespace { if device.GetName() == image && device.GetPool() == pool && device.GetRadosNamespace() == namespace {
return device.Device, true return device.GetDevice(), true
} }
} }