From 8c0d67a56e38a7f7e46b79b6a5f4240ad59253bd Mon Sep 17 00:00:00 2001 From: Travis Glenn Hansen Date: Sat, 12 Sep 2020 12:58:51 -0600 Subject: [PATCH] smb support --- README.md | 15 ++++++- examples/freenas-nfs.yaml | 4 ++ examples/zfs-generic-nfs.yaml | 4 ++ src/driver/controller-zfs-ssh/index.js | 1 + src/driver/freenas/index.js | 12 +++--- src/driver/index.js | 55 ++++++++++++++++---------- src/utils/filesystem.js | 19 ++++++--- src/utils/mount.js | 2 +- 8 files changed, 77 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index ff2c05d..05fca2a 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ have access to resizing, snapshots, clones, etc functionality. - several implementations of `csi` drivers - `freenas-nfs` (manages zfs datasets to share over nfs) - `freenas-iscsi` (manages zfs zvols to share over iscsi) + - `freenas-smb` (manages zfs datasets to share over smb) - `zfs-generic-nfs` (works with any ZoL installation...ie: Ubuntu) - `zfs-generic-iscsi` (works with any ZoL installation...ie: Ubuntu) - `zfs-local-ephemeral-inline` (provisions node-local zfs datasets) @@ -43,6 +44,16 @@ If you are running Kubernetes with rancher/rke please see the following: - https://github.com/rancher/rke/issues/1846 +### freenas-smb + +If using with Windows based machines you may need to enable guest access (even +if you are connecting with credentiasl) + +``` +Set-ItemProperty HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters AllowInsecureGuestAuth -Value 1 +Restart-Service LanmanWorkstation -Force +``` + ### zfs-local-ephemeral-inline This `driver` provisions node-local ephemeral storage on a per-pod basis. Each @@ -58,13 +69,15 @@ necessary. Server preparation depends slightly on which `driver` you are using. -### FreeNAS (freenas-nfs, freenas-iscsi) +### FreeNAS (freenas-nfs, freenas-iscsi, freenas-smb) Ensure the following services are configurged and running: - ssh (if you use a password for authentication make sure it is allowed) +- ensure `zsh`, `bash`, or `sh` is set as the root shell, `csh` gives false errors due to quoting - nfs - iscsi +- smb ### ZoL (zfs-generic-nfs, zfs-generic-iscsi) diff --git a/examples/freenas-nfs.yaml b/examples/freenas-nfs.yaml index a65e9de..6d915ab 100644 --- a/examples/freenas-nfs.yaml +++ b/examples/freenas-nfs.yaml @@ -41,6 +41,10 @@ zfs: datasetPermissionsMode: "0777" datasetPermissionsUser: root datasetPermissionsGroup: wheel + #datasetPermissionsAcls: + #- "-m everyone@:full_set:allow" + #- "-m u:kube:full_set:allow" + nfs: shareHost: server address shareAlldirs: false diff --git a/examples/zfs-generic-nfs.yaml b/examples/zfs-generic-nfs.yaml index b94c9f7..ed4f36b 100644 --- a/examples/zfs-generic-nfs.yaml +++ b/examples/zfs-generic-nfs.yaml @@ -38,6 +38,10 @@ zfs: datasetPermissionsMode: "0777" datasetPermissionsUser: root datasetPermissionsGroup: root + #datasetPermissionsAcls: + #- "-m everyone@:full_set:allow" + #- "-m u:kube:full_set:allow" + nfs: # https://docs.oracle.com/cd/E23824_01/html/821-1448/gayne.html # https://www.hiroom2.com/2016/05/18/ubuntu-16-04-share-zfs-storage-via-nfs-smb/ diff --git a/src/driver/controller-zfs-ssh/index.js b/src/driver/controller-zfs-ssh/index.js index 18b1fde..67c1eb1 100644 --- a/src/driver/controller-zfs-ssh/index.js +++ b/src/driver/controller-zfs-ssh/index.js @@ -696,6 +696,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver { // set acls // TODO: this is unsfafe approach, make it better + // probably could see if ^-.*\s and split and then shell escape if (this.options.zfs.datasetPermissionsAcls) { for (const acl of this.options.zfs.datasetPermissionsAcls) { command = sshClient.buildCommand("setfacl", [ diff --git a/src/driver/freenas/index.js b/src/driver/freenas/index.js index 7df05b0..0f56d57 100644 --- a/src/driver/freenas/index.js +++ b/src/driver/freenas/index.js @@ -45,12 +45,12 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver { case "freenas-nfs": case "truenas-nfs": return "nfs"; - case "freenas-iscsi": - case "truenas-iscsi": - return "iscsi"; case "freenas-smb": case "truenas-smb": return "smb"; + case "freenas-iscsi": + case "truenas-iscsi": + return "iscsi"; default: throw new Error("unknown driver: " + this.ctx.args.driver); } @@ -301,7 +301,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver { }; let propertyMapping = { - shareTemplate: "auxsmbconf", + shareAuxiliaryConfigurationTemplate: "auxsmbconf", shareHome: "home", shareAllowedHosts: "hostsallow", shareDeniedHosts: "hostsdeny", @@ -320,9 +320,9 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver { if (this.options.smb.hasOwnProperty(key)) { let value; switch (key) { - case "shareTemplate": + case "shareAuxiliaryConfigurationTemplate": value = Handlebars.compile( - this.options.smb.shareTemplate + this.options.smb.shareAuxiliaryConfigurationTemplate )({ name: call.request.name, parameters: call.request.parameters, diff --git a/src/driver/index.js b/src/driver/index.js index dc974f5..056b7c6 100644 --- a/src/driver/index.js +++ b/src/driver/index.js @@ -272,9 +272,19 @@ class CsiBaseDriver { const bind_mount_flags = []; bind_mount_flags.push("defaults"); + const normalizedSecrets = this.getNormalizedParameters( + call.request.secrets, + call.request.volume_context.provisioner_driver, + call.request.volume_context.provisioner_driver_instance_id + ); + if (access_type == "mount") { fs_type = capability.mount.fs_type; mount_flags = capability.mount.mount_flags || []; + // add secrets mount_flags + if (normalizedSecrets.mount_flags) { + mount_flags.push(normalizedSecrets.mount_flags); + } mount_flags.push("defaults"); } @@ -307,11 +317,6 @@ class CsiBaseDriver { "node.startup": "manual", }; const nodeDBKeyPrefix = "node-db."; - const normalizedSecrets = this.getNormalizedParameters( - call.request.secrets, - call.request.volume_context.provisioner_driver, - call.request.volume_context.provisioner_driver_instance_id - ); for (const key in normalizedSecrets) { if (key.startsWith(nodeDBKeyPrefix)) { nodeDB[key.substr(nodeDBKeyPrefix.length)] = normalizedSecrets[key]; @@ -355,24 +360,31 @@ class CsiBaseDriver { switch (access_type) { case "mount": - if (await filesystem.isBlockDevice(device)) { - // format - result = await filesystem.deviceIsFormatted(device); - if (!result) { - await filesystem.formatDevice(device, fs_type); - } + switch (node_attach_driver) { + // block specific logic + case "iscsi": + if (await filesystem.isBlockDevice(device)) { + // format + result = await filesystem.deviceIsFormatted(device); + if (!result) { + await filesystem.formatDevice(device, fs_type); + } - let fs_info = await filesystem.getDeviceFilesystemInfo(device); - fs_type = fs_info.type; + let fs_info = await filesystem.getDeviceFilesystemInfo(device); + fs_type = fs_info.type; - // fsck - result = await mount.deviceIsMountedAtPath( - device, - staging_target_path - ); - if (!result) { - await filesystem.checkFilesystem(device, fs_type); - } + // fsck + result = await mount.deviceIsMountedAtPath( + device, + staging_target_path + ); + if (!result) { + await filesystem.checkFilesystem(device, fs_type); + } + } + break; + default: + break; } result = await mount.deviceIsMountedAtPath(device, staging_target_path); @@ -614,6 +626,7 @@ class CsiBaseDriver { switch (node_attach_driver) { case "nfs": + case "smb": case "iscsi": // ensure appropriate directories/files switch (access_type) { diff --git a/src/utils/filesystem.js b/src/utils/filesystem.js index dbe70a0..fb03909 100644 --- a/src/utils/filesystem.js +++ b/src/utils/filesystem.js @@ -22,7 +22,7 @@ class Filesystem { if (!options.executor) { options.executor = { - spawn: cp.spawn + spawn: cp.spawn, }; } } @@ -35,13 +35,20 @@ class Filesystem { async isBlockDevice(device) { const filesystem = this; + // nfs paths if (!device.startsWith("/")) { return false; } + + // smb paths + if (device.startsWith("//")) { + return false; + } + const device_path = await filesystem.realpath(device); const blockdevices = await filesystem.getAllBlockDevices(); - return blockdevices.some(i => { + return blockdevices.some((i) => { if (i.path == device_path) { return true; } @@ -192,7 +199,7 @@ class Filesystem { const entries = result.stdout.trim().split("\n"); const properties = {}; let fields, key, value; - entries.forEach(entry => { + entries.forEach((entry) => { fields = entry.split("="); key = fields[0].toLowerCase(); value = fields[1]; @@ -440,15 +447,15 @@ class Filesystem { } return new Promise((resolve, reject) => { - child.stdout.on("data", function(data) { + child.stdout.on("data", function (data) { stdout = stdout + data; }); - child.stderr.on("data", function(data) { + child.stderr.on("data", function (data) { stderr = stderr + data; }); - child.on("close", function(code) { + child.on("close", function (code) { const result = { code, stdout, stderr }; if (timeout) { clearTimeout(timeout); diff --git a/src/utils/mount.js b/src/utils/mount.js index 893b41c..7e50535 100644 --- a/src/utils/mount.js +++ b/src/utils/mount.js @@ -111,7 +111,7 @@ class Mount { */ async deviceIsMountedAtPath(device, path) { const filesystem = new Filesystem(); - if (device.startsWith("/")) { + if (device.startsWith("/") && !device.startsWith("//")) { device = await filesystem.realpath(device); }