Skip to content

Commit

Permalink
feat: putBucketLifecycle supports ColdArchive and DeepColdArchive (#1256
Browse files Browse the repository at this point in the history
)

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

* fix: putBucketLifecycle add ColdArchive and DeepColdArchive

---------

Co-authored-by: csg01123119 <[email protected]>
  • Loading branch information
shungang and csg01123119 authored Aug 7, 2024
1 parent fc6040b commit 4c028d6
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -994,12 +994,12 @@ parameters:
- [createdBeforeDate] {String} expire date, e.g.: `2022-10-11T00:00:00.000Z`
`createdBeforeDate` and `days` must have one.
- [transition] {Object} Specifies the time when an object is converted to the IA or archive storage class during a valid life cycle.
- storageClass {String} Specifies the storage class that objects that conform to the rule are converted into. allow values: `IA` or `Archive`
- storageClass {String} Specifies the storage class that objects that conform to the rule are converted into. allow values: `IA` or `Archive` or `ColdArchive` or `DeepColdArchive`
- [days] {Number|String} expire after the `days`
- [createdBeforeDate] {String} expire date, e.g.: `2022-10-11T00:00:00.000Z`
`createdBeforeDate` and `days` must have one.
- [noncurrentVersionTransition] {Object} Specifies the time when an object is converted to the IA or archive storage class during a valid life cycle.
- storageClass {String} Specifies the storage class that history objects that conform to the rule are converted into. allow values: `IA` or `Archive`
- storageClass {String} Specifies the storage class that history objects that conform to the rule are converted into. allow values: `IA` or `Archive` or `ColdArchive` or `DeepColdArchive`
- noncurrentDays {String} expire after the `noncurrentDays`
`expiration``abortMultipartUpload``transition``noncurrentVersionTransition` must have one.
- [noncurrentVersionExpiration] {Object} specifies the expiration attribute of the lifecycle rules for the history object.
Expand Down
36 changes: 32 additions & 4 deletions lib/common/bucket/putBucketLifecycle.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,15 @@ function checkDaysAndDate(obj, key) {
}
}

function checkNoncurrentDays(obj, key) {
const { noncurrentDays } = obj;
if (!noncurrentDays) {
throw new Error(`${key} must includes noncurrentDays`);
} else if (noncurrentDays && !/^[1-9][0-9]*$/.test(noncurrentDays)) {
throw new Error('noncurrentDays must be a positive integer');
}
}

