many fixes, support auto-detection of truenas binary paths and apiVersion, fix config typo, better support for potential race conditions with deleting shares

This commit is contained in:
Travis Glenn Hansen 2020-11-27 14:19:13 -07:00
parent 6c79b32f9b
commit c4a36750cd
8 changed files with 258 additions and 65 deletions

View File

@ -12,6 +12,7 @@ httpConnection:
password: password:
allowInsecure: true allowInsecure: true
# use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well) # use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well)
# leave unset for auto-detection
#apiVersion: 2 #apiVersion: 2
sshConnection: sshConnection:
host: server address host: server address
@ -28,6 +29,8 @@ zfs:
# the example below is useful for TrueNAS 12 # the example below is useful for TrueNAS 12
#cli: #cli:
# sudoEnabled: true # sudoEnabled: true
#
# leave paths unset for auto-detection
# paths: # paths:
# zfs: /usr/local/sbin/zfs # zfs: /usr/local/sbin/zfs
# zpool: /usr/local/sbin/zpool # zpool: /usr/local/sbin/zpool

View File

@ -12,6 +12,7 @@ httpConnection:
password: password:
allowInsecure: true allowInsecure: true
# use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well) # use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well)
# leave unset for auto-detection
#apiVersion: 2 #apiVersion: 2
sshConnection: sshConnection:
host: server address host: server address
@ -28,6 +29,8 @@ zfs:
# the example below is useful for TrueNAS 12 # the example below is useful for TrueNAS 12
#cli: #cli:
# sudoEnabled: true # sudoEnabled: true
#
# leave paths unset for auto-detection
# paths: # paths:
# zfs: /usr/local/sbin/zfs # zfs: /usr/local/sbin/zfs
# zpool: /usr/local/sbin/zpool # zpool: /usr/local/sbin/zpool

View File

@ -12,6 +12,7 @@ httpConnection:
password: password:
allowInsecure: true allowInsecure: true
# use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well) # use apiVersion 2 for TrueNAS-12 and up (will work on 11.x in some scenarios as well)
# leave unset for auto-detection
#apiVersion: 2 #apiVersion: 2
sshConnection: sshConnection:
host: server address host: server address
@ -28,6 +29,8 @@ zfs:
# the example below is useful for TrueNAS 12 # the example below is useful for TrueNAS 12
#cli: #cli:
# sudoEnabled: true # sudoEnabled: true
#
# leave paths unset for auto-detection
# paths: # paths:
# zfs: /usr/local/sbin/zfs # zfs: /usr/local/sbin/zfs
# zpool: /usr/local/sbin/zpool # zpool: /usr/local/sbin/zpool

View File

@ -51,7 +51,7 @@ iscsi:
# http://www.linux-iscsi.org/wiki/ISCSI # http://www.linux-iscsi.org/wiki/ISCSI
# https://bugzilla.redhat.com/show_bug.cgi?id=1659195 # https://bugzilla.redhat.com/show_bug.cgi?id=1659195
# http://atodorov.org/blog/2015/04/07/how-to-configure-iscsi-target-on-red-hat-enterprise-linux-7/ # http://atodorov.org/blog/2015/04/07/how-to-configure-iscsi-target-on-red-hat-enterprise-linux-7/
shareStragetyTargetCli: shareStrategyTargetCli:
#sudoEnabled: true #sudoEnabled: true
basename: "iqn.2003-01.org.linux-iscsi.ubuntu-19.x8664" basename: "iqn.2003-01.org.linux-iscsi.ubuntu-19.x8664"
tpg: tpg:

View File

