Skip to content

Commit d37c0fb

Browse files
authored
Merge pull request #8475 from aspandey/list-bucket-pagination
bucket_api: Pagination support for list_bucket API
2 parents b27e63b + d6edc45 commit d37c0fb

16 files changed

+277
-60
lines changed

1

Whitespace-only changes.

src/api/bucket_api.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,17 @@ module.exports = {
441441

442442
list_buckets: {
443443
method: 'GET',
444+
params: {
445+
type: 'object',
446+
properties: {
447+
continuation_token: { $ref: 'common_api#/definitions/continuation_token' },
448+
max_buckets: {
449+
type: 'integer',
450+
minimum: 1,
451+
maximum: 1000
452+
}
453+
}
454+
},
444455
reply: {
445456
type: 'object',
446457
required: ['buckets'],
@@ -454,10 +465,11 @@ module.exports = {
454465
name: { $ref: 'common_api#/definitions/bucket_name' },
455466
creation_date: {
456467
idate: true
457-
},
468+
}
458469
}
459470
}
460-
}
471+
},
472+
continuation_token: { $ref: 'common_api#/definitions/continuation_token' }
461473
}
462474
},
463475
auth: {

src/api/common_api.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,6 +1210,10 @@ module.exports = {
12101210
wrapper: SensitiveString,
12111211
},
12121212

1213+
continuation_token: {
1214+
wrapper: SensitiveString,
1215+
},
1216+
12131217
port: {
12141218
type: 'integer',
12151219
minimum: 0,

src/endpoint/s3/ops/s3_get_bucket.js

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ async function get_bucket(req) {
4343
delimiter: req.query.delimiter,
4444
limit: Math.min(max_keys_received, 1000),
4545
key_marker: list_type === '2' ?
46-
(cont_tok_to_key_marker(cont_tok) || start_after) : req.query.marker,
46+
(s3_utils.cont_tok_to_key_marker(cont_tok) || start_after) : req.query.marker,
4747
};
4848

4949
if (req.query.get_from_cache) {
@@ -66,7 +66,7 @@ async function get_bucket(req) {
6666
ContinuationToken: cont_tok,
6767
StartAfter: field_encoder(start_after),
6868
KeyCount: reply.objects.length + reply.common_prefixes.length,
69-
NextContinuationToken: key_marker_to_cont_tok(
69+
NextContinuationToken: s3_utils.key_marker_to_cont_tok(
7070
reply.next_marker, reply.objects, reply.is_truncated),
7171
} : { // list_type v1
7272
Marker: req.query.marker || '',
@@ -96,25 +96,6 @@ async function get_bucket(req) {
9696
};
9797
}
9898

99-
function cont_tok_to_key_marker(cont_tok) {
100-
if (!cont_tok) return;
101-
try {
102-
const b = Buffer.from(cont_tok, 'base64');
103-
const j = JSON.parse(b.toString());
104-
return j.key;
105-
} catch (err) {
106-
throw new S3Error(S3Error.InvalidArgument);
107-
}
108-
}
109-
110-
function key_marker_to_cont_tok(key_marker, objects_arr, is_truncated) {
111-
if (!key_marker && !is_truncated) return;
112-
// next marker is the key marker we got or the key of the last item in the objects list.
113-
const next_marker = key_marker || objects_arr[objects_arr.length - 1].key;
114-
const j = JSON.stringify({ key: next_marker });
115-
return Buffer.from(j).toString('base64');
116-
}
117-
11899
function get_object_restore_status(obj, restore_status_requested) {
119100
if (!restore_status_requested || !obj.restore_status) {
120101
return;

src/endpoint/s3/ops/s3_get_service.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@ const s3_utils = require('../s3_utils');
77
* http://docs.aws.amazon.com/AmazonS3/latest/API/RESTServiceGET.html
88
*/
99
async function list_buckets(req) {
10-
const reply = await req.object_sdk.list_buckets();
10+
11+
const params = {
12+
continuation_token: s3_utils.cont_tok_to_key_marker(req.query['continuation-token']),
13+
max_buckets: req.query['max-buckets'] ? Number(req.query['max-buckets']) : undefined
14+
};
15+
16+
const reply = await req.object_sdk.list_buckets(params);
1117
const date = s3_utils.format_s3_xml_date(new Date());
18+
const bucket_cont_token = s3_utils.key_marker_to_cont_tok(reply.continuation_token, null, false);
19+
// const bucket_cont_token = bucket_name_to_cont_token(reply.continuation_token);
20+
1221
return {
1322
ListAllMyBucketsResult: {
1423
Owner: s3_utils.DEFAULT_S3_USER,
@@ -17,7 +26,8 @@ async function list_buckets(req) {
1726
Name: bucket.name.unwrap(),
1827
CreationDate: bucket.creation_date ? s3_utils.format_s3_xml_date(bucket.creation_date) : date,
1928
}
20-
}))
29+
})),
30+
ContinuationToken: bucket_cont_token,
2131
}
2232
};
2333
}

