Skip to content

Commit

Permalink
lxd/storage/drivers/powerflex: Use connector for handling storage sub…
Browse files Browse the repository at this point in the history
…system

Use storage connector and also do not use "disconnect-all" for NVMe to prevent
disconnecting volumes from other storage pools or drivers that rely on the NVMe
connector.

Signed-off-by: Din Music <[email protected]>
  • Loading branch information
MusicDin committed Dec 20, 2024
1 parent d91c4f7 commit e96dfb6
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 237 deletions.
61 changes: 35 additions & 26 deletions lxd/storage/drivers/driver_powerflex.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/canonical/lxd/lxd/migration"
"github.com/canonical/lxd/lxd/operations"
"github.com/canonical/lxd/lxd/storage/connectors"
"github.com/canonical/lxd/shared"
"github.com/canonical/lxd/shared/api"
"github.com/canonical/lxd/shared/validate"
Expand All @@ -19,17 +20,21 @@ const powerFlexDefaultUser = "admin"
// powerFlexDefaultSize represents the default PowerFlex volume size.
const powerFlexDefaultSize = "8GiB"

const (
powerFlexModeNVMe = "nvme"
powerFlexModeSDC = "sdc"
)
var powerflexSupportedConnectors = []string{
connectors.TypeNVME,
connectors.TypeSDC,
}

var powerFlexLoaded bool
var powerFlexVersion string

type powerflex struct {
common

// Holds the low level connector for the PowerFlex driver.
// Use powerflex.connector() to retrieve the initialized connector.
storageConnector connectors.Connector

// Holds the low level HTTP client for the PowerFlex API.
// Use powerflex.client() to retrieve the client struct.
httpClient *powerFlexClient
Expand All @@ -46,28 +51,29 @@ func (d *powerflex) load() error {
return nil
}

// Detect and record the version.
// The NVMe CLI is shipped with the snap.
out, err := shared.RunCommand("nvme", "version")
if err != nil {
return fmt.Errorf("Failed to get nvme-cli version: %w", err)
}

fields := strings.Split(strings.TrimSpace(out), " ")
if strings.HasPrefix(out, "nvme version ") && len(fields) > 2 {
powerFlexVersion = fmt.Sprintf("%s (nvme-cli)", fields[2])
}
versions := connectors.GetSupportedVersions(powerflexSupportedConnectors)
powerFlexVersion = strings.Join(versions, " / ")
powerFlexLoaded = true

// Load the NVMe/TCP kernel modules.
// Load the kernel modules of the respective connector.
// Ignore if the modules cannot be loaded.
// Support for the NVMe/TCP mode is checked during pool creation.
// Support for a specific connector is checked during pool creation.
// When a LXD host gets rebooted this ensures that the kernel modules are still loaded.
_ = d.loadNVMeModules()
_ = d.connector().LoadModules()

powerFlexLoaded = true
return nil
}

// connector retrieves an initialized storage connector based on the configured
// PowerFlex mode. The connector is cached in the driver struct.
func (d *powerflex) connector() connectors.Connector {
if d.storageConnector == nil {
d.storageConnector = connectors.NewConnector(d.config["powerflex.mode"], d.state.ServerUUID)
}

return d.storageConnector
}

// isRemote returns true indicating this driver uses remote storage.
func (d *powerflex) isRemote() bool {
return true
Expand Down Expand Up @@ -102,10 +108,13 @@ func (d *powerflex) FillConfig() error {
// First try if the NVMe/TCP kernel modules can be loaed.
// Second try if the SDC kernel module is setup.
if d.config["powerflex.mode"] == "" {
if d.loadNVMeModules() {
d.config["powerflex.mode"] = powerFlexModeNVMe
// Create temporary connector to check if NVMe/TCP kernel modules can be loaded.
nvmeConnector := connectors.NewConnector(connectors.TypeNVME, "")

if nvmeConnector.LoadModules() {
d.config["powerflex.mode"] = connectors.TypeNVME
} else if goscaleio.DrvCfgIsSDCInstalled() {
d.config["powerflex.mode"] = powerFlexModeSDC
d.config["powerflex.mode"] = connectors.TypeSDC
}
}

Expand Down Expand Up @@ -139,7 +148,7 @@ func (d *powerflex) Create() error {
client := d.client()

switch d.config["powerflex.mode"] {
case powerFlexModeNVMe:
case connectors.TypeNVME:
// Discover one of the storage pools SDT services.
if d.config["powerflex.sdt"] == "" {
pool, err := d.resolvePool()
Expand All @@ -163,7 +172,7 @@ func (d *powerflex) Create() error {
d.config["powerflex.sdt"] = relations[0].IPList[0].IP
}

case powerFlexModeSDC:
case connectors.TypeSDC:
if d.config["powerflex.sdt"] != "" {
return fmt.Errorf("The powerflex.sdt config key is specific to the NVMe/TCP mode")
}
Expand Down Expand Up @@ -295,8 +304,8 @@ func (d *powerflex) Validate(config map[string]string) error {
// on the other cluster members too. This can be done here since Validate
// gets executed on every cluster member when receiving the cluster
// notification to finally create the pool.
if d.config["powerflex.mode"] == powerFlexModeNVMe && !d.loadNVMeModules() {
return fmt.Errorf("NVMe/TCP is not supported")
if newMode != "" && !connectors.NewConnector(newMode, "").LoadModules() {
return fmt.Errorf("PowerFlex mode %q is not supported due to missing kernel modules", newMode)
}

return nil
Expand Down
Loading

0 comments on commit e96dfb6

Please sign in to comment.