From 2e908e3d6371ae72a6715c4529ae17efc3d77627 Mon Sep 17 00:00:00 2001 From: KillianG Date: Wed, 28 Jun 2023 09:20:56 +0000 Subject: [PATCH] Adding replicationinfo to overwriteVersionning to avoid loosing replication info in case of a restore Issue: CLDSRV-408 --- lib/api/apiUtils/object/versioning.js | 6 +- tests/unit/api/apiUtils/versioning.js | 277 +++++++++++++++++--------- 2 files changed, 193 insertions(+), 90 deletions(-) diff --git a/lib/api/apiUtils/object/versioning.js b/lib/api/apiUtils/object/versioning.js index b183c655d4..d386ecbe6c 100644 --- a/lib/api/apiUtils/object/versioning.js +++ b/lib/api/apiUtils/object/versioning.js @@ -453,12 +453,16 @@ function overwritingVersioning(objMD, metadataStoreParams) { // set correct originOp metadataStoreParams.originOp = 's3:ObjectRestore:Completed'; + const userMDNotToKeep = ['x-amz-meta-scal-s3-restore-attempt']; // We need to keep user metadata and tags for (const key of Object.keys(objMD)) { - if (key.startsWith('x-amz-meta-')) { + if (key.startsWith('x-amz-meta-') && !userMDNotToKeep.includes(key)) { metadataStoreParams.metaHeaders[key] = objMD[key]; } } + if (objMD.replicationInfo?.status === 'COMPLETED') { + metadataStoreParams.replicationInfo = objMD.replicationInfo; + } metadataStoreParams.taggingCopy = objMD.tags; // update restore const days = objMD.archive?.restoreRequestedDays; diff --git a/tests/unit/api/apiUtils/versioning.js b/tests/unit/api/apiUtils/versioning.js index 3ff5d9b17a..d3c5d06aaa 100644 --- a/tests/unit/api/apiUtils/versioning.js +++ b/tests/unit/api/apiUtils/versioning.js @@ -620,123 +620,222 @@ describe('versioning helpers', () => { }))); }); - describe('overwritingVersioning', () => { - const now = Date.now(); - sinon.useFakeTimers(now); + describe.only('overwritingVersioning', () => { + sinon.useFakeTimers(); const days = 3; + const now = Date.now(); const archiveInfo = { 'archiveID': '126783123678', }; - it('Should update archive with restore infos', () => { - const metadataStoreParams = {}; - const objMD = { - 'versionId': '2345678', - 'creation-time': now, - 'last-modified': now, - 'originOp': 's3:PutObject', - archive: { - 'restoreRequestedDays': days, - 'restoreRequestedAt': now, - archiveInfo - } - }; - const options = overwritingVersioning(objMD, metadataStoreParams); - - const expectedRes = { - 'creationTime': now, - 'lastModifiedDate': now, - 'updateMicroVersionId': true, - 'originOp': 's3:ObjectRestore:Completed', - taggingCopy: undefined, - archive: { - archiveInfo, - 'restoreRequestedDays': 3, - 'restoreRequestedAt': now, - 'restoreCompletedAt': new Date(now), - 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), - } - }; - assert.deepStrictEqual(options.versionId, '2345678'); - assert.deepStrictEqual(metadataStoreParams, expectedRes); - }); - - it('Should keep user mds and tags', () => { - const metadataStoreParams = { - 'metaHeaders': {}, - }; - const objMD = { + const array = [ + { + description: 'Should update archive with restore infos', + objMD: { 'versionId': '2345678', 'creation-time': now, 'last-modified': now, 'originOp': 's3:PutObject', - 'x-amz-meta-test': 'test', - 'x-amz-meta-test2': 'test2', - 'tags': { 'testtag': 'testtag', 'testtag2': 'testtag2' }, archive: { 'restoreRequestedDays': days, 'restoreRequestedAt': now, archiveInfo + }}, + expectedRes : { + 'creationTime': now, + 'lastModifiedDate': now, + 'updateMicroVersionId': true, + 'originOp': 's3:ObjectRestore:Completed', + taggingCopy: undefined, + archive: { + archiveInfo, + 'restoreRequestedDays': 3, + 'restoreRequestedAt': now, + 'restoreCompletedAt': new Date(now), + 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + } } - }; - const options = overwritingVersioning(objMD, metadataStoreParams); - - const expectedRes = { - 'creationTime': now, - 'lastModifiedDate': now, - 'updateMicroVersionId': true, - 'originOp': 's3:ObjectRestore:Completed', - 'metaHeaders': { + }, + { + description: 'Should keep user mds and tags', + hasUserMD: true, + objMD: { + 'versionId': '2345678', + 'creation-time': now, + 'last-modified': now, + 'originOp': 's3:PutObject', 'x-amz-meta-test': 'test', 'x-amz-meta-test2': 'test2', + 'tags': { 'testtag': 'testtag', 'testtag2': 'testtag2' }, + archive: { + 'restoreRequestedDays': days, + 'restoreRequestedAt': now, + archiveInfo + } }, - taggingCopy: { 'testtag': 'testtag', 'testtag2': 'testtag2' }, - archive: { - archiveInfo, - 'restoreRequestedDays': 3, - 'restoreRequestedAt': now, - 'restoreCompletedAt': new Date(now), - 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + expectedRes: { + 'creationTime': now, + 'lastModifiedDate': now, + 'updateMicroVersionId': true, + 'originOp': 's3:ObjectRestore:Completed', + 'metaHeaders': { + 'x-amz-meta-test': 'test', + 'x-amz-meta-test2': 'test2', + }, + taggingCopy: { 'testtag': 'testtag', 'testtag2': 'testtag2' }, + archive: { + archiveInfo, + 'restoreRequestedDays': 3, + 'restoreRequestedAt': now, + 'restoreCompletedAt': new Date(now), + 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + } + }, + }, + { + description: 'Should return nullVersionId', + objMD: { + 'creation-time': now, + 'last-modified': now, + 'originOp': 's3:PutObject', + 'nullVersionId': 'vnull', + 'isNull': true, + archive: { + 'restoreRequestedDays': days, + 'restoreRequestedAt': now, + archiveInfo + } + }, + expectedRes: { + 'creationTime': now, + 'lastModifiedDate': now, + 'updateMicroVersionId': true, + 'originOp': 's3:ObjectRestore:Completed', + taggingCopy: undefined, + archive: { + archiveInfo, + 'restoreRequestedDays': 3, + 'restoreRequestedAt': now, + 'restoreCompletedAt': new Date(now), + 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + } } - }; - assert.deepStrictEqual(options.versionId, '2345678'); - assert.deepStrictEqual(metadataStoreParams, expectedRes); - }); - - it('Should return nullVersionId', () => { - const metadataStoreParams = {}; - const objMD = { + }, + { + description: 'Should not keep x-amz-meta-scal-s3-restore-attempt user MD', + hasUserMD: true, + objMD: { + 'versionId': '2345678', + 'creation-time': now, + 'last-modified': now, + 'originOp': 's3:PutObject', + 'x-amz-meta-test': 'test', + 'x-amz-meta-scal-s3-restore-attempt': 14, + archive: { + 'restoreRequestedDays': days, + 'restoreRequestedAt': now, + archiveInfo + } + }, + expectedRes: { + 'creationTime': now, + 'lastModifiedDate': now, + 'updateMicroVersionId': true, + 'originOp': 's3:ObjectRestore:Completed', + 'metaHeaders': { + 'x-amz-meta-test': 'test', + }, + taggingCopy: undefined, + archive: { + archiveInfo, + 'restoreRequestedDays': 3, + 'restoreRequestedAt': now, + 'restoreCompletedAt': new Date(now), + 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + } + } + }, + { + description: 'Should not update replication infos if COMPLETED', + objMD: { + 'versionId': '2345678', 'creation-time': now, 'last-modified': now, 'originOp': 's3:PutObject', - 'nullVersionId': 'vnull', - 'isNull': true, + 'replicationInfo': { + 'status' : 'COMPLETED', + 'backends' : [ + { + 'site' : 'azure-blob', + 'status' : 'COMPLETED', + 'dataStoreVersionId' : '' + } + ], + 'content' : [ + 'DATA', + 'METADATA' + ], + 'destination' : 'arn:aws:s3:::replicate-cold', + 'storageClass' : 'azure-blob', + 'role' : 'arn:aws:iam::root:role/s3-replication-role', + 'storageType' : 'azure', + 'dataStoreVersionId' : '', + }, archive: { 'restoreRequestedDays': days, 'restoreRequestedAt': now, archiveInfo + } + }, + expectedRes : { + 'creationTime': now, + 'lastModifiedDate': now, + 'updateMicroVersionId': true, + 'originOp': 's3:ObjectRestore:Completed', + 'replicationInfo': { + 'status' : 'COMPLETED', + 'backends' : [ + { + 'site' : 'azure-blob', + 'status' : 'COMPLETED', + 'dataStoreVersionId' : '' + } + ], + 'content' : [ + 'DATA', + 'METADATA' + ], + 'destination' : 'arn:aws:s3:::replicate-cold', + 'storageClass' : 'azure-blob', + 'role' : 'arn:aws:iam::root:role/s3-replication-role', + 'storageType' : 'azure', + 'dataStoreVersionId' : '', + }, + taggingCopy: undefined, + archive: { + archiveInfo, + 'restoreRequestedDays': 3, + 'restoreRequestedAt': now, + 'restoreCompletedAt': new Date(now), + 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + } + } + }, + ].forEach(testCase => { + it(testCase.description, () => { + const metadataStoreParams = {}; + if (testCase.hasUserMD) { + metadataStoreParams.metaHeaders = {}; } - }; - const options = overwritingVersioning(objMD, metadataStoreParams); + const options = overwritingVersioning(testCase.objMD, metadataStoreParams); + assert.deepStrictEqual(options.versionId, testCase.objMD.versionId); + assert.deepStrictEqual(metadataStoreParams, testCase.expectedRes); - const expectedRes = { - 'creationTime': now, - 'lastModifiedDate': now, - 'updateMicroVersionId': true, - 'originOp': 's3:ObjectRestore:Completed', - taggingCopy: undefined, - archive: { - archiveInfo, - 'restoreRequestedDays': 3, - 'restoreRequestedAt': now, - 'restoreCompletedAt': new Date(now), - 'restoreWillExpireAt': new Date(now + (days * scaledMsPerDay)), + if (testCase.objMD.isNull) { + assert.deepStrictEqual(options.extraMD.nullVersionId, 'vnull'); + assert.deepStrictEqual(options.isNull, true); } - }; - assert.deepStrictEqual(options.versionId, undefined); - assert.deepStrictEqual(options.extraMD.nullVersionId, 'vnull'); - assert.deepStrictEqual(options.isNull, true); - assert.deepStrictEqual(metadataStoreParams, expectedRes); + }); }); }); });