Skip to content

Commit

Permalink
Merge branch 'improvement/ARSN-410-quotas-for-bucket-apis' into q/8.1
Browse files Browse the repository at this point in the history
  • Loading branch information
bert-e committed Apr 30, 2024
2 parents fe29bac + c464a70 commit 2c06963
Show file tree
Hide file tree
Showing 10 changed files with 94 additions and 4 deletions.
14 changes: 13 additions & 1 deletion documentation/BucketInfoModelVersion.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,16 @@ For capacity-enabled buckets, contains the following data:

### Usage

Used to store bucket tagging
Used to store bucket tagging

## Model version 17

### Properties Added

```javascript
this._quotaMax = quotaMax || 0;
```

### Usage

Used to store bucket quota
7 changes: 7 additions & 0 deletions lib/errors/arsenalErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1042,3 +1042,10 @@ export const AuthMethodNotImplemented: ErrorFormat = {
description: 'AuthMethodNotImplemented',
code: 501,
};

// --------------------- quotaErros ---------------------

export const NoSuchQuota: ErrorFormat = {
code: 404,
description: 'The specified resource does not have a quota.',
};
32 changes: 30 additions & 2 deletions lib/models/BucketInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export default class BucketInfo {
_azureInfo: any | null;
_ingestion: { status: 'enabled' | 'disabled' } | null;
_capabilities?: Capabilities;
_quotaMax: number | 0;

/**
* Represents all bucket information.
Expand Down Expand Up @@ -157,6 +158,7 @@ export default class BucketInfo {
* @param [notificationConfiguration] - bucket notification configuration
* @param [tags] - bucket tag set
* @param [capabilities] - capabilities for the bucket
* @param quotaMax - bucket quota
*/
constructor(
name: string,
Expand Down Expand Up @@ -185,6 +187,7 @@ export default class BucketInfo {
notificationConfiguration?: any,
tags?: Array<BucketTag> | [],
capabilities?: Capabilities,
quotaMax?: number | 0,
) {
assert.strictEqual(typeof name, 'string');
assert.strictEqual(typeof owner, 'string');
Expand Down Expand Up @@ -285,6 +288,10 @@ export default class BucketInfo {
tags = [] as BucketTag[];
}
assert.strictEqual(areTagsValid(tags), true);
if (quotaMax) {
assert.strictEqual(typeof quotaMax, 'number');
assert(quotaMax >= 0, 'Quota cannot be negative');
}

// IF UPDATING PROPERTIES, INCREMENT MODELVERSION NUMBER ABOVE
this._acl = aclInstance;
Expand Down Expand Up @@ -313,6 +320,7 @@ export default class BucketInfo {
this._notificationConfiguration = notificationConfiguration || null;
this._tags = tags;
this._capabilities = capabilities || undefined;
this._quotaMax = quotaMax || 0;
return this;
}

Expand Down Expand Up @@ -348,6 +356,7 @@ export default class BucketInfo {
notificationConfiguration: this._notificationConfiguration,
tags: this._tags,
capabilities: this._capabilities,
quotaMax: this._quotaMax,
};
const final = this._websiteConfiguration
? {
Expand All @@ -374,7 +383,7 @@ export default class BucketInfo {
obj.bucketPolicy, obj.uid, obj.readLocationConstraint, obj.isNFS,
obj.ingestion, obj.azureInfo, obj.objectLockEnabled,
obj.objectLockConfiguration, obj.notificationConfiguration, obj.tags,
obj.capabilities);
obj.capabilities, obj.quotaMax);
}

/**
Expand All @@ -401,7 +410,8 @@ export default class BucketInfo {
data._bucketPolicy, data._uid, data._readLocationConstraint,
data._isNFS, data._ingestion, data._azureInfo,
data._objectLockEnabled, data._objectLockConfiguration,
data._notificationConfiguration, data._tags, data._capabilities);
data._notificationConfiguration, data._tags, data._capabilities,
data._quotaMax);
}

/**
Expand Down Expand Up @@ -939,4 +949,22 @@ export default class BucketInfo {
this._capabilities = capabilities;
return this;
}

/**
* Get the bucket quota information
* @return quotaMax
*/
getQuota() {
return this._quotaMax;
}

/**
* Set bucket quota
* @param quota - quota to be set
* @return - bucket quota info
*/
setQuota(quota: number) {
this._quotaMax = quota || 0;
return this;
}
}
3 changes: 3 additions & 0 deletions lib/policyEvaluator/utils/actionMaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ const actionMonitoringMapS3 = {
objectPutTagging: 'PutObjectTagging',
objectRestore: 'RestoreObject',
serviceGet: 'ListBuckets',
bucketGetQuota: 'GetBucketQuota',
bucketUpdateQuota: 'UpdateBucketQuota',
bucketDeleteQuota: 'DeleteBucketQuota',
};

const actionMapAccountQuotas = {
Expand Down
2 changes: 2 additions & 0 deletions lib/s3routes/routes/routeDELETE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ export default function routeDELETE(
return call('bucketDeleteEncryption');
} else if (query?.tagging !== undefined) {
return call('bucketDeleteTagging');
} else if (query?.quota !== undefined) {
return call('bucketDeleteQuota');
}
call('bucketDelete');
} else {
Expand Down
2 changes: 2 additions & 0 deletions lib/s3routes/routes/routeGET.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ export default function routerGET(
call('bucketGetEncryption');
} else if (query.search !== undefined) {
call('metadataSearch')
} else if (query.quota !== undefined) {
call('bucketGetQuota');
} else {
// GET bucket
call('bucketGet');
Expand Down
7 changes: 7 additions & 0 deletions lib/s3routes/routes/routePUT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ export default function routePUT(
return routesUtils.responseNoBody(err, corsHeaders,
response, 200, log);
});
} else if (query.quota !== undefined) {
api.callApiMethod('bucketUpdateQuota', request, response,
log, (err, resHeaders) => {
routesUtils.statsReport500(err, statsClient);
return routesUtils.responseNoBody(err, resHeaders, response,
200, log);
});
} else {
// PUT bucket
return api.callApiMethod('bucketPut', request, response, log,
Expand Down
13 changes: 13 additions & 0 deletions lib/storage/metadata/MetadataWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,19 @@ class MetadataWrapper {
});
}

getBucketQuota(bucketName, log, cb) {
log.debug('getting bucket quota from metadata');
this.client.getBucketAttributes(bucketName, log, (err, data) => {
if (err) {
log.debug('error from metadata', { implName: this.implName,
error: err });
return cb(err);
}
const bucketInfo = BucketInfo.fromObj(data);
return cb(err, { quota: bucketInfo.getQuota() });
});
}

deleteBucket(bucketName, log, cb) {
log.debug('deleting bucket from metadata');
this.client.deleteBucket(bucketName, log, err => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"engines": {
"node": ">=16"
},
"version": "8.1.128",
"version": "8.1.129",
"description": "Common utilities for the S3 project components",
"main": "build/index.js",
"repository": {
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/models/BucketInfo.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ const testBucketCapabilities = {
},
};

const testBucketQuota = 100000;

// create a dummy bucket to test getters and setters
Object.keys(acl).forEach(
aclObj => describe(`different acl configurations : ${aclObj}`, () => {
Expand All @@ -252,6 +254,7 @@ Object.keys(acl).forEach(
testNotificationConfiguration,
testBucketTagging,
testBucketCapabilities,
testBucketQuota,
);

describe('serialize/deSerialize on BucketInfo class', () => {
Expand Down Expand Up @@ -290,6 +293,7 @@ Object.keys(acl).forEach(
notificationConfiguration: dummyBucket._notificationConfiguration,
tags: dummyBucket._tags,
capabilities: dummyBucket._capabilities,
quotaMax: dummyBucket._quotaMax,
};
assert.strictEqual(serialized, JSON.stringify(bucketInfos));
done();
Expand Down Expand Up @@ -339,6 +343,7 @@ Object.keys(acl).forEach(
dummyBucket._notificationConfiguration,
_tags: dummyBucket._tags,
_capabilities: dummyBucket._capabilities,
_quotaMax: dummyBucket._quotaMax,
};
const fromObj = BucketInfo.fromObj(dataObj);
assert(fromObj instanceof BucketInfo);
Expand Down Expand Up @@ -694,6 +699,17 @@ Object.keys(acl).forEach(
assert.deepStrictEqual(
dummyBucket.getCapabilities(), testCapabilities);
});
it('setQuota should set bucket quota', () => {
const testQuota = testBucketQuota;
dummyBucket.setQuota(testQuota);
assert.deepStrictEqual(
dummyBucket.getQuota(), testQuota);
});
it('setQuota should set bucket quota', () => {
dummyBucket.setQuota();
assert.deepStrictEqual(
dummyBucket.getQuota(), 0);
});
});
}),
);
Expand Down

0 comments on commit 2c06963

Please sign in to comment.