Merge 10aa9c539a into 55c36d62ff
This commit is contained in:
commit
f17cfd9bde
|
|
@ -150,6 +150,48 @@ class FreeNASApiDriver extends CsiBaseDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an error response indicates a target already exists.
|
||||||
|
* This method handles variations in TrueNAS API error messages across different API versions.
|
||||||
|
*
|
||||||
|
* @param {string|Object} responseBody - The HTTP response body (string or object)
|
||||||
|
* @returns {boolean} - true if the error indicates target already exists
|
||||||
|
*/
|
||||||
|
isTargetAlreadyExistsError(responseBody) {
|
||||||
|
// Extract error message more efficiently
|
||||||
|
let errorString = '';
|
||||||
|
|
||||||
|
if (typeof responseBody === 'string') {
|
||||||
|
errorString = responseBody;
|
||||||
|
} else if (responseBody && typeof responseBody === 'object') {
|
||||||
|
// Try common error message fields first to avoid full JSON.stringify
|
||||||
|
errorString = responseBody.message ||
|
||||||
|
responseBody.error ||
|
||||||
|
responseBody.detail ||
|
||||||
|
JSON.stringify(responseBody);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle multiple variations of the target already exists error message
|
||||||
|
const targetExistsPatterns = [
|
||||||
|
"Target name already exists", // Original pattern in code (API v1)
|
||||||
|
"Target with this name already exists", // Actual TrueNAS error message (API v2)
|
||||||
|
"Target\\b.*\\balready\\b.*\\bexists" // Flexible pattern with word boundaries
|
||||||
|
];
|
||||||
|
|
||||||
|
return targetExistsPatterns.some(pattern => {
|
||||||
|
if (pattern.includes("\\")) {
|
||||||
|
// Use regex for flexible patterns with word boundaries
|
||||||
|
const regex = new RegExp(pattern, "i");
|
||||||
|
return regex.test(errorString);
|
||||||
|
} else {
|
||||||
|
// Use case-insensitive simple string matching for exact patterns
|
||||||
|
return errorString.toLowerCase().includes(pattern.toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* only here for the helpers
|
* only here for the helpers
|
||||||
* @returns
|
* @returns
|
||||||
|
|
@ -835,14 +877,12 @@ class FreeNASApiDriver extends CsiBaseDriver {
|
||||||
target
|
target
|
||||||
);
|
);
|
||||||
|
|
||||||
// 409 if invalid
|
// 409 Conflict - target already exists or other validation errors
|
||||||
if (response.statusCode != 201) {
|
if (response.statusCode != 201) {
|
||||||
target = null;
|
target = null;
|
||||||
if (
|
if (
|
||||||
response.statusCode == 409 &&
|
response.statusCode == 409 &&
|
||||||
JSON.stringify(response.body).includes(
|
this.isTargetAlreadyExistsError(response.body)
|
||||||
"Target name already exists"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
target = await httpApiClient.findResourceByProperties(
|
target = await httpApiClient.findResourceByProperties(
|
||||||
"/services/iscsi/target",
|
"/services/iscsi/target",
|
||||||
|
|
@ -1123,14 +1163,12 @@ class FreeNASApiDriver extends CsiBaseDriver {
|
||||||
|
|
||||||
response = await httpClient.post("/iscsi/target", target);
|
response = await httpClient.post("/iscsi/target", target);
|
||||||
|
|
||||||
// 409 if invalid
|
// 422 Unprocessable Entity - validation errors including duplicate targets
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
target = null;
|
target = null;
|
||||||
if (
|
if (
|
||||||
response.statusCode == 422 &&
|
response.statusCode == 422 &&
|
||||||
JSON.stringify(response.body).includes(
|
this.isTargetAlreadyExistsError(response.body)
|
||||||
"Target name already exists"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
target = await httpApiClient.findResourceByProperties(
|
target = await httpApiClient.findResourceByProperties(
|
||||||
"/iscsi/target",
|
"/iscsi/target",
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,8 @@ class Api {
|
||||||
// crude stoppage attempt
|
// crude stoppage attempt
|
||||||
let response = await httpClient.get(endpoint, queryParams);
|
let response = await httpClient.get(endpoint, queryParams);
|
||||||
if (lastReponse) {
|
if (lastReponse) {
|
||||||
if (JSON.stringify(lastReponse) == JSON.stringify(response)) {
|
// Compare only the response body to avoid circular reference issues
|
||||||
|
if (JSON.stringify(lastReponse.body) == JSON.stringify(response.body)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,48 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if an error response indicates a target already exists.
|
||||||
|
* This method handles variations in TrueNAS API error messages across different API versions.
|
||||||
|
*
|
||||||
|
* @param {string|Object} responseBody - The HTTP response body (string or object)
|
||||||
|
* @returns {boolean} - true if the error indicates target already exists
|
||||||
|
*/
|
||||||
|
isTargetAlreadyExistsError(responseBody) {
|
||||||
|
// Extract error message more efficiently
|
||||||
|
let errorString = '';
|
||||||
|
|
||||||
|
if (typeof responseBody === 'string') {
|
||||||
|
errorString = responseBody;
|
||||||
|
} else if (responseBody && typeof responseBody === 'object') {
|
||||||
|
// Try common error message fields first to avoid full JSON.stringify
|
||||||
|
errorString = responseBody.message ||
|
||||||
|
responseBody.error ||
|
||||||
|
responseBody.detail ||
|
||||||
|
JSON.stringify(responseBody);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle multiple variations of the target already exists error message
|
||||||
|
const targetExistsPatterns = [
|
||||||
|
"Target name already exists", // Original pattern in code (API v1)
|
||||||
|
"Target with this name already exists", // Actual TrueNAS error message (API v2)
|
||||||
|
"Target\\b.*\\balready\\b.*\\bexists" // Flexible pattern with word boundaries
|
||||||
|
];
|
||||||
|
|
||||||
|
return targetExistsPatterns.some(pattern => {
|
||||||
|
if (pattern.includes("\\")) {
|
||||||
|
// Use regex for flexible patterns with word boundaries
|
||||||
|
const regex = new RegExp(pattern, "i");
|
||||||
|
return regex.test(errorString);
|
||||||
|
} else {
|
||||||
|
// Use case-insensitive simple string matching for exact patterns
|
||||||
|
return errorString.toLowerCase().includes(pattern.toLowerCase());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async findResourceByProperties(endpoint, match) {
|
async findResourceByProperties(endpoint, match) {
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -210,7 +252,8 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
||||||
// crude stoppage attempt
|
// crude stoppage attempt
|
||||||
let response = await httpClient.get(endpoint, queryParams);
|
let response = await httpClient.get(endpoint, queryParams);
|
||||||
if (lastReponse) {
|
if (lastReponse) {
|
||||||
if (JSON.stringify(lastReponse) == JSON.stringify(response)) {
|
// Compare only the response body to avoid circular reference issues
|
||||||
|
if (JSON.stringify(lastReponse.body) == JSON.stringify(response.body)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -924,21 +967,30 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
||||||
target
|
target
|
||||||
);
|
);
|
||||||
|
|
||||||
// 409 if invalid
|
// 409 Conflict - target already exists or other validation errors
|
||||||
if (response.statusCode != 201) {
|
if (response.statusCode != 201) {
|
||||||
target = null;
|
target = null;
|
||||||
if (
|
if (
|
||||||
response.statusCode == 409 &&
|
response.statusCode == 409 &&
|
||||||
JSON.stringify(response.body).includes(
|
this.isTargetAlreadyExistsError(response.body)
|
||||||
"Target name already exists"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
|
this.ctx.logger.debug(
|
||||||
|
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||||
|
iscsiName
|
||||||
|
);
|
||||||
target = await this.findResourceByProperties(
|
target = await this.findResourceByProperties(
|
||||||
"/services/iscsi/target",
|
"/services/iscsi/target",
|
||||||
{
|
{
|
||||||
iscsi_target_name: iscsiName,
|
iscsi_target_name: iscsiName,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
if (target) {
|
||||||
|
this.ctx.logger.debug(
|
||||||
|
"Found existing iSCSI target with ID: %s, name: %s",
|
||||||
|
target.id,
|
||||||
|
target.iscsi_target_name
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new GrpcError(
|
throw new GrpcError(
|
||||||
grpc.status.UNKNOWN,
|
grpc.status.UNKNOWN,
|
||||||
|
|
@ -1212,21 +1264,30 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
||||||
|
|
||||||
response = await httpClient.post("/iscsi/target", target);
|
response = await httpClient.post("/iscsi/target", target);
|
||||||
|
|
||||||
// 409 if invalid
|
// 422 Unprocessable Entity - validation errors including duplicate targets
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
target = null;
|
target = null;
|
||||||
if (
|
if (
|
||||||
response.statusCode == 422 &&
|
response.statusCode == 422 &&
|
||||||
JSON.stringify(response.body).includes(
|
this.isTargetAlreadyExistsError(response.body)
|
||||||
"Target name already exists"
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
|
this.ctx.logger.debug(
|
||||||
|
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||||
|
iscsiName
|
||||||
|
);
|
||||||
target = await this.findResourceByProperties(
|
target = await this.findResourceByProperties(
|
||||||
"/iscsi/target",
|
"/iscsi/target",
|
||||||
{
|
{
|
||||||
name: iscsiName,
|
name: iscsiName,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
if (target) {
|
||||||
|
this.ctx.logger.debug(
|
||||||
|
"Found existing iSCSI target with ID: %s, name: %s",
|
||||||
|
target.id,
|
||||||
|
target.name
|
||||||
|
);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new GrpcError(
|
throw new GrpcError(
|
||||||
grpc.status.UNKNOWN,
|
grpc.status.UNKNOWN,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue