Compare commits
1 Commits
developmen
...
n2b/put-ve
Author | SHA1 | Date |
---|---|---|
Nicolas Humbert | f78b2eb8a5 |
|
@ -1,5 +1,5 @@
|
||||||
const async = require('async');
|
const async = require('async');
|
||||||
const { errors, s3middleware } = require('arsenal');
|
const { errors, s3middleware, models } = require('arsenal');
|
||||||
const getMetaHeaders = s3middleware.userMetadata.getMetaHeaders;
|
const getMetaHeaders = s3middleware.userMetadata.getMetaHeaders;
|
||||||
|
|
||||||
const constants = require('../../../../constants');
|
const constants = require('../../../../constants');
|
||||||
|
@ -16,6 +16,8 @@ const validateWebsiteHeader = require('./websiteServing')
|
||||||
.validateWebsiteHeader;
|
.validateWebsiteHeader;
|
||||||
const applyZenkoUserMD = require('./applyZenkoUserMD');
|
const applyZenkoUserMD = require('./applyZenkoUserMD');
|
||||||
const { externalBackends, versioningNotImplBackends } = constants;
|
const { externalBackends, versioningNotImplBackends } = constants;
|
||||||
|
const { BackendInfo } = models;
|
||||||
|
const { isValidLocationConstraint } = BackendInfo;
|
||||||
|
|
||||||
const externalVersioningErrorMessage = 'We do not currently support putting ' +
|
const externalVersioningErrorMessage = 'We do not currently support putting ' +
|
||||||
'a versioned object to a location-constraint of type Azure or GCP.';
|
'a versioned object to a location-constraint of type Azure or GCP.';
|
||||||
|
@ -61,7 +63,7 @@ function createAndStoreObject(bucketName, bucketMD, objectKey, objMD, authInfo,
|
||||||
canonicalID, cipherBundle, request, isDeleteMarker, streamingV4Params,
|
canonicalID, cipherBundle, request, isDeleteMarker, streamingV4Params,
|
||||||
log, callback) {
|
log, callback) {
|
||||||
const putVersionId = request.headers['x-scal-s3-version-id'];
|
const putVersionId = request.headers['x-scal-s3-version-id'];
|
||||||
const isPutVersion = putVersionId || putVersionId === '';
|
const isPutVersion = !!putVersionId || putVersionId === '';
|
||||||
|
|
||||||
const size = isDeleteMarker ? 0 : request.parsedContentLength;
|
const size = isDeleteMarker ? 0 : request.parsedContentLength;
|
||||||
// although the request method may actually be 'DELETE' if creating a
|
// although the request method may actually be 'DELETE' if creating a
|
||||||
|
@ -160,18 +162,36 @@ function createAndStoreObject(bucketName, bucketMD, objectKey, objMD, authInfo,
|
||||||
metadataStoreParams.originOp = 's3:ObjectRemoved:DeleteMarkerCreated';
|
metadataStoreParams.originOp = 's3:ObjectRemoved:DeleteMarkerCreated';
|
||||||
}
|
}
|
||||||
|
|
||||||
const backendInfoObj =
|
let location;
|
||||||
locationConstraintCheck(request, null, bucketMD, log);
|
let locationType;
|
||||||
if (backendInfoObj.err) {
|
let backendInfo;
|
||||||
return process.nextTick(() => {
|
|
||||||
callback(backendInfoObj.err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const backendInfo = backendInfoObj.backendInfo;
|
if (isPutVersion) {
|
||||||
const location = backendInfo.getControllingLocationConstraint();
|
location = objMD.archive.archiveInfo.hotLocation
|
||||||
const locationType = backendInfoObj.defaultedToDataBackend ? location :
|
const valid = isValidLocationConstraint(config, location, log);
|
||||||
config.getLocationConstraintType(location);
|
if (!valid) {
|
||||||
|
return process.nextTick(() =>
|
||||||
|
callback(errors.InvalidArgument.customizeDescription('Object Location Error')));
|
||||||
|
}
|
||||||
|
|
||||||
|
backendInfo = new BackendInfo(config, location);
|
||||||
|
locationType = config.getLocationConstraintType(location);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
const backendInfoObj =
|
||||||
|
locationConstraintCheck(request, null, bucketMD, log);
|
||||||
|
if (backendInfoObj.err) {
|
||||||
|
return process.nextTick(() => {
|
||||||
|
callback(backendInfoObj.err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
backendInfo = backendInfoObj.backendInfo;
|
||||||
|
location = backendInfo.getControllingLocationConstraint();
|
||||||
|
locationType = backendInfoObj.defaultedToDataBackend ? location :
|
||||||
|
config.getLocationConstraintType(location);
|
||||||
|
}
|
||||||
|
|
||||||
metadataStoreParams.dataStoreName = location;
|
metadataStoreParams.dataStoreName = location;
|
||||||
|
|
||||||
if (versioningNotImplBackends[locationType]) {
|
if (versioningNotImplBackends[locationType]) {
|
||||||
|
|
|
@ -71,32 +71,10 @@ const REPLICATION_ACTION = 'MPU';
|
||||||
*/
|
*/
|
||||||
function completeMultipartUpload(authInfo, request, log, callback) {
|
function completeMultipartUpload(authInfo, request, log, callback) {
|
||||||
log.debug('processing request', { method: 'completeMultipartUpload' });
|
log.debug('processing request', { method: 'completeMultipartUpload' });
|
||||||
const bucketName = request.bucketName;
|
|
||||||
const objectKey = request.objectKey;
|
|
||||||
const hostname = request.parsedHost;
|
|
||||||
const uploadId = request.query.uploadId;
|
|
||||||
const metadataValParams = {
|
|
||||||
authInfo,
|
|
||||||
bucketName,
|
|
||||||
objectKey,
|
|
||||||
uploadId,
|
|
||||||
// Note: permissions for completing a multipart upload are the
|
|
||||||
// same as putting a part.
|
|
||||||
requestType: 'putPart or complete',
|
|
||||||
log,
|
|
||||||
request,
|
|
||||||
};
|
|
||||||
const xmlParams = {
|
|
||||||
bucketName,
|
|
||||||
objectKey,
|
|
||||||
hostname,
|
|
||||||
};
|
|
||||||
let oldByteLength = null;
|
|
||||||
const responseHeaders = {};
|
|
||||||
|
|
||||||
let versionId;
|
let versionId;
|
||||||
const putVersionId = request.headers['x-scal-s3-version-id'];
|
const putVersionId = request.headers['x-scal-s3-version-id'];
|
||||||
const isPutVersion = putVersionId || putVersionId === '';
|
const isPutVersion = !!putVersionId || putVersionId === '';
|
||||||
if (putVersionId) {
|
if (putVersionId) {
|
||||||
const decodedVidResult = decodeVID(putVersionId);
|
const decodedVidResult = decodeVID(putVersionId);
|
||||||
if (decodedVidResult instanceof Error) {
|
if (decodedVidResult instanceof Error) {
|
||||||
|
@ -109,6 +87,31 @@ function completeMultipartUpload(authInfo, request, log, callback) {
|
||||||
versionId = decodedVidResult;
|
versionId = decodedVidResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bucketName = request.bucketName;
|
||||||
|
const objectKey = request.objectKey;
|
||||||
|
const hostname = request.parsedHost;
|
||||||
|
const uploadId = request.query.uploadId;
|
||||||
|
const metadataValMPUParams = {
|
||||||
|
authInfo,
|
||||||
|
bucketName,
|
||||||
|
objectKey,
|
||||||
|
uploadId,
|
||||||
|
// Note: permissions for completing a multipart upload are the
|
||||||
|
// same as putting a part.
|
||||||
|
requestType: 'putPart or complete',
|
||||||
|
log,
|
||||||
|
request,
|
||||||
|
isPutVersion,
|
||||||
|
versionId,
|
||||||
|
};
|
||||||
|
const xmlParams = {
|
||||||
|
bucketName,
|
||||||
|
objectKey,
|
||||||
|
hostname,
|
||||||
|
};
|
||||||
|
let oldByteLength = null;
|
||||||
|
const responseHeaders = {};
|
||||||
|
|
||||||
const queryContainsVersionId = checkQueryVersionId(request.query);
|
const queryContainsVersionId = checkQueryVersionId(request.query);
|
||||||
if (queryContainsVersionId instanceof Error) {
|
if (queryContainsVersionId instanceof Error) {
|
||||||
return callback(queryContainsVersionId);
|
return callback(queryContainsVersionId);
|
||||||
|
@ -134,7 +137,6 @@ function completeMultipartUpload(authInfo, request, log, callback) {
|
||||||
// Required permissions for this action
|
// Required permissions for this action
|
||||||
// at the destinationBucket level are same as objectPut
|
// at the destinationBucket level are same as objectPut
|
||||||
requestType: 'objectPut',
|
requestType: 'objectPut',
|
||||||
versionId,
|
|
||||||
};
|
};
|
||||||
metadataValidateBucketAndObj(metadataValParams, log, next);
|
metadataValidateBucketAndObj(metadataValParams, log, next);
|
||||||
},
|
},
|
||||||
|
@ -142,30 +144,7 @@ function completeMultipartUpload(authInfo, request, log, callback) {
|
||||||
if (objMD) {
|
if (objMD) {
|
||||||
oldByteLength = objMD['content-length'];
|
oldByteLength = objMD['content-length'];
|
||||||
}
|
}
|
||||||
|
return services.metadataValidateMultipart(metadataValMPUParams,
|
||||||
if (isPutVersion) {
|
|
||||||
if (!objMD) {
|
|
||||||
const err = putVersionId ? errors.NoSuchVersion : errors.NoSuchKey;
|
|
||||||
log.error('error no object metadata found', { method: 'completeMultipartUpload', putVersionId });
|
|
||||||
return callback(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objMD.isDeleteMarker) {
|
|
||||||
log.error('version is a delete marker', { method: 'completeMultipartUpload', putVersionId });
|
|
||||||
return callback(errors.MethodNotAllowed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure object archive restoration is in progress
|
|
||||||
// NOTE: we do not use putObjectVersion to update the restoration period.
|
|
||||||
if (!objMD.archive || !objMD.archive.restoreRequestedAt || !objMD.archive.restoreRequestedDays
|
|
||||||
|| objMD.archive.restoreCompletedAt || objMD.archive.restoreWillExpireAt) {
|
|
||||||
log.error('object archive restoration is not in progress',
|
|
||||||
{ method: 'completeMultipartUpload', putVersionId });
|
|
||||||
return callback(errors.InvalidObjectState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return services.metadataValidateMultipart(metadataValParams,
|
|
||||||
(err, mpuBucket, mpuOverview, storedMetadata) => {
|
(err, mpuBucket, mpuOverview, storedMetadata) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err, destBucket);
|
return next(err, destBucket);
|
||||||
|
|
|
@ -21,6 +21,7 @@ const { validateHeaders, compareObjectLockInformation } =
|
||||||
require('./apiUtils/object/objectLockHelpers');
|
require('./apiUtils/object/objectLockHelpers');
|
||||||
const { getObjectSSEConfiguration } = require('./apiUtils/bucket/bucketEncryption');
|
const { getObjectSSEConfiguration } = require('./apiUtils/bucket/bucketEncryption');
|
||||||
const { setExpirationHeaders } = require('./apiUtils/object/expirationHeaders');
|
const { setExpirationHeaders } = require('./apiUtils/object/expirationHeaders');
|
||||||
|
const { decodeVID } = require('./apiUtils/object/versioning');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Sample xml response:
|
Sample xml response:
|
||||||
|
@ -47,6 +48,22 @@ Sample xml response:
|
||||||
*/
|
*/
|
||||||
function initiateMultipartUpload(authInfo, request, log, callback) {
|
function initiateMultipartUpload(authInfo, request, log, callback) {
|
||||||
log.debug('processing request', { method: 'initiateMultipartUpload' });
|
log.debug('processing request', { method: 'initiateMultipartUpload' });
|
||||||
|
|
||||||
|
let versionId;
|
||||||
|
const putVersionId = request.headers['x-scal-s3-version-id'];
|
||||||
|
const isPutVersion = !!putVersionId || putVersionId === '';
|
||||||
|
if (putVersionId) {
|
||||||
|
const decodedVidResult = decodeVID(putVersionId);
|
||||||
|
if (decodedVidResult instanceof Error) {
|
||||||
|
log.trace('invalid x-scal-s3-version-id header', {
|
||||||
|
versionId: putVersionId,
|
||||||
|
error: decodedVidResult,
|
||||||
|
});
|
||||||
|
return process.nextTick(() => callback(decodedVidResult));
|
||||||
|
}
|
||||||
|
versionId = decodedVidResult;
|
||||||
|
}
|
||||||
|
|
||||||
const bucketName = request.bucketName;
|
const bucketName = request.bucketName;
|
||||||
const objectKey = request.objectKey;
|
const objectKey = request.objectKey;
|
||||||
|
|
||||||
|
@ -107,6 +124,7 @@ function initiateMultipartUpload(authInfo, request, log, callback) {
|
||||||
// Required permissions for this action are same as objectPut
|
// Required permissions for this action are same as objectPut
|
||||||
requestType: 'objectPut',
|
requestType: 'objectPut',
|
||||||
request,
|
request,
|
||||||
|
versionId,
|
||||||
};
|
};
|
||||||
const accountCanonicalID = authInfo.getCanonicalID();
|
const accountCanonicalID = authInfo.getCanonicalID();
|
||||||
let initiatorID = accountCanonicalID;
|
let initiatorID = accountCanonicalID;
|
||||||
|
@ -134,6 +152,7 @@ function initiateMultipartUpload(authInfo, request, log, callback) {
|
||||||
// Otherwise, it is the same as the ownerDisplayName.
|
// Otherwise, it is the same as the ownerDisplayName.
|
||||||
initiatorDisplayName,
|
initiatorDisplayName,
|
||||||
splitter: constants.splitter,
|
splitter: constants.splitter,
|
||||||
|
versionId,
|
||||||
};
|
};
|
||||||
const tagging = request.headers['x-amz-tagging'];
|
const tagging = request.headers['x-amz-tagging'];
|
||||||
if (tagging) {
|
if (tagging) {
|
||||||
|
@ -275,7 +294,31 @@ function initiateMultipartUpload(authInfo, request, log, callback) {
|
||||||
|
|
||||||
async.waterfall([
|
async.waterfall([
|
||||||
next => metadataValidateBucketAndObj(metadataValParams, log,
|
next => metadataValidateBucketAndObj(metadataValParams, log,
|
||||||
(error, destinationBucket) => {
|
(error, destinationBucket, objMD) => {
|
||||||
|
if (isPutVersion) {
|
||||||
|
if (!objMD) {
|
||||||
|
const err = putVersionId ? errors.NoSuchVersion : errors.NoSuchKey;
|
||||||
|
log.error('error no object metadata found', { method: 'initiateMultipartUpload', putVersionId });
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objMD.isDeleteMarker) {
|
||||||
|
log.error('version is a delete marker', { method: 'initiateMultipartUpload', putVersionId });
|
||||||
|
return callback(errors.MethodNotAllowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO check object is in cold storage location
|
||||||
|
|
||||||
|
// make sure object archive restoration is in progress
|
||||||
|
// NOTE: we do not use putObjectVersion to update the restoration period.
|
||||||
|
if (!objMD.archive || !objMD.archive.restoreRequestedAt || !objMD.archive.restoreRequestedDays
|
||||||
|
|| objMD.archive.restoreCompletedAt || objMD.archive.restoreWillExpireAt) {
|
||||||
|
log.error('object archive restoration is not in progress',
|
||||||
|
{ method: 'initiateMultipartUpload', putVersionId });
|
||||||
|
return callback(errors.InvalidObjectState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, destinationBucket);
|
const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, destinationBucket);
|
||||||
if (error) {
|
if (error) {
|
||||||
log.debug('error processing request', {
|
log.debug('error processing request', {
|
||||||
|
|
|
@ -43,7 +43,7 @@ function objectPut(authInfo, request, streamingV4Params, log, callback) {
|
||||||
log.debug('processing request', { method: 'objectPut' });
|
log.debug('processing request', { method: 'objectPut' });
|
||||||
|
|
||||||
const putVersionId = request.headers['x-scal-s3-version-id'];
|
const putVersionId = request.headers['x-scal-s3-version-id'];
|
||||||
const isPutVersion = putVersionId || putVersionId === '';
|
const isPutVersion = !!putVersionId || putVersionId === '';
|
||||||
|
|
||||||
let versionId;
|
let versionId;
|
||||||
|
|
||||||
|
@ -139,8 +139,12 @@ function objectPut(authInfo, request, streamingV4Params, log, callback) {
|
||||||
|
|
||||||
// make sure object archive restoration is in progress
|
// make sure object archive restoration is in progress
|
||||||
// NOTE: we do not use putObjectVersion to update the restoration period.
|
// NOTE: we do not use putObjectVersion to update the restoration period.
|
||||||
if (!objMD.archive || !objMD.archive.restoreRequestedAt || !objMD.archive.restoreRequestedDays
|
const isRestoreReady = !objMD.archive || !objMD.archive.archiveInfo
|
||||||
|| objMD.archive.restoreCompletedAt || objMD.archive.restoreWillExpireAt) {
|
|| !objMD.archive.archiveInfo.hotLocation
|
||||||
|
|| !objMD.archive.restoreRequestedAt || !objMD.archive.restoreRequestedDays
|
||||||
|
|| objMD.archive.restoreCompletedAt || objMD.archive.restoreWillExpireAt;
|
||||||
|
|
||||||
|
if (isRestoreReady) {
|
||||||
log.error('object archive restoration is not in progress', { method: 'objectPut', putVersionId });
|
log.error('object archive restoration is not in progress', { method: 'objectPut', putVersionId });
|
||||||
return callback(errors.InvalidObjectState);
|
return callback(errors.InvalidObjectState);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ const { BackendInfo } = models;
|
||||||
const writeContinue = require('../utilities/writeContinue');
|
const writeContinue = require('../utilities/writeContinue');
|
||||||
const { getObjectSSEConfiguration } = require('./apiUtils/bucket/bucketEncryption');
|
const { getObjectSSEConfiguration } = require('./apiUtils/bucket/bucketEncryption');
|
||||||
const skipError = new Error('skip');
|
const skipError = new Error('skip');
|
||||||
|
const { decodeVID } = require('./apiUtils/object/versioning');
|
||||||
|
|
||||||
// We pad the partNumbers so that the parts will be sorted in numerical order.
|
// We pad the partNumbers so that the parts will be sorted in numerical order.
|
||||||
function _getPaddedPartNumber(number) {
|
function _getPaddedPartNumber(number) {
|
||||||
|
@ -57,6 +58,22 @@ function _getPartKey(uploadId, splitter, paddedPartNumber) {
|
||||||
function objectPutPart(authInfo, request, streamingV4Params, log,
|
function objectPutPart(authInfo, request, streamingV4Params, log,
|
||||||
cb) {
|
cb) {
|
||||||
log.debug('processing request', { method: 'objectPutPart' });
|
log.debug('processing request', { method: 'objectPutPart' });
|
||||||
|
|
||||||
|
let versionId;
|
||||||
|
const putVersionId = request.headers['x-scal-s3-version-id'];
|
||||||
|
const isPutVersion = !!putVersionId || putVersionId === '';
|
||||||
|
if (putVersionId) {
|
||||||
|
const decodedVidResult = decodeVID(putVersionId);
|
||||||
|
if (decodedVidResult instanceof Error) {
|
||||||
|
log.trace('invalid x-scal-s3-version-id header', {
|
||||||
|
versionId: putVersionId,
|
||||||
|
error: decodedVidResult,
|
||||||
|
});
|
||||||
|
return process.nextTick(() => callback(decodedVidResult));
|
||||||
|
}
|
||||||
|
versionId = decodedVidResult;
|
||||||
|
}
|
||||||
|
|
||||||
const size = request.parsedContentLength;
|
const size = request.parsedContentLength;
|
||||||
|
|
||||||
if (Number.parseInt(size, 10) > constants.maximumAllowedPartSize) {
|
if (Number.parseInt(size, 10) > constants.maximumAllowedPartSize) {
|
||||||
|
@ -179,6 +196,28 @@ function objectPutPart(authInfo, request, streamingV4Params, log,
|
||||||
});
|
});
|
||||||
return next(err, destinationBucket);
|
return next(err, destinationBucket);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('res.versionId!!!!', res.versionId);
|
||||||
|
console.log('versionId!!!', versionId);
|
||||||
|
if (isPutVersion && res.versionId !== versionId) {
|
||||||
|
log.error('x-scal-s3-version-id header is incorrect', {
|
||||||
|
initiateMPUVersionId: res.versionId,
|
||||||
|
putPartVersionId: versionId,
|
||||||
|
method: 'objectPutPart::metadata.getObjectMD',
|
||||||
|
});
|
||||||
|
// TODO: probably not the correct error.
|
||||||
|
return next(errors.NoSuchUpload, destinationBucket);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isPutVersion && res.versionId) {
|
||||||
|
log.error('missing the x-scal-s3-version-id header', {
|
||||||
|
initiateMPUVersionId: res.versionId,
|
||||||
|
method: 'objectPutPart::metadata.getObjectMD',
|
||||||
|
});
|
||||||
|
|
||||||
|
return next(errors.NoSuchUpload, destinationBucket);
|
||||||
|
}
|
||||||
|
|
||||||
const initiatorID = res.initiator.ID;
|
const initiatorID = res.initiator.ID;
|
||||||
const requesterID = authInfo.isRequesterAnIAMUser() ?
|
const requesterID = authInfo.isRequesterAnIAMUser() ?
|
||||||
authInfo.getArn() : authInfo.getCanonicalID();
|
authInfo.getArn() : authInfo.getCanonicalID();
|
||||||
|
|
|
@ -416,6 +416,8 @@ const services = {
|
||||||
}
|
}
|
||||||
multipartObjectMD.controllingLocationConstraint =
|
multipartObjectMD.controllingLocationConstraint =
|
||||||
params.controllingLocationConstraint;
|
params.controllingLocationConstraint;
|
||||||
|
multipartObjectMD.versionId =
|
||||||
|
params.versionId;
|
||||||
multipartObjectMD.dataStoreName = params.dataStoreName;
|
multipartObjectMD.dataStoreName = params.dataStoreName;
|
||||||
if (params.tagging) {
|
if (params.tagging) {
|
||||||
const validationTagRes = parseTagFromQuery(params.tagging);
|
const validationTagRes = parseTagFromQuery(params.tagging);
|
||||||
|
@ -459,6 +461,7 @@ const services = {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
multipartObjectMD.acl = parsedACL;
|
multipartObjectMD.acl = parsedACL;
|
||||||
|
console.log('multipartObjectMD!!!', multipartObjectMD);
|
||||||
metadata.putObjectMD(bucketName, longMPUIdentifier,
|
metadata.putObjectMD(bucketName, longMPUIdentifier,
|
||||||
multipartObjectMD, {}, log, err => {
|
multipartObjectMD, {}, log, err => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -562,7 +565,7 @@ const services = {
|
||||||
*/
|
*/
|
||||||
metadataValidateMultipart(params, cb) {
|
metadataValidateMultipart(params, cb) {
|
||||||
const { bucketName, uploadId, authInfo,
|
const { bucketName, uploadId, authInfo,
|
||||||
objectKey, requestType, log } = params;
|
objectKey, requestType, isPutVersion, versionId, log } = params;
|
||||||
|
|
||||||
assert.strictEqual(typeof bucketName, 'string');
|
assert.strictEqual(typeof bucketName, 'string');
|
||||||
// This checks whether the mpu bucket exists.
|
// This checks whether the mpu bucket exists.
|
||||||
|
@ -598,6 +601,20 @@ const services = {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isPutVersion && storedMetadata.versionId !== versionId) {
|
||||||
|
log.error('x-scal-s3-version-id header is incorrect', {
|
||||||
|
initiateMPUVersionId: storedMetadata.versionId,
|
||||||
|
putPartVersionId: versionId,
|
||||||
|
method: 'objectPutPart::metadata.getObjectMD',
|
||||||
|
});
|
||||||
|
// TODO: probably not the correct error.
|
||||||
|
return cb(errors.NoSuchUpload);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No need to check if (!isPutVersion && storedMetadata.versionId) since
|
||||||
|
// the user should be able to list, abort or complete MPU without the need
|
||||||
|
// of specifying the x-scal-s3-version-id header.
|
||||||
|
|
||||||
const initiatorID = storedMetadata.initiator.ID;
|
const initiatorID = storedMetadata.initiator.ID;
|
||||||
const ownerID = storedMetadata['owner-id'];
|
const ownerID = storedMetadata['owner-id'];
|
||||||
const mpuOverview = {
|
const mpuOverview = {
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"cloudserver": "S3METADATA=mongodb npm-run-all --parallel start_dataserver start_s3server",
|
"cloudserver": "S3METADATA=mongodb npm-run-all --parallel start_dataserver start_s3server",
|
||||||
"ft_awssdk": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/",
|
"ft_awssdk": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/object/mpuVersion.js",
|
||||||
"ft_awssdk_aws": "cd tests/functional/aws-node-sdk && AWS_ON_AIR=true mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/",
|
"ft_awssdk_aws": "cd tests/functional/aws-node-sdk && AWS_ON_AIR=true mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/",
|
||||||
"ft_awssdk_buckets": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/bucket",
|
"ft_awssdk_buckets": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/bucket",
|
||||||
"ft_awssdk_objects_misc": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/legacy test/object test/service test/support",
|
"ft_awssdk_objects_misc": "cd tests/functional/aws-node-sdk && mocha --reporter mocha-multi-reporters --reporter-options configFile=$INIT_CWD/tests/reporter-config.json test/legacy test/object test/service test/support",
|
||||||
|
|
|
@ -10,7 +10,7 @@ const { getMetadata, fakeMetadataRestore } = require('../utils/init');
|
||||||
|
|
||||||
const log = new DummyRequestLogger();
|
const log = new DummyRequestLogger();
|
||||||
|
|
||||||
const bucketName = 'bucket1putversion33';
|
const bucketName = 'bucket1putversion34';
|
||||||
const objectName = 'object1putversion';
|
const objectName = 'object1putversion';
|
||||||
const mdListingParams = { listingType: 'DelimiterVersions', maxKeys: 1000 };
|
const mdListingParams = { listingType: 'DelimiterVersions', maxKeys: 1000 };
|
||||||
const archive = {
|
const archive = {
|
||||||
|
@ -208,7 +208,7 @@ describe('MPU with x-scal-s3-version-id header', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should overwrite a version', done => {
|
it.only('should overwrite a version', done => {
|
||||||
const vParams = {
|
const vParams = {
|
||||||
Bucket: bucketName,
|
Bucket: bucketName,
|
||||||
VersioningConfiguration: {
|
VersioningConfiguration: {
|
||||||
|
|
|
@ -13,8 +13,11 @@ const log = new DummyRequestLogger();
|
||||||
const bucketName = 'bucket1putversion32';
|
const bucketName = 'bucket1putversion32';
|
||||||
const objectName = 'object1putversion';
|
const objectName = 'object1putversion';
|
||||||
const mdListingParams = { listingType: 'DelimiterVersions', maxKeys: 1000 };
|
const mdListingParams = { listingType: 'DelimiterVersions', maxKeys: 1000 };
|
||||||
|
const hotLocation = 'us-east-2';
|
||||||
const archive = {
|
const archive = {
|
||||||
archiveInfo: {},
|
archiveInfo: {
|
||||||
|
hotLocation,
|
||||||
|
},
|
||||||
restoreRequestedAt: new Date(0).toString(),
|
restoreRequestedAt: new Date(0).toString(),
|
||||||
restoreRequestedDays: 5,
|
restoreRequestedDays: 5,
|
||||||
};
|
};
|
||||||
|
@ -112,7 +115,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length', 'content-md5',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length', 'content-md5',
|
||||||
'microVersionId', 'x-amz-restore', 'archive']);
|
'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -163,7 +166,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -214,7 +217,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -327,7 +330,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -379,7 +382,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -434,7 +437,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -487,7 +490,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -539,7 +542,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -598,7 +601,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -645,7 +648,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
assert.deepStrictEqual(versionsAfter, versionsBefore);
|
||||||
|
|
||||||
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
checkObjMdAndUpdate(objMDBefore, objMDAfter, ['location', 'content-length',
|
||||||
'content-md5', 'microVersionId', 'x-amz-restore', 'archive']);
|
'content-md5', 'microVersionId', 'x-amz-restore', 'archive', 'dataStoreName']);
|
||||||
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
assert.deepStrictEqual(objMDAfter, objMDBefore);
|
||||||
return done();
|
return done();
|
||||||
});
|
});
|
||||||
|
@ -742,6 +745,7 @@ describe('PUT object with x-scal-s3-version-id header', () => {
|
||||||
assert.deepStrictEqual(objMDAfter.archive.restoreRequestedAt, objMDBefore.archive.restoreRequestedAt);
|
assert.deepStrictEqual(objMDAfter.archive.restoreRequestedAt, objMDBefore.archive.restoreRequestedAt);
|
||||||
assert.deepStrictEqual(objMDAfter.archive.restoreRequestedDays,
|
assert.deepStrictEqual(objMDAfter.archive.restoreRequestedDays,
|
||||||
objMDBefore.archive.restoreRequestedDays);
|
objMDBefore.archive.restoreRequestedDays);
|
||||||
|
assert.deepStrictEqual(objMDAfter.archive.archiveInfo.hotLocation, hotLocation);
|
||||||
assert.deepStrictEqual(objMDAfter['x-amz-restore']['ongoing-request'], false);
|
assert.deepStrictEqual(objMDAfter['x-amz-restore']['ongoing-request'], false);
|
||||||
|
|
||||||
assert(objMDAfter.archive.restoreCompletedAt);
|
assert(objMDAfter.archive.restoreCompletedAt);
|
||||||
|
|
|
@ -50,6 +50,7 @@ function fakeMetadataRestore(bucketName, objectName, versionId, archive, cb) {
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
objMD.archive = archive;
|
objMD.archive = archive;
|
||||||
|
objMD.dataStoreName = 'location-dmf-v1';
|
||||||
return metadata.putObjectMD(bucketName, objectName, objMD, { versionId: decodedVersionId },
|
return metadata.putObjectMD(bucketName, objectName, objMD, { versionId: decodedVersionId },
|
||||||
log, err => cb(err));
|
log, err => cb(err));
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue