diff --git a/src/backupformat/rsync.js b/src/backupformat/rsync.js index 19d61671d..0447e57aa 100644 --- a/src/backupformat/rsync.js +++ b/src/backupformat/rsync.js @@ -196,7 +196,7 @@ async function downloadDir(backupConfig, backupFilePath, dataLayout, progressCal assert(dataLayout instanceof DataLayout, 'dataLayout must be a DataLayout'); assert.strictEqual(typeof progressCallback, 'function'); - debug(`downloadDir: ${backupFilePath} to ${dataLayout.toString()}. encryption filenames: ${backupConfig.encryptedFilenames} content: ${backupConfig.encryption}`); + debug(`downloadDir: ${backupFilePath} to ${dataLayout.toString()}. encryption filenames: ${backupConfig.encryptedFilenames} content: ${!!backupConfig.encryption}`); async function downloadFile(entry) { let relativePath = path.relative(backupFilePath, entry.fullPath); diff --git a/src/storage/s3.js b/src/storage/s3.js index e7a2d6ccb..92151889a 100644 --- a/src/storage/s3.js +++ b/src/storage/s3.js @@ -44,6 +44,10 @@ function S3_NOT_FOUND(error) { return error instanceof NoSuchKey || error instanceof NoSuchBucket; } +function formatError(error) { + return `code: ${error.Code} message: ${error.message} HTTP: ${error.$metadata.httpStatusCode}`; +} + const RETRY_STRATEGY = new ConfiguredRetryStrategy(10 /* max attempts */, (/* attempt */) => 20000 /* constant backoff */); function createS3Client(apiConfig, options) { @@ -144,7 +148,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.$metadata.httpStatusCode}`); + if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error headObject ${backupFilePath}. ${formatError(error)}`); if (!response || typeof response.Metadata !== 'object') throw new BoxError(BoxError.EXTERNAL_ERROR, 'not a s3 endpoint'); return true; @@ -156,7 +160,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.$metadata.httpStatusCode}`); + if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects ${backupFilePath}. ${formatError(error)}`); return listData.Contents.length !== 0; } @@ -186,7 +190,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.$metadata.httpStatusCode}`)); + this.destroy(new BoxError(BoxError.EXTERNAL_ERROR, `Error multipartDownload ${this._path}. ${formatError(error)}`)); } } @@ -270,7 +274,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.$metadata.httpStatusCode}`); + if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects in ${dir}. ${formatError(error)}`); 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 }; @@ -422,7 +426,7 @@ async function remove(apiConfig, filename) { // deleteObjects does not return error if key is not found const [error] = await safe(s3.deleteObjects(deleteParams)); - if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unable to remove ${deleteParams.Key}. error: ${error.message}`); + if (error) throw new BoxError(BoxError.EXTERNAL_ERROR, `Unable to remove ${deleteParams.Key}. ${formatError(error)}`); } function chunk(array, size) { @@ -530,7 +534,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.$metadata.httpStatusCode}`); + if (putError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error put object cloudron-testfile. ${formatError(putError)}`); const listParams = { Bucket: apiConfig.bucket, @@ -539,7 +543,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.$metadata.httpStatusCode}`); + if (listError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error listing objects. ${formatError(listError)}`); const delParams = { Bucket: apiConfig.bucket, @@ -547,7 +551,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.$metadata.httpStatusCode}`); + if (delError) throw new BoxError(BoxError.EXTERNAL_ERROR, `Error del object cloudron-testfile. ${formatError(delError)}`); } function removePrivateFields(apiConfig) {