fix target idempotency, bump binary versions
Signed-off-by: Travis Glenn Hansen <travisghansen@yahoo.com>
This commit is contained in:
parent
b3292da53d
commit
ddf6b0d320
|
|
@ -121,19 +121,19 @@ RUN \
|
|||
echo '83e7a026-2564-455b-ada6-ddbdaf0bc519' > /etc/nvme/hostid && \
|
||||
echo 'nqn.2014-08.org.nvmexpress:uuid:941e4f03-2cd6-435e-86df-731b1c573d86' > /etc/nvme/hostnqn
|
||||
|
||||
ARG RCLONE_VERSION=1.69.1
|
||||
ARG RCLONE_VERSION=1.71.2
|
||||
ADD docker/rclone-installer.sh /usr/local/sbin
|
||||
RUN chmod +x /usr/local/sbin/rclone-installer.sh && rclone-installer.sh
|
||||
|
||||
ARG RESTIC_VERSION=0.18.0
|
||||
ARG RESTIC_VERSION=0.18.1
|
||||
ADD docker/restic-installer.sh /usr/local/sbin
|
||||
RUN chmod +x /usr/local/sbin/restic-installer.sh && restic-installer.sh
|
||||
|
||||
ARG KOPIA_VERSION=0.19.0
|
||||
ARG KOPIA_VERSION=0.21.1
|
||||
ADD docker/kopia-installer.sh /usr/local/sbin
|
||||
RUN chmod +x /usr/local/sbin/kopia-installer.sh && kopia-installer.sh
|
||||
|
||||
ARG YQ_VERSION=v4.45.1
|
||||
ARG YQ_VERSION=v4.48.1
|
||||
ADD docker/yq-installer.sh /usr/local/sbin
|
||||
RUN chmod +x /usr/local/sbin/yq-installer.sh && yq-installer.sh
|
||||
|
||||
|
|
|
|||
|
|
@ -41,22 +41,22 @@ RUN Invoke-WebRequest $('https://nodejs.org/dist/v{0}/node-v{0}-win-x64.zip' -f
|
|||
|
||||
RUN mkdir \usr\local\bin; mkdir \tmp
|
||||
|
||||
ARG RCLONE_VERSION=v1.69.1
|
||||
ARG RCLONE_VERSION=v1.71.2
|
||||
RUN Invoke-WebRequest "https://github.com/rclone/rclone/releases/download/${env:RCLONE_VERSION}/rclone-${env:RCLONE_VERSION}-windows-amd64.zip" -OutFile '/tmp/rclone.zip' -UseBasicParsing ; \
|
||||
Expand-Archive C:\tmp\rclone.zip -DestinationPath C:\tmp ; \
|
||||
Copy-Item $('C:\tmp\rclone-{0}-windows-amd64\rclone.exe' -f $env:RCLONE_VERSION) -Destination "C:\usr\local\bin"
|
||||
|
||||
ARG RESTIC_VERSION=0.18.0
|
||||
ARG RESTIC_VERSION=0.18.1
|
||||
RUN Invoke-WebRequest "https://github.com/restic/restic/releases/download/v${env:RESTIC_VERSION}/restic_${env:RESTIC_VERSION}_windows_amd64.zip" -OutFile '/tmp/restic.zip' -UseBasicParsing ; \
|
||||
Expand-Archive C:\tmp\restic.zip -DestinationPath C:\tmp ; \
|
||||
Copy-Item $('C:\tmp\restic_{0}_windows_amd64.exe' -f $env:RESTIC_VERSION) -Destination "C:\usr\local\bin\restic.exe"
|
||||
|
||||
ARG KOPIA_VERSION=0.19.0
|
||||
ARG KOPIA_VERSION=0.21.1
|
||||
RUN Invoke-WebRequest "https://github.com/kopia/kopia/releases/download/v${env:KOPIA_VERSION}/kopia-${env:KOPIA_VERSION}-windows-x64.zip" -OutFile '/tmp/kopia.zip' -UseBasicParsing ; \
|
||||
Expand-Archive C:\tmp\kopia.zip -DestinationPath C:\tmp ; \
|
||||
Copy-Item $('C:\tmp\kopia-{0}-windows-x64\kopia.exe' -f $env:KOPIA_VERSION) -Destination "C:\usr\local\bin"
|
||||
|
||||
ARG YQ_VERSION=v4.45.1
|
||||
ARG YQ_VERSION=v4.48.1
|
||||
RUN Invoke-WebRequest "https://github.com/mikefarah/yq/releases/download/${env:YQ_VERSION}/yq_windows_amd64.zip" -OutFile '/tmp/yq.zip' -UseBasicParsing ; \
|
||||
Expand-Archive C:\tmp\yq.zip -DestinationPath C:\tmp ; \
|
||||
Copy-Item $('C:\tmp\yq_windows_amd64.exe') -Destination "C:\usr\local\bin\yq.exe"
|
||||
|
|
|
|||
|
|
@ -178,6 +178,49 @@ 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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* should create any necessary share resources
|
||||
* should set the SHARE_VOLUME_CONTEXT_PROPERTY_NAME propery
|
||||
|
|
@ -884,21 +927,30 @@ class FreeNASApiDriver extends CsiBaseDriver {
|
|||
target
|
||||
);
|
||||
|
||||
// 409 if invalid
|
||||
// 409 Conflict - target already exists or other validation errors
|
||||
if (response.statusCode != 201) {
|
||||
target = null;
|
||||
if (
|
||||
response.statusCode == 409 &&
|
||||
JSON.stringify(response.body).includes(
|
||||
"Target name already exists"
|
||||
)
|
||||
this.isTargetAlreadyExistsError(response.body)
|
||||
) {
|
||||
this.ctx.logger.debug(
|
||||
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||
iscsiName
|
||||
);
|
||||
target = await httpApiClient.findResourceByProperties(
|
||||
"/services/iscsi/target",
|
||||
{
|
||||
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 {
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
|
|
@ -1175,21 +1227,30 @@ class FreeNASApiDriver extends CsiBaseDriver {
|
|||
|
||||
response = await httpClient.post("/iscsi/target", target);
|
||||
|
||||
// 409 if invalid
|
||||
// 422 Unprocessable Entity - validation errors including duplicate targets
|
||||
if (response.statusCode != 200) {
|
||||
target = null;
|
||||
if (
|
||||
response.statusCode == 422 &&
|
||||
JSON.stringify(response.body).includes(
|
||||
"Target name already exists"
|
||||
)
|
||||
this.isTargetAlreadyExistsError(response.body)
|
||||
) {
|
||||
this.ctx.logger.debug(
|
||||
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||
iscsiName
|
||||
);
|
||||
target = await httpApiClient.findResourceByProperties(
|
||||
"/iscsi/target",
|
||||
{
|
||||
name: iscsiName,
|
||||
}
|
||||
);
|
||||
if (target) {
|
||||
this.ctx.logger.debug(
|
||||
"Found existing iSCSI target with ID: %s, name: %s",
|
||||
target.id,
|
||||
target.name
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ class Api {
|
|||
// crude stoppage attempt
|
||||
let response = await httpClient.get(endpoint, queryParams);
|
||||
if (lastReponse) {
|
||||
if (JSON.stringify(lastReponse) == JSON.stringify(response)) {
|
||||
if (JSON.stringify(lastReponse.body) == JSON.stringify(response.body)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -228,7 +228,7 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
|||
// crude stoppage attempt
|
||||
let response = await httpClient.get(endpoint, queryParams);
|
||||
if (lastReponse) {
|
||||
if (JSON.stringify(lastReponse) == JSON.stringify(response)) {
|
||||
if (JSON.stringify(lastReponse.body) == JSON.stringify(response.body)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -273,6 +273,49 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
|||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* should create any necessary share resources
|
||||
* should set the SHARE_VOLUME_CONTEXT_PROPERTY_NAME propery
|
||||
|
|
@ -982,21 +1025,30 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
|||
target
|
||||
);
|
||||
|
||||
// 409 if invalid
|
||||
// 409 Conflict - target already exists or other validation errors
|
||||
if (response.statusCode != 201) {
|
||||
target = null;
|
||||
if (
|
||||
response.statusCode == 409 &&
|
||||
JSON.stringify(response.body).includes(
|
||||
"Target name already exists"
|
||||
)
|
||||
this.isTargetAlreadyExistsError(response.body)
|
||||
) {
|
||||
this.ctx.logger.debug(
|
||||
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||
iscsiName
|
||||
);
|
||||
target = await this.findResourceByProperties(
|
||||
"/services/iscsi/target",
|
||||
{
|
||||
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 {
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
|
|
@ -1271,21 +1323,30 @@ class FreeNASSshDriver extends ControllerZfsBaseDriver {
|
|||
|
||||
response = await httpClient.post("/iscsi/target", target);
|
||||
|
||||
// 409 if invalid
|
||||
// 422 Unprocessable Entity - validation errors including duplicate targets
|
||||
if (response.statusCode != 200) {
|
||||
target = null;
|
||||
if (
|
||||
response.statusCode == 422 &&
|
||||
JSON.stringify(response.body).includes(
|
||||
"Target name already exists"
|
||||
)
|
||||
this.isTargetAlreadyExistsError(response.body)
|
||||
) {
|
||||
this.ctx.logger.debug(
|
||||
"iSCSI target already exists, attempting to find existing target with name: %s",
|
||||
iscsiName
|
||||
);
|
||||
target = await this.findResourceByProperties(
|
||||
"/iscsi/target",
|
||||
{
|
||||
name: iscsiName,
|
||||
}
|
||||
);
|
||||
if (target) {
|
||||
this.ctx.logger.debug(
|
||||
"Found existing iSCSI target with ID: %s, name: %s",
|
||||
target.id,
|
||||
target.name
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new GrpcError(
|
||||
grpc.status.UNKNOWN,
|
||||
|
|
|
|||
Loading…
Reference in New Issue