Skip to content

Commit 79eb5ef

Browse files
luozhang002binghaiwang
authored andcommitted
feat: restore object api and support to create archvie bucket (#450)
* feat: add restore object api * feat:support create archive bucket * test:add restore object api test case * docs:add restore object and modify putBucket docs * test: add test case about creating archive bucket
1 parent 3190ce6 commit 79eb5ef

File tree

7 files changed

+158
-5
lines changed

7 files changed

+158
-5
lines changed

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ OSS, Object Storage Service. Equal to well known Amazon [S3](http://aws.amazon.c
9393
- [.signatureUrl(name[, options])](#signatureurlname-options)
9494
- [.putACL*(name, acl[, options])](#putaclname-acl-options)
9595
- [.getACL*(name[, options])](#getaclname-options)
96+
- [.restore*(name[, options])](#restorename-options)
9697
- [.initMultipartUpload*(name[, options])](#initmultipartuploadname-options)
9798
- [.uploadPart*(name, uploadId, partNo, file, start, end[, options])](#uploadpartname-uploadid-partno-file-start-end-options)
9899
- [.uploadPartCopy*(name, uploadId, partNo, range, sourceData[, options])](#uploadpartcopyname-uploadid-partno-range-sourcedata-options)
@@ -242,6 +243,7 @@ parameters:
242243
If region value invalid, will throw InvalidLocationConstraintError.
243244
- [options] {Object} optional parameters
244245
- [timeout] {Number} the operation timeout
246+
- [StorageClass] {String} the storeage type include (Standard,IA,Archive)
245247

246248
Success will return the bucket name on `bucket` properties.
247249

@@ -262,6 +264,14 @@ yield store.putBucket('helloworld', 'oss-cn-hongkong');
262264
store.useBucket('helloworld', 'oss-cn-hongkong');
263265
```
264266

267+
- Create a bucket name `helloworld` location on HongKong StorageClass `Archive`
268+
269+
```js
270+
yield store.putBucket('helloworld', 'oss-cn-hongkong', { StorageClass: 'Archive' });
271+
// use it by default
272+
store.useBucket('helloworld', 'oss-cn-hongkong');
273+
```
274+
265275
### .deleteBucket*(name, region[, options])
266276

267277
Delete an empty bucket.
@@ -1568,6 +1578,33 @@ var result = yield store.getACL('ossdemo.txt');
15681578
console.log(result.acl);
15691579
```
15701580
1581+
### .restore*(name[, options])
1582+
1583+
Restore Object.
1584+
1585+
parameters:
1586+
1587+
- name {String} object name
1588+
- [options] {Object} optional parameters
1589+
- [timeout] {Number} the operation timeout
1590+
1591+
Success will return:
1592+
1593+
- res {Object} response info, including
1594+
- status {Number} response status
1595+
- headers {Object} response headers
1596+
- size {Number} response size
1597+
- rt {Number} request total use time (ms)
1598+
1599+
example:
1600+
1601+
- Restore an object
1602+
1603+
```js
1604+
var result = yield store.restore('ossdemo.txt');
1605+
console.log(result.status);
1606+
```
1607+
15711608
### .initMultipartUpload(name[, options])
15721609
Before transmitting data in the Multipart Upload mode,
15731610
you must call the Initiate Multipart Upload interface to notify the OSS to initiate a Multipart Upload event.
@@ -2923,6 +2960,7 @@ Will put to all clients.
29232960
- `client.copy()`
29242961
- `client.putMeta()`
29252962
- `client.putACL()`
2963+
- `client.restore()`
29262964
29272965
## Wrapper Usage
29282966
@@ -3049,6 +3087,8 @@ name | code | status | message | message in Chinese
30493087
AccessDeniedError | AccessDenied | 403 | Access Denied | 拒绝访问
30503088
BucketAlreadyExistsError | BucketAlreadyExists | 409 | Bucket already exists | Bucket 已经存在
30513089
BucketNotEmptyError | BucketNotEmpty | 409 | Bucket is not empty | Bucket 不为空
3090+
RestoreAlreadyInProgressError | RestoreAlreadyInProgress | 409 | The restore operation is in progress. | restore 操作正在进行中
3091+
OperationNotSupportedError | OperationNotSupported | 400 | The operation is not supported for this resource | 该资源暂不支持restore操作
30523092
EntityTooLargeError | EntityTooLarge | 400 | Entity too large | 实体过大
30533093
EntityTooSmallError | EntityTooSmall | 400 | Entity too small | 实体过小
30543094
FileGroupTooLargeError | FileGroupTooLarge | 400 | File group too large | 文件组过大

lib/browser/bucket.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ proto.putBucket = function* putBucket(name, region, options) {
8080
if (region) {
8181
params.mime = 'xml';
8282
params.content = `${'<?xml version="1.0" encoding="UTF-8"?>\n' +
83-
'<CreateBucketConfiguration><LocationConstraint>'}${region
83+
'<CreateBucketConfiguration><LocationConstraint>'}${region
8484
}</LocationConstraint></CreateBucketConfiguration>`;
8585
}
8686
params.successStatuses = [200];

lib/browser/object.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,25 @@ proto.getACL = function* getACL(name, options) {
429429
};
430430
};
431431

432+
/**
433+
* Restore Object
434+
* @param {String} name the object key
435+
* @param {Object} options
436+
* @returns {{res}}
437+
*/
438+
proto.restore = function* restore(name, options) {
439+
options = options || {}
440+
options.subres = 'restore';
441+
const params = this._objectRequestParams('POST', name, options);
442+
params.successStatuses = [202];
443+
444+
const result = yield this.request(params);
445+
446+
return {
447+
res: result.res,
448+
};
449+
}
450+
432451
proto.signatureUrl = function (name, options) {
433452
options = options || {};
434453
name = this._objectName(name);

lib/bucket.js

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ proto.listBuckets = function* listBuckets(query, options) {
4343
name: item.Name,
4444
region: item.Location,
4545
creationDate: item.CreationDate,
46+
StorageClass: item.StorageClass,
4647
}));
4748
}
4849
return {
@@ -75,13 +76,28 @@ proto.getBucket = function getBucket() {
7576
};
7677

7778
proto.putBucket = function* putBucket(name, region, options) {
79+
options = options || {};
7880
const params = this._bucketRequestParams('PUT', name, '', options);
79-
if (region) {
81+
82+
const startTag = '<?xml version="1.0" encoding="UTF-8"?>\n<CreateBucketConfiguration>'
83+
const endTag = '</CreateBucketConfiguration>'
84+
let paramlXML = '';
85+
86+
// server not support
87+
// if (region) {
88+
// paramlXML += `<LocationConstraint>${region}</LocationConstraint>`;
89+
// params.content = `${startTag}${paramlXML}${endTag}`;
90+
// }
91+
92+
if (options.StorageClass) {
93+
paramlXML += `<StorageClass>${options.StorageClass}</StorageClass>`;
94+
}
95+
96+
if (paramlXML) {
8097
params.mime = 'xml';
81-
params.content = `${'<?xml version="1.0" encoding="UTF-8"?>\n' +
82-
'<CreateBucketConfiguration><LocationConstraint>'}${region
83-
}</LocationConstraint></CreateBucketConfiguration>`;
98+
params.content = `${startTag}${paramlXML}${endTag}`;
8499
}
100+
85101
params.successStatuses = [200];
86102
const result = yield this.request(params);
87103
return {

lib/object.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,25 @@ proto.getACL = function* getACL(name, options) {
429429
};
430430
};
431431

432+
/**
433+
* Restore Object
434+
* @param {String} name the object key
435+
* @param {Object} options
436+
* @returns {{res}}
437+
*/
438+
proto.restore = function* restore(name, options) {
439+
options = options || {}
440+
options.subres = 'restore';
441+
const params = this._objectRequestParams('POST', name, options);
442+
params.successStatuses = [202];
443+
444+
const result = yield this.request(params);
445+
446+
return {
447+
res: result.res,
448+
};
449+
}
450+
432451
proto.signatureUrl = function (name, options) {
433452
options = options || {};
434453
name = this._objectName(name);

test/node/bucket.test.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,16 @@ describe('test/bucket.test.js', () => {
3939
const result = yield this.store.putBucket(this.bucket, this.region);
4040
assert.equal(result.bucket, this.bucket);
4141
assert.equal(result.res.status, 200);
42+
43+
// just for archive bucket test
44+
this.archvieBucket = `ali-oss-archive-bucket-${prefix.replace(/[/.]/g, '-')}`;
45+
this.archvieBucket = this.bucket.substring(0, this.bucket.length - 1);
46+
yield this.store.putBucket(this.archvieBucket, this.region, { StorageClass: 'Archive' });
4247
});
4348

4449
after(function* () {
4550
yield utils.cleanBucket(this.store, this.bucket, this.region);
51+
// yield utils.cleanBucket(this.store, this.archvieBucket, this.region);
4652
});
4753

4854
describe('putBucket()', () => {
@@ -62,8 +68,22 @@ describe('test/bucket.test.js', () => {
6268
assert.equal(result2.bucket, this.name);
6369
});
6470

71+
it('should create an archive bucket', function* () {
72+
const result2 = yield this.store.listBuckets();
73+
const { buckets } = result2;
74+
const m = buckets.some(item => item.name === this.archvieBucket);
75+
assert(m === true);
76+
buckets.map((item) => {
77+
if (item.name === this.archvieBucket) {
78+
assert(item.StorageClass === 'Archive');
79+
}
80+
return 1;
81+
});
82+
});
83+
6584
after(function* () {
6685
const result = yield this.store.deleteBucket(this.name);
86+
yield this.store.deleteBucket(this.archvieBucket);
6787
assert(result.res.status === 200 || result.res.status === 204);
6888
});
6989
});

test/node/object.test.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ describe('test/object.test.js', () => {
2727
this.store = oss(config);
2828
this.bucket = `ali-oss-test-object-bucket-${prefix.replace(/[/.]/g, '-')}`;
2929
this.bucket = this.bucket.substring(0, this.bucket.length - 1);
30+
31+
// just for archive bucket test
32+
this.archvieBucket = `oss-archvie-bucket-${prefix.replace(/[/.]/g, '-')}`;
33+
this.archvieBucket = this.archvieBucket.substring(0, this.archvieBucket.length - 1);
34+
3035
this.region = config.region;
3136
// console.log('current buckets: %j',
3237
// (yield this.store.listBuckets()).buckets.map(function (item) {
@@ -35,10 +40,14 @@ describe('test/object.test.js', () => {
3540
// );
3641
yield this.store.putBucket(this.bucket, this.region);
3742
this.store.useBucket(this.bucket, this.region);
43+
44+
yield this.store.putBucket(this.archvieBucket, this.region, { StorageClass: 'Archive' });
45+
// this.store.useBucket(this.archvieBucket, this.region);
3846
});
3947

4048
after(function* () {
4149
yield utils.cleanBucket(this.store, this.bucket, this.region);
50+
yield utils.cleanBucket(this.store, this.archvieBucket, this.region);
4251
});
4352

4453
describe('putStream()', () => {
@@ -1566,4 +1575,34 @@ describe('test/object.test.js', () => {
15661575
assert(res.headers['x-oss-next-append-position'] === '9');
15671576
});
15681577
});
1578+
1579+
describe('restore()', () => {
1580+
it('Should return OperationNotSupportedError when the type of bucket is not archive', function* () {
1581+
const name = '/oss/restore.js';
1582+
yield this.store.put(name, __filename);
1583+
1584+
try {
1585+
yield this.store.restore(name);
1586+
throw new Error('should not run this');
1587+
} catch (err) {
1588+
assert.equal(err.name, 'OperationNotSupportedError');
1589+
}
1590+
});
1591+
it('Should return 202 when restore is called first', function* () {
1592+
yield this.store.useBucket(this.archvieBucket, this.region);
1593+
1594+
const name = '/oss/restore.js';
1595+
yield this.store.put(name, __filename);
1596+
1597+
const info = yield this.store.restore(name);
1598+
assert.equal(info.res.status, 202);
1599+
1600+
// in 1 minute veriy RestoreAlreadyInProgressError
1601+
try {
1602+
yield this.store.restore(name);
1603+
} catch (err) {
1604+
assert.equal(err.name, 'RestoreAlreadyInProgressError');
1605+
}
1606+
});
1607+
});
15691608
});

0 commit comments

Comments
 (0)