support setting custom binary paths for zfs, support custom dataset properties with templating
This commit is contained in:
parent
d6dbbbe951
commit
699b65d931
|
|
@ -18,6 +18,22 @@ sshConnection:
|
||||||
...
|
...
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
zfs:
|
zfs:
|
||||||
|
# can be used to override defaults if necessary
|
||||||
|
# the example below is useful for TrueNAS 12
|
||||||
|
#cli:
|
||||||
|
# paths:
|
||||||
|
# zfs: /usr/local/sbin/zfs
|
||||||
|
# zpool: /usr/local/sbin/zpool
|
||||||
|
# sudo: /usr/local/bin/sudo
|
||||||
|
# chroot: /usr/sbin/chroot
|
||||||
|
|
||||||
|
# can be used to set arbitrary values on the dataset/zvol
|
||||||
|
# can use handlebars templates with the parameters from the storage class/CO
|
||||||
|
#datasetProperties:
|
||||||
|
# "org.freenas:description": "{{ parameters.[csi.storage.k8s.io/pvc/namespace] }}/{{ parameters.[csi.storage.k8s.io/pvc/name] }}"
|
||||||
|
# "org.freenas:test": "{{ parameters.foo }}"
|
||||||
|
# "org.freenas:test2": "some value"
|
||||||
|
|
||||||
# total volume name (zvol/<datasetParentName>/<pvc name>) length cannot exceed 63 chars
|
# total volume name (zvol/<datasetParentName>/<pvc name>) length cannot exceed 63 chars
|
||||||
# https://www.ixsystems.com/documentation/freenas/11.2-U5/storage.html#zfs-zvol-config-opts-tab
|
# https://www.ixsystems.com/documentation/freenas/11.2-U5/storage.html#zfs-zvol-config-opts-tab
|
||||||
# standard volume naming overhead is 46 chars
|
# standard volume naming overhead is 46 chars
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,22 @@ sshConnection:
|
||||||
...
|
...
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
zfs:
|
zfs:
|
||||||
|
# can be used to override defaults if necessary
|
||||||
|
# the example below is useful for TrueNAS 12
|
||||||
|
#cli:
|
||||||
|
# paths:
|
||||||
|
# zfs: /usr/local/sbin/zfs
|
||||||
|
# zpool: /usr/local/sbin/zpool
|
||||||
|
# sudo: /usr/local/bin/sudo
|
||||||
|
# chroot: /usr/sbin/chroot
|
||||||
|
|
||||||
|
# can be used to set arbitrary values on the dataset/zvol
|
||||||
|
# can use handlebars templates with the parameters from the storage class/CO
|
||||||
|
#datasetProperties:
|
||||||
|
# "org.freenas:description": "{{ parameters.[csi.storage.k8s.io/pvc/namespace] }}/{{ parameters.[csi.storage.k8s.io/pvc/name] }}"
|
||||||
|
# "org.freenas:test": "{{ parameters.foo }}"
|
||||||
|
# "org.freenas:test2": "some value"
|
||||||
|
|
||||||
datasetParentName: tank/k8s/a/vols
|
datasetParentName: tank/k8s/a/vols
|
||||||
detachedSnapshotsDatasetParentName: tank/k8s/a/snaps
|
detachedSnapshotsDatasetParentName: tank/k8s/a/snaps
|
||||||
datasetEnableQuotas: true
|
datasetEnableQuotas: true
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ instance_id:
|
||||||
nfs:
|
nfs:
|
||||||
shareHost: server address
|
shareHost: server address
|
||||||
shareBasePath: "/some/path"
|
shareBasePath: "/some/path"
|
||||||
|
# shareHost:shareBasePath should be mounted at this location in the controller container
|
||||||
controllerBasePath: "/storage"
|
controllerBasePath: "/storage"
|
||||||
dirPermissionsMode: "0777"
|
dirPermissionsMode: "0777"
|
||||||
dirPermissionsUser: root
|
dirPermissionsUser: root
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,22 @@ service:
|
||||||
controller: {}
|
controller: {}
|
||||||
node: {}
|
node: {}
|
||||||
zfs:
|
zfs:
|
||||||
|
# can be used to override defaults if necessary
|
||||||
|
# the example below is useful for TrueNAS 12
|
||||||
|
#cli:
|
||||||
|
# paths:
|
||||||
|
# zfs: /usr/local/sbin/zfs
|
||||||
|
# zpool: /usr/local/sbin/zpool
|
||||||
|
# sudo: /usr/local/bin/sudo
|
||||||
|
# chroot: /usr/sbin/chroot
|
||||||
|
|
||||||
|
# can be used to set arbitrary values on the dataset/zvol
|
||||||
|
# can use handlebars templates with the parameters from the storage class/CO
|
||||||
|
#datasetProperties:
|
||||||
|
# "org.freenas:description": "{{ parameters.[csi.storage.k8s.io/pvc/namespace] }}/{{ parameters.[csi.storage.k8s.io/pvc/name] }}"
|
||||||
|
# "org.freenas:test": "{{ parameters.foo }}"
|
||||||
|
# "org.freenas:test2": "some value"
|
||||||
|
|
||||||
datasetParentName: tank/k8s/test
|
datasetParentName: tank/k8s/test
|
||||||
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,22 @@ service:
|
||||||
controller: {}
|
controller: {}
|
||||||
node: {}
|
node: {}
|
||||||
zfs:
|
zfs:
|
||||||
|
# can be used to override defaults if necessary
|
||||||
|
# the example below is useful for TrueNAS 12
|
||||||
|
#cli:
|
||||||
|
# paths:
|
||||||
|
# zfs: /usr/local/sbin/zfs
|
||||||
|
# zpool: /usr/local/sbin/zpool
|
||||||
|
# sudo: /usr/local/bin/sudo
|
||||||
|
# chroot: /usr/sbin/chroot
|
||||||
|
|
||||||
|
# can be used to set arbitrary values on the dataset/zvol
|
||||||
|
# can use handlebars templates with the parameters from the storage class/CO
|
||||||
|
#datasetProperties:
|
||||||
|
# "org.freenas:description": "{{ parameters.[csi.storage.k8s.io/pvc/namespace] }}/{{ parameters.[csi.storage.k8s.io/pvc/name] }}"
|
||||||
|
# "org.freenas:test": "{{ parameters.foo }}"
|
||||||
|
# "org.freenas:test2": "some value"
|
||||||
|
|
||||||
datasetParentName: tank/k8s/test
|
datasetParentName: tank/k8s/test
|
||||||
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -820,6 +820,18 @@
|
||||||
"protobufjs": "^5.0.3"
|
"protobufjs": "^5.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"handlebars": {
|
||||||
|
"version": "4.7.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz",
|
||||||
|
"integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==",
|
||||||
|
"requires": {
|
||||||
|
"minimist": "^1.2.5",
|
||||||
|
"neo-async": "^2.6.0",
|
||||||
|
"source-map": "^0.6.1",
|
||||||
|
"uglify-js": "^3.1.4",
|
||||||
|
"wordwrap": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"har-schema": {
|
"har-schema": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||||
|
|
@ -1127,6 +1139,11 @@
|
||||||
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
|
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"neo-async": {
|
||||||
|
"version": "2.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||||
|
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
|
||||||
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
|
|
@ -1502,6 +1519,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"source-map": {
|
||||||
|
"version": "0.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||||
|
},
|
||||||
"sprintf-js": {
|
"sprintf-js": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
|
@ -1696,6 +1718,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
|
||||||
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA=="
|
||||||
},
|
},
|
||||||
|
"uglify-js": {
|
||||||
|
"version": "3.10.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.3.tgz",
|
||||||
|
"integrity": "sha512-Lh00i69Uf6G74mvYpHCI9KVVXLcHW/xu79YTvH7Mkc9zyKUeSPz0owW0dguj0Scavns3ZOh3wY63J0Zb97Za2g==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"uri-js": {
|
"uri-js": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
|
||||||
|
|
@ -1806,6 +1834,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
|
||||||
},
|
},
|
||||||
|
"wordwrap": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
|
||||||
|
},
|
||||||
"wrap-ansi": {
|
"wrap-ansi": {
|
||||||
"version": "6.2.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
||||||
"bunyan": "^1.8.14",
|
"bunyan": "^1.8.14",
|
||||||
"eslint": "^7.4.0",
|
"eslint": "^7.4.0",
|
||||||
"grpc-uds": "^0.1.4",
|
"grpc-uds": "^0.1.4",
|
||||||
|
"handlebars": "^4.7.6",
|
||||||
"js-yaml": "^3.14.0",
|
"js-yaml": "^3.14.0",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ const SshClient = require("../../utils/ssh").SshClient;
|
||||||
const { GrpcError, grpc } = require("../../utils/grpc");
|
const { GrpcError, grpc } = require("../../utils/grpc");
|
||||||
|
|
||||||
const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
||||||
|
|
||||||
|
const Handlebars = require("handlebars");
|
||||||
const uuidv4 = require("uuid").v4;
|
const uuidv4 = require("uuid").v4;
|
||||||
|
|
||||||
// zfs common properties
|
// zfs common properties
|
||||||
|
|
@ -122,10 +124,18 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
|
|
||||||
getZetabyte() {
|
getZetabyte() {
|
||||||
const sshClient = this.getSshClient();
|
const sshClient = this.getSshClient();
|
||||||
return new Zetabyte({
|
const options = {};
|
||||||
executor: new ZfsSshProcessManager(sshClient),
|
options.executor = new ZfsSshProcessManager(sshClient);
|
||||||
idempotent: true,
|
options.idempotent = true;
|
||||||
});
|
|
||||||
|
if (
|
||||||
|
this.options.zfs.hasOwnProperty("cli") &&
|
||||||
|
this.options.zfs.cli.hasOwnProperty("paths")
|
||||||
|
) {
|
||||||
|
options.paths = this.options.zfs.cli.paths;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Zetabyte(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
getDatasetParentName() {
|
getDatasetParentName() {
|
||||||
|
|
@ -335,6 +345,20 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
let volume_content_source_volume_id;
|
let volume_content_source_volume_id;
|
||||||
let fullSnapshotName;
|
let fullSnapshotName;
|
||||||
let volumeProperties = {};
|
let volumeProperties = {};
|
||||||
|
|
||||||
|
// user-supplied properties
|
||||||
|
// put early to prevent stupid (user-supplied values overwriting system values)
|
||||||
|
if (driver.options.zfs.datasetProperties) {
|
||||||
|
for (let property in driver.options.zfs.datasetProperties) {
|
||||||
|
let value = driver.options.zfs.datasetProperties[property];
|
||||||
|
const template = Handlebars.compile(value);
|
||||||
|
|
||||||
|
volumeProperties[property] = template({
|
||||||
|
parameters: call.request.parameters,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
volumeProperties[VOLUME_CSI_NAME_PROPERTY_NAME] = name;
|
volumeProperties[VOLUME_CSI_NAME_PROPERTY_NAME] = name;
|
||||||
volumeProperties[MANAGED_PROPERTY_NAME] = "true";
|
volumeProperties[MANAGED_PROPERTY_NAME] = "true";
|
||||||
volumeProperties[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME] =
|
volumeProperties[VOLUME_CONTEXT_PROVISIONER_DRIVER_PROPERTY_NAME] =
|
||||||
|
|
@ -346,7 +370,6 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
|
|
||||||
// TODO: also set access_mode as property?
|
// TODO: also set access_mode as property?
|
||||||
// TODO: also set fsType as property?
|
// TODO: also set fsType as property?
|
||||||
// TODO: allow for users to configure arbitrary/custom properties to add
|
|
||||||
|
|
||||||
// zvol enables reservation by default
|
// zvol enables reservation by default
|
||||||
// this implements 'sparse' zvols
|
// this implements 'sparse' zvols
|
||||||
|
|
@ -691,8 +714,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
||||||
|
|
||||||
volume_context = await this.createShare(call, datasetName);
|
volume_context = await this.createShare(call, datasetName);
|
||||||
await zb.zfs.set(datasetName, {
|
await zb.zfs.set(datasetName, {
|
||||||
[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]:
|
[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]: JSON.stringify(volume_context),
|
||||||
"'" + JSON.stringify(volume_context) + "'",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
volume_context["provisioner_driver"] = driver.options.driver;
|
volume_context["provisioner_driver"] = driver.options.driver;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
const events = require("events");
|
const events = require("events");
|
||||||
const cp = require("child_process");
|
const cp = require("child_process");
|
||||||
|
|
||||||
|
const escapeShell = function (cmd) {
|
||||||
|
cmd = String(cmd);
|
||||||
|
return '"' + cmd.replace(/(["$`\\])/g, "\\$1") + '"';
|
||||||
|
};
|
||||||
|
|
||||||
class Zetabyte {
|
class Zetabyte {
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
const zb = this;
|
const zb = this;
|
||||||
|
|
@ -283,7 +288,8 @@ class Zetabyte {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (options.fsProperties) {
|
if (options.fsProperties) {
|
||||||
for (const [key, value] of Object.entries(options.fsProperties)) {
|
for (let [key, value] of Object.entries(options.fsProperties)) {
|
||||||
|
value = escapeShell(value);
|
||||||
args.push("-O");
|
args.push("-O");
|
||||||
args.push(`${key}=${value}`);
|
args.push(`${key}=${value}`);
|
||||||
}
|
}
|
||||||
|
|
@ -774,6 +780,7 @@ class Zetabyte {
|
||||||
* @param {*} value
|
* @param {*} value
|
||||||
*/
|
*/
|
||||||
set: function (pool, property, value) {
|
set: function (pool, property, value) {
|
||||||
|
value = escapeShell(value);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let args = [];
|
let args = [];
|
||||||
args.push("set");
|
args.push("set");
|
||||||
|
|
@ -913,7 +920,8 @@ class Zetabyte {
|
||||||
if (options.unmounted) args.push("-u");
|
if (options.unmounted) args.push("-u");
|
||||||
if (options.blocksize) args = args.concat(["-b", options.blocksize]);
|
if (options.blocksize) args = args.concat(["-b", options.blocksize]);
|
||||||
if (options.properties) {
|
if (options.properties) {
|
||||||
for (const [key, value] of Object.entries(options.properties)) {
|
for (let [key, value] of Object.entries(options.properties)) {
|
||||||
|
value = escapeShell(value);
|
||||||
args.push("-o");
|
args.push("-o");
|
||||||
args.push(`${key}=${value}`);
|
args.push(`${key}=${value}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1012,7 +1020,8 @@ class Zetabyte {
|
||||||
args.push("snapshot");
|
args.push("snapshot");
|
||||||
if (options.recurse) args.push("-r");
|
if (options.recurse) args.push("-r");
|
||||||
if (options.properties) {
|
if (options.properties) {
|
||||||
for (const [key, value] of Object.entries(options.properties)) {
|
for (let [key, value] of Object.entries(options.properties)) {
|
||||||
|
value = escapeShell(value);
|
||||||
args.push("-o");
|
args.push("-o");
|
||||||
args.push(`${key}=${value}`);
|
args.push(`${key}=${value}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1093,7 +1102,8 @@ class Zetabyte {
|
||||||
args.push("clone");
|
args.push("clone");
|
||||||
if (options.parents) args.push("-p");
|
if (options.parents) args.push("-p");
|
||||||
if (options.properties) {
|
if (options.properties) {
|
||||||
for (const [key, value] of Object.entries(options.properties)) {
|
for (let [key, value] of Object.entries(options.properties)) {
|
||||||
|
value = escapeShell(value);
|
||||||
args.push("-o");
|
args.push("-o");
|
||||||
args.push(`${key}=${value}`);
|
args.push(`${key}=${value}`);
|
||||||
}
|
}
|
||||||
|
|
@ -1301,7 +1311,8 @@ class Zetabyte {
|
||||||
args.push("set");
|
args.push("set");
|
||||||
|
|
||||||
if (properties) {
|
if (properties) {
|
||||||
for (const [key, value] of Object.entries(properties)) {
|
for (let [key, value] of Object.entries(properties)) {
|
||||||
|
value = escapeShell(value);
|
||||||
args.push(`${key}=${value}`);
|
args.push(`${key}=${value}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue