Compare commits
1 Commits
developmen
...
feature/re
Author | SHA1 | Date |
---|---|---|
Dora Korpar | 9e2252d26a |
|
@ -27,9 +27,9 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
function checkDestBucketVal(next) {
|
function checkDestBucketVal(next) {
|
||||||
metadataValidateBucketAndObj(metadataValParams, log,
|
metadataValidateBucketAndObj(metadataValParams, log,
|
||||||
(err, destinationBucket) => {
|
(err, destinationBucket, objMD) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err, destinationBucket);
|
return next(err, destinationBucket, 0, objMD);
|
||||||
}
|
}
|
||||||
if (destinationBucket.policies) {
|
if (destinationBucket.policies) {
|
||||||
// TODO: Check bucket policies to see if user is granted
|
// TODO: Check bucket policies to see if user is granted
|
||||||
|
@ -41,21 +41,22 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
metadataValMPUparams.requestType =
|
metadataValMPUparams.requestType =
|
||||||
'bucketPolicyGoAhead';
|
'bucketPolicyGoAhead';
|
||||||
}
|
}
|
||||||
return next(null, destinationBucket);
|
return next(null, destinationBucket, objMD);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function checkMPUval(destBucket, next) {
|
function checkMPUval(destBucket, objMD, next) {
|
||||||
metadataValParams.log = log;
|
metadataValParams.log = log;
|
||||||
services.metadataValidateMultipart(metadataValParams,
|
services.metadataValidateMultipart(metadataValParams,
|
||||||
(err, mpuBucket, mpuOverviewObj) => {
|
(err, mpuBucket, mpuOverviewObj) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err, destBucket);
|
return next(err, destBucket, 0, objMD);
|
||||||
}
|
}
|
||||||
return next(err, mpuBucket, mpuOverviewObj, destBucket);
|
return next(err, mpuBucket, mpuOverviewObj, destBucket,
|
||||||
|
objMD);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function ifMultipleBackend(mpuBucket, mpuOverviewObj, destBucket,
|
function ifMultipleBackend(mpuBucket, mpuOverviewObj, destBucket,
|
||||||
next) {
|
objMD, next) {
|
||||||
if (config.backends.data === 'multiple') {
|
if (config.backends.data === 'multiple') {
|
||||||
let location;
|
let location;
|
||||||
// if controlling location constraint is not stored in object
|
// if controlling location constraint is not stored in object
|
||||||
|
@ -66,7 +67,7 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
null, destBucket, log);
|
null, destBucket, log);
|
||||||
if (backendInfoObj.err) {
|
if (backendInfoObj.err) {
|
||||||
return process.nextTick(() => {
|
return process.nextTick(() => {
|
||||||
next(backendInfoObj.err, destBucket);
|
next(backendInfoObj.err, destBucket, 0, objMD);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
location = backendInfoObj.controllingLC;
|
location = backendInfoObj.controllingLC;
|
||||||
|
@ -76,37 +77,37 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
return multipleBackendGateway.abortMPU(objectKey, uploadId,
|
return multipleBackendGateway.abortMPU(objectKey, uploadId,
|
||||||
location, bucketName, log, (err, skipDataDelete) => {
|
location, bucketName, log, (err, skipDataDelete) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err, destBucket);
|
return next(err, destBucket, 0, objMD);
|
||||||
}
|
}
|
||||||
return next(null, mpuBucket, destBucket,
|
return next(null, mpuBucket, destBucket,
|
||||||
skipDataDelete);
|
skipDataDelete, objMD);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return next(null, mpuBucket, destBucket, false);
|
return next(null, mpuBucket, destBucket, false, objMD);
|
||||||
},
|
},
|
||||||
function getPartLocations(mpuBucket, destBucket, skipDataDelete,
|
function getPartLocations(mpuBucket, destBucket, skipDataDelete,
|
||||||
next) {
|
objMD, next) {
|
||||||
services.getMPUparts(mpuBucket.getName(), uploadId, log,
|
services.getMPUparts(mpuBucket.getName(), uploadId, log,
|
||||||
(err, result) => {
|
(err, result) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err, destBucket);
|
return next(err, destBucket, 0, objMD);
|
||||||
}
|
}
|
||||||
const storedParts = result.Contents;
|
const storedParts = result.Contents;
|
||||||
return next(null, mpuBucket, storedParts, destBucket,
|
return next(null, mpuBucket, storedParts, destBucket,
|
||||||
skipDataDelete);
|
skipDataDelete, objMD);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
function deleteData(mpuBucket, storedParts, destBucket,
|
function deleteData(mpuBucket, storedParts, destBucket,
|
||||||
skipDataDelete, next) {
|
skipDataDelete, objMD, next) {
|
||||||
// for Azure we do not need to delete data
|
// for Azure we do not need to delete data
|
||||||
if (skipDataDelete) {
|
if (skipDataDelete) {
|
||||||
return next(null, mpuBucket, storedParts, destBucket);
|
return next(null, mpuBucket, storedParts, destBucket, objMD);
|
||||||
}
|
}
|
||||||
// The locations were sent to metadata as an array
|
// The locations were sent to metadata as an array
|
||||||
// under partLocations. Pull the partLocations.
|
// under partLocations. Pull the partLocations.
|
||||||
let locations = storedParts.map(item => item.value.partLocations);
|
let locations = storedParts.map(item => item.value.partLocations);
|
||||||
if (locations.length === 0) {
|
if (locations.length === 0) {
|
||||||
return next(null, mpuBucket, storedParts, destBucket);
|
return next(null, mpuBucket, storedParts, destBucket, objMD);
|
||||||
}
|
}
|
||||||
// flatten the array
|
// flatten the array
|
||||||
locations = [].concat(...locations);
|
locations = [].concat(...locations);
|
||||||
|
@ -117,9 +118,10 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
}
|
}
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
}, () => next(null, mpuBucket, storedParts, destBucket));
|
}, () => next(null, mpuBucket, storedParts, destBucket, objMD));
|
||||||
},
|
},
|
||||||
function deleteMetadata(mpuBucket, storedParts, destBucket, next) {
|
function deleteMetadata(mpuBucket, storedParts, destBucket, objMD,
|
||||||
|
next) {
|
||||||
let splitter = constants.splitter;
|
let splitter = constants.splitter;
|
||||||
// BACKWARD: Remove to remove the old splitter
|
// BACKWARD: Remove to remove the old splitter
|
||||||
if (mpuBucket.getMdBucketModelVersion() < 2) {
|
if (mpuBucket.getMdBucketModelVersion() < 2) {
|
||||||
|
@ -135,7 +137,8 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
const keysToDelete = storedParts.map(item => item.key);
|
const keysToDelete = storedParts.map(item => item.key);
|
||||||
keysToDelete.push(mpuOverviewKey);
|
keysToDelete.push(mpuOverviewKey);
|
||||||
services.batchDeleteObjectMetadata(mpuBucket.getName(),
|
services.batchDeleteObjectMetadata(mpuBucket.getName(),
|
||||||
keysToDelete, log, err => next(err, destBucket, partSizeSum));
|
keysToDelete, log, err => next(err, destBucket, partSizeSum,
|
||||||
|
objMD));
|
||||||
},
|
},
|
||||||
], callback);
|
], callback);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,9 +180,17 @@ function _parseXml(xmlToParse, next) {
|
||||||
*/
|
*/
|
||||||
function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||||
bucketName, bucket, quietSetting, errorResults, inPlay, log, next) {
|
bucketName, bucket, quietSetting, errorResults, inPlay, log, next) {
|
||||||
|
const deletedObjStats = {
|
||||||
|
requesterIsObjOwner: {
|
||||||
|
totalContentLengthDeleted: 0,
|
||||||
|
numOfObjectsRemoved: 0,
|
||||||
|
},
|
||||||
|
requesterNotObjOwner: {
|
||||||
|
totalContentLengthDeleted: 0,
|
||||||
|
numOfObjectsRemoved: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
const successfullyDeleted = [];
|
const successfullyDeleted = [];
|
||||||
let totalContentLengthDeleted = 0;
|
|
||||||
let numOfObjectsRemoved = 0;
|
|
||||||
const skipError = new Error('skip');
|
const skipError = new Error('skip');
|
||||||
|
|
||||||
// doing 5 requests at a time. note that the data wrapper
|
// doing 5 requests at a time. note that the data wrapper
|
||||||
|
@ -253,9 +261,19 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||||
errorResults.push({ entry, error: err });
|
errorResults.push({ entry, error: err });
|
||||||
return moveOn();
|
return moveOn();
|
||||||
}
|
}
|
||||||
|
const reqObjDiffOwners = objMD && canonicalID !== objMD['owner-id'];
|
||||||
if (deleteInfo.deleted && objMD['content-length']) {
|
if (deleteInfo.deleted && objMD['content-length']) {
|
||||||
numOfObjectsRemoved++;
|
if (reqObjDiffOwners) {
|
||||||
totalContentLengthDeleted += objMD['content-length'];
|
deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved++;
|
||||||
|
deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted += objMD['content-length'];
|
||||||
|
deletedObjStats.requesterNotObjOwner.objOwnerCanonicalID =
|
||||||
|
objMD['owner-id'];
|
||||||
|
} else {
|
||||||
|
deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved++;
|
||||||
|
deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted += objMD['content-length'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let isDeleteMarker;
|
let isDeleteMarker;
|
||||||
let deleteMarkerVersionId;
|
let deleteMarkerVersionId;
|
||||||
|
@ -269,7 +287,11 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||||
deleteMarkerVersionId = versionIdUtils.encode(versionId);
|
deleteMarkerVersionId = versionIdUtils.encode(versionId);
|
||||||
// In this case we are putting a new object (i.e., the delete
|
// In this case we are putting a new object (i.e., the delete
|
||||||
// marker), so we decrement the numOfObjectsRemoved value.
|
// marker), so we decrement the numOfObjectsRemoved value.
|
||||||
numOfObjectsRemoved--;
|
if (reqObjDiffOwners) {
|
||||||
|
deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved--;
|
||||||
|
} else {
|
||||||
|
deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved--;
|
||||||
|
}
|
||||||
// If trying to delete a delete marker, DeleteMarkerVersionId equals
|
// If trying to delete a delete marker, DeleteMarkerVersionId equals
|
||||||
// deleteMarker's versionID and DeleteMarker equals true
|
// deleteMarker's versionID and DeleteMarker equals true
|
||||||
} else if (objMD && objMD.isDeleteMarker) {
|
} else if (objMD && objMD.isDeleteMarker) {
|
||||||
|
@ -283,9 +305,13 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||||
},
|
},
|
||||||
// end of forEach func
|
// end of forEach func
|
||||||
err => {
|
err => {
|
||||||
log.trace('finished deleting objects', { numOfObjectsRemoved });
|
const totalObjectsRemoved = deletedObjStats.requesterIsObjOwner.
|
||||||
return next(err, quietSetting, errorResults, numOfObjectsRemoved,
|
numOfObjectsRemoved + deletedObjStats.requesterNotObjOwner.
|
||||||
successfullyDeleted, totalContentLengthDeleted, bucket);
|
numberOfObjectsRemoved;
|
||||||
|
log.trace('finished deleting objects',
|
||||||
|
{ numOfObjectsRemoved: totalObjectsRemoved });
|
||||||
|
return next(err, quietSetting, errorResults, deletedObjStats,
|
||||||
|
successfullyDeleted, bucket);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,8 +499,8 @@ function multiObjectDelete(authInfo, request, log, callback) {
|
||||||
bucketName, bucket, quietSetting, errorResults, inPlay,
|
bucketName, bucket, quietSetting, errorResults, inPlay,
|
||||||
log, next);
|
log, next);
|
||||||
},
|
},
|
||||||
], (err, quietSetting, errorResults, numOfObjectsRemoved,
|
], (err, quietSetting, errorResults, deletedObjStats,
|
||||||
successfullyDeleted, totalContentLengthDeleted, bucket) => {
|
successfullyDeleted, bucket) => {
|
||||||
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
||||||
request.method, bucket);
|
request.method, bucket);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -483,13 +509,30 @@ function multiObjectDelete(authInfo, request, log, callback) {
|
||||||
const xml = _formatXML(quietSetting, errorResults,
|
const xml = _formatXML(quietSetting, errorResults,
|
||||||
successfullyDeleted);
|
successfullyDeleted);
|
||||||
const deletedKeys = successfullyDeleted.map(item => item.key);
|
const deletedKeys = successfullyDeleted.map(item => item.key);
|
||||||
pushMetric('multiObjectDelete', log, {
|
if (deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved > 0) {
|
||||||
authInfo,
|
pushMetric('multiObjectDelete', log, {
|
||||||
bucket: bucketName,
|
authInfo,
|
||||||
keys: deletedKeys,
|
bucket: bucketName,
|
||||||
byteLength: Number.parseInt(totalContentLengthDeleted, 10),
|
keys: deletedKeys,
|
||||||
numberOfObjects: numOfObjectsRemoved,
|
byteLength: Number.parseInt(deletedObjStats.requesterIsObjOwner.
|
||||||
});
|
totalContentLengthDeleted, 10),
|
||||||
|
numberOfObjects: deletedObjStats.requesterIsObjOwner.
|
||||||
|
numOfObjectsRemoved,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved > 0) {
|
||||||
|
pushMetric('multiObjectDelete', log, {
|
||||||
|
authInfo,
|
||||||
|
bucket: bucketName,
|
||||||
|
keys: deletedKeys,
|
||||||
|
byteLength: Number.parseInt(deletedObjStats.
|
||||||
|
requesterNotObjOwner.totalContentLengthDeleted, 10),
|
||||||
|
numberOfObjects: deletedObjStats.requesterNotObjOwner.
|
||||||
|
numOfObjectsRemoved,
|
||||||
|
objOwnerCanonicalID: deletedObjStats.requesterNotObjOwner.
|
||||||
|
objOwnerCanonicalID,
|
||||||
|
});
|
||||||
|
}
|
||||||
return callback(null, xml, corsHeaders);
|
return callback(null, xml, corsHeaders);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ function multipartDelete(authInfo, request, log, callback) {
|
||||||
const uploadId = request.query.uploadId;
|
const uploadId = request.query.uploadId;
|
||||||
|
|
||||||
abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||||
(err, destinationBucket, partSizeSum) => {
|
(err, destinationBucket, partSizeSum, objMD) => {
|
||||||
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
||||||
request.method, destinationBucket);
|
request.method, destinationBucket);
|
||||||
const location = destinationBucket ?
|
const location = destinationBucket ?
|
||||||
|
@ -49,6 +49,7 @@ function multipartDelete(authInfo, request, log, callback) {
|
||||||
bucket: bucketName,
|
bucket: bucketName,
|
||||||
keys: [objectKey],
|
keys: [objectKey],
|
||||||
byteLength: partSizeSum,
|
byteLength: partSizeSum,
|
||||||
|
objOwnerCanonicalID: objMD ? objMD['owner-id'] : '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return callback(null, corsHeaders);
|
return callback(null, corsHeaders);
|
||||||
|
|
|
@ -146,8 +146,12 @@ function objectDelete(authInfo, request, log, cb) {
|
||||||
resHeaders['x-amz-version-id'] = result.versionId === 'null' ?
|
resHeaders['x-amz-version-id'] = result.versionId === 'null' ?
|
||||||
result.versionId : versionIdUtils.encode(result.versionId);
|
result.versionId : versionIdUtils.encode(result.versionId);
|
||||||
}
|
}
|
||||||
pushMetric('putDeleteMarkerObject', log, { authInfo,
|
pushMetric('putDeleteMarkerObject', log, {
|
||||||
bucket: bucketName, keys: [objectKey] });
|
authInfo,
|
||||||
|
bucket: bucketName,
|
||||||
|
keys: [objectKey],
|
||||||
|
objOwnerCanonicalID: objectMD ? objectMD['owner-id'] : '',
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
log.end().addDefaultFields({
|
log.end().addDefaultFields({
|
||||||
contentLength: objectMD['content-length'],
|
contentLength: objectMD['content-length'],
|
||||||
|
@ -157,7 +161,9 @@ function objectDelete(authInfo, request, log, cb) {
|
||||||
bucket: bucketName,
|
bucket: bucketName,
|
||||||
keys: [objectKey],
|
keys: [objectKey],
|
||||||
byteLength: Number.parseInt(objectMD['content-length'], 10),
|
byteLength: Number.parseInt(objectMD['content-length'], 10),
|
||||||
numberOfObjects: 1 });
|
numberOfObjects: 1,
|
||||||
|
objOwnerCanonicalID: objectMD ? objectMD['owner-id'] : '',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return cb(err, resHeaders);
|
return cb(err, resHeaders);
|
||||||
});
|
});
|
||||||
|
|
|
@ -196,7 +196,8 @@ function listMetrics(metricType) {
|
||||||
*/
|
*/
|
||||||
function pushMetric(action, log, metricObj) {
|
function pushMetric(action, log, metricObj) {
|
||||||
const { bucket, keys, byteLength, newByteLength,
|
const { bucket, keys, byteLength, newByteLength,
|
||||||
oldByteLength, numberOfObjects, authInfo, canonicalID } = metricObj;
|
oldByteLength, numberOfObjects, authInfo, canonicalID,
|
||||||
|
objOwnerCanonicalID } = metricObj;
|
||||||
const utapiObj = {
|
const utapiObj = {
|
||||||
bucket,
|
bucket,
|
||||||
keys,
|
keys,
|
||||||
|
@ -205,10 +206,14 @@ function pushMetric(action, log, metricObj) {
|
||||||
oldByteLength,
|
oldByteLength,
|
||||||
numberOfObjects,
|
numberOfObjects,
|
||||||
};
|
};
|
||||||
|
// If objOwnerCanonicalID is included, there is possible discrepancy between
|
||||||
|
// object owner and requester, so use objOwnerCanonicalID for metrics
|
||||||
// If `authInfo` is included by the API, get the account's canonical ID for
|
// If `authInfo` is included by the API, get the account's canonical ID for
|
||||||
// account-level metrics and the shortId for user-level metrics. Otherwise
|
// account-level metrics and the shortId for user-level metrics. Otherwise
|
||||||
// check if the canonical ID is already provided for account-level metrics.
|
// check if the canonical ID is already provided for account-level metrics.
|
||||||
if (authInfo) {
|
if (objOwnerCanonicalID) {
|
||||||
|
utapiObj.accountId = objOwnerCanonicalID;
|
||||||
|
} else if (authInfo) {
|
||||||
utapiObj.accountId = authInfo.getCanonicalID();
|
utapiObj.accountId = authInfo.getCanonicalID();
|
||||||
utapiObj.userId = authInfo.isRequesterAnIAMUser() ?
|
utapiObj.userId = authInfo.isRequesterAnIAMUser() ?
|
||||||
authInfo.getShortid() : undefined;
|
authInfo.getShortid() : undefined;
|
||||||
|
|
|
@ -9,76 +9,92 @@ const { ds } = require('../../../lib/data/in_memory/backend');
|
||||||
const DummyRequest = require('../DummyRequest');
|
const DummyRequest = require('../DummyRequest');
|
||||||
const { bucketPut } = require('../../../lib/api/bucketPut');
|
const { bucketPut } = require('../../../lib/api/bucketPut');
|
||||||
const objectPut = require('../../../lib/api/objectPut');
|
const objectPut = require('../../../lib/api/objectPut');
|
||||||
|
const bucketPutACL = require('../../../lib/api/bucketPutACL');
|
||||||
|
|
||||||
const log = new DummyRequestLogger();
|
const log = new DummyRequestLogger();
|
||||||
const canonicalID = 'accessKey1';
|
const canonicalID = 'accessKey1';
|
||||||
|
const altCanonicalID = 'accessKey2';
|
||||||
const authInfo = makeAuthInfo(canonicalID);
|
const authInfo = makeAuthInfo(canonicalID);
|
||||||
|
const altAuthInfo = makeAuthInfo(altCanonicalID);
|
||||||
const namespace = 'default';
|
const namespace = 'default';
|
||||||
const bucketName = 'bucketname';
|
const bucketName = 'bucketname';
|
||||||
const postBody = Buffer.from('I am a body', 'utf8');
|
const postBody = Buffer.from('I am a body', 'utf8');
|
||||||
const contentLength = 2 * postBody.length;
|
const contentLength = 2 * postBody.length;
|
||||||
const objectKey1 = 'objectName1';
|
const objectKey1 = 'objectName1';
|
||||||
const objectKey2 = 'objectName2';
|
const objectKey2 = 'objectName2';
|
||||||
|
const objectKey3 = 'objectName3';
|
||||||
const testBucketPutRequest = new DummyRequest({
|
const testBucketPutRequest = new DummyRequest({
|
||||||
bucketName,
|
bucketName,
|
||||||
namespace,
|
namespace,
|
||||||
headers: {},
|
headers: {},
|
||||||
url: `/${bucketName}`,
|
url: `/${bucketName}`,
|
||||||
});
|
});
|
||||||
|
const testPutObjectRequest1 = new DummyRequest({
|
||||||
|
bucketName,
|
||||||
|
namespace,
|
||||||
|
objectKey: objectKey1,
|
||||||
|
headers: {},
|
||||||
|
url: `/${bucketName}/${objectKey1}`,
|
||||||
|
}, postBody);
|
||||||
|
const testPutObjectRequest2 = new DummyRequest({
|
||||||
|
bucketName,
|
||||||
|
namespace,
|
||||||
|
objectKey: objectKey2,
|
||||||
|
headers: {},
|
||||||
|
url: `/${bucketName}/${objectKey2}`,
|
||||||
|
}, postBody);
|
||||||
|
const testPutObjectRequest3 = new DummyRequest({
|
||||||
|
bucketName,
|
||||||
|
namespace,
|
||||||
|
objectKey: objectKey3,
|
||||||
|
headers: {},
|
||||||
|
url: `/${bucketName}/${objectKey3}`,
|
||||||
|
}, postBody);
|
||||||
|
|
||||||
describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
||||||
let testPutObjectRequest1;
|
|
||||||
let testPutObjectRequest2;
|
|
||||||
const request = new DummyRequest({
|
const request = new DummyRequest({
|
||||||
headers: {},
|
headers: {},
|
||||||
parsedContentLength: contentLength,
|
parsedContentLength: contentLength,
|
||||||
}, postBody);
|
}, postBody);
|
||||||
const bucket = { getVersioningConfiguration: () => null };
|
const bucket = { getVersioningConfiguration: () => null };
|
||||||
|
|
||||||
beforeEach(done => {
|
describe('bucket and objects belong to same account', () => {
|
||||||
cleanup();
|
beforeEach(done => {
|
||||||
testPutObjectRequest1 = new DummyRequest({
|
cleanup();
|
||||||
bucketName,
|
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
||||||
namespace,
|
objectPut(authInfo, testPutObjectRequest1, undefined,
|
||||||
objectKey: objectKey1,
|
log, () => {
|
||||||
headers: {},
|
objectPut(authInfo, testPutObjectRequest2, undefined,
|
||||||
url: `/${bucketName}/${objectKey1}`,
|
log, () => {
|
||||||
}, postBody);
|
assert.strictEqual(metadata.keyMaps
|
||||||
testPutObjectRequest2 = new DummyRequest({
|
.get(bucketName)
|
||||||
bucketName,
|
.has(objectKey1), true);
|
||||||
namespace,
|
assert.strictEqual(metadata.keyMaps
|
||||||
objectKey: objectKey2,
|
.get(bucketName)
|
||||||
headers: {},
|
.has(objectKey2), true);
|
||||||
url: `/${bucketName}/${objectKey2}`,
|
done();
|
||||||
}, postBody);
|
});
|
||||||
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
|
||||||
objectPut(authInfo, testPutObjectRequest1,
|
|
||||||
undefined, log, () => {
|
|
||||||
objectPut(authInfo, testPutObjectRequest2,
|
|
||||||
undefined, log, () => {
|
|
||||||
assert.strictEqual(metadata.keyMaps
|
|
||||||
.get(bucketName)
|
|
||||||
.has(objectKey1), true);
|
|
||||||
assert.strictEqual(metadata.keyMaps
|
|
||||||
.get(bucketName)
|
|
||||||
.has(objectKey2), true);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should successfully get object metadata and then ' +
|
it('should successfully get object metadata and then ' +
|
||||||
'delete metadata and data', done => {
|
'delete metadata and data', done => {
|
||||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
true, [], [{ key: objectKey1 }, { key: objectKey2 }], log,
|
request, bucketName, bucket, true, [],
|
||||||
(err, quietSetting, errorResults, numOfObjects,
|
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||||
successfullyDeleted, totalContentLengthDeleted) => {
|
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.strictEqual(quietSetting, true);
|
assert.strictEqual(quietSetting, true);
|
||||||
assert.deepStrictEqual(errorResults, []);
|
assert.deepStrictEqual(errorResults, []);
|
||||||
assert.strictEqual(numOfObjects, 2);
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
assert.strictEqual(totalContentLengthDeleted, contentLength);
|
numOfObjectsRemoved, 2);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
numOfObjectsRemoved, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted, contentLength);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
.has(objectKey1), false);
|
.has(objectKey1), false);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
|
@ -91,37 +107,42 @@ describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
||||||
done();
|
done();
|
||||||
}, 20);
|
}, 20);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return success results if no such key', done => {
|
it('should return success results if no such key', done => {
|
||||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
true, [], [{ key: 'madeup1' }, { key: 'madeup2' }], log,
|
request, bucketName, bucket, true, [],
|
||||||
(err, quietSetting, errorResults, numOfObjects,
|
[{ key: 'madeup1' }, { key: 'madeup2' }], log,
|
||||||
successfullyDeleted, totalContentLengthDeleted) => {
|
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.strictEqual(quietSetting, true);
|
assert.strictEqual(quietSetting, true);
|
||||||
assert.deepStrictEqual(errorResults, []);
|
assert.deepStrictEqual(errorResults, []);
|
||||||
assert.strictEqual(numOfObjects, 0);
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
assert.strictEqual(totalContentLengthDeleted,
|
numOfObjectsRemoved, 0);
|
||||||
0);
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
numOfObjectsRemoved, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
.has(objectKey1), true);
|
.has(objectKey1), true);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
.has(objectKey2), true);
|
.has(objectKey2), true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return error results if err from metadata getting object' +
|
it('should return error results if err from metadata getting object' +
|
||||||
'is error other than NoSuchKey', done => {
|
'is error other than NoSuchKey', done => {
|
||||||
// we fake an error by calling on an imaginary bucket
|
// we fake an error by calling on an imaginary bucket
|
||||||
// even though the getObjMetadataAndDelete function would
|
// even though the getObjMetadataAndDelete function would
|
||||||
// never be called if there was no bucket (would error out earlier
|
// never be called if there was no bucket (would error out earlier
|
||||||
// in API)
|
// in API)
|
||||||
getObjMetadataAndDelete(authInfo, 'foo', request, 'madeupbucket',
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
bucket, true, [], [{ key: objectKey1 }, { key: objectKey2 }], log,
|
request, 'madeupbucket', bucket, true, [],
|
||||||
(err, quietSetting, errorResults, numOfObjects,
|
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||||
successfullyDeleted, totalContentLengthDeleted) => {
|
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.strictEqual(quietSetting, true);
|
assert.strictEqual(quietSetting, true);
|
||||||
assert.deepStrictEqual(errorResults, [
|
assert.deepStrictEqual(errorResults, [
|
||||||
|
@ -134,54 +155,151 @@ describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
||||||
error: errors.NoSuchBucket,
|
error: errors.NoSuchBucket,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
assert.strictEqual(totalContentLengthDeleted,
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
0);
|
totalContentLengthDeleted, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
.has(objectKey1), true);
|
.has(objectKey1), true);
|
||||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
.has(objectKey2), true);
|
.has(objectKey2), true);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
it('should return no error or success results if no objects in play',
|
|
||||||
done => {
|
|
||||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName,
|
|
||||||
bucket, true, [], [], log,
|
|
||||||
(err, quietSetting, errorResults, numOfObjects,
|
|
||||||
successfullyDeleted, totalContentLengthDeleted) => {
|
|
||||||
assert.ifError(err);
|
|
||||||
assert.strictEqual(quietSetting, true);
|
|
||||||
assert.deepStrictEqual(errorResults, []);
|
|
||||||
assert.strictEqual(numOfObjects, 0);
|
|
||||||
assert.strictEqual(totalContentLengthDeleted,
|
|
||||||
0);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass along error results', done => {
|
it('should return no error or success results if no objects in play',
|
||||||
const errorResultsSample = [
|
done => {
|
||||||
{
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
key: 'somekey1',
|
request, bucketName, bucket, true, [], [], log,
|
||||||
error: errors.AccessDenied,
|
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
},
|
assert.ifError(err);
|
||||||
{
|
assert.strictEqual(quietSetting, true);
|
||||||
key: 'somekey2',
|
assert.deepStrictEqual(errorResults, []);
|
||||||
error: errors.AccessDenied,
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
},
|
numOfObjectsRemoved, 0);
|
||||||
];
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
numOfObjectsRemoved, 0);
|
||||||
true, errorResultsSample,
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass along error results', done => {
|
||||||
|
const errorResultsSample = [
|
||||||
|
{
|
||||||
|
key: 'somekey1',
|
||||||
|
error: errors.AccessDenied,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'somekey2',
|
||||||
|
error: errors.AccessDenied,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
|
request, bucketName, bucket, true, errorResultsSample,
|
||||||
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||||
(err, quietSetting, errorResults, numOfObjects,
|
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
successfullyDeleted, totalContentLengthDeleted) => {
|
|
||||||
assert.ifError(err);
|
assert.ifError(err);
|
||||||
assert.strictEqual(quietSetting, true);
|
assert.strictEqual(quietSetting, true);
|
||||||
assert.deepStrictEqual(errorResults, errorResultsSample);
|
assert.deepStrictEqual(errorResults, errorResultsSample);
|
||||||
assert.strictEqual(numOfObjects, 2);
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
assert.strictEqual(totalContentLengthDeleted, contentLength);
|
numOfObjectsRemoved, 2);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
numOfObjectsRemoved, 0);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted, contentLength);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, 0);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('bucket and objects belong to different accounts', () => {
|
||||||
|
beforeEach(done => {
|
||||||
|
cleanup();
|
||||||
|
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
||||||
|
const testACLRequest = {
|
||||||
|
bucketName,
|
||||||
|
namespace,
|
||||||
|
headers: { host: `${bucketName}.s3.amazonaws.com` },
|
||||||
|
post: '<AccessControlPolicy xmlns=' +
|
||||||
|
'"http://s3.amazonaws.com/doc/2006-03-01/">' +
|
||||||
|
'<Owner>' +
|
||||||
|
`<ID>${authInfo.getCanonicalID()}</ID>` +
|
||||||
|
'<DisplayName>OwnerDisplayName</DisplayName>' +
|
||||||
|
'</Owner>' +
|
||||||
|
'<AccessControlList>' +
|
||||||
|
'<Grant>' +
|
||||||
|
'<Grantee xsi:type="CanonicalUser">' +
|
||||||
|
`<ID>${altAuthInfo.getCanonicalID()}</ID>` +
|
||||||
|
'<DisplayName>OwnerDisplayName</DisplayName>' +
|
||||||
|
'</Grantee>' +
|
||||||
|
'<Permission>WRITE</Permission>' +
|
||||||
|
'</Grant>' +
|
||||||
|
'</AccessControlList>' +
|
||||||
|
'</AccessControlPolicy>',
|
||||||
|
url: '/?acl',
|
||||||
|
query: { acl: '' },
|
||||||
|
};
|
||||||
|
bucketPutACL(authInfo, testACLRequest, log, () => {
|
||||||
|
objectPut(authInfo, testPutObjectRequest1, undefined,
|
||||||
|
log, () => {
|
||||||
|
objectPut(altAuthInfo, testPutObjectRequest2, undefined,
|
||||||
|
log, () => {
|
||||||
|
objectPut(altAuthInfo, testPutObjectRequest3,
|
||||||
|
undefined, log, () => {
|
||||||
|
assert.strictEqual(metadata.keyMaps
|
||||||
|
.get(bucketName)
|
||||||
|
.has(objectKey1), true);
|
||||||
|
assert.strictEqual(metadata.keyMaps
|
||||||
|
.get(bucketName)
|
||||||
|
.has(objectKey2), true);
|
||||||
|
assert.strictEqual(metadata.keyMaps
|
||||||
|
.get(bucketName)
|
||||||
|
.has(objectKey3), true);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should successfully get object metadata and then ' +
|
||||||
|
'delete metadata and data', done => {
|
||||||
|
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||||
|
request, bucketName, bucket, true, [],
|
||||||
|
[{ key: objectKey1 }, { key: objectKey2 }, { key: objectKey3 }],
|
||||||
|
log, (err, quietSetting, errorResults, deletedObjStats) => {
|
||||||
|
assert.ifError(err);
|
||||||
|
assert.strictEqual(quietSetting, true);
|
||||||
|
assert.deepStrictEqual(errorResults, []);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
numOfObjectsRemoved, 1);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
numOfObjectsRemoved, 2);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||||
|
totalContentLengthDeleted, postBody.length);
|
||||||
|
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||||
|
totalContentLengthDeleted, contentLength);
|
||||||
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
|
.has(objectKey1), false);
|
||||||
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
|
.has(objectKey2), false);
|
||||||
|
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||||
|
.has(objectKey3), false);
|
||||||
|
// call to delete data is async so wait 20 ms to check
|
||||||
|
// that data deleted
|
||||||
|
setTimeout(() => {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
assert.deepStrictEqual(ds, [ , , , , ]);
|
||||||
|
done();
|
||||||
|
}, 20);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue