further abstraction to support zfs-local
Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
parent
7c5448bff7
commit
94f6df240b
|
|
@ -1,12 +1,50 @@
|
||||||
const { ControllerZfsSshBaseDriver } = require("../controller-zfs-ssh");
|
const { ControllerZfsBaseDriver } = require("../controller-zfs");
|
||||||
const { GrpcError, grpc } = require("../../utils/grpc");
|
const { GrpcError, grpc } = require("../../utils/grpc");
|
||||||
|
const SshClient = require("../../utils/ssh").SshClient;
|
||||||
const sleep = require("../../utils/general").sleep;
|
const sleep = require("../../utils/general").sleep;
|
||||||
|
const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
||||||
|
|
||||||
const Handlebars = require("handlebars");
|
const Handlebars = require("handlebars");
|
||||||
|
|
||||||
const ISCSI_ASSETS_NAME_PROPERTY_NAME = "democratic-csi:iscsi_assets_name";
|
const ISCSI_ASSETS_NAME_PROPERTY_NAME = "democratic-csi:iscsi_assets_name";
|
||||||
|
|
||||||
class ControllerZfsGenericDriver extends ControllerZfsSshBaseDriver {
|
class ControllerZfsGenericDriver extends ControllerZfsBaseDriver {
|
||||||
|
getExecClient() {
|
||||||
|
return new SshClient({
|
||||||
|
logger: this.ctx.logger,
|
||||||
|
connection: this.options.sshConnection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getZetabyte() {
|
||||||
|
const execClient = this.getExecClient();
|
||||||
|
const options = {};
|
||||||
|
options.executor = new ZfsSshProcessManager(execClient);
|
||||||
|
options.idempotent = true;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.options.zfs.hasOwnProperty("cli") &&
|
||||||
|
this.options.zfs.cli &&
|
||||||
|
this.options.zfs.cli.hasOwnProperty("paths")
|
||||||
|
) {
|
||||||
|
options.paths = this.options.zfs.cli.paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.options.zfs.hasOwnProperty("cli") &&
|
||||||
|
this.options.zfs.cli &&
|
||||||
|
this.options.zfs.cli.hasOwnProperty("sudoEnabled")
|
||||||
|
) {
|
||||||
|
options.sudo = this.getSudoEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.setZetabyteCustomOptions === "function") {
|
||||||
|
await this.setZetabyteCustomOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Zetabyte(options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cannot make this a storage class parameter as storage class/etc context is *not* sent
|
* cannot make this a storage class parameter as storage class/etc context is *not* sent
|
||||||
* into various calls such as GetControllerCapabilities etc
|
* into various calls such as GetControllerCapabilities etc
|
||||||
|
|
@ -30,7 +68,7 @@ class ControllerZfsGenericDriver extends ControllerZfsSshBaseDriver {
|
||||||
*/
|
*/
|
||||||
async createShare(call, datasetName) {
|
async createShare(call, datasetName) {
|
||||||
const zb = await this.getZetabyte();
|
const zb = await this.getZetabyte();
|
||||||
const sshClient = this.getSshClient();
|
const execClient = this.getExecClient();
|
||||||
|
|
||||||
let properties;
|
let properties;
|
||||||
let response;
|
let response;
|
||||||
|
|
@ -194,7 +232,7 @@ create /backstores/block/${iscsiName}
|
||||||
|
|
||||||
async deleteShare(call, datasetName) {
|
async deleteShare(call, datasetName) {
|
||||||
const zb = await this.getZetabyte();
|
const zb = await this.getZetabyte();
|
||||||
const sshClient = this.getSshClient();
|
const execClient = this.getExecClient();
|
||||||
|
|
||||||
let response;
|
let response;
|
||||||
let properties;
|
let properties;
|
||||||
|
|
@ -317,7 +355,7 @@ delete ${iscsiName}
|
||||||
}
|
}
|
||||||
|
|
||||||
async targetCliCommand(data) {
|
async targetCliCommand(data) {
|
||||||
const sshClient = this.getSshClient();
|
const execClient = this.getExecClient();
|
||||||
const driver = this;
|
const driver = this;
|
||||||
|
|
||||||
data = data.trim();
|
data = data.trim();
|
||||||
|
|
@ -361,8 +399,8 @@ delete ${iscsiName}
|
||||||
let options = {
|
let options = {
|
||||||
pty: true,
|
pty: true,
|
||||||
};
|
};
|
||||||
let response = await sshClient.exec(
|
let response = await execClient.exec(
|
||||||
sshClient.buildCommand(command, args),
|
execClient.buildCommand(command, args),
|
||||||
options
|
options
|
||||||
);
|
);
|
||||||
if (response.code != 0) {
|
if (response.code != 0) {
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ const VOLUME_CONTEXT_PROVISIONER_INSTANCE_ID_PROPERTY_NAME =
|
||||||
* - async getZetabyte()
|
* - async getZetabyte()
|
||||||
* - async setZetabyteCustomOptions(options) // optional
|
* - async setZetabyteCustomOptions(options) // optional
|
||||||
* - getDriverZfsResourceType() // return "filesystem" or "volume"
|
* - getDriverZfsResourceType() // return "filesystem" or "volume"
|
||||||
|
* - getFSTypes() // optional
|
||||||
|
* - getAccessModes() // optional
|
||||||
|
* - async getAccessibleTopology() // optional
|
||||||
* - async createShare(call, datasetName) // return appropriate volume_context for Node operations
|
* - async createShare(call, datasetName) // return appropriate volume_context for Node operations
|
||||||
* - async deleteShare(call, datasetName) // no return expected
|
* - async deleteShare(call, datasetName) // no return expected
|
||||||
* - async expandVolume(call, datasetName) // no return expected, used for restarting services etc if needed
|
* - async expandVolume(call, datasetName) // no return expected, used for restarting services etc if needed
|
||||||
|
|
@ -182,6 +185,43 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
await zb.zfs.destroy(datasetName + "@%", options);
|
await zb.zfs.destroy(datasetName + "@%", options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFSTypes() {
|
||||||
|
const driverZfsResourceType = this.getDriverZfsResourceType();
|
||||||
|
switch (driverZfsResourceType) {
|
||||||
|
case "filesystem":
|
||||||
|
return ["nfs", "cifs"];
|
||||||
|
case "volume":
|
||||||
|
return ["ext3", "ext4", "ext4dev", "xfs"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getAccessModes() {
|
||||||
|
const driverZfsResourceType = this.getDriverZfsResourceType();
|
||||||
|
switch (driverZfsResourceType) {
|
||||||
|
case "filesystem":
|
||||||
|
return [
|
||||||
|
"UNKNOWN",
|
||||||
|
"SINGLE_NODE_WRITER",
|
||||||
|
"SINGLE_NODE_SINGLE_WRITER", // added in v1.5.0
|
||||||
|
"SINGLE_NODE_MULTI_WRITER", // added in v1.5.0
|
||||||
|
"SINGLE_NODE_READER_ONLY",
|
||||||
|
"MULTI_NODE_READER_ONLY",
|
||||||
|
"MULTI_NODE_SINGLE_WRITER",
|
||||||
|
"MULTI_NODE_MULTI_WRITER",
|
||||||
|
];
|
||||||
|
case "volume":
|
||||||
|
return [
|
||||||
|
"UNKNOWN",
|
||||||
|
"SINGLE_NODE_WRITER",
|
||||||
|
"SINGLE_NODE_SINGLE_WRITER", // added in v1.5.0
|
||||||
|
"SINGLE_NODE_MULTI_WRITER", // added in v1.5.0
|
||||||
|
"SINGLE_NODE_READER_ONLY",
|
||||||
|
"MULTI_NODE_READER_ONLY",
|
||||||
|
"MULTI_NODE_SINGLE_WRITER",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assertCapabilities(capabilities) {
|
assertCapabilities(capabilities) {
|
||||||
const driverZfsResourceType = this.getDriverZfsResourceType();
|
const driverZfsResourceType = this.getDriverZfsResourceType();
|
||||||
this.ctx.logger.verbose("validating capabilities: %j", capabilities);
|
this.ctx.logger.verbose("validating capabilities: %j", capabilities);
|
||||||
|
|
@ -198,24 +238,13 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
capability.mount.fs_type &&
|
capability.mount.fs_type &&
|
||||||
!["nfs", "cifs"].includes(capability.mount.fs_type)
|
!this.getFSTypes().includes(capability.mount.fs_type)
|
||||||
) {
|
) {
|
||||||
message = `invalid fs_type ${capability.mount.fs_type}`;
|
message = `invalid fs_type ${capability.mount.fs_type}`;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!this.getAccessModes().includes(capability.access_mode.mode)) {
|
||||||
![
|
|
||||||
"UNKNOWN",
|
|
||||||
"SINGLE_NODE_WRITER",
|
|
||||||
"SINGLE_NODE_SINGLE_WRITER", // added in v1.5.0
|
|
||||||
"SINGLE_NODE_MULTI_WRITER", // added in v1.5.0
|
|
||||||
"SINGLE_NODE_READER_ONLY",
|
|
||||||
"MULTI_NODE_READER_ONLY",
|
|
||||||
"MULTI_NODE_SINGLE_WRITER",
|
|
||||||
"MULTI_NODE_MULTI_WRITER",
|
|
||||||
].includes(capability.access_mode.mode)
|
|
||||||
) {
|
|
||||||
message = `invalid access_mode, ${capability.access_mode.mode}`;
|
message = `invalid access_mode, ${capability.access_mode.mode}`;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -225,26 +254,14 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
if (capability.access_type == "mount") {
|
if (capability.access_type == "mount") {
|
||||||
if (
|
if (
|
||||||
capability.mount.fs_type &&
|
capability.mount.fs_type &&
|
||||||
!["ext3", "ext4", "ext4dev", "xfs"].includes(
|
!this.getFSTypes().includes(capability.mount.fs_type)
|
||||||
capability.mount.fs_type
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
message = `invalid fs_type ${capability.mount.fs_type}`;
|
message = `invalid fs_type ${capability.mount.fs_type}`;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (!this.getAccessModes().includes(capability.access_mode.mode)) {
|
||||||
![
|
|
||||||
"UNKNOWN",
|
|
||||||
"SINGLE_NODE_WRITER",
|
|
||||||
"SINGLE_NODE_SINGLE_WRITER", // added in v1.5.0
|
|
||||||
"SINGLE_NODE_MULTI_WRITER", // added in v1.5.0
|
|
||||||
"SINGLE_NODE_READER_ONLY",
|
|
||||||
"MULTI_NODE_READER_ONLY",
|
|
||||||
"MULTI_NODE_SINGLE_WRITER",
|
|
||||||
].includes(capability.access_mode.mode)
|
|
||||||
) {
|
|
||||||
message = `invalid access_mode, ${capability.access_mode.mode}`;
|
message = `invalid access_mode, ${capability.access_mode.mode}`;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -344,6 +361,11 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let accessible_topology;
|
||||||
|
if (typeof this.getAccessibleTopology === "function") {
|
||||||
|
accessible_topology = await this.getAccessibleTopology();
|
||||||
|
}
|
||||||
|
|
||||||
let volume = {
|
let volume = {
|
||||||
// remove parent dataset info
|
// remove parent dataset info
|
||||||
volume_id: row["name"].replace(new RegExp("^" + datasetName + "/"), ""),
|
volume_id: row["name"].replace(new RegExp("^" + datasetName + "/"), ""),
|
||||||
|
|
@ -353,6 +375,7 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
: row["volsize"],
|
: row["volsize"],
|
||||||
content_source: volume_content_source,
|
content_source: volume_content_source,
|
||||||
volume_context,
|
volume_context,
|
||||||
|
accessible_topology,
|
||||||
};
|
};
|
||||||
|
|
||||||
return volume;
|
return volume;
|
||||||
|
|
@ -1101,6 +1124,11 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
// this should give us a relatively sane way to clean up artifacts over time
|
// this should give us a relatively sane way to clean up artifacts over time
|
||||||
await zb.zfs.set(datasetName, { [SUCCESS_PROPERTY_NAME]: "true" });
|
await zb.zfs.set(datasetName, { [SUCCESS_PROPERTY_NAME]: "true" });
|
||||||
|
|
||||||
|
let accessible_topology;
|
||||||
|
if (typeof this.getAccessibleTopology === "function") {
|
||||||
|
accessible_topology = await this.getAccessibleTopology();
|
||||||
|
}
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
volume: {
|
volume: {
|
||||||
volume_id: name,
|
volume_id: name,
|
||||||
|
|
@ -1112,6 +1140,7 @@ class ControllerZfsBaseDriver extends CsiBaseDriver {
|
||||||
: 0,
|
: 0,
|
||||||
content_source: volume_content_source,
|
content_source: volume_content_source,
|
||||||
volume_context,
|
volume_context,
|
||||||
|
accessible_topology,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
const { ControllerZfsSshBaseDriver } = require("../controller-zfs-ssh");
|
const { ControllerZfsBaseDriver } = require("../controller-zfs");
|
||||||
const { GrpcError, grpc } = require("../../utils/grpc");
|
const { GrpcError, grpc } = require("../../utils/grpc");
|
||||||
|
const SshClient = require("../../utils/ssh").SshClient;
|
||||||
const HttpClient = require("./http").Client;
|
const HttpClient = require("./http").Client;
|
||||||
|
const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
||||||
|
|
||||||
const Handlebars = require("handlebars");
|
const Handlebars = require("handlebars");
|
||||||
|
|
||||||
|
|
@ -18,7 +20,43 @@ const FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME =
|
||||||
|
|
||||||
// used for in-memory cache of the version info
|
// used for in-memory cache of the version info
|
||||||
const FREENAS_SYSTEM_VERSION_CACHE_KEY = "freenas:system_version";
|
const FREENAS_SYSTEM_VERSION_CACHE_KEY = "freenas:system_version";
|
||||||
class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
||||||
|
getExecClient() {
|
||||||
|
return new SshClient({
|
||||||
|
logger: this.ctx.logger,
|
||||||
|
connection: this.options.sshConnection,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getZetabyte() {
|
||||||
|
const sshClient = this.getExecClient();
|
||||||
|
const options = {};
|
||||||
|
options.executor = new ZfsSshProcessManager(sshClient);
|
||||||
|
options.idempotent = true;
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.options.zfs.hasOwnProperty("cli") &&
|
||||||
|
this.options.zfs.cli &&
|
||||||
|
this.options.zfs.cli.hasOwnProperty("paths")
|
||||||
|
) {
|
||||||
|
options.paths = this.options.zfs.cli.paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this.options.zfs.hasOwnProperty("cli") &&
|
||||||
|
this.options.zfs.cli &&
|
||||||
|
this.options.zfs.cli.hasOwnProperty("sudoEnabled")
|
||||||
|
) {
|
||||||
|
options.sudo = this.getSudoEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof this.setZetabyteCustomOptions === "function") {
|
||||||
|
await this.setZetabyteCustomOptions(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Zetabyte(options);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* cannot make this a storage class parameter as storage class/etc context is *not* sent
|
* cannot make this a storage class parameter as storage class/etc context is *not* sent
|
||||||
* into various calls such as GetControllerCapabilities etc
|
* into various calls such as GetControllerCapabilities etc
|
||||||
|
|
@ -169,7 +207,7 @@ class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
||||||
async createShare(call, datasetName) {
|
async createShare(call, datasetName) {
|
||||||
const driver = this;
|
const driver = this;
|
||||||
const driverShareType = this.getDriverShareType();
|
const driverShareType = this.getDriverShareType();
|
||||||
const sshClient = this.getSshClient();
|
const execClient = this.getExecClient();
|
||||||
const httpClient = await this.getHttpClient();
|
const httpClient = await this.getHttpClient();
|
||||||
const apiVersion = httpClient.getApiVersion();
|
const apiVersion = httpClient.getApiVersion();
|
||||||
const zb = await this.getZetabyte();
|
const zb = await this.getZetabyte();
|
||||||
|
|
@ -1626,7 +1664,7 @@ class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
||||||
|
|
||||||
async expandVolume(call, datasetName) {
|
async expandVolume(call, datasetName) {
|
||||||
const driverShareType = this.getDriverShareType();
|
const driverShareType = this.getDriverShareType();
|
||||||
const sshClient = this.getSshClient();
|
const execClient = this.getExecClient();
|
||||||
const zb = await this.getZetabyte();
|
const zb = await this.getZetabyte();
|
||||||
|
|
||||||
switch (driverShareType) {
|
switch (driverShareType) {
|
||||||
|
|
@ -1645,7 +1683,7 @@ class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
||||||
properties[FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME].value;
|
properties[FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME].value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* command = sshClient.buildCommand("systemctl", ["reload", "scst"]);
|
* command = execClient.buildCommand("systemctl", ["reload", "scst"]);
|
||||||
* does not help ^
|
* does not help ^
|
||||||
*
|
*
|
||||||
* echo 1 > /sys/kernel/scst_tgt/devices/${iscsiName}/resync_size
|
* echo 1 > /sys/kernel/scst_tgt/devices/${iscsiName}/resync_size
|
||||||
|
|
@ -1657,13 +1695,13 @@ class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
||||||
* midclt resync_lun_size_for_zvol tank/foo/bar
|
* midclt resync_lun_size_for_zvol tank/foo/bar
|
||||||
* works on SCALE only ^
|
* works on SCALE only ^
|
||||||
*/
|
*/
|
||||||
command = sshClient.buildCommand("sh", [
|
command = execClient.buildCommand("sh", [
|
||||||
"-c",
|
"-c",
|
||||||
`echo 1 > /sys/kernel/scst_tgt/devices/${iscsiName}/resync_size`,
|
`echo 1 > /sys/kernel/scst_tgt/devices/${iscsiName}/resync_size`,
|
||||||
]);
|
]);
|
||||||
reload = true;
|
reload = true;
|
||||||
} else {
|
} else {
|
||||||
command = sshClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
|
command = execClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
|
||||||
reload = true;
|
reload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1677,7 +1715,7 @@ class FreeNASSshDriver extends ControllerZfsSshBaseDriver {
|
||||||
command
|
command
|
||||||
);
|
);
|
||||||
|
|
||||||
let response = await sshClient.exec(command);
|
let response = await execClient.exec(command);
|
||||||
if (response.code != 0) {
|
if (response.code != 0) {
|
||||||
throw new GrpcError(
|
throw new GrpcError(
|
||||||
grpc.status.UNKNOWN,
|
grpc.status.UNKNOWN,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue