democratic-csi/src/driver/controller-zfs-local/index.js

242 lines
6.2 KiB
JavaScript

const _ = require("lodash");
const { ControllerZfsBaseDriver } = require("../controller-zfs");
const { GrpcError, grpc } = require("../../utils/grpc");
const GeneralUtils = require("../../utils/general");
const LocalCliExecClient =
require("../../utils/zfs_local_exec_client").LocalCliClient;
const { Zetabyte } = require("../../utils/zfs");
const ZFS_ASSET_NAME_PROPERTY_NAME = "zfs_asset_name";
const NODE_TOPOLOGY_KEY_NAME = "org.democratic-csi.topology/node";
const __REGISTRY_NS__ = "ControllerZfsLocalDriver";
class ControllerZfsLocalDriver extends ControllerZfsBaseDriver {
constructor(ctx, options) {
const i_caps = _.get(
options,
"service.identity.capabilities.service",
false
);
super(...arguments);
if (!i_caps) {
this.ctx.logger.debug("setting zfs-local identity service caps");
options.service.identity.capabilities.service = [
//"UNKNOWN",
"CONTROLLER_SERVICE",
"VOLUME_ACCESSIBILITY_CONSTRAINTS",
];
}
}
getExecClient() {
return this.ctx.registry.get(`${__REGISTRY_NS__}:exec_client`, () => {
return new LocalCliExecClient({
logger: this.ctx.logger,
});
});
}
async getZetabyte() {
return this.ctx.registry.getAsync(`${__REGISTRY_NS__}:zb`, async () => {
const execClient = this.getExecClient();
const options = {};
options.executor = 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;
}
*/
// use env based paths to allow for custom wrapper scripts to chroot to the host
options.paths = {
zfs: "zfs",
zpool: "zpool",
sudo: "sudo",
chroot: "chroot",
};
options.sudo = _.get(this.options, "zfs.cli.sudoEnabled", false);
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
* into various calls such as GetControllerCapabilities etc
*/
getDriverZfsResourceType() {
switch (this.options.driver) {
case "zfs-local-dataset":
return "filesystem";
case "zfs-local-zvol":
return "volume";
default:
throw new Error("unknown driver: " + this.ctx.args.driver);
}
}
getFSTypes() {
const driverZfsResourceType = this.getDriverZfsResourceType();
switch (driverZfsResourceType) {
case "filesystem":
return ["zfs"];
case "volume":
return GeneralUtils.default_supported_block_filesystems();
}
}
/**
* Although it is conter-intuitive to advertise node-local volumes as RWX we
* do so here to provide an easy out-of-the-box experience as users will by
* default want to provision volumes of RWX. The topology contraints
* implicity will enforce only a single node can use the volume at a given
* time.
*
* @returns Array
*/
getAccessModes(capability) {
let access_modes = _.get(this.options, "csi.access_modes", null);
if (access_modes !== null) {
return access_modes;
}
const driverZfsResourceType = this.getDriverZfsResourceType();
switch (driverZfsResourceType) {
case "filesystem":
access_modes = [
"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",
];
break;
case "volume":
access_modes = [
"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",
];
break;
}
if (
capability.access_type == "block" &&
!access_modes.includes("MULTI_NODE_MULTI_WRITER")
) {
access_modes.push("MULTI_NODE_MULTI_WRITER");
}
return access_modes;
}
/**
* csi controller service
*
* should create any necessary share resources and return volume context
*
* @param {*} datasetName
*/
async createShare(call, datasetName) {
let volume_context = {};
switch (this.options.driver) {
case "zfs-local-dataset":
volume_context = {
node_attach_driver: "zfs-local",
[ZFS_ASSET_NAME_PROPERTY_NAME]: datasetName,
};
return volume_context;
case "zfs-local-zvol":
volume_context = {
node_attach_driver: "zfs-local",
[ZFS_ASSET_NAME_PROPERTY_NAME]: datasetName,
};
return volume_context;
default:
throw new GrpcError(
grpc.status.FAILED_PRECONDITION,
`invalid configuration: unknown driver ${this.options.driver}`
);
}
}
/**
* csi controller service
*
* @param {*} call
* @param {*} datasetName
* @returns
*/
async deleteShare(call, datasetName) {
return {};
}
/**
* csi controller service
*
* @param {*} call
* @param {*} datasetName
*/
async expandVolume(call, datasetName) {}
/**
* List of topologies associated with the *volume*
*
* @returns array
*/
async getAccessibleTopology() {
const response = await super.NodeGetInfo(...arguments);
return [
{
segments: {
[NODE_TOPOLOGY_KEY_NAME]: response.node_id,
},
},
];
}
/**
* Add node topologies
*
* @param {*} call
* @returns
*/
async NodeGetInfo(call) {
const response = await super.NodeGetInfo(...arguments);
response.accessible_topology = {
segments: {
[NODE_TOPOLOGY_KEY_NAME]: response.node_id,
},
};
return response;
}
}
module.exports.ControllerZfsLocalDriver = ControllerZfsLocalDriver;