attempt to fix missing group behavior for iscsi target creation
This commit is contained in:
parent
716cde8f29
commit
01113c8270
|
|
@ -1,6 +1,7 @@
|
||||||
const { ControllerZfsSshBaseDriver } = require("../controller-zfs-ssh");
|
const { ControllerZfsSshBaseDriver } = require("../controller-zfs-ssh");
|
||||||
const { GrpcError, grpc } = require("../../utils/grpc");
|
const { GrpcError, grpc } = require("../../utils/grpc");
|
||||||
const HttpClient = require("./http").Client;
|
const HttpClient = require("./http").Client;
|
||||||
|
const sleep = require("../../utils/general").sleep;
|
||||||
|
|
||||||
const Handlebars = require("handlebars");
|
const Handlebars = require("handlebars");
|
||||||
|
|
||||||
|
|
@ -955,6 +956,47 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handle situations/race conditions where groups failed to be added/created on the target
|
||||||
|
// groups":[{"portal":1,"initiator":1,"auth":null,"authmethod":"NONE"},{"portal":2,"initiator":1,"auth":null,"authmethod":"NONE"}]
|
||||||
|
// TODO: this logic could be more intelligent but this should do for now as it appears in the failure scenario no groups are added
|
||||||
|
// in other words, I have never seen them invalid, only omitted so this should be enough
|
||||||
|
if (target.groups.length != targetGroups.length) {
|
||||||
|
response = await httpClient.put(`/iscsi/target/id/${target.id}`, {
|
||||||
|
groups: targetGroups,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.statusCode != 200) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.UNKNOWN,
|
||||||
|
`failed setting target groups`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
target = response.body;
|
||||||
|
|
||||||
|
// re-run sanity checks
|
||||||
|
if (!target) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.UNKNOWN,
|
||||||
|
`unknown error creating iscsi target`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.name != iscsiName) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.UNKNOWN,
|
||||||
|
`mismatch name error creating iscsi target`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.groups.length != targetGroups.length) {
|
||||||
|
throw new GrpcError(
|
||||||
|
grpc.status.UNKNOWN,
|
||||||
|
`failed setting target groups`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.ctx.logger.verbose("FreeNAS ISCSI TARGET: %j", target);
|
this.ctx.logger.verbose("FreeNAS ISCSI TARGET: %j", target);
|
||||||
|
|
||||||
// set target.id on zvol
|
// set target.id on zvol
|
||||||
|
|
@ -1524,6 +1566,103 @@ class FreeNASDriver extends ControllerZfsSshBaseDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async failedAttachHelper(call, err) {
|
||||||
|
const driverShareType = this.getDriverShareType();
|
||||||
|
const sshClient = this.getSshClient();
|
||||||
|
let response;
|
||||||
|
|
||||||
|
// not fully implemented
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (driverShareType) {
|
||||||
|
case "iscsi":
|
||||||
|
const isScale = await this.getIsScale();
|
||||||
|
const majorMinor = await this.getSystemVersionMajorMinor();
|
||||||
|
|
||||||
|
// only works for BSD-based and 11.3+
|
||||||
|
if (!isScale && majorMinor >= 11.3) {
|
||||||
|
const sudoEnabled = this.getSudoEnabled();
|
||||||
|
const sudoPath = await this.getSudoPath();
|
||||||
|
let command;
|
||||||
|
|
||||||
|
//19 - encountered non-retryable iSCSI login failure
|
||||||
|
// ^ could be missing groups on the target
|
||||||
|
|
||||||
|
//cat /var/run/ctld.pid
|
||||||
|
// ps -p <pid> | grep ctld
|
||||||
|
// ps -p `cat /var/run/ctld.pid` | grep ctld (if 0 exit status it's running, otherwise no)
|
||||||
|
|
||||||
|
// random settle time
|
||||||
|
// this could be getting invoked by other instances of the same controller
|
||||||
|
// or other deployments of controllers in the same of different clusters
|
||||||
|
// altogether
|
||||||
|
let maxSettleTime = 10000;
|
||||||
|
let settleTime = Math.floor(Math.random() * maxSettleTime + 1);
|
||||||
|
await sleep(settleTime);
|
||||||
|
|
||||||
|
// test if config is bad
|
||||||
|
// if so regen
|
||||||
|
command = sshClient.buildCommand("/usr/sbin/ctld", ["-d"]);
|
||||||
|
if (sudoEnabled) {
|
||||||
|
command = sudoPath + " " + command;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.logger.verbose("FailedAttachHelper command: %s", command);
|
||||||
|
|
||||||
|
response = await sshClient.exec(command);
|
||||||
|
let configError = false;
|
||||||
|
let serviceRunning = false;
|
||||||
|
if (response.stderr.includes("configuration error")) {
|
||||||
|
configError = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: this will not be in the output if the config file has an error
|
||||||
|
if (response.stderr.includes("daemon already running")) {
|
||||||
|
serviceRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configError) {
|
||||||
|
this.ctx.logger.warn(
|
||||||
|
"FailedAttachHelper: ctld appears to have a bad configuration file, attempting to regenerate"
|
||||||
|
);
|
||||||
|
// regen config
|
||||||
|
// midclt call etc.generate ctld
|
||||||
|
command = sshClient.buildCommand("midclt", [
|
||||||
|
"call",
|
||||||
|
"etc.generate",
|
||||||
|
"ctld",
|
||||||
|
]);
|
||||||
|
if (sudoEnabled) {
|
||||||
|
command = sudoPath + " " + command;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.logger.verbose("FailedAttachHelper command: %s", command);
|
||||||
|
response = await sshClient.exec(command);
|
||||||
|
|
||||||
|
// reload service (may not be enough)
|
||||||
|
command = sshClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
|
||||||
|
if (sudoEnabled) {
|
||||||
|
command = sudoPath + " " + command;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ctx.logger.verbose("FailedAttachHelper command: %s", command);
|
||||||
|
response = await sshClient.exec(command);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// note, when the 'bad' state is entered, the status still shows as running
|
||||||
|
// check if service is running
|
||||||
|
// /etc/rc.d/ctld status ...exits 0 if running
|
||||||
|
//command = sshClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
|
||||||
|
|
||||||
|
// if service is not running attempt a restart
|
||||||
|
// /etc/rc.d/ctld restart
|
||||||
|
//command = sshClient.buildCommand("/etc/rc.d/ctld", ["reload"]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getApiVersion() {
|
async getApiVersion() {
|
||||||
const systemVersion = await this.getSystemVersion();
|
const systemVersion = await this.getSystemVersion();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,15 @@ class CsiBaseDriver {
|
||||||
nodeDB
|
nodeDB
|
||||||
);
|
);
|
||||||
// login
|
// login
|
||||||
await iscsi.iscsiadm.login(volume_context.iqn, portal);
|
try {
|
||||||
|
await iscsi.iscsiadm.login(volume_context.iqn, portal);
|
||||||
|
} catch (err) {
|
||||||
|
if (typeof this.failedAttachHelper === "function") {
|
||||||
|
// no need to await this
|
||||||
|
this.failedAttachHelper(call, err);
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
// find device name
|
// find device name
|
||||||
device = `/dev/disk/by-path/ip-${portal}-iscsi-${volume_context.iqn}-lun-${volume_context.lun}`;
|
device = `/dev/disk/by-path/ip-${portal}-iscsi-${volume_context.iqn}-lun-${volume_context.lun}`;
|
||||||
|
|
@ -378,6 +386,16 @@ class CsiBaseDriver {
|
||||||
|
|
||||||
let current_time = Math.round(new Date().getTime() / 1000);
|
let current_time = Math.round(new Date().getTime() / 1000);
|
||||||
if (!result && current_time - timer_start > timer_max) {
|
if (!result && current_time - timer_start > timer_max) {
|
||||||
|
if (typeof this.failedAttachHelper === "function") {
|
||||||
|
// no need to await this
|
||||||
|
this.failedAttachHelper(
|
||||||
|
call,
|
||||||
|
new Error(
|
||||||
|
`hit timeout waiting for device node to appear: ${device}`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
driver.ctx.logger.warn(
|
driver.ctx.logger.warn(
|
||||||
`hit timeout waiting for device node to appear: ${device}`
|
`hit timeout waiting for device node to appear: ${device}`
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue