Skip to content

Commit 5830a39

Browse files
authored
Merge pull request #8424 from dannyzaken/danny-fixes
Lifecycle changes - Allow all actions in put lifecycle configuration
2 parents c8c8002 + 524869f commit 5830a39

File tree

2 files changed

+73
-57
lines changed

2 files changed

+73
-57
lines changed

src/api/common_api.js

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ module.exports = {
148148
},
149149

150150
// bucket lifecycle
151-
152151
bucket_lifecycle_rule_expiration: {
153152
type: 'object',
154153
properties: {
@@ -159,11 +158,9 @@ module.exports = {
159158
date: {
160159
idate: true
161160
},
162-
/*
163161
expired_object_delete_marker: {
164162
type: 'boolean'
165163
}
166-
*/
167164
}
168165
},
169166
bucket_lifecycle_rule_status: {
@@ -203,7 +200,7 @@ module.exports = {
203200
},
204201
bucket_lifecycle_rule: {
205202
type: 'object',
206-
required: ['id', 'filter', 'expiration', 'status'],
203+
required: ['id', 'filter', 'status'],
207204
properties: {
208205
id: {
209206
type: 'string'
@@ -220,9 +217,9 @@ module.exports = {
220217
last_sync: {
221218
idate: true
222219
},
223-
/*
224220
abort_incomplete_multipart_upload: {
225221
type: 'object',
222+
required: ['days_after_initiation'],
226223
properties: {
227224
days_after_initiation: {
228225
type: 'integer'
@@ -235,6 +232,9 @@ module.exports = {
235232
date: {
236233
idate: true
237234
},
235+
days: {
236+
type: 'integer'
237+
},
238238
storage_class: {
239239
$ref: '#/definitions/storage_class_enum'
240240
}
@@ -246,6 +246,9 @@ module.exports = {
246246
noncurrent_days: {
247247
type: 'integer'
248248
},
249+
newer_noncurrent_versions: {
250+
type: 'integer'
251+
}
249252
}
250253
},
251254
noncurrent_version_transition: {
@@ -254,12 +257,14 @@ module.exports = {
254257
noncurrent_days: {
255258
type: 'integer'
256259
},
260+
newer_noncurrent_versions: {
261+
type: 'integer'
262+
},
257263
storage_class: {
258264
$ref: '#/definitions/storage_class_enum'
259265
}
260266
}
261267
},
262-
*/
263268
}
264269
},
265270

src/endpoint/s3/ops/s3_put_bucket_lifecycle.js

Lines changed: 62 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,22 @@ const { v4: uuid } = require('uuid');
66
const dbg = require('../../../util/debug_module')(__filename);
77
const S3Error = require('../s3_errors').S3Error;
88

9+
const true_regex = /true/i;
10+
911
// parse lifecycle rule filter
1012
function parse_filter(filter) {
1113
const current_rule_filter = {};
12-
if (filter.Tag && filter.Tag.length === 1) {
14+
if (filter.Tag?.length === 1) {
1315
const tag = filter.Tag[0];
1416
current_rule_filter.tags = [{ key: tag.Key[0], value: tag.Value[0] }];
1517
}
16-
if (filter.Prefix && filter.Prefix.length === 1) {
18+
if (filter.Prefix?.length === 1) {
1719
current_rule_filter.prefix = filter.Prefix[0];
1820
}
19-
if (filter.ObjectSizeGreaterThan &&
20-
filter.ObjectSizeGreaterThan.length === 1) {
21+
if (filter.ObjectSizeGreaterThan?.length === 1) {
2122
current_rule_filter.object_size_greater_than = parseInt(filter.ObjectSizeGreaterThan[0], 10);
2223
}
23-
if (filter.ObjectSizeLessThan &&
24-
filter.ObjectSizeLessThan.length === 1) {
24+
if (filter.ObjectSizeLessThan?.length === 1) {
2525
current_rule_filter.object_size_less_than = parseInt(filter.ObjectSizeLessThan[0], 10);
2626
}
2727
if (current_rule_filter.object_size_greater_than !== undefined &&
@@ -30,21 +30,16 @@ function parse_filter(filter) {
3030
dbg.error('Invalid size range: filter', filter, 'size range: object_size_greater_than', current_rule_filter.object_size_greater_than, '>= object_size_less_than', current_rule_filter.object_size_less_than);
3131
throw new S3Error(S3Error.InvalidArgument);
3232
}
33-
if (filter.And &&
34-
filter.And.length === 1) {
35-
33+
if (filter.And?.length === 1) {
3634
current_rule_filter.and = true;
37-
if (filter.And[0].Prefix &&
38-
filter.And[0].Prefix.length === 1) {
39-
current_rule_filter.prefix = filter.And[0].Prefix[0];
35+
if (filter.And[0].Prefix?.length === 1) {
36+
current_rule_filter.prefix = filter.And[0].Prefix[0];
4037
}
41-
current_rule_filter.tags = _.map(filter.And[0].Tag, tag => ({ key: tag.Key[0], value: tag.Value[0]}));
42-
if (filter.And[0].ObjectSizeGreaterThan &&
43-
filter.And[0].ObjectSizeGreaterThan.length === 1) {
38+
current_rule_filter.tags = _.map(filter.And[0].Tag, tag => ({ key: tag.Key[0], value: tag.Value[0] }));
39+
if (filter.And[0].ObjectSizeGreaterThan?.length === 1) {
4440
current_rule_filter.object_size_greater_than = parseInt(filter.And[0].ObjectSizeGreaterThan[0], 10);
4541
}
46-
if (filter.And[0].ObjectSizeLessThan &&
47-
filter.And[0].ObjectSizeLessThan.length === 1) {
42+
if (filter.And[0].ObjectSizeLessThan?.length === 1) {
4843
current_rule_filter.object_size_less_than = parseInt(filter.And[0].ObjectSizeLessThan[0], 10);
4944
}
5045
}
@@ -54,24 +49,28 @@ function parse_filter(filter) {
5449
// parse lifecycle rule expiration
5550
function parse_expiration(expiration) {
5651
const output_expiration = {};
57-
if (expiration.Days && expiration.Days.length === 1) {
52+
if (expiration.Days?.length === 1) {
5853
output_expiration.days = parseInt(expiration.Days[0], 10);
5954
if (output_expiration.days < 1) {
6055
dbg.error('Minimum value for expiration days is 1, actual', expiration.Days,
6156
'converted', output_expiration.days);
6257
throw new S3Error(S3Error.InvalidArgument);
6358
}
64-
} else if (expiration.Date && expiration.Date.length === 1) {
59+
} else if (expiration.Date?.length === 1) {
6560
output_expiration.date = (new Date(expiration.Date[0])).getTime();
66-
} else if (expiration.ExpiredObjectDeleteMarker &&
67-
expiration.ExpiredObjectDeleteMarker.length === 1 &&
68-
expiration.ExpiredObjectDeleteMarker[0] === 'true') {
69-
dbg.error('ExpiredObjectDeleteMarker is not implemented, expiration:', expiration);
70-
throw new S3Error(S3Error.NotImplemented);
61+
} else if (expiration.ExpiredObjectDeleteMarker?.length === 1) {
62+
output_expiration.expired_object_delete_marker = true_regex.test(expiration.ExpiredObjectDeleteMarker[0]);
7163
}
7264
return output_expiration;
7365
}
7466

67+
function parse_lifecycle_field(field, field_parser = parseInt) {
68+
if (field?.length === 1) {
69+
return field_parser(field[0]);
70+
}
71+
return undefined;
72+
}
73+
7574
/**
7675
* http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html
7776
*/
@@ -81,53 +80,65 @@ async function put_bucket_lifecycle(req) {
8180
filter: {},
8281
};
8382

84-
if (rule.ID && rule.ID.length === 1) {
83+
if (rule.ID?.length === 1) {
8584
current_rule.id = rule.ID[0];
8685
} else {
8786
// Generate a random ID if missing
8887
current_rule.id = uuid();
8988
}
9089

91-
if (!(rule.Status && rule.Status.length === 1)) {
90+
if (rule.Status?.length !== 1) {
9291
dbg.error('Rule should have status', rule);
9392
throw new S3Error(S3Error.InvalidArgument);
9493
}
9594
current_rule.status = rule.Status[0];
9695

9796
if (rule.Prefix) {
98-
dbg.error('Rule should not have prefix, it should be filter.prefix', rule);
99-
throw new S3Error(S3Error.InvalidArgument);
100-
}
97+
if (rule.Filter?.length === 1) {
98+
dbg.error('Rule should not have prefix together with a filter', rule);
99+
throw new S3Error(S3Error.InvalidArgument);
100+
}
101+
current_rule.filter.prefix = rule.Prefix[0];
101102

102-
if (!(rule.Filter && rule.Filter.length === 1)) {
103-
dbg.error('Rule should have filter', rule);
104-
throw new S3Error(S3Error.InvalidArgument);
103+
} else {
104+
if (rule.Filter?.length !== 1) {
105+
dbg.error('Rule should have filter', rule);
106+
throw new S3Error(S3Error.InvalidArgument);
107+
}
108+
current_rule.filter = parse_filter(rule.Filter[0]);
105109
}
106-
current_rule.filter = parse_filter(rule.Filter[0]);
107110

108-
// Since other actions are not implemented, Expiration
109-
// is expected here
110-
if (!(rule.Expiration && rule.Expiration.length === 1)) {
111-
dbg.error('Rule is expected to have expiration', rule);
112-
throw new S3Error(S3Error.NotImplemented);
111+
if (rule.Expiration?.length === 1) {
112+
current_rule.expiration = parse_expiration(rule.Expiration[0]);
113113
}
114-
current_rule.expiration = parse_expiration(rule.Expiration[0]);
115114

116-
if (rule.AbortIncompleteMultipartUpload) {
117-
dbg.error('AbortIncompleteMultipartUpload is not implemented, rule:', rule);
118-
throw new S3Error(S3Error.NotImplemented);
115+
if (rule.AbortIncompleteMultipartUpload?.length === 1) {
116+
current_rule.abort_incomplete_multipart_upload = _.omitBy({
117+
days_after_initiation: parse_lifecycle_field(rule.AbortIncompleteMultipartUpload[0].DaysAfterInitiation),
118+
}, _.isUndefined);
119119
}
120-
if (rule.Transition) {
121-
dbg.error('Transition is not implemented, rule:', rule);
122-
throw new S3Error(S3Error.NotImplemented);
120+
121+
if (rule.Transition?.length === 1) {
122+
current_rule.transition = _.omitBy({
123+
storage_class: parse_lifecycle_field(rule.Transition[0].StorageClass, String),
124+
date: parse_lifecycle_field(rule.Transition[0].Date, s => new Date(s)),
125+
days: parse_lifecycle_field(rule.Transition[0].Days),
126+
}, _.isUndefined);
123127
}
124-
if (rule.NoncurrentVersionExpiration) {
125-
dbg.error('NoncurrentVersionExpiration is not implemented, rule:', rule);
126-
throw new S3Error(S3Error.NotImplemented);
128+
129+
if (rule.NoncurrentVersionExpiration?.length === 1) {
130+
current_rule.noncurrent_version_expiration = _.omitBy({
131+
noncurrent_days: parse_lifecycle_field(rule.NoncurrentVersionExpiration[0].NoncurrentDays),
132+
newer_noncurrent_versions: parse_lifecycle_field(rule.NoncurrentVersionExpiration[0].NewerNoncurrentVersions),
133+
}, _.isUndefined);
127134
}
128-
if (rule.NoncurrentVersionTransition) {
129-
dbg.error('NoncurrentVersionTransition is not implemented, rule:', rule);
130-
throw new S3Error(S3Error.NotImplemented);
135+
136+
if (rule.NoncurrentVersionTransition?.length === 1) {
137+
current_rule.noncurrent_version_transition = _.omitBy({
138+
storage_class: parse_lifecycle_field(rule.NoncurrentVersionTransition[0].StorageClass, String),
139+
noncurrent_days: parse_lifecycle_field(rule.NoncurrentVersionTransition[0].NoncurrentDays),
140+
newer_noncurrent_versions: parse_lifecycle_field(rule.NoncurrentVersionTransition[0].NewerNoncurrentVersions),
141+
}, _.isUndefined);
131142
}
132143

133144
return current_rule;

0 commit comments

Comments
 (0)