function handleCheckTag(tag) {
if (!isArray(tag) && !isObject(tag)) {
throw new Error('tag must be Object or Array');
Expand All @@ -87,6 +96,11 @@ function handleCheckTag(tag) {
checkObjectTag(tagObj);
}

function checkStorageClass(storageClass) {
if (!['IA', 'Archive', 'ColdArchive', 'DeepColdArchive'].includes(storageClass))
throw new Error(`StorageClass must be IA or Archive or ColdArchive or DeepColdArchive`);
}

function checkRule(rule) {
if (rule.id && getStrBytesCount(rule.id) > 255) throw new Error('ID is composed of 255 bytes at most');

Expand All @@ -95,8 +109,7 @@ function checkRule(rule) {
if (!['Enabled', 'Disabled'].includes(rule.status)) throw new Error('Status must be Enabled or Disabled');

if (rule.transition) {
if (!['IA', 'Archive'].includes(rule.transition.storageClass))
throw new Error('StorageClass must be IA or Archive');
checkStorageClass(rule.transition.storageClass);
checkDaysAndDate(rule.transition, 'Transition');
}

Expand All @@ -112,12 +125,27 @@ function checkRule(rule) {
checkDaysAndDate(rule.abortMultipartUpload, 'AbortMultipartUpload');
}

if (!rule.expiration && !rule.abortMultipartUpload && !rule.transition && !rule.noncurrentVersionTransition) {
if (
!rule.expiration &&
!rule.noncurrentVersionExpiration &&
!rule.abortMultipartUpload &&
!rule.transition &&
!rule.noncurrentVersionTransition
) {
throw new Error(
'Rule must includes expiration or abortMultipartUpload or transition or noncurrentVersionTransition'
'Rule must includes expiration or noncurrentVersionExpiration or abortMultipartUpload or transition or noncurrentVersionTransition'
);
}

if (rule.noncurrentVersionTransition) {
checkStorageClass(rule.noncurrentVersionTransition.storageClass);
checkNoncurrentDays(rule.noncurrentVersionTransition, 'NoncurrentVersionTransition');
}

if (rule.noncurrentVersionExpiration) {
checkNoncurrentDays(rule.noncurrentVersionExpiration, 'NoncurrentVersionExpiration');
}

if (rule.tag) {
if (rule.abortMultipartUpload) {
throw new Error('Tag cannot be used with abortMultipartUpload');
Expand Down
64 changes: 58 additions & 6 deletions test/node/bucket.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('test/bucket.test.js', () => {
const { prefix, includesConf } = utils;
let store;
let bucket;
const bucketRegion = config.region;
const bucketRegion = 'oss-ap-southeast-1'; // oss-ap-southeast-1 suport PutBucketLifecycle DeepColdArchive
const { accountId } = config;
[
{
Expand All @@ -25,7 +25,7 @@ describe('test/bucket.test.js', () => {
].forEach((moreConfigs, idx) => {
describe(`test bucket in iterate ${idx}`, () => {
before(async () => {
store = oss({ ...config, ...moreConfigs });
store = oss({ ...config, ...moreConfigs, region: bucketRegion });
bucket = `ali-oss-test-bucket-${prefix.replace(/[/.]/g, '-')}${idx}`;

const result = await store.putBucket(bucket, { timeout });
Expand Down Expand Up @@ -764,7 +764,25 @@ describe('test/bucket.test.js', () => {
});

describe('putBucketLifecycle()', () => {
// todo delete
it('should put the lifecycle throw error', async () => {
try {
await store.putBucketLifecycle(bucket, [
{
id: 'expiration1',
prefix: 'logs/',
status: 'Enabled',
day: 1
}
]);
assert.fail('expected an error to be thrown');
} catch (e) {
assert.equal(
e.message,
'Rule must includes expiration or noncurrentVersionExpiration or abortMultipartUpload or transition or noncurrentVersionTransition'
);
}
});

it('should put the lifecycle with old api', async () => {
const putresult1 = await store.putBucketLifecycle(bucket, [
{
Expand All @@ -774,6 +792,7 @@ describe('test/bucket.test.js', () => {
days: 1
}
]);

assert.equal(putresult1.res.status, 200);

const putresult2 = await store.putBucketLifecycle(bucket, [
Expand Down Expand Up @@ -864,7 +883,7 @@ describe('test/bucket.test.js', () => {
status: 'Enabled',
transition: {
createdBeforeDate: '2020-02-18T00:00:00.000Z',
storageClass: 'Archive'
storageClass: 'IA'
},
expiration: {
createdBeforeDate: '2020-02-17T00:00:00.000Z'
Expand Down Expand Up @@ -893,6 +912,39 @@ describe('test/bucket.test.js', () => {
}
]);
assert.equal(putresult2.res.status, 200);
const putresult3 = await store.putBucketLifecycle(bucket, [
{
id: 'transition3',
prefix: 'logs/',
status: 'Enabled',
transition: {
days: 20,
storageClass: 'ColdArchive'
},
tag: {
key: 'test3',
value: '123'
}
}
]);
assert.equal(putresult3.res.status, 200);
// Regions that need to support DeepColdArchive
const putresult4 = await store.putBucketLifecycle(bucket, [
{
id: 'transition4',
prefix: 'logs/',
status: 'Enabled',
transition: {
days: 20,
storageClass: 'DeepColdArchive'
},
tag: {
key: 'test4',
value: '123'
}
}
]);
assert.equal(putresult4.res.status, 200);
});

it('should put the lifecycle with expiration and Tag', async () => {
Expand Down Expand Up @@ -1023,7 +1075,7 @@ describe('test/bucket.test.js', () => {
]);
assert(false);
} catch (error) {
assert(error.message.includes('IA or Archive'));
assert(error.message.includes('IA or Archive or ColdArchive or DeepColdArchive'));
}
});

Expand Down Expand Up @@ -1206,7 +1258,7 @@ describe('test/bucket.test.js', () => {
});

it('should throw error when rule have no expiration or abortMultipartUpload', async () => {
const errorMessage = 'expiration or abortMultipartUpload';
const errorMessage = 'expiration or noncurrentVersionExpiration or abortMultipartUpload';
try {
await store.putBucketLifecycle(bucket, [
{
Expand Down
69 changes: 53 additions & 16 deletions test/node/multiversion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ describe('test/multiversion.test.js', () => {
].forEach((moreConfigs, idx) => {
describe(`test multiversion in iterate ${idx}`, () => {
before(async () => {
store = oss({ ...config, ...moreConfigs });
// oss-ap-southeast-1 suport PutBucketLifecycle DeepColdArchive
store = oss({ ...config, ...moreConfigs, region: 'oss-ap-southeast-1' });
bucket = `ali-oss-test-bucket-version-${prefix.replace(/[/.]/g, '-')}${idx}`;

const result = await store.putBucket(bucket);
Expand Down Expand Up @@ -117,12 +118,11 @@ describe('test/multiversion.test.js', () => {
});

describe('putBucketLifecycle() getBucketLifecycle()', async () => {
it('should putBucketLifecycle with NoncurrentVersionExpiration', async () => {
it('should putBucketLifecycle with noncurrentVersionExpiration', async () => {
const putresult1 = await store.putBucketLifecycle(
bucket,
[
{
id: 'expiration1',
prefix: 'logs/',
status: 'Enabled',
expiration: {
Expand All @@ -131,6 +131,13 @@ describe('test/multiversion.test.js', () => {
noncurrentVersionExpiration: {
noncurrentDays: 1
}
},
{
prefix: 'logss/',
status: 'Enabled',
noncurrentVersionExpiration: {
noncurrentDays: 1
}
}
],
{
Expand All @@ -142,6 +149,7 @@ describe('test/multiversion.test.js', () => {
const { rules } = await store.getBucketLifecycle(bucket);
assert.strictEqual(rules[0].noncurrentVersionExpiration.noncurrentDays, '1');
});

it('should putBucketLifecycle with expiredObjectDeleteMarker', async () => {
const putresult1 = await store.putBucketLifecycle(bucket, [
{
Expand All @@ -151,7 +159,7 @@ describe('test/multiversion.test.js', () => {
expiration: {
expiredObjectDeleteMarker: 'true'
},
NoncurrentVersionExpiration: {
noncurrentVersionExpiration: {
noncurrentDays: 1
}
}
Expand All @@ -163,26 +171,55 @@ describe('test/multiversion.test.js', () => {
});

it('should putBucketLifecycle with noncurrentVersionTransition', async () => {
const putresult1 = await store.putBucketLifecycle(bucket, [
{
id: 'expiration1',
prefix: 'logs/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'IA'
const putresult = await store.putBucketLifecycle(
bucket,
[
{
prefix: 'log/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'IA'
}
},
{
prefix: 'log/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'Archive'
}
},
{
prefix: 'log/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'ColdArchive'
}
},
{
prefix: 'log/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'DeepColdArchive'
}
}
}
]);
assert.equal(putresult1.res.status, 200);
],
{ headers: { 'x-oss-allow-same-action-overlap': 'true' } }
);
assert.equal(putresult.res.status, 200);
await utils.sleep(1000);

const { rules } = await store.getBucketLifecycle(bucket);
const [
{
noncurrentVersionTransition: { noncurrentDays, storageClass }
}
] = rules;
assert(noncurrentDays === '10' && storageClass === 'IA');

assert(noncurrentDays === '10' && storageClass === 'IA' && rules.length === 4);
});
});

Expand Down

0 comments on commit 4c028d6

Please sign in to comment.