s3: error handling has changed in v3 api
This commit is contained in:
@@ -36,12 +36,12 @@ const assert = require('assert'),
|
||||
{ PassThrough } = require('node:stream'),
|
||||
path = require('path'),
|
||||
{ Readable } = require('stream'),
|
||||
{ S3 } = require('@aws-sdk/client-s3'),
|
||||
{ S3, NoSuchKey, NoSuchBucket } = require('@aws-sdk/client-s3'),
|
||||
safe = require('safetydance'),
|
||||
{ Upload } = require('@aws-sdk/lib-storage');
|
||||
|
||||
function S3_NOT_FOUND(error) {
|
||||
return error.code === 'NoSuchKey' || error.code === 'NotFound' || error.code === 'ENOENT';
|
||||
return error instanceof NoSuchKey || error instanceof NoSuchBucket;
|
||||
}
|
||||
|
||||
const RETRY_STRATEGY = new ConfiguredRetryStrategy(10 /* max attempts */, (/* attempt */) => 20000 /* constant backoff */);
|
||||
@@ -124,7 +124,7 @@ async function upload(apiConfig, backupFilePath) {
|
||||
stream: passThrough,
|
||||
async finish() {
|
||||
const [error, data] = await safe(uploadPromise);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Upload error: code: ${error.code} message: ${error.message}`); // sometimes message is null
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Upload error: code: ${error.Code} message: ${error.message}`); // sometimes message is null
|
||||
debug(`Upload finished. ${JSON.stringify(data)}`);
|
||||
}
|
||||
};
|
||||
@@ -144,7 +144,7 @@ async function exists(apiConfig, backupFilePath) {
|
||||
|
||||
const [error, response] = await safe(s3.headObject(params));
|
||||
if (error && S3_NOT_FOUND(error)) return false;
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error headObject ${backupFilePath}. Message: ${error.message} HTTP Code: ${error.code}`);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error headObject ${backupFilePath}. Message: ${error.message} HTTP Code: ${error.$metadata.httpStatusCode}`);
|
||||
if (!response || typeof response.Metadata !== 'object') throw new BoxError(BoxError.EXTERNAL_ERROR, 'not a s3 endpoint');
|
||||
|
||||
return true;
|
||||
@@ -156,7 +156,7 @@ async function exists(apiConfig, backupFilePath) {
|
||||
};
|
||||
|
||||
const [error, listData] = await safe(s3.listObjectsV2(listParams));
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects ${backupFilePath}. Message: ${error.message} HTTP Code: ${error.code}`);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects ${backupFilePath}. Message: ${error.message} HTTP Code: ${error.$metadata.httpStatusCode}`);
|
||||
|
||||
return listData.Contents.length !== 0;
|
||||
}
|
||||
@@ -186,7 +186,7 @@ class S3MultipartDownloadStream extends Readable {
|
||||
this.destroy(new BoxError(BoxError.NOT_FOUND, `Backup not found: ${this._path}`));
|
||||
} else {
|
||||
debug(`download: ${this._path} s3 stream error. %o`, error);
|
||||
this.destroy(new BoxError(BoxError.EXTERNAL_ERROR, `Error multipartDownload ${this._path}. Message: ${error.message} HTTP Code: ${error.code}`));
|
||||
this.destroy(new BoxError(BoxError.EXTERNAL_ERROR, `Error multipartDownload ${this._path}. Message: ${error.message} HTTP Code: ${error.$metadata.httpStatusCode}`));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ async function listDir(apiConfig, dir, batchSize, marker) {
|
||||
if (marker) listParams.ContinuationToken = marker;
|
||||
|
||||
const [error, listData] = await safe(s3.listObjectsV2(listParams));
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects in ${dir}. Message: ${error.message} HTTP Code: ${error.code}`);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects in ${dir}. Message: ${error.message} HTTP Code: ${error.$metadata.httpStatusCode}`);
|
||||
if (listData.Contents.length === 0) return { entries: [], marker: null }; // no more
|
||||
const entries = listData.Contents.map(function (c) { return { fullPath: c.Key, size: c.Size }; });
|
||||
return { entries, marker: !listData.IsTruncated ? null : listData.NextContinuationToken };
|
||||
@@ -303,7 +303,7 @@ async function copyFile(apiConfig, oldFilePath, newFilePath, entry, progressCall
|
||||
if (error) debug(`copy: s3 copy error when copying ${entry.fullPath}: ${error}`);
|
||||
|
||||
if (error && S3_NOT_FOUND(error)) throw new BoxError(BoxError.NOT_FOUND, `Old backup not found: ${entry.fullPath}`);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error copying ${entry.fullPath} (${entry.size} bytes): ${error.code || ''} ${error}`);
|
||||
if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error copying ${entry.fullPath} (${entry.size} bytes): ${error.Code || ''} ${error}`);
|
||||
}
|
||||
|
||||
const copyParams = {
|
||||
@@ -472,7 +472,7 @@ async function removeDir(apiConfig, pathPrefix, progressCallback) {
|
||||
// deleteObjects does not return error if key is not found
|
||||
const [error] = await safe(s3.deleteObjects(deleteParams));
|
||||
if (error) {
|
||||
progressCallback({ message: `Unable to remove ${deleteParams.Key} ${error.message || error.code}` });
|
||||
progressCallback({ message: `Unable to remove ${deleteParams.Key} ${error.message || error.Code}` });
|
||||
throw new BoxError(BoxError.EXTERNAL_ERROR, `Unable to remove ${deleteParams.Key}. error: ${error.message}`);
|
||||
}
|
||||
});
|
||||
@@ -530,7 +530,7 @@ async function testConfig(apiConfig) {
|
||||
|
||||
const s3 = createS3Client(apiConfig, {});
|
||||
const [putError] = await safe(s3.putObject(putParams));
|
||||
if (putError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error put object cloudron-testfile. Message: ${putError.message} HTTP Code: ${putError.code}`);
|
||||
if (putError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error put object cloudron-testfile. Message: ${putError.message} HTTP Code: ${putError.$metadata.httpStatusCode}`);
|
||||
|
||||
const listParams = {
|
||||
Bucket: apiConfig.bucket,
|
||||
@@ -539,7 +539,7 @@ async function testConfig(apiConfig) {
|
||||
};
|
||||
|
||||
const [listError] = await safe(s3.listObjectsV2(listParams));
|
||||
if (listError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects. Message: ${listError.message} HTTP Code: ${listError.code}`);
|
||||
if (listError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects. Message: ${listError.message} HTTP Code: ${listError.$metadata.httpStatusCode}`);
|
||||
|
||||
const delParams = {
|
||||
Bucket: apiConfig.bucket,
|
||||
@@ -547,7 +547,7 @@ async function testConfig(apiConfig) {
|
||||
};
|
||||
|
||||
const [delError] = await safe(s3.deleteObject(delParams));
|
||||
if (delError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error del object cloudron-testfile. Message: ${delError.message} HTTP Code: ${delError.code}`);
|
||||
if (delError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error del object cloudron-testfile. Message: ${delError.message} HTTP Code: ${delError.$metadata.httpStatusCode}`);
|
||||
}
|
||||
|
||||
function removePrivateFields(apiConfig) {
|
||||
|
||||
Reference in New Issue
Block a user