Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: putBucketLifecycle add ColdArchive and DeepColdArchive #1256

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -957,12 +957,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(name, storageClass) {
if (!['IA', 'Archive', 'ColdArchive', 'DeepColdArchive'].includes(storageClass))
throw new Error(`${name} must be IA or Archive or ColdArchive or DeepColdArchive`);
shungang marked this conversation as resolved.
Show resolved Hide resolved
}

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('StorageClass', 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'
);
shungang marked this conversation as resolved.
Show resolved Hide resolved
}

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

shungang marked this conversation as resolved.
Show resolved Hide resolved
if (rule.noncurrentVersionExpiration) {
checkNoncurrentDays(rule.noncurrentVersionExpiration, 'NoncurrentVersionExpiration');
}

if (rule.tag) {
if (rule.abortMultipartUpload) {
throw new Error('Tag cannot be used with abortMultipartUpload');
Expand Down
3 changes: 1 addition & 2 deletions test/config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
const { env } = process;

const config = module.exports;
const USWEST = 'oss-us-west-1'; // ONCI=true Using the region of Silicon Valley in the United States would be faster

config.oss = {
accessKeyId: env.ALI_SDK_OSS_ID,
accessKeySecret: env.ALI_SDK_OSS_SECRET,
accountId: env.ALI_SDK_STS_ROLE.match(/^acs:ram::(\d+):role/i)[1], // Obtain the main account ID through roleRan
region: env.ALI_SDK_OSS_REGION,
endpoint: env.ONCI ? `https://${USWEST}.aliyuncs.com` : undefined,
endpoint: env.ONCI ? `https://${env.ALI_SDK_OSS_REGION}.aliyuncs.com` : undefined,
maxSocket: 50
};

Expand Down
37 changes: 35 additions & 2 deletions test/node/bucket.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,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 @@ -857,6 +857,39 @@ describe('test/bucket.test.js', () => {
}
]);
assert.equal(putresult2.res.status, 200);
shungang marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -987,7 +1020,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
48 changes: 40 additions & 8 deletions test/node/multiversion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,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 @@ -125,6 +124,13 @@ describe('test/multiversion.test.js', () => {
noncurrentVersionExpiration: {
noncurrentDays: 1
}
},
{
prefix: 'logss/',
status: 'Enabled',
noncurrentVersionExpiration: {
noncurrentDays: 1
}
}
],
{
Expand All @@ -136,6 +142,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 @@ -145,7 +152,7 @@ describe('test/multiversion.test.js', () => {
expiration: {
expiredObjectDeleteMarker: 'true'
},
NoncurrentVersionExpiration: {
noncurrentVersionExpiration: {
shungang marked this conversation as resolved.
Show resolved Hide resolved
noncurrentDays: 1
}
}
Expand All @@ -156,25 +163,50 @@ describe('test/multiversion.test.js', () => {
});

it('should putBucketLifecycle with noncurrentVersionTransition', async () => {
const putresult1 = await store.putBucketLifecycle(bucket, [
const putresult = await store.putBucketLifecycle(bucket, [
{
id: 'expiration1',
prefix: 'logs/',
prefix: 'log/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'IA'
}
},
{
prefix: 'logs/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'Archive'
}
},
{
prefix: 'logss/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'ColdArchive'
}
},
{
prefix: 'logsss/',
status: 'Enabled',
noncurrentVersionTransition: {
noncurrentDays: '10',
storageClass: 'DeepColdArchive'
}
}
]);
assert.equal(putresult1.res.status, 200);
assert.equal(putresult.res.status, 200);

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
Loading