From 721d37553182d0279b5bd157e80aafc55ad082e4 Mon Sep 17 00:00:00 2001 From: perf3ct Date: Wed, 20 Aug 2025 20:13:29 +0000 Subject: [PATCH] feat(ssh/zfs): update path resolution logic for scale --- src/driver/controller-zfs-generic/index.js | 20 ++++--- src/driver/freenas/ssh.js | 64 ++++++++++++++++------ 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/driver/controller-zfs-generic/index.js b/src/driver/controller-zfs-generic/index.js index 3e4836f..bec3c68 100644 --- a/src/driver/controller-zfs-generic/index.js +++ b/src/driver/controller-zfs-generic/index.js @@ -39,20 +39,26 @@ class ControllerZfsGenericDriver extends ControllerZfsBaseDriver { } options.idempotent = true; + options.sudo = _.get(this.options, "zfs.cli.sudoEnabled", false); + + // Run automatic detection first + if (typeof this.setZetabyteCustomOptions === "function") { + await this.setZetabyteCustomOptions(options); + } + + // Manual override comes after automatic detection + // Only apply if user explicitly provided non-empty paths if ( this.options.zfs.hasOwnProperty("cli") && this.options.zfs.cli && - this.options.zfs.cli.hasOwnProperty("paths") + this.options.zfs.cli.hasOwnProperty("paths") && + this.options.zfs.cli.paths && + Object.keys(this.options.zfs.cli.paths).length > 0 ) { + // User explicitly configured paths - use them options.paths = this.options.zfs.cli.paths; } - options.sudo = _.get(this.options, "zfs.cli.sudoEnabled", false); - - if (typeof this.setZetabyteCustomOptions === "function") { - await this.setZetabyteCustomOptions(options); - } - return new Zetabyte(options); }); } diff --git a/src/driver/freenas/ssh.js b/src/driver/freenas/ssh.js index 7163d7f..05a5cf3 100644 --- a/src/driver/freenas/ssh.js +++ b/src/driver/freenas/ssh.js @@ -71,20 +71,26 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver { options.executor = new ZfsSshProcessManager(sshClient); options.idempotent = true; + options.sudo = _.get(this.options, "zfs.cli.sudoEnabled", false); + + // Run automatic detection first + if (typeof this.setZetabyteCustomOptions === "function") { + await this.setZetabyteCustomOptions(options); + } + + // Manual override comes after automatic detection + // Only apply if user explicitly provided non-empty paths if ( this.options.zfs.hasOwnProperty("cli") && this.options.zfs.cli && - this.options.zfs.cli.hasOwnProperty("paths") + this.options.zfs.cli.hasOwnProperty("paths") && + this.options.zfs.cli.paths && + Object.keys(this.options.zfs.cli.paths).length > 0 ) { + // User explicitly configured paths - use them options.paths = this.options.zfs.cli.paths; } - options.sudo = _.get(this.options, "zfs.cli.sudoEnabled", false); - - if (typeof this.setZetabyteCustomOptions === "function") { - await this.setZetabyteCustomOptions(options); - } - return new Zetabyte(options); }); } @@ -112,22 +118,33 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver { if (!options.hasOwnProperty("paths")) { const majorMinor = await this.getSystemVersionMajorMinor(); const isScale = await this.getIsScale(); + if (!isScale && Number(majorMinor) >= 12) { + // TrueNAS CORE/Enterprise version 12+ options.paths = { zfs: "/usr/local/sbin/zfs", zpool: "/usr/local/sbin/zpool", sudo: "/usr/local/bin/sudo", chroot: "/usr/sbin/chroot", }; - } - - if (isScale && Number(majorMinor) >= 25) { - options.paths = { - zfs: "/usr/sbin/zfs", - zpool: "/usr/sbin/zpool", - sudo: "/usr/bin/sudo", - chroot: "/usr/sbin/chroot", - }; + } else if (isScale) { + if (Number(majorMinor) >= 25) { + // TrueNAS SCALE version 25+ (paths changed to /usr/sbin in 25.04) + options.paths = { + zfs: "/usr/sbin/zfs", + zpool: "/usr/sbin/zpool", + sudo: "/usr/bin/sudo", + chroot: "/usr/sbin/chroot", + }; + } else { + // TrueNAS SCALE versions before 25 + options.paths = { + zfs: "/usr/local/sbin/zfs", + zpool: "/usr/local/sbin/zpool", + sudo: "/usr/bin/sudo", + chroot: "/usr/sbin/chroot", + }; + } } } } @@ -2179,8 +2196,19 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver { async getIsScale() { const systemVersion = await this.getSystemVersion(); - if (systemVersion.v2 && systemVersion.v2.toLowerCase().includes("scale")) { - return true; + if (systemVersion.v2) { + const versionLower = systemVersion.v2.toLowerCase(); + // Check for explicit "scale" in version string + if (versionLower.includes("scale")) { + return true; + } + // TrueNAS 25+ doesn't include "SCALE" in version string, but versions 25+ are SCALE-only + if (versionLower.includes("truenas")) { + const majorVersion = await this.getSystemVersionMajor(); + if (Number(majorVersion) >= 25) { + return true; + } + } } return false;