-
Notifications
You must be signed in to change notification settings - Fork 253
Expand file tree
/
Copy pathabortMultipartUpload.js
More file actions
142 lines (137 loc) · 6.28 KB
/
abortMultipartUpload.js
File metadata and controls
142 lines (137 loc) · 6.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
const async = require('async');
const constants = require('../../../../constants');
const { data } = require('../../../data/wrapper');
const locationConstraintCheck = require('../object/locationConstraintCheck');
const { metadataValidateBucketAndObj } =
require('../../../metadata/metadataUtils');
const services = require('../../../services');
function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
callback, request) {
const metadataValMPUparams = {
authInfo,
bucketName,
objectKey,
uploadId,
preciseRequestType: 'multipartDelete',
request,
};
// For validating the request at the destinationBucket level
// params are the same as validating at the MPU level
// but the requestType is the more general 'objectDelete'
const metadataValParams = Object.assign({}, metadataValMPUparams);
metadataValParams.requestType = 'objectPut';
const authzIdentityResult = request ? request.actionImplicitDenies : true;
async.waterfall([
function checkDestBucketVal(next) {
metadataValidateBucketAndObj(metadataValParams, authzIdentityResult, log,
(err, destinationBucket) => {
if (err) {
return next(err, destinationBucket);
}
if (destinationBucket.policies) {
// TODO: Check bucket policies to see if user is granted
// permission or forbidden permission to take
// given action.
// If permitted, add 'bucketPolicyGoAhead'
// attribute to params for validating at MPU level.
// This is GH Issue#76
metadataValMPUparams.requestType =
'bucketPolicyGoAhead';
}
return next(null, destinationBucket);
});
},
function checkMPUval(destBucket, next) {
metadataValParams.log = log;
services.metadataValidateMultipart(metadataValParams,
(err, mpuBucket, mpuOverviewObj) => {
if (err) {
return next(err, destBucket);
}
return next(err, mpuBucket, mpuOverviewObj, destBucket);
});
},
function abortExternalMpu(mpuBucket, mpuOverviewObj, destBucket,
next) {
const location = mpuOverviewObj.controllingLocationConstraint;
const originalIdentityImpDenies = request.actionImplicitDenies;
// eslint-disable-next-line no-param-reassign
// eslint-disable-next-line no-param-reassign
delete request.actionImplicitDenies;
return data.abortMPU(objectKey, uploadId, location, bucketName,
request, destBucket, locationConstraintCheck, log,
(err, skipDataDelete) => {
// eslint-disable-next-line no-param-reassign
request.actionImplicitDenies = originalIdentityImpDenies;
if (err) {
return next(err, destBucket);
}
// for Azure and GCP we do not need to delete data
// for all other backends, skipDataDelete will be set to false
return next(null, mpuBucket, destBucket, skipDataDelete);
});
},
function sendAbortPut(mpuBucket, destBucket, skipDataDelete, next) {
services.sendAbortMPUPut(bucketName, objectKey, uploadId, log,
err => {
if (err) {
return next(err, destBucket);
}
return next(null, mpuBucket, destBucket, skipDataDelete);
});
},
function getPartLocations(mpuBucket, destBucket, skipDataDelete,
next) {
services.getMPUparts(mpuBucket.getName(), uploadId, log,
(err, result) => {
if (err) {
return next(err, destBucket);
}
const storedParts = result.Contents;
return next(null, mpuBucket, storedParts, destBucket,
skipDataDelete);
});
},
function deleteData(mpuBucket, storedParts, destBucket,
skipDataDelete, next) {
// for Azure we do not need to delete data
if (skipDataDelete) {
return next(null, mpuBucket, storedParts, destBucket);
}
// The locations were sent to metadata as an array
// under partLocations. Pull the partLocations.
let locations = storedParts.map(item => item.value.partLocations);
if (locations.length === 0) {
return next(null, mpuBucket, storedParts, destBucket);
}
// flatten the array
locations = [].concat(...locations);
return async.eachLimit(locations, 5, (loc, cb) => {
data.delete(loc, log, err => {
if (err) {
log.fatal('delete ObjectPart failed', { err });
}
cb();
});
}, () => next(null, mpuBucket, storedParts, destBucket));
},
function deleteMetadata(mpuBucket, storedParts, destBucket, next) {
let splitter = constants.splitter;
// BACKWARD: Remove to remove the old splitter
if (mpuBucket.getMdBucketModelVersion() < 2) {
splitter = constants.oldSplitter;
}
// Reconstruct mpuOverviewKey
const mpuOverviewKey =
`overview${splitter}${objectKey}${splitter}${uploadId}`;
// Get the sum of all part sizes to include in pushMetric object
const partSizeSum = storedParts.map(item => item.value.Size)
.reduce((currPart, nextPart) => currPart + nextPart, 0);
const keysToDelete = storedParts.map(item => item.key);
keysToDelete.push(mpuOverviewKey);
services.batchDeleteObjectMetadata(mpuBucket.getName(),
keysToDelete, log, err => next(err, destBucket, partSizeSum));
},
], callback);
}
module.exports = abortMultipartUpload;