Skip to content

Commit 2de1d3a

Browse files
Merge branch 'improvement/CLDSRV-613' into w/9.0/improvement/CLDSRV-613
2 parents ca03c40 + 4e41fa7 commit 2de1d3a

File tree

11 files changed

+366
-49
lines changed

11 files changed

+366
-49
lines changed

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
@@ -243,16 +243,26 @@ function _updateRestoreInfo(objectMD, restoreParam, log) {
243243
*
244244
*/
245245
function startRestore(objectMD, restoreParam, log, cb) {
246-
log.info('Validating if restore can be done or not.');
246+
log.debug('Validating if restore can be done or not.');
247247
const checkResultError = _validateStartRestore(objectMD, log);
248248
if (checkResultError) {
249+
log.debug('Restore cannot be done.', {
250+
error: checkResultError,
251+
method: 'startRestore'
252+
});
249253
return cb(checkResultError);
250254
}
251-
log.info('Updating restore information.');
252255
const updateResultError = _updateRestoreInfo(objectMD, restoreParam, log);
253256
if (updateResultError) {
257+
log.debug('Failed to update restore information.', {
258+
error: updateResultError,
259+
method: 'startRestore'
260+
});
254261
return cb(updateResultError);
255262
}
263+
log.debug('Validated and updated restore information', {
264+
method: 'startRestore'
265+
});
256266
const isObjectAlreadyRestored = _updateObjectExpirationDate(objectMD, log);
257267
return cb(null, isObjectAlreadyRestored);
258268
}

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
@@ -86,6 +86,21 @@ function objectDeleteInternal(authInfo, request, log, isExpiration, cb) {
8686
// versioning has been configured
8787
return next(null, bucketMD, objMD);
8888
}
89+
90+
if (versioningCfg && versioningCfg.Status === 'Enabled' &&
91+
objMD.versionId === reqVersionId && isExpiration &&
92+
!objMD.isDeleteMarker) {
93+
log.warn('expiration is trying to delete a master version ' +
94+
'of an object with versioning enabled', {
95+
method: 'objectDeleteInternal',
96+
isExpiration,
97+
reqVersionId,
98+
versionId: objMD.versionId,
99+
replicationState: objMD.replicationInfo,
100+
location: objMD.location,
101+
originOp: objMD.originOp,
102+
});
103+
}
89104
if (reqVersionId && objMD.location &&
90105
Array.isArray(objMD.location) && objMD.location[0]) {
91106
// 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
});

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
});

tests/unit/api/objectDelete.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const bucketPutACL = require('../../../lib/api/bucketPutACL');
99
const constants = require('../../../constants');
1010
const { cleanup, DummyRequestLogger, makeAuthInfo } = require('../helpers');
1111
const objectPut = require('../../../lib/api/objectPut');
12-
const { objectDelete } = require('../../../lib/api/objectDelete');
12+
const { objectDelete, objectDeleteInternal } = require('../../../lib/api/objectDelete');
1313
const objectGet = require('../../../lib/api/objectGet');
1414
const DummyRequest = require('../DummyRequest');
1515
const mpuUtils = require('../utils/mpuUtils');
@@ -263,6 +263,38 @@ describe('objectDelete API', () => {
263263
});
264264
});
265265

266+
it('should log when expiration is trying to delete a master version', done => {
267+
const warnStub = sinon.stub(log, 'warn');
268+
const testBucketPutVersionRequest = new DummyRequest({
269+
bucketName,
270+
namespace,
271+
headers: { 'x-amz-bucket-object-lock-enabled': 'true' },
272+
url: `/${bucketName}`,
273+
});
274+
275+
bucketPut(authInfo, testBucketPutVersionRequest, log, () => {
276+
objectPut(authInfo, testPutObjectRequest,
277+
undefined, log, (err, data) => {
278+
const deleteObjectVersionRequest = new DummyRequest({
279+
bucketName,
280+
namespace,
281+
objectKey,
282+
headers: {},
283+
url: `/${bucketName}/${objectKey}?versionId=${data['x-amz-version-id']}`,
284+
query: {
285+
versionId: data['x-amz-version-id'],
286+
},
287+
});
288+
objectDeleteInternal(authInfo, deleteObjectVersionRequest, log, true, err => {
289+
assert.strictEqual(err, null);
290+
sinon.assert.calledWith(warnStub, 'expiration is trying to delete a master version ' +
291+
'of an object with versioning enabled');
292+
done();
293+
});
294+
});
295+
});
296+
});
297+
266298
describe('with \'modified\' headers', () => {
267299
beforeEach(done => {
268300
bucketPut(authInfo, testBucketPutRequest, log, () => {

tests/unit/internal/routeVeeam.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const assert = require('assert');
22
const { DummyRequestLogger } = require('../helpers');
33
const routeVeeam = require('../../../lib/routes/routeVeeam');
4+
const DummyRequest = require('../DummyRequest');
45

56
const log = new DummyRequestLogger();
67

@@ -111,3 +112,25 @@ describe('RouteVeeam: _normalizeVeeamRequest', () => {
111112
assert.doesNotThrow(() => routeVeeam._normalizeVeeamRequest(request));
112113
});
113114
});
115+
116+
describe('RouteVeeam: routeVeeam', () => {
117+
it('should return error for unsupported routes', done => {
118+
const req = new DummyRequest({
119+
method: 'PATCH',
120+
resourceType: 'bucket',
121+
subresource: 'veeam',
122+
apiMethod: 'routeVeeam',
123+
url: '/bucket/veeam',
124+
});
125+
req.method = 'PATCH';
126+
routeVeeam.routeVeeam('127.0.0.1', req, {
127+
setHeader: () => {},
128+
writeHead: () => {},
129+
end: data => {
130+
assert(data.includes('MethodNotAllowed'));
131+
done();
132+
},
133+
headersSent: false,
134+
}, log);
135+
});
136+
});

0 commit comments

Comments
 (0)