foundations for more flexible iscsi connections

Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
Travis Glenn Hansen
2021-09-01 21:42:31 -06:00
parent 339c53c93b
commit aa3f5a5484
3 changed files with 146 additions and 10 deletions
+51 -9
View File
@@ -298,6 +298,14 @@ class CsiBaseDriver {
call.request.volume_context.provisioner_driver_instance_id
);
/*
let mount_options = await mount.getMountOptions(staging_target_path);
console.log(mount_options);
console.log(await mount.getMountOptionValue(mount_options, "stripe"));
console.log(await mount.getMountOptionPresent(mount_options, "stripee"));
throw new Error("foobar");
*/
if (access_type == "mount") {
fs_type = capability.mount.fs_type;
mount_flags = capability.mount.mount_flags || [];
@@ -307,6 +315,10 @@ class CsiBaseDriver {
}
mount_flags.push("defaults");
// https://github.com/karelzak/util-linux/issues/1429
//mount_flags.push("x-democratic-csi.managed");
//mount_flags.push("x-democratic-csi.staged");
if (
semver.satisfies(driver.ctx.csiVersion, ">=1.5.0") &&
driver.options.service.node.capabilities.rpc.includes(
@@ -373,9 +385,27 @@ class CsiBaseDriver {
// ensure unique entries only
portals = [...new Set(portals)];
// stores actual device paths after iscsi login
let iscsiDevices = [];
// stores configuration of targets/iqn/luns to connect to
let iscsiConnections = [];
for (let portal of portals) {
iscsiConnections.push({
portal,
iqn: volume_context.iqn,
lun: volume_context.lun,
});
}
/**
* TODO: allow sending in iscsiConnection in a raw/manual format
* TODO: allow option to determine if send_targets should be invoked
* TODO: allow option to control whether nodedb entry should be created by driver
* TODO: allow option to control whether nodedb entry should be deleted by driver
*/
for (let iscsiConnection of iscsiConnections) {
// create DB entry
// https://library.netapp.com/ecmdocs/ECMP1654943/html/GUID-8EC685B4-8CB6-40D8-A8D5-031A3899BCDC.html
// put these options in place to force targets managed by csi to be explicitly attached (in the case of unclearn shutdown etc)
@@ -391,24 +421,27 @@ class CsiBaseDriver {
}
}
await iscsi.iscsiadm.createNodeDBEntry(
volume_context.iqn,
portal,
iscsiConnection.iqn,
iscsiConnection.portal,
nodeDB
);
// login
await iscsi.iscsiadm.login(volume_context.iqn, portal);
await iscsi.iscsiadm.login(
iscsiConnection.iqn,
iscsiConnection.portal
);
// get associated session
let session = await iscsi.iscsiadm.getSession(
volume_context.iqn,
portal
iscsiConnection.iqn,
iscsiConnection.portal
);
// rescan in scenarios when login previously occurred but volumes never appeared
await iscsi.iscsiadm.rescanSession(session);
// find device name
device = `/dev/disk/by-path/ip-${portal}-iscsi-${volume_context.iqn}-lun-${volume_context.lun}`;
device = `/dev/disk/by-path/ip-${iscsiConnection.portal}-iscsi-${iscsiConnection.iqn}-lun-${iscsiConnection.lun}`;
let deviceByPath = device;
// can take some time for device to show up, loop for some period
@@ -439,7 +472,7 @@ class CsiBaseDriver {
iscsiDevices.push(device);
driver.ctx.logger.info(
`successfully logged into portal ${portal} and created device ${deviceByPath} with realpath ${device}`
`successfully logged into portal ${iscsiConnection.portal} and created device ${deviceByPath} with realpath ${device}`
);
}
}
@@ -461,7 +494,7 @@ class CsiBaseDriver {
);
}
if (iscsiDevices.length != portals.length) {
if (iscsiDevices.length != iscsiConnections.length) {
driver.ctx.logger.warn(
`failed to attach all iscsi devices/targets/portals`
);
@@ -484,7 +517,8 @@ class CsiBaseDriver {
iscsiDevices.includes(value)
);
const useMultipath = portals.length > 1 || commonDevices.length > 0;
const useMultipath =
iscsiConnections.length > 1 || commonDevices.length > 0;
// discover multipath device to use
if (useMultipath) {
@@ -679,6 +713,8 @@ class CsiBaseDriver {
//result = await mount.pathIsMounted(block_path);
//result = await mount.pathIsMounted(staging_target_path)
// TODO: use the x-* mount options to detect if we should delete target
try {
result = await mount.pathIsMounted(block_path);
} catch (err) {
@@ -900,7 +936,13 @@ class CsiBaseDriver {
}
bind_mount_flags.push("defaults");
// https://github.com/karelzak/util-linux/issues/1429
//bind_mount_flags.push("x-democratic-csi.managed");
//bind_mount_flags.push("x-democratic-csi.published");
if (readonly) bind_mount_flags.push("ro");
// , "x-democratic-csi.ro"
switch (node_attach_driver) {
case "nfs":
+5
View File
@@ -326,9 +326,14 @@ class Filesystem {
try {
result = await filesystem.exec("blkid", args);
} catch (err) {
if (err.code == 2 && err.stderr.includes("No such device or address")) {
throw err;
}
if (err.code == 2) {
return false;
}
throw err;
}
+90 -1
View File
@@ -145,7 +145,7 @@ class Mount {
*
* @param {*} path
*/
async getMountDetails(path, extraOutputProperties = []) {
async getMountDetails(path, extraOutputProperties = [], extraArgs = []) {
const mount = this;
let args = [];
const common_options = JSON.parse(JSON.stringify(FINDMNT_COMMON_OPTIONS));
@@ -156,6 +156,7 @@ class Mount {
args = args.concat(["--mountpoint", path]);
args = args.concat(common_options);
args = args.concat(extraArgs);
let result;
try {
@@ -167,6 +168,94 @@ class Mount {
}
}
/**
* parse a mount options string into an array
*
* @param {*} options
* @returns
*/
async parseMountOptions(options) {
if (!options) {
return [];
}
if (Array.isArray(options)) {
return options;
}
options = options.split(",");
return options;
}
/**
* Given the set of mount options and sought after option, return true if the option is present
*
* @param {*} options
* @param {*} option
* @returns
*/
async getMountOptionPresent(options, option) {
const mount = this;
if (!Array.isArray(options)) {
options = await mount.parseMountOptions(options);
}
for (let i of options) {
let parts = i.split("=", 2);
if (parts[0] == option) {
return true;
}
}
return false;
}
/**
* Get the value of the given mount option
*
* if the mount option is present by has no value null is returned
* if the mount option is NOT present undefined is returned
* is the mount option has a value that value is returned
*
* @param {*} options
* @param {*} option
* @returns
*/
async getMountOptionValue(options, option) {
const mount = this;
if (!Array.isArray(options)) {
options = await mount.parseMountOptions(options);
}
for (let i of options) {
let parts = i.split("=", 2);
if (parts[0] == option) {
if (typeof parts[1] === "undefined") {
return null;
} else {
return parts[1];
}
}
}
return undefined;
}
/**
* Get mount optsion for a given path
*
* @param {*} path
* @returns Array
*/
async getMountOptions(path) {
const mount = this;
let details = await mount.getMountDetails(path, [], ["-m"]);
return await mount.parseMountOptions(details.options);
}
/**
* Get the device (source) at the given mount point
*