src/endpoint/s3/s3_utils.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,42 @@ function parse_restore_request_days(req) {
724724
return days;
725725
}
726726

727+
/**
728+
* cont_tok_to_key_marker takes an encoded string and decodes it.
729+
* cont_tok is the token which represents the next item in
730+
* the list which some API returns to user in parts.
731+
* @param {string} cont_tok
732+
* @returns {string}
733+
*/
734+
function cont_tok_to_key_marker(cont_tok) {
735+
if (!cont_tok) return;
736+
try {
737+
const b = Buffer.from(cont_tok, 'base64');
738+
const j = JSON.parse(b.toString());
739+
return j.key;
740+
} catch (err) {
741+
throw new S3Error(S3Error.InvalidArgument);
742+
}
743+
}
744+
745+
/**
746+
* key_marker_to_cont_tok takes a string and returns an encoded
747+
* string. key_marker is the token which represents the next item in
748+
* the list which some API returns to user in parts.
749+
* @param {string} key_marker
750+
* @param {array} objects_arr
751+
* @param {boolean} is_truncated
752+
* @returns {string}
753+
*/
754+
755+
function key_marker_to_cont_tok(key_marker, objects_arr, is_truncated) {
756+
if (!key_marker && !is_truncated) return;
757+
// next marker is the key marker we got or the key of the last item in the objects list.
758+
const next_marker = key_marker || (objects_arr && objects_arr.length > 0 ? objects_arr[objects_arr.length - 1].key : undefined);
759+
const j = JSON.stringify({ key: next_marker });
760+
return Buffer.from(j).toString('base64');
761+
}
762+
727763
exports.STORAGE_CLASS_STANDARD = STORAGE_CLASS_STANDARD;
728764
exports.STORAGE_CLASS_GLACIER = STORAGE_CLASS_GLACIER;
729765
exports.STORAGE_CLASS_GLACIER_IR = STORAGE_CLASS_GLACIER_IR;
@@ -763,3 +799,5 @@ exports.parse_version_id = parse_version_id;
763799
exports.get_object_owner = get_object_owner;
764800
exports.get_default_object_owner = get_default_object_owner;
765801
exports.set_response_supported_storage_classes = set_response_supported_storage_classes;
802+
exports.cont_tok_to_key_marker = cont_tok_to_key_marker;
803+
exports.key_marker_to_cont_tok = key_marker_to_cont_tok;

src/sdk/bucketspace_fs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ class BucketSpaceFS extends BucketSpaceSimpleFS {
192192
* @param {nb.ObjectSDK} object_sdk
193193
* @returns {Promise<object>}
194194
*/
195-
async list_buckets(object_sdk) {
195+
async list_buckets(params, object_sdk) {
196196
let bucket_names;
197197
try {
198198
bucket_names = await this.config_fs.list_buckets();

src/sdk/bucketspace_nb.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ class BucketSpaceNB {
3232
// BUCKET //
3333
////////////
3434

35-
async list_buckets(object_sdk) {
36-
const { buckets } = (await this.rpc_client.bucket.list_buckets());
35+
async list_buckets(params, object_sdk) {
36+
const { buckets, continuation_token} = (await this.rpc_client.bucket.list_buckets(params));
37+
3738
const has_access_buckets = (await P.all(_.map(
3839
buckets,
3940
async bucket => {
@@ -43,7 +44,7 @@ class BucketSpaceNB {
4344
object_sdk.has_non_nsfs_bucket_access(object_sdk.requesting_account, ns);
4445
return has_access_to_bucket && bucket;
4546
}))).filter(bucket => bucket);
46-
return { buckets: has_access_buckets };
47+
return { buckets: has_access_buckets, continuation_token};
4748
}
4849

4950
async read_bucket(params) {

src/sdk/bucketspace_s3.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class BucketSpaceS3 {
2727
// BUCKET //
2828
////////////
2929

30-
async list_buckets() {
30+
async list_buckets(params) {
3131
try {
3232
console.log(`bss3: list_buckets`);
3333
const res = await this.s3.listBuckets({});

src/sdk/bucketspace_simple_fs.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class BucketSpaceSimpleFS {
4040
* @param {nb.ObjectSDK} object_sdk
4141
* @returns {Promise<object>}
4242
*/
43-
async list_buckets(object_sdk) {
43+
async list_buckets(params, object_sdk) {
4444
try {
4545
const entries = await nb_native().fs.readdir(this.fs_context, this.fs_root);
4646
const dirs_only = entries.filter(entree => native_fs_utils.isDirectory(entree));

0 commit comments

Comments
 (0)