implement nvmeof node expand

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen 2022-12-29 21:58:47 -07:00
parent 4e99e81255
commit 9bf6d46b66
2 changed files with 103 additions and 8 deletions

View File

@ -980,14 +980,13 @@ class CsiBaseDriver {
} }
// find namespace device // find namespace device
// rescan in scenarios when login previously occurred but volumes never appeared
// must be the NVMe char device, not the namespace device
await nvmeof.rescanNamespace(controllerDevice);
let namespaceDevice; let namespaceDevice;
try { try {
await GeneralUtils.retry(15, 2000, async () => { await GeneralUtils.retry(15, 2000, async () => {
// rescan in scenarios when login previously occurred but volumes never appeared
// must be the NVMe char device, not the namespace device
await nvmeof.rescanNamespace(controllerDevice);
namespaceDevice = namespaceDevice =
await nvmeof.namespaceDevicePathByTransportNQNNamespace( await nvmeof.namespaceDevicePathByTransportNQNNamespace(
nvmeofConnection.transport, nvmeofConnection.transport,
@ -3499,6 +3498,8 @@ class CsiBaseDriver {
const driver = this; const driver = this;
const mount = driver.getDefaultMountInstance(); const mount = driver.getDefaultMountInstance();
const filesystem = driver.getDefaultFilesystemInstance(); const filesystem = driver.getDefaultFilesystemInstance();
const nvmeof = driver.getDefaultNVMEoFInstance();
let device; let device;
let fs_info; let fs_info;
let device_path; let device_path;
@ -3561,6 +3562,14 @@ class CsiBaseDriver {
rescan_devices.push(device); rescan_devices.push(device);
for (let sdevice of rescan_devices) { for (let sdevice of rescan_devices) {
let is_nvmeof = await filesystem.deviceIsNVMEoF(sdevice);
if (is_nvmeof) {
let controllers =
await nvmeof.getControllersByNamespaceDeviceName(sdevice);
for (let controller of controllers) {
await nvmeof.rescanNamespace(`/dev/${controller.Controller}`);
}
}
// TODO: technically rescan is only relevant/available for remote drives // TODO: technically rescan is only relevant/available for remote drives
// such as iscsi etc, should probably limit this call as appropriate // such as iscsi etc, should probably limit this call as appropriate
// for now crudely checking the scenario inside the method itself // for now crudely checking the scenario inside the method itself

View File

@ -153,6 +153,54 @@ class NVMEoF {
await nvmeof.exec(nvmeof.options.paths.nvme, args); await nvmeof.exec(nvmeof.options.paths.nvme, args);
} }
async deviceIsNamespaceDevice(device) {
const nvmeof = this;
device = device.replace("/dev/", "");
const subsystems = await nvmeof.getSubsystems();
for (let subsystem of subsystems) {
// check subsystem namespaces
if (subsystem.Namespaces) {
for (let namespace of subsystem.Namespaces) {
if (namespace.NameSpace == device) {
return true;
}
}
}
// check controller namespaces
if (subsystem.Controllers) {
for (let controller of subsystem.Controllers) {
if (controller.Namespaces) {
for (let namespace of controller.Namespaces) {
if (namespace.NameSpace == device) {
return true;
}
}
}
}
}
}
return false;
}
async deviceIsControllerDevice(device) {
const nvmeof = this;
device = device.replace("/dev/", "");
const subsystems = await nvmeof.getSubsystems();
for (let subsystem of subsystems) {
if (subsystem.Controllers) {
for (let controller of subsystem.Controllers) {
if (controller.Controller == device) {
return true;
}
}
}
}
return false;
}
async parseTransport(transport) { async parseTransport(transport) {
if (typeof transport === "object") { if (typeof transport === "object") {
return transport; return transport;
@ -267,9 +315,9 @@ class NVMEoF {
/** /**
* used to normalize subsystem list/response across different versions of nvme-cli * used to normalize subsystem list/response across different versions of nvme-cli
* *
* @param {*} result * @param {*} result
* @returns * @returns
*/ */
async getNormalizedSubsystems(result) { async getNormalizedSubsystems(result) {
let subsystems = []; let subsystems = [];
@ -298,6 +346,44 @@ class NVMEoF {
nvmeof.logger.warn(`failed to find subsystem for nqn: ${nqn}`); nvmeof.logger.warn(`failed to find subsystem for nqn: ${nqn}`);
} }
async getControllersByNamespaceDeviceName(name) {
const nvmeof = this;
name = name.replace("/dev/", "");
let nativeMultipathEnabled = await nvmeof.nativeMultipathEnabled();
const subsystems = await nvmeof.getSubsystems();
if (nativeMultipathEnabled) {
// using per-subsystem namespace
for (let subsystem of subsystems) {
if (subsystem.Namespaces) {
for (let namespace of subsystem.Namespaces) {
if (namespace.NameSpace == name) {
return subsystem.Controllers;
}
}
}
}
} else {
// using per-controller namespace
for (let subsystem of subsystems) {
if (subsystem.Controllers) {
for (let controller of subsystem.Controllers) {
if (controller.Namespaces) {
for (let namespace of controller.Namespaces) {
if (namespace.NameSpace == name) {
return subsystem.Controllers;
}
}
}
}
}
}
}
nvmeof.logger.warn(`failed to find controllers for device: ${name}`);
return [];
}
async getControllerByTransportNQN(transport, nqn) { async getControllerByTransportNQN(transport, nqn) {
const nvmeof = this; const nvmeof = this;
transport = await nvmeof.parseTransport(transport); transport = await nvmeof.parseTransport(transport);