diff --git a/migrations/20250716070056-fixup-linode-objectstorage-settings.js b/migrations/20250716070056-fixup-linode-objectstorage-settings.js new file mode 100644 index 000000000..1d8cf8e38 --- /dev/null +++ b/migrations/20250716070056-fixup-linode-objectstorage-settings.js @@ -0,0 +1,34 @@ +'use strict'; + +function s3like(provider) { + return provider === 's3' || provider === 'minio' || provider === 's3-v4-compat' + || provider === 'exoscale-sos' || provider === 'digitalocean-spaces' || provider === 'hetzner-objectstorage' + || provider === 'scaleway-objectstorage' || provider === 'wasabi' || provider === 'backblaze-b2' || provider === 'cloudflare-r2' + || provider === 'linode-objectstorage' || provider === 'ovh-objectstorage' || provider === 'ionos-objectstorage' + || provider === 'vultr-objectstorage' || provider === 'upcloud-objectstorage' || provider === 'idrive-e2' + || provider === 'contabo-objectstorage'; +} + +exports.up = async function (db) { + const result = await db.runSql('SELECT * FROM settings WHERE name=?', [ 'backup_storage' ]); + if (!result.length) return; + + const storageConfig = JSON.parse(result[0].value); + if (!s3like(storageConfig.provider)) return; + + if (storageConfig.endpoint && !storageConfig.endpoint.match(/^(http:|https:)\/\//)) { + console.log('migrating backup provider endpoint to https'); + storageConfig.endpoint = `https://${storageConfig.endpoint}`; + } + + if (storageConfig.provider === 'linode-objectstorage') { // in some old release, we didn't set the region correctly + const match = storageConfig.endpoint.match(/^https:\/\/(.*).linodeobjects.com$/); + storageConfig.region = match ? match[1] : storageConfig.region; + } + + await db.runSql('UPDATE settings SET value=? WHERE name=?', [ JSON.stringify(storageConfig), 'backup_storage']); + +}; + +exports.down = async function (db) { +}; diff --git a/src/storage/s3.js b/src/storage/s3.js index 4bfa20d65..bbd4c7bba 100644 --- a/src/storage/s3.js +++ b/src/storage/s3.js @@ -46,7 +46,8 @@ function S3_NOT_FOUND(error) { } function formatError(error) { - return `code: ${error.Code} message: ${error.message} HTTP: ${error.$metadata.httpStatusCode}`; + // $metadata can be undefined if HTTP request was never sent + return `code: ${error.Code} message: ${error.message} HTTP: ${error.$metadata?.httpStatusCode}`; } const RETRY_STRATEGY = new ConfiguredRetryStrategy(10 /* max attempts */, (/* attempt */) => 20000 /* constant backoff */);