Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions lib/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,17 @@ function locationConstraintAssert(locationConstraints) {
// eslint-disable-next-line no-param-reassign
locationConstraints[l].details.pathStyle = false;
}

if (details.supportsVersioning !== undefined) {
assert(typeof details.supportsVersioning === 'boolean',
'bad config: locationConstraints[region].supportsVersioning' +
'must be a boolean');
} else {
// default to true
// eslint-disable-next-line no-param-reassign
locationConstraints[l].details.supportsVersioning = true;
}

if (locationConstraints[l].type === 'azure') {
azureLocationConstraintAssert(l, locationConstraints[l]);
}
Expand Down Expand Up @@ -943,6 +954,10 @@ class Config extends EventEmitter {
return dataStoreName && dataStoreName.type;
}

getLocationConstraint(locationConstraintName) {
return this.locationConstraints[locationConstraintName];
}

setRestEndpoints(restEndpoints) {
restEndpointsAssert(restEndpoints, this.locationConstraints);
this.restEndpoints = restEndpoints;
Expand Down
8 changes: 8 additions & 0 deletions lib/api/bucketPutVersioning.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,17 @@ function _checkBackendVersioningImplemented(bucket) {
const bucketLocation = bucket.getLocationConstraint();
const bucketLocationType = config.getLocationConstraintType(bucketLocation);

// backend types known not to support versioning
if (versioningNotImplBackends[bucketLocationType]) {
return false;
}

// versioning disabled per-location constraint
const lc = config.getLocationConstraint(bucketLocation);
if (lc.details && !lc.details.supportsVersioning) {
return false;
}

return true;
}

Expand Down
13 changes: 10 additions & 3 deletions lib/data/external/AwsClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class AwsClient {
this._bucketMatch = config.bucketMatch;
this._dataStoreName = config.dataStoreName;
this._serverSideEncryption = config.serverSideEncryption;
this._supportsVersioning = config.supportsVersioning;
this._client = new AWS.S3(this._s3Params);
}

Expand All @@ -46,7 +47,7 @@ class AwsClient {
`${this.type}: ${err.message}`)
);
}
if (!data.VersionId) {
if (!data.VersionId && this._supportsVersioning) {
logHelper(log, 'error', 'missing version id for data ' +
'backend object', missingVerIdInternalError,
this._dataStoreName, this.clientType);
Expand Down Expand Up @@ -180,6 +181,12 @@ class AwsClient {
awsResp[location] = { error: err, external: true };
return callback(null, awsResp);
}
if (!this._supportsVersioning) {
awsResp[location] = {
message: 'Congrats! You own the bucket',
};
return callback(null, awsResp);
}
return this._client.getBucketVersioning({
Bucket: this._awsBucketName },
(err, data) => {
Expand Down Expand Up @@ -362,7 +369,7 @@ class AwsClient {
`${this.type}: ${err.message}`)
);
}
if (!completeMpuRes.VersionId) {
if (!completeMpuRes.VersionId && this._supportsVersioning) {
logHelper(log, 'error', 'missing version id for data ' +
'backend object', missingVerIdInternalError,
this._dataStoreName, this.clientType);
Expand Down Expand Up @@ -504,7 +511,7 @@ class AwsClient {
`${this.type}: ${err.message}`)
);
}
if (!copyResult.VersionId) {
if (!copyResult.VersionId && this._supportsVersioning) {
logHelper(log, 'error', 'missing version id for data ' +
'backend object', missingVerIdInternalError,
this._dataStoreName, this.clientType);
Expand Down
1 change: 1 addition & 0 deletions lib/data/locationConstraintParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ function parseLC() {
bucketMatch: locationObj.details.bucketMatch,
serverSideEncryption: locationObj.details.serverSideEncryption,
dataStoreName: location,
supportsVersioning: locationObj.details.supportsVersioning,
};
if (locationObj.type === 'gcp') {
clientConfig.mpuBucket = locationObj.details.mpuBucketName;
Expand Down
24 changes: 21 additions & 3 deletions lib/management/configuration.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const forge = require('node-forge');
const { URL } = require('url');

const { buildAuthDataAccount } = require('../auth/in_memory/builder');
const _config = require('../Config').config;
Expand Down Expand Up @@ -95,6 +96,9 @@ function patchConfiguration(instanceId, newConf, log, cb) {
Object.keys(newConf.locations || {}).forEach(k => {
const l = newConf.locations[k];
const location = {};
let supportsVersioning = false;
let pathStyle = false;

switch (l.locationType) {
case 'location-mem-v1':
location.type = 'mem';
Expand All @@ -115,11 +119,23 @@ function patchConfiguration(instanceId, newConf, log, cb) {
};
}
break;
case 'location-do-spaces-v1':
case 'location-scality-ring-s3-v1':
pathStyle = true; // fallthrough
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reporting the style comment about using a mapping object rather than relying on fallthrough of a switch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good cleanup, we'll follow up on it

case 'location-aws-s3-v1':
case 'location-wasabi-v1':
supportsVersioning = true; // fallthrough
case 'location-do-spaces-v1':
location.type = 'aws_s3';
if (l.details.secretKey && l.details.secretKey.length > 0) {
let https = true;
let awsEndpoint = l.details.endpoint ||
's3.amazonaws.com';
if (awsEndpoint.includes('://')) {
const url = new URL(awsEndpoint);
awsEndpoint = url.host;
https = url.scheme === 'https';
}

location.details = {
credentials: {
accessKey: l.details.accessKey,
Expand All @@ -130,8 +146,10 @@ function patchConfiguration(instanceId, newConf, log, cb) {
bucketMatch: l.details.bucketMatch,
serverSideEncryption:
Boolean(l.details.serverSideEncryption),
awsEndpoint: l.details.endpoint ||
's3.amazonaws.com',
awsEndpoint,
supportsVersioning,
pathStyle,
https,
};
}
break;
Expand Down
22 changes: 22 additions & 0 deletions tests/locationConfig/locationConfigLegacy.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,27 @@
"bucketMatch": true,
"credentialsProfile": "google"
}
},
"withversioning": {
"type": "aws_s3",
"legacyAwsBehavior": true,
"details": {
"awsEndpoint": "s3.amazonaws.com",
"bucketName": "multitester555",
"bucketMatch": true,
"credentialsProfile": "default",
"supportsVersioning": true
}
},
"withoutversioning": {
"type": "aws_s3",
"legacyAwsBehavior": true,
"details": {
"awsEndpoint": "s3.amazonaws.com",
"bucketName": "multitester555",
"bucketMatch": true,
"credentialsProfile": "default",
"supportsVersioning": false
}
}
}
22 changes: 22 additions & 0 deletions tests/locationConfig/locationConfigTests.json
Original file line number Diff line number Diff line change
Expand Up @@ -163,5 +163,27 @@
"bucketMatch": false,
"credentialsProfile": "google"
}
},
"withversioning": {
"type": "aws_s3",
"legacyAwsBehavior": true,
"details": {
"awsEndpoint": "s3.amazonaws.com",
"bucketName": "multitester555",
"bucketMatch": true,
"credentialsProfile": "default",
"supportsVersioning": true
}
},
"withoutversioning": {
"type": "aws_s3",
"legacyAwsBehavior": true,
"details": {
"awsEndpoint": "s3.amazonaws.com",
"bucketName": "multitester555",
"bucketMatch": true,
"credentialsProfile": "default",
"supportsVersioning": false
}
}
}
41 changes: 40 additions & 1 deletion tests/unit/DummyService.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
const uuid = require('uuid/v4');

class DummyService {
constructor(config = {}) {
this.versioning = config.versioning;
}
headBucket(params, callback) {
return callback();
}
getBucketVersioning(params, callback) {
if (this.versioning) {
return callback(null, { Status: 'Enabled' });
}
return callback(null, {});
}
headObject(params, callback) {
const retObj = {
ContentLength: `${1024 * 1024 * 1024}`,
Expand All @@ -11,10 +23,37 @@ class DummyService {
const retObj = {
Bucket: params.Bucket,
Key: params.Key,
VersionId: uuid().replace(/-/g, ''),
ETag: `"${uuid().replace(/-/g, '')}"`,
ContentLength: `${1024 * 1024 * 1024}`,
};
if (this.versioning) {
retObj.VersionId = uuid().replace(/-/g, '');
}
return callback(null, retObj);
}
upload(params, callback) {
this.putObject(params, callback);
}
putObject(params, callback) {
const retObj = {
ETag: `"${uuid().replace(/-/g, '')}"`,
};
if (this.versioning) {
retObj.VersionId = uuid().replace(/-/g, '');
}
return callback(null, retObj);
}
copyObject(params, callback) {
const retObj = {
CopyObjectResult: {
ETag: `"${uuid().replace(/-/g, '')}"`,
LastModified: new Date().toISOString(),
},
VersionId: null,
};
if (this.versioning) {
retObj.VersionId = uuid().replace(/-/g, '');
}
return callback(null, retObj);
}
// To-Do: add tests for other methods
Expand Down
Loading