@ -26,7 +26,7 @@ class ControllerZfsGenericDriver extends ControllerZfsSshBaseDriver {
* @param {*} datasetName * @param {*} datasetName
*/ */
async createShare(call, datasetName) { async createShare(call, datasetName) {
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
const sshClient = this.getSshClient(); const sshClient = this.getSshClient();
let properties; let properties;
@ -105,25 +105,25 @@ class ControllerZfsGenericDriver extends ControllerZfsSshBaseDriver {
switch (this.options.iscsi.shareStrategy) { switch (this.options.iscsi.shareStrategy) {
case "targetCli": case "targetCli":
basename = this.options.iscsi.shareStragetyTargetCli.basename; basename = this.options.iscsi.shareStrategyTargetCli.basename;
let setAttributesText = ""; let setAttributesText = "";
let setAuthText = ""; let setAuthText = "";
if (this.options.iscsi.shareStragetyTargetCli.tpg) { if (this.options.iscsi.shareStrategyTargetCli.tpg) {
if (this.options.iscsi.shareStragetyTargetCli.tpg.attributes) { if (this.options.iscsi.shareStrategyTargetCli.tpg.attributes) {
for (const attributeName in this.options.iscsi for (const attributeName in this.options.iscsi
.shareStragetyTargetCli.tpg.attributes) { .shareStrategyTargetCli.tpg.attributes) {
const attributeValue = this.options.iscsi const attributeValue = this.options.iscsi
.shareStragetyTargetCli.tpg.attributes[attributeName]; .shareStrategyTargetCli.tpg.attributes[attributeName];
setAttributesText += "\n"; setAttributesText += "\n";
setAttributesText += `set attribute ${attributeName}=${attributeValue}`; setAttributesText += `set attribute ${attributeName}=${attributeValue}`;
} }
} }
if (this.options.iscsi.shareStragetyTargetCli.tpg.auth) { if (this.options.iscsi.shareStrategyTargetCli.tpg.auth) {
for (const attributeName in this.options.iscsi for (const attributeName in this.options.iscsi
.shareStragetyTargetCli.tpg.auth) { .shareStrategyTargetCli.tpg.auth) {
const attributeValue = this.options.iscsi const attributeValue = this.options.iscsi
.shareStragetyTargetCli.tpg.auth[attributeName]; .shareStrategyTargetCli.tpg.auth[attributeName];
setAttributesText += "\n"; setAttributesText += "\n";
setAttributesText += `set auth ${attributeName}=${attributeValue}`; setAttributesText += `set auth ${attributeName}=${attributeValue}`;
} }
@ -178,7 +178,7 @@ create /backstores/block/${iscsiName}
} }
async deleteShare(call, datasetName) { async deleteShare(call, datasetName) {
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
const sshClient = this.getSshClient(); const sshClient = this.getSshClient();
let response; let response;
@ -210,7 +210,7 @@ create /backstores/block/${iscsiName}
iscsiName = iscsiName.toLowerCase(); iscsiName = iscsiName.toLowerCase();
switch (this.options.iscsi.shareStrategy) { switch (this.options.iscsi.shareStrategy) {
case "targetCli": case "targetCli":
basename = this.options.iscsi.shareStragetyTargetCli.basename; basename = this.options.iscsi.shareStrategyTargetCli.basename;
response = await this.targetCliCommand( response = await this.targetCliCommand(
` `
cd /iscsi cd /iscsi
@ -267,7 +267,7 @@ delete ${iscsiName}
taregetCliCommand.push("|"); taregetCliCommand.push("|");
taregetCliCommand.push("targetcli"); taregetCliCommand.push("targetcli");
if (this.options.iscsi.shareStragetyTargetCli.sudoEnabled) { if (this.options.iscsi.shareStrategyTargetCli.sudoEnabled) {
command = "sudo"; command = "sudo";
args.unshift("sh"); args.unshift("sh");
} }

View File

@ -122,7 +122,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
}); });
} }
getZetabyte() { async getZetabyte() {
const sshClient = this.getSshClient(); const sshClient = this.getSshClient();
const options = {}; const options = {};
options.executor = new ZfsSshProcessManager(sshClient); options.executor = new ZfsSshProcessManager(sshClient);
@ -130,6 +130,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
if ( if (
this.options.zfs.hasOwnProperty("cli") && this.options.zfs.hasOwnProperty("cli") &&
this.options.zfs.cli &&
this.options.zfs.cli.hasOwnProperty("paths") this.options.zfs.cli.hasOwnProperty("paths")
) { ) {
options.paths = this.options.zfs.cli.paths; options.paths = this.options.zfs.cli.paths;
@ -137,20 +138,26 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
if ( if (
this.options.zfs.hasOwnProperty("cli") && this.options.zfs.hasOwnProperty("cli") &&
this.options.zfs.cli &&
this.options.zfs.cli.hasOwnProperty("sudoEnabled") this.options.zfs.cli.hasOwnProperty("sudoEnabled")
) { ) {
options.sudo = this.getSudoEnabled(); options.sudo = this.getSudoEnabled();
} }
if (typeof this.setZetabyteCustomOptions === "function") {
await this.setZetabyteCustomOptions(options);
}
return new Zetabyte(options); return new Zetabyte(options);
} }
getSudoEnabled() { getSudoEnabled() {
return this.options.zfs.cli.sudoEnabled === true; return this.options.zfs.cli && this.options.zfs.cli.sudoEnabled === true;
} }
getSudoPath() { async getSudoPath() {
return this.options.zfs.cli.paths.sudo || "/usr/bin/sudo"; const zb = await this.getZetabyte();
return zb.options.paths.sudo || "/usr/bin/sudo";
} }
getDatasetParentName() { getDatasetParentName() {
@ -175,7 +182,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
} }
async removeSnapshotsFromDatatset(datasetName, options = {}) { async removeSnapshotsFromDatatset(datasetName, options = {}) {
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
await zb.zfs.destroy(datasetName + "@%", options); await zb.zfs.destroy(datasetName + "@%", options);
} }
@ -265,7 +272,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
const driver = this; const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType(); const driverZfsResourceType = this.getDriverZfsResourceType();
const sshClient = this.getSshClient(); const sshClient = this.getSshClient();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let datasetParentName = this.getVolumeParentDatasetName(); let datasetParentName = this.getVolumeParentDatasetName();
let snapshotParentDatasetName = this.getDetachedSnapshotParentDatasetName(); let snapshotParentDatasetName = this.getDetachedSnapshotParentDatasetName();
@ -687,7 +694,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
properties.mountpoint.value, properties.mountpoint.value,
]); ]);
if (this.getSudoEnabled()) { if (this.getSudoEnabled()) {
command = this.getSudoPath() + " " + command; command = (await this.getSudoPath()) + " " + command;
} }
driver.ctx.logger.verbose("set permission command: %s", command); driver.ctx.logger.verbose("set permission command: %s", command);
@ -710,7 +717,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
properties.mountpoint.value, properties.mountpoint.value,
]); ]);
if (this.getSudoEnabled()) { if (this.getSudoEnabled()) {
command = this.getSudoPath() + " " + command; command = (await this.getSudoPath()) + " " + command;
} }
driver.ctx.logger.verbose("set ownership command: %s", command); driver.ctx.logger.verbose("set ownership command: %s", command);
@ -727,7 +734,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
properties.mountpoint.value, properties.mountpoint.value,
]); ]);
if (this.getSudoEnabled()) { if (this.getSudoEnabled()) {
command = this.getSudoPath() + " " + command; command = (await this.getSudoPath()) + " " + command;
} }
driver.ctx.logger.verbose("set acl command: %s", command); driver.ctx.logger.verbose("set acl command: %s", command);
@ -799,7 +806,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
*/ */
async DeleteVolume(call) { async DeleteVolume(call) {
const driver = this; const driver = this;
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let datasetParentName = this.getVolumeParentDatasetName(); let datasetParentName = this.getVolumeParentDatasetName();
let name = call.request.volume_id; let name = call.request.volume_id;
@ -904,7 +911,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
async ControllerExpandVolume(call) { async ControllerExpandVolume(call) {
const driver = this; const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType(); const driverZfsResourceType = this.getDriverZfsResourceType();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let datasetParentName = this.getVolumeParentDatasetName(); let datasetParentName = this.getVolumeParentDatasetName();
let name = call.request.volume_id; let name = call.request.volume_id;
@ -1017,7 +1024,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
*/ */
async GetCapacity(call) { async GetCapacity(call) {
const driver = this; const driver = this;
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let datasetParentName = this.getVolumeParentDatasetName(); let datasetParentName = this.getVolumeParentDatasetName();
@ -1054,7 +1061,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
async ListVolumes(call) { async ListVolumes(call) {
const driver = this; const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType(); const driverZfsResourceType = this.getDriverZfsResourceType();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let datasetParentName = this.getVolumeParentDatasetName(); let datasetParentName = this.getVolumeParentDatasetName();
let entries = []; let entries = [];
@ -1239,7 +1246,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
async ListSnapshots(call) { async ListSnapshots(call) {
const driver = this; const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType(); const driverZfsResourceType = this.getDriverZfsResourceType();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let entries = []; let entries = [];
let entries_length = 0; let entries_length = 0;
@ -1471,7 +1478,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
async CreateSnapshot(call) { async CreateSnapshot(call) {
const driver = this; const driver = this;
const driverZfsResourceType = this.getDriverZfsResourceType(); const driverZfsResourceType = this.getDriverZfsResourceType();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let detachedSnapshot = false; let detachedSnapshot = false;
try { try {
@ -1705,7 +1712,7 @@ class ControllerZfsSshBaseDriver extends CsiBaseDriver {
*/ */
async DeleteSnapshot(call) { async DeleteSnapshot(call) {
const driver = this; const driver = this;
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
const snapshot_id = call.request.snapshot_id; const snapshot_id = call.request.snapshot_id;

View File

@ -4,7 +4,7 @@ const USER_AGENT = "democratic-csi-driver";
class Client { class Client {
constructor(options = {}) { constructor(options = {}) {
this.options = options; this.options = JSON.parse(JSON.stringify(options));
this.logger = console; this.logger = console;
// default to v1.0 for now // default to v1.0 for now

View File

@ -15,7 +15,6 @@ const FREENAS_ISCSI_TARGETTOEXTENT_ID_PROPERTY_NAME =
"democratic-csi:freenas_iscsi_targettoextent_id"; "democratic-csi:freenas_iscsi_targettoextent_id";
const FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME = const FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME =
"democratic-csi:freenas_iscsi_assets_name"; "democratic-csi:freenas_iscsi_assets_name";
class FreeNASDriver extends ControllerZfsSshBaseDriver { class FreeNASDriver extends ControllerZfsSshBaseDriver {
/** /**
* cannot make this a storage class parameter as storage class/etc context is *not* sent * cannot make this a storage class parameter as storage class/etc context is *not* sent
@ -36,9 +35,30 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
} }
} }
getHttpClient() { async setZetabyteCustomOptions(options) {
if (!options.hasOwnProperty("paths")) {
const majorMinor = await this.getSystemVersionMajorMinor();
const isScale = await this.getIsScale();
if (!isScale && Number(majorMinor) >= 12) {
options.paths = {
zfs: "/usr/local/sbin/zfs",
zpool: "/usr/local/sbin/zpool",
sudo: "/usr/local/bin/sudo",
chroot: "/usr/sbin/chroot",
};
}
}
}
async getHttpClient(autoDetectVersion = true) {
const client = new HttpClient(this.options.httpConnection); const client = new HttpClient(this.options.httpConnection);
client.logger = this.ctx.logger; client.logger = this.ctx.logger;
if (autoDetectVersion && !!!this.options.httpConnection.apiVersion) {
const apiVersion = await this.getApiVersion();
client.setApiVersion(apiVersion);
}
return client; return client;
} }
@ -62,7 +82,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
if (!match || Object.keys(match).length < 1) { if (!match || Object.keys(match).length < 1) {
return; return;
} }
const httpClient = this.getHttpClient(); const httpClient = await this.getHttpClient();
let target; let target;
let page = 0; let page = 0;
@ -126,9 +146,9 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
*/ */
async createShare(call, datasetName) { async createShare(call, datasetName) {
const driverShareType = this.getDriverShareType(); const driverShareType = this.getDriverShareType();
const httpClient = this.getHttpClient(); const httpClient = await this.getHttpClient();
const apiVersion = httpClient.getApiVersion(); const apiVersion = httpClient.getApiVersion();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let properties; let properties;
let endpoint; let endpoint;
@ -1017,19 +1037,22 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
async deleteShare(call, datasetName) { async deleteShare(call, datasetName) {
const driverShareType = this.getDriverShareType(); const driverShareType = this.getDriverShareType();
const httpClient = this.getHttpClient(); const httpClient = await this.getHttpClient();
const apiVersion = httpClient.getApiVersion(); const apiVersion = httpClient.getApiVersion();
const zb = this.getZetabyte(); const zb = await this.getZetabyte();
let properties; let properties;
let response; let response;
let endpoint; let endpoint;
let shareId; let shareId;
let deleteAsset;
let sharePaths;
switch (driverShareType) { switch (driverShareType) {
case "nfs": case "nfs":
try { try {
properties = await zb.zfs.get(datasetName, [ properties = await zb.zfs.get(datasetName, [
"mountpoint",
FREENAS_NFS_SHARE_PROPERTY_NAME, FREENAS_NFS_SHARE_PROPERTY_NAME,
]); ]);
} catch (err) { } catch (err) {
@ -1063,6 +1086,20 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
// assume share is gone for now // assume share is gone for now
if ([404, 500].includes(response.statusCode)) { if ([404, 500].includes(response.statusCode)) {
} else { } else {
switch (apiVersion) {
case 1:
sharePaths = response.body.nfs_paths;
break;
case 2:
sharePaths = response.body.paths;
break;
}
deleteAsset = sharePaths.some((value) => {
return value == properties.mountpoint.value;
});
if (deleteAsset) {
response = await httpClient.delete(endpoint); response = await httpClient.delete(endpoint);
// returns a 500 if does not exist // returns a 500 if does not exist
@ -1077,6 +1114,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
); );
} }
} }
}
break; break;
default: default:
throw new GrpcError( throw new GrpcError(
@ -1089,6 +1127,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
case "smb": case "smb":
try { try {
properties = await zb.zfs.get(datasetName, [ properties = await zb.zfs.get(datasetName, [
"mountpoint",
FREENAS_SMB_SHARE_PROPERTY_NAME, FREENAS_SMB_SHARE_PROPERTY_NAME,
]); ]);
} catch (err) { } catch (err) {
@ -1125,6 +1164,20 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
// assume share is gone for now // assume share is gone for now
if ([404, 500].includes(response.statusCode)) { if ([404, 500].includes(response.statusCode)) {
} else { } else {
switch (apiVersion) {
case 1:
sharePaths = [response.body.cifs_path];
break;
case 2:
sharePaths = [response.body.path];
break;
}
deleteAsset = sharePaths.some((value) => {
return value == properties.mountpoint.value;
});
if (deleteAsset) {
response = await httpClient.delete(endpoint); response = await httpClient.delete(endpoint);
// returns a 500 if does not exist // returns a 500 if does not exist
@ -1139,6 +1192,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
); );
} }
} }
}
break; break;
default: default:
throw new GrpcError( throw new GrpcError(
@ -1175,7 +1229,6 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
let iscsiName = let iscsiName =
properties[FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME].value; properties[FREENAS_ISCSI_ASSETS_NAME_PROPERTY_NAME].value;
let assetName; let assetName;
let deleteAsset;
switch (apiVersion) { switch (apiVersion) {
case 1: case 1:
@ -1310,10 +1363,18 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
switch (driverShareType) { switch (driverShareType) {
case "iscsi": case "iscsi":
const isScale = this.getIsScale();
if (isScale) {
this.ctx.logger.verbose("FreeNAS reloading scst");
await sshClient.exec(
sshClient.buildCommand("systemctl", ["reload", "scst"])
);
} else {
this.ctx.logger.verbose("FreeNAS reloading ctld"); this.ctx.logger.verbose("FreeNAS reloading ctld");
await sshClient.exec( await sshClient.exec(
sshClient.buildCommand("/etc/rc.d/ctld", ["reload"]) sshClient.buildCommand("/etc/rc.d/ctld", ["reload"])
); );
}
break; break;
} }
} }
@ -1321,11 +1382,120 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
async getApiVersion() { async getApiVersion() {
const systemVersion = await this.getSystemVersion(); const systemVersion = await this.getSystemVersion();
if (systemVersion.v2) {
return 2;
}
return 1; return 1;
} }
async getIsFreeNAS() {
const systemVersion = await this.getSystemVersion();
let version;
if (systemVersion.v2) {
version = systemVersion.v2;
} else {
version = systemVersion.v1.fullversion;
}
if (version.toLowerCase().includes("freenas")) {
return true;
}
return false;
}
async getIsTrueNAS() {
const systemVersion = await this.getSystemVersion();
let version;
if (systemVersion.v2) {
version = systemVersion.v2;
} else {
version = systemVersion.v1.fullversion;
}
if (version.toLowerCase().includes("truenas")) {
return true;
}
return false;
}
async getIsScale() {
const systemVersion = await this.getSystemVersion();
if (systemVersion.v2 && systemVersion.v2.toLowerCase().includes("scale")) {
return true;
}
return false;
}
async getSystemVersionMajorMinor() {
const systemVersion = await this.getSystemVersion();
let parts;
let parts_i;
let version;
/*
systemVersion.v2 = "FreeNAS-11.2-U5";
systemVersion.v2 = "TrueNAS-SCALE-20.11-MASTER-20201127-092915";
systemVersion.v1 = {
fullversion: "FreeNAS-9.3-STABLE-201503200528",
fullversion: "FreeNAS-11.2-U5 (c129415c52)",
};
systemVersion.v2 = null;
*/
if (systemVersion.v2) {
version = systemVersion.v2;
} else {
version = systemVersion.v1.fullversion;
}
if (version) {
parts = version.split("-");
parts_i = [];
parts.forEach((value) => {
let i = value.replace(/[^\d.]/g, "");
if (i.length > 0) {
parts_i.push(i);
}
});
// join and resplit to deal with single elements which contain a decimal
parts_i = parts_i.join(".").split(".");
parts_i.splice(2);
return parts_i.join(".");
}
}
async getSystemVersionMajor() {
const majorMinor = await this.getSystemVersionMajorMinor();
return majorMinor.split(".")[0];
}
async setVersionInfoCache(versionInfo) {
const driver = this;
this.cache = this.cache || {};
this.cache.versionInfo = versionInfo;
// crude timeout
setTimeout(function () {
driver.cache.versionInfo = null;
}, 60 * 1000);
}
async getSystemVersion() { async getSystemVersion() {
const httpClient = this.getHttpClient(); this.cache = this.cache || {};
if (this.cache.versionInfo) {
return this.cache.versionInfo;
}
const httpClient = await this.getHttpClient(false);
const endpoint = "/system/version/"; const endpoint = "/system/version/";
let response; let response;
const startApiVersion = httpClient.getApiVersion(); const startApiVersion = httpClient.getApiVersion();
@ -1334,12 +1504,18 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
httpClient.setApiVersion(2); httpClient.setApiVersion(2);
/** /**
* FreeNAS-11.2-U5 * FreeNAS-11.2-U5
* TrueNAS-12.0-RELEASE
* TrueNAS-SCALE-20.11-MASTER-20201127-092915
*/ */
try { try {
response = await httpClient.get(endpoint); response = await httpClient.get(endpoint);
if (response.statusCode == 200) { if (response.statusCode == 200) {
versionInfo.v2 = response.body; versionInfo.v2 = response.body;
} }
// return immediately to save on resources and silly requests
await this.setVersionInfoCache(versionInfo);
return versionInfo;
} catch (e) {} } catch (e) {}
httpClient.setApiVersion(1); httpClient.setApiVersion(1);
@ -1357,6 +1533,7 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
// reset apiVersion // reset apiVersion
httpClient.setApiVersion(startApiVersion); httpClient.setApiVersion(startApiVersion);
await this.setVersionInfoCache(versionInfo);
return versionInfo; return versionInfo;
} }
} }