Skip to content

Commit 2c73021

Browse files
committed
Merge branches 'development/8.8' and 'w/7.70/bugfix/CLDSRV-620/strip-trailing-checksums' into tmp/octopus/w/8.8/bugfix/CLDSRV-620/strip-trailing-checksums
3 parents f6d8473 + 4e41fa7 + 63547e5 commit 2c73021

14 files changed

Lines changed: 441 additions & 54 deletions

File tree

lib/api/apiUtils/object/abortMultipartUpload.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
100100
// In case there has been an error during cleanup after a complete MPU
101101
// (e.g. failure to delete MPU MD in shadow bucket),
102102
// we need to ensure that the MPU metadata is deleted.
103-
log.info('Object has existing metadata, deleting them', {
103+
log.debug('Object has existing metadata, deleting them', {
104104
method: 'abortMultipartUpload',
105105
bucketName,
106106
objectKey,

lib/api/apiUtils/object/coldStorage.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,16 +244,26 @@ function _updateRestoreInfo(objectMD, restoreParam, log) {
244244
*
245245
*/
246246
function startRestore(objectMD, restoreParam, log, cb) {
247-
log.info('Validating if restore can be done or not.');
247+
log.debug('Validating if restore can be done or not.');
248248
const checkResultError = _validateStartRestore(objectMD, log);
249249
if (checkResultError) {
250+
log.debug('Restore cannot be done.', {
251+
error: checkResultError,
252+
method: 'startRestore'
253+
});
250254
return cb(checkResultError);
251255
}
252-
log.info('Updating restore information.');
253256
const updateResultError = _updateRestoreInfo(objectMD, restoreParam, log);
254257
if (updateResultError) {
258+
log.debug('Failed to update restore information.', {
259+
error: updateResultError,
260+
method: 'startRestore'
261+
});
255262
return cb(updateResultError);
256263
}
264+
log.debug('Validated and updated restore information', {
265+
method: 'startRestore'
266+
});
257267
const isObjectAlreadyRestored = _updateObjectExpirationDate(objectMD, log);
258268
return cb(null, isObjectAlreadyRestored);
259269
}

lib/api/apiUtils/object/objectRestore.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ function objectRestore(metadata, mdUtils, userInfo, request, log, callback) {
9494
log.trace('version is a delete marker', { method: METHOD, error: err });
9595
return next(err, bucketMD, objectMD);
9696
}
97-
log.info('it acquired the object metadata.', {
97+
log.debug('acquired the object metadata.', {
9898
'method': METHOD,
9999
});
100100
return next(null, bucketMD, objectMD);
@@ -108,7 +108,7 @@ function objectRestore(metadata, mdUtils, userInfo, request, log, callback) {
108108
if (err) {
109109
return next(err, bucketMD, objectMD, restoreInfo);
110110
}
111-
log.info('it parsed xml of the request body.', { method: METHOD, value: restoreInfo });
111+
log.debug('parsed xml of the request body.', { method: METHOD, value: restoreInfo });
112112
const checkTierResult = checkTierSupported(restoreInfo);
113113
if (checkTierResult instanceof Error) {
114114
return next(checkTierResult);

lib/api/objectDelete.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ function objectDeleteInternal(authInfo, request, log, isExpiration, cb) {
8787
// versioning has been configured
8888
return next(null, bucketMD, objMD);
8989
}
90+
91+
if (versioningCfg && versioningCfg.Status === 'Enabled' &&
92+
objMD.versionId === reqVersionId && isExpiration &&
93+
!objMD.isDeleteMarker) {
94+
log.warn('expiration is trying to delete a master version ' +
95+
'of an object with versioning enabled', {
96+
method: 'objectDeleteInternal',
97+
isExpiration,
98+
reqVersionId,
99+
versionId: objMD.versionId,
100+
replicationState: objMD.replicationInfo,
101+
location: objMD.location,
102+
originOp: objMD.originOp,
103+
});
104+
}
90105
if (reqVersionId && objMD.location &&
91106
Array.isArray(objMD.location) && objMD.location[0]) {
92107
// we need this information for data deletes to AWS

lib/routes/routeBackbeat.js

Lines changed: 20 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,7 +1047,7 @@ function _azureConditionalDelete(request, response, log, cb) {
10471047
const reqUids = log.getSerializedUids();
10481048
return dataClient.delete(objectGetInfo, reqUids, err => {
10491049
if (err && err.code === 412) {
1050-
log.info('precondition for Azure deletion was not met', {
1050+
log.error('precondition for Azure deletion was not met', {
10511051
method: '_azureConditionalDelete',
10521052
key: request.objectKey,
10531053
bucket: request.bucketName,
@@ -1086,7 +1086,7 @@ function _conditionalTagging(request, response, locations, log, cb) {
10861086
}
10871087
const ifUnmodifiedSince = request.headers['if-unmodified-since'];
10881088
if (new Date(ifUnmodifiedSince) < new Date(lastModified)) {
1089-
log.info('object has been modified, skipping tagging operation', {
1089+
log.debug('object has been modified, skipping tagging operation', {
10901090
method: '_conditionalTagging',
10911091
ifUnmodifiedSince,
10921092
lastModified,
@@ -1103,7 +1103,7 @@ function _performConditionalDelete(request, response, locations, log, cb) {
11031103
const { headers } = request;
11041104
const location = locationConstraints[headers['x-scal-storage-class']];
11051105
if (!request.headers['if-unmodified-since']) {
1106-
log.info('unknown last modified time, skipping conditional delete', {
1106+
log.debug('unknown last modified time, skipping conditional delete', {
11071107
method: '_performConditionalDelete',
11081108
});
11091109
return _respond(response, null, log, cb);
@@ -1387,10 +1387,18 @@ function routeBackbeat(clientIP, request, response, log) {
13871387
// Attach the apiMethod method to the request, so it can used by monitoring in the server
13881388
// eslint-disable-next-line no-param-reassign
13891389
request.apiMethod = 'routeBackbeat';
1390-
log.debug('routing request', {
1391-
method: 'routeBackbeat',
1390+
log.addDefaultFields({
1391+
clientIP,
13921392
url: request.url,
1393+
method: 'routeBackbeat',
1394+
resourceType: request.resourceType,
1395+
bucketName: request.bucketName,
1396+
objectKey: request.objectKey,
1397+
bytesReceived: request.parsedContentLength || 0,
1398+
bodyLength: parseInt(request.headers['content-length'], 10) || 0,
13931399
});
1400+
1401+
log.debug('routing request');
13941402
_normalizeBackbeatRequest(request);
13951403
const requestContexts = prepareRequestContexts('objectReplicate', request);
13961404

@@ -1429,9 +1437,6 @@ function routeBackbeat(clientIP, request, response, log) {
14291437
if (err) {
14301438
log.debug('authentication error', {
14311439
error: err,
1432-
method: request.method,
1433-
bucketName: request.bucketName,
1434-
objectKey: request.objectKey,
14351440
});
14361441
return responseJSONBody(err, null, response, log);
14371442
}
@@ -1444,8 +1449,6 @@ function routeBackbeat(clientIP, request, response, log) {
14441449
if (userInfo.getCanonicalID() === constants.publicId) {
14451450
log.debug('unauthenticated access to API routes', {
14461451
method: request.method,
1447-
bucketName: request.bucketName,
1448-
objectKey: request.objectKey,
14491452
});
14501453
return responseJSONBody(
14511454
errors.AccessDenied, null, response, log);
@@ -1473,18 +1476,8 @@ function routeBackbeat(clientIP, request, response, log) {
14731476
(backbeatRoutes[request.method][request.resourceType]
14741477
[request.query.operation] === undefined &&
14751478
request.resourceType === 'multiplebackenddata'));
1476-
log.addDefaultFields({
1477-
bucketName: request.bucketName,
1478-
objectKey: request.objectKey,
1479-
bytesReceived: request.parsedContentLength || 0,
1480-
bodyLength: parseInt(request.headers['content-length'], 10) || 0,
1481-
});
14821479
if (invalidRequest || invalidRoute) {
1483-
log.debug(invalidRequest ? 'invalid request' : 'no such route', {
1484-
method: request.method,
1485-
resourceType: request.resourceType,
1486-
query: request.query,
1487-
});
1480+
log.debug(invalidRequest ? 'invalid request' : 'no such route');
14881481
return responseJSONBody(errors.MethodNotAllowed, null, response, log);
14891482
}
14901483

@@ -1494,9 +1487,6 @@ function routeBackbeat(clientIP, request, response, log) {
14941487
if (err) {
14951488
log.debug('authentication error', {
14961489
error: err,
1497-
method: request.method,
1498-
bucketName: request.bucketName,
1499-
objectKey: request.objectKey,
15001490
});
15011491
}
15021492
// eslint-disable-next-line no-param-reassign
@@ -1507,11 +1497,7 @@ function routeBackbeat(clientIP, request, response, log) {
15071497
// TODO: understand why non-object requests (batchdelete) were not authenticated
15081498
if (!_isObjectRequest(request)) {
15091499
if (userInfo.getCanonicalID() === constants.publicId) {
1510-
log.debug(`unauthenticated access to backbeat ${request.resourceType} routes`, {
1511-
method: request.method,
1512-
bucketName: request.bucketName,
1513-
objectKey: request.objectKey,
1514-
});
1500+
log.debug(`unauthenticated access to backbeat ${request.resourceType} routes`);
15151501
return responseJSONBody(
15161502
errors.AccessDenied, null, response, log);
15171503
}
@@ -1559,12 +1545,7 @@ function routeBackbeat(clientIP, request, response, log) {
15591545
// target buckets with versioning enabled.
15601546
const isVersioningRequired = request.headers['x-scal-versioning-required'] === 'true';
15611547
if (isVersioningRequired && (!versioningConfig || versioningConfig.Status !== 'Enabled')) {
1562-
log.debug('bucket versioning is not enabled', {
1563-
method: request.method,
1564-
bucketName: request.bucketName,
1565-
objectKey: request.objectKey,
1566-
resourceType: request.resourceType,
1567-
});
1548+
log.debug('bucket versioning is not enabled');
15681549
return next(errors.InvalidBucketState);
15691550
}
15701551
return backbeatRoutes[request.method][request.resourceType](
@@ -1586,12 +1567,12 @@ function routeBackbeat(clientIP, request, response, log) {
15861567
(hook, done) => hook(err, done),
15871568
() => {
15881569
if (err) {
1570+
log.error('error processing backbeat request', {
1571+
error: err,
1572+
});
15891573
return responseJSONBody(err, null, response, log);
15901574
}
1591-
log.debug('backbeat route response sent successfully',
1592-
{ method: request.method,
1593-
bucketName: request.bucketName,
1594-
objectKey: request.objectKey });
1575+
log.debug('backbeat route response sent successfully');
15951576
return undefined;
15961577
},
15971578
));

lib/routes/routeVeeam.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ function routeVeeam(clientIP, request, response, log) {
188188
request.apiMethod = 'routeVeeam';
189189
_normalizeVeeamRequest(request);
190190

191-
log.info('routing request', {
191+
log.debug('routing request', {
192192
method: 'routeVeeam',
193193
url: request.url,
194194
clientIP,

lib/server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ class S3Server {
292292
next => clientCheck(true, log, next),
293293
], (err, results) => {
294294
if (err) {
295-
log.info('initial health check failed, delaying startup', {
295+
log.warn('initial health check failed, delaying startup', {
296296
error: err,
297297
healthStatus: results,
298298
});

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@zenko/cloudserver",
3-
"version": "8.8.43",
3+
"version": "8.8.44",
44
"description": "Zenko CloudServer, an open-source Node.js implementation of a server handling the Amazon S3 protocol",
55
"main": "index.js",
66
"engines": {
@@ -21,7 +21,7 @@
2121
"dependencies": {
2222
"@azure/storage-blob": "^12.12.0",
2323
"@hapi/joi": "^17.1.0",
24-
"arsenal": "git+https://github.com/scality/arsenal#8.1.146",
24+
"arsenal": "git+https://github.com/scality/arsenal#8.1.148",
2525
"async": "~2.5.0",
2626
"aws-sdk": "2.905.0",
2727
"bucketclient": "scality/bucketclient#8.1.9",
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const assert = require('assert');
2+
const { makeS3Request } = require('../utils/makeRequest');
3+
const HttpRequestAuthV4 = require('../utils/HttpRequestAuthV4');
4+
5+
const bucket = 'testunsupportedchecksumsbucket';
6+
const objectKey = 'key';
7+
const objData = Buffer.alloc(1024, 'a');
8+
9+
const authCredentials = {
10+
accessKey: 'accessKey1',
11+
secretKey: 'verySecretKey1',
12+
};
13+
14+
const itSkipIfAWS = process.env.AWS_ON_AIR ? it.skip : it;
15+
16+
describe('unsupported checksum requests:', () => {
17+
before(done => {
18+
makeS3Request({
19+
method: 'PUT',
20+
authCredentials,
21+
bucket,
22+
}, err => {
23+
assert.ifError(err);
24+
done();
25+
});
26+
});
27+
28+
after(done => {
29+
makeS3Request({
30+
method: 'DELETE',
31+
authCredentials,
32+
bucket,
33+
}, err => {
34+
assert.ifError(err);
35+
done();
36+
});
37+
});
38+
39+
itSkipIfAWS('should respond with BadRequest for trailing checksum', done => {
40+
const req = new HttpRequestAuthV4(
41+
`http://localhost:8000/${bucket}/${objectKey}`,
42+
Object.assign(
43+
{
44+
method: 'PUT',
45+
headers: {
46+
'content-length': objData.length,
47+
'x-amz-content-sha256': 'STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER',
48+
'x-amz-trailer': 'x-amz-checksum-sha256',
49+
},
50+
},
51+
authCredentials
52+
),
53+
res => {
54+
assert.strictEqual(res.statusCode, 400);
55+
res.on('data', () => {});
56+
res.on('end', done);
57+
}
58+
);
59+
60+
req.on('error', err => {
61+
assert.ifError(err);
62+
});
63+
64+
req.write(objData);
65+
66+
req.once('drain', () => {
67+
req.end();
68+
});
69+
});
70+
});

tests/unit/api/apiUtils/coldStorage.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,5 +243,16 @@ describe('cold storage', () => {
243243
done();
244244
});
245245
});
246+
247+
it('should fail if _updateRestoreInfo fails', done => {
248+
const objectMd = new ObjectMD().setDataStoreName(
249+
'location-dmf-v1'
250+
).setArchive(false).getValue();
251+
252+
startRestore(objectMd, { days: 7 }, log, err => {
253+
assert.deepStrictEqual(err, errors.InternalError);
254+
done();
255+
});
256+
});
246257
});
247258
});

0 commit comments

Comments
 (0)