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-----
|
||||
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
|
||||
# https://www.ixsystems.com/documentation/freenas/11.2-U5/storage.html#zfs-zvol-config-opts-tab
|
||||
# standard volume naming overhead is 46 chars
|
||||
|
|
|
|||
|
|
@ -18,6 +18,22 @@ sshConnection:
|
|||
...
|
||||
-----END RSA PRIVATE KEY-----
|
||||
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
|
||||
detachedSnapshotsDatasetParentName: tank/k8s/a/snaps
|
||||
datasetEnableQuotas: true
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ instance_id:
|
|||
nfs:
|
||||
shareHost: server address
|
||||
shareBasePath: "/some/path"
|
||||
# shareHost:shareBasePath should be mounted at this location in the controller container
|
||||
controllerBasePath: "/storage"
|
||||
dirPermissionsMode: "0777"
|
||||
dirPermissionsUser: root
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ service:
|
|||
controller: {}
|
||||
node: {}
|
||||
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
|
||||
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ service:
|
|||
controller: {}
|
||||
node: {}
|
||||
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
|
||||
detachedSnapshotsDatasetParentName: tanks/k8s/test-snapshots
|
||||
|
||||
|
|
|
|||
|
|
@ -820,6 +820,18 @@
|
|||
"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": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
|
||||
|
|
@ -1127,6 +1139,11 @@
|
|||
"integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
|
||||
"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": {
|
||||
"version": "1.0.1",
|
||||
"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": {
|
||||
"version": "1.0.3",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "4.2.2",
|
||||
"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",
|
||||
"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": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
"bunyan": "^1.8.14",
|
||||
"eslint": "^7.4.0",
|
||||
"grpc-uds": "^0.1.4",
|
||||
"handlebars": "^4.7.6",
|
||||
"js-yaml": "^3.14.0",
|
||||
"lru-cache": "^5.1.1",
|
||||
"request": "^2.88.2",
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ const SshClient = require("../../utils/ssh").SshClient;
|
|||
const { GrpcError, grpc } = require("../../utils/grpc");
|
||||
|
||||
const { Zetabyte, ZfsSshProcessManager } = require("../../utils/zfs");
|
||||
|
||||
const Handlebars = require("handlebars");
|
||||
const uuidv4 = require("uuid").v4;
|
||||
|
||||
// zfs common properties
|
||||
|
|
@ -122,10 +124,18 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
|||
|
||||
getZetabyte() {
|
||||
const sshClient = this.getSshClient();
|
||||
return new Zetabyte({
|
||||
executor: new ZfsSshProcessManager(sshClient),
|
||||
idempotent: true,
|
||||
});
|
||||
const options = {};
|
||||
options.executor = new ZfsSshProcessManager(sshClient);
|
||||
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() {
|
||||
|
|
@ -335,6 +345,20 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
|||
let volume_content_source_volume_id;
|
||||
let fullSnapshotName;
|
||||
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[MANAGED_PROPERTY_NAME] = "true";
|
||||
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 fsType as property?
|
||||
// TODO: allow for users to configure arbitrary/custom properties to add
|
||||
|
||||
// zvol enables reservation by default
|
||||
// this implements 'sparse' zvols
|
||||
|
|
@ -691,8 +714,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
|
|||
|
||||
volume_context = await this.createShare(call, datasetName);
|
||||
await zb.zfs.set(datasetName, {
|
||||
[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]:
|
||||
"'" + JSON.stringify(volume_context) + "'",
|
||||
[SHARE_VOLUME_CONTEXT_PROPERTY_NAME]: JSON.stringify(volume_context),
|
||||
});
|
||||
|
||||
volume_context["provisioner_driver"] = driver.options.driver;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
const events = require("events");
|
||||
const cp = require("child_process");
|
||||
|
||||
const escapeShell = function (cmd) {
|
||||
cmd = String(cmd);
|
||||
return '"' + cmd.replace(/(["$`\\])/g, "\\$1") + '"';
|
||||
};
|
||||
|
||||
class Zetabyte {
|
||||
constructor(options = {}) {
|
||||
const zb = this;
|
||||
|
|
@ -283,7 +288,8 @@ class Zetabyte {
|
|||
}
|
||||
}
|
||||
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(`${key}=${value}`);
|
||||
}
|
||||
|
|
@ -774,6 +780,7 @@ class Zetabyte {
|
|||
* @param {*} value
|
||||
*/
|
||||
set: function (pool, property, value) {
|
||||
value = escapeShell(value);
|
||||
return new Promise((resolve, reject) => {
|
||||
let args = [];
|
||||
args.push("set");
|
||||
|
|
@ -913,7 +920,8 @@ class Zetabyte {
|
|||
if (options.unmounted) args.push("-u");
|
||||
if (options.blocksize) args = args.concat(["-b", options.blocksize]);
|
||||
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(`${key}=${value}`);
|
||||
}
|
||||
|
|
@ -1012,7 +1020,8 @@ class Zetabyte {
|
|||
args.push("snapshot");
|
||||
if (options.recurse) args.push("-r");
|
||||
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(`${key}=${value}`);
|
||||
}
|
||||
|
|
@ -1093,7 +1102,8 @@ class Zetabyte {
|
|||
args.push("clone");
|
||||
if (options.parents) args.push("-p");
|
||||
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(`${key}=${value}`);
|
||||
}
|
||||
|
|
@ -1301,7 +1311,8 @@ class Zetabyte {
|
|||
args.push("set");
|
||||
|
||||
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}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue