oneclient support
Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
parent
edf3916c71
commit
38199e90b7
|
|
@ -101,6 +101,8 @@ ADD docker/zfs /usr/local/bin/zfs
|
|||
RUN chmod +x /usr/local/bin/zfs
|
||||
ADD docker/zpool /usr/local/bin/zpool
|
||||
RUN chmod +x /usr/local/bin/zpool
|
||||
ADD docker/oneclient /usr/local/bin/oneclient
|
||||
RUN chmod +x /usr/local/bin/oneclient
|
||||
|
||||
# Run as a non-root user
|
||||
RUN useradd --create-home csi \
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
chroot /host /usr/bin/env -i PATH="/sbin:/bin:/usr/bin:/usr/sbin" oneclient "${@:1}"
|
||||
|
|
@ -4,6 +4,7 @@ const os = require("os");
|
|||
const fs = require("fs");
|
||||
const { GrpcError, grpc } = require("../utils/grpc");
|
||||
const { Mount } = require("../utils/mount");
|
||||
const { OneClient } = require("../utils/oneclient");
|
||||
const { Filesystem } = require("../utils/filesystem");
|
||||
const { ISCSI } = require("../utils/iscsi");
|
||||
const semver = require("semver");
|
||||
|
|
@ -327,11 +328,19 @@ class CsiBaseDriver {
|
|||
if (normalizedSecrets.mount_flags) {
|
||||
mount_flags.push(normalizedSecrets.mount_flags);
|
||||
}
|
||||
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");
|
||||
switch (node_attach_driver) {
|
||||
case "oneclient":
|
||||
// move along
|
||||
break;
|
||||
default:
|
||||
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");
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
semver.satisfies(driver.ctx.csiVersion, ">=1.5.0") &&
|
||||
|
|
@ -566,6 +575,45 @@ class CsiBaseDriver {
|
|||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "oneclient":
|
||||
let oneclient = new OneClient();
|
||||
device = "oneclient";
|
||||
result = await mount.deviceIsMountedAtPath(device, staging_target_path);
|
||||
if (result) {
|
||||
return {};
|
||||
}
|
||||
|
||||
if (volume_context.space_names) {
|
||||
volume_context.space_names.split(",").forEach((space) => {
|
||||
mount_flags.push("--space", space);
|
||||
});
|
||||
}
|
||||
|
||||
if (volume_context.space_ids) {
|
||||
volume_context.space_ids.split(",").forEach((space) => {
|
||||
mount_flags.push("--space-id", space);
|
||||
});
|
||||
}
|
||||
|
||||
if (volume_context.token) {
|
||||
mount_flags.push("-t", volume_context.token);
|
||||
}
|
||||
|
||||
result = await oneclient.mount(
|
||||
staging_target_path,
|
||||
["-H", volume_context.server].concat(mount_flags)
|
||||
);
|
||||
|
||||
if (result) {
|
||||
return {};
|
||||
}
|
||||
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
`failed to mount oneclient: ${volume_context.server}`
|
||||
);
|
||||
|
||||
break;
|
||||
case "zfs-local":
|
||||
// TODO: make this a geneic zb instance (to ensure works with node-manual driver)
|
||||
|
|
|
|||
|
|
@ -121,6 +121,10 @@ class NodeManualDriver extends CsiBaseDriver {
|
|||
driverResourceType = "filesystem";
|
||||
fs_types = ["lustre"];
|
||||
break;
|
||||
case "oneclient":
|
||||
driverResourceType = "filesystem";
|
||||
fs_types = ["oneclient", "fuse.oneclient"];
|
||||
break;
|
||||
case "iscsi":
|
||||
driverResourceType = "volume";
|
||||
fs_types = ["ext3", "ext4", "ext4dev", "xfs"];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,147 @@
|
|||
const cp = require("child_process");
|
||||
|
||||
DEFAULT_TIMEOUT = process.env.MOUNT_DEFAULT_TIMEOUT || 30000;
|
||||
|
||||
/**
|
||||
* - https://github.com/onedata/oneclient
|
||||
*/
|
||||
class OneClient {
|
||||
constructor(options = {}) {
|
||||
const oneclient = this;
|
||||
oneclient.options = options;
|
||||
|
||||
options.paths = options.paths || {};
|
||||
if (!options.paths.oneclient) {
|
||||
options.paths.oneclient = "oneclient";
|
||||
}
|
||||
|
||||
if (!options.paths.sudo) {
|
||||
options.paths.sudo = "/usr/bin/sudo";
|
||||
}
|
||||
|
||||
if (!options.paths.chroot) {
|
||||
options.paths.chroot = "/usr/sbin/chroot";
|
||||
}
|
||||
|
||||
if (!options.timeout) {
|
||||
options.timeout = 10 * 60 * 1000;
|
||||
}
|
||||
|
||||
if (!options.executor) {
|
||||
options.executor = {
|
||||
spawn: cp.spawn,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* oneclient [options] <directory>
|
||||
*
|
||||
* @param {*} target
|
||||
* @param {*} options
|
||||
*/
|
||||
async mount(target, options = []) {
|
||||
const oneclient = this;
|
||||
let args = [];
|
||||
args = args.concat(options);
|
||||
args = args.concat([target]);
|
||||
|
||||
let result;
|
||||
try {
|
||||
result = await oneclient.exec(oneclient.options.paths.oneclient, args);
|
||||
return result;
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* oneclient -u <directory>
|
||||
*
|
||||
* @param {*} target
|
||||
*/
|
||||
async umount(target) {
|
||||
const oneclient = this;
|
||||
let args = ["-u"];
|
||||
args.push(target);
|
||||
|
||||
try {
|
||||
await oneclient.exec(oneclient.options.paths.oneclient, args);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
exec(command, args, options = {}) {
|
||||
if (!options.hasOwnProperty("timeout")) {
|
||||
options.timeout = DEFAULT_TIMEOUT;
|
||||
}
|
||||
|
||||
const oneclient = this;
|
||||
args = args || [];
|
||||
|
||||
let timeout;
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
|
||||
if (oneclient.options.sudo) {
|
||||
args.unshift(command);
|
||||
command = oneclient.options.paths.sudo;
|
||||
}
|
||||
|
||||
// replace -t <token> with -t redacted
|
||||
const regex = /(?<=\-t) (?:[^\s]+)/gi;
|
||||
const cleansedLog = `${command} ${args.join(" ")}`.replace(
|
||||
regex,
|
||||
" redacted"
|
||||
);
|
||||
|
||||
console.log("executing oneclient command: %s", cleansedLog);
|
||||
const child = oneclient.options.executor.spawn(command, args, options);
|
||||
|
||||
/**
|
||||
* timeout option natively supported since v16
|
||||
* TODO: properly handle this based on nodejs version
|
||||
*/
|
||||
let didTimeout = false;
|
||||
if (options && options.timeout) {
|
||||
timeout = setTimeout(() => {
|
||||
didTimeout = true;
|
||||
child.kill(options.killSignal || "SIGTERM");
|
||||
}, options.timeout);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
child.stdout.on("data", function (data) {
|
||||
stdout = stdout + data;
|
||||
});
|
||||
|
||||
child.stderr.on("data", function (data) {
|
||||
stderr = stderr + data;
|
||||
});
|
||||
|
||||
child.on("close", function (code) {
|
||||
const result = { code, stdout, stderr, timeout: false };
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
|
||||
// timeout scenario
|
||||
if (code === null) {
|
||||
result.timeout = true;
|
||||
reject(result);
|
||||
}
|
||||
|
||||
if (code) {
|
||||
reject(result);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.OneClient = OneClient;
|
||||
Loading…
Reference in New Issue