Skip to content

Commit da53daf

Browse files
authored
Add UI to select number of non-current versions subject to ILM expiry rule (#3088)
1 parent 8c26eff commit da53daf

File tree

9 files changed

+135
-28
lines changed

9 files changed

+135
-28
lines changed

models/add_bucket_lifecycle.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

models/expiration_response.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

portal-ui/src/api/consoleApi.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,8 @@ export interface ExpirationResponse {
880880
delete_marker?: boolean;
881881
/** @format int64 */
882882
noncurrent_expiration_days?: number;
883+
/** @format int64 */
884+
newer_noncurrent_expiration_versions?: number;
883885
}
884886

885887
export interface TransitionResponse {
@@ -943,6 +945,12 @@ export interface AddBucketLifecycle {
943945
* @default 0
944946
*/
945947
noncurrentversion_transition_days?: number;
948+
/**
949+
* Non required, can be set in case of expiration is enabled
950+
* @format int32
951+
* @default 0
952+
*/
953+
newer_noncurrentversion_expiration_versions?: number;
946954
/** Non required, can be set in case of transition is enabled */
947955
noncurrentversion_transition_storage_class?: string;
948956
}

portal-ui/src/screens/Console/Buckets/BucketDetails/AddLifecycleModal.tsx

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ import React, { Fragment, useEffect, useState } from "react";
1919
import get from "lodash/get";
2020
import {
2121
Accordion,
22+
AlertIcon,
2223
Button,
2324
FormLayout,
2425
Grid,
26+
HelpTip,
2527
InputBox,
2628
LifecycleConfigIcon,
2729
ProgressBar,
@@ -74,6 +76,7 @@ const AddLifecycleModal = ({
7476
const [loadingVersioning, setLoadingVersioning] = useState<boolean>(true);
7577
const [expandedAdv, setExpandedAdv] = useState<boolean>(false);
7678
const [expanded, setExpanded] = useState<boolean>(false);
79+
const [expiryUnit, setExpiryUnit] = useState<string>("days");
7780

7881
/*To be removed on component replacement*/
7982
const formFieldRowFilter = {
@@ -116,6 +119,13 @@ const AddLifecycleModal = ({
116119
valid = false;
117120
}
118121
}
122+
if (!lifecycleDays || parseInt(lifecycleDays) === 0) {
123+
valid = false;
124+
}
125+
if (parseInt(lifecycleDays) > 2147483647) {
126+
//values over int32 cannot be parsed
127+
valid = false;
128+
}
119129
setIsFormValid(valid);
120130
}, [ilmType, lifecycleDays, storageClass]);
121131

@@ -142,8 +152,11 @@ const AddLifecycleModal = ({
142152

143153
if (targetVersion === "current") {
144154
expiry["expiry_days"] = parseInt(lifecycleDays);
145-
} else {
155+
} else if (expiryUnit === "days") {
146156
expiry["noncurrentversion_expiration_days"] = parseInt(lifecycleDays);
157+
} else {
158+
expiry["newer_noncurrentversion_expiration_versions"] =
159+
parseInt(lifecycleDays);
147160
}
148161

149162
rules = {
@@ -154,7 +167,7 @@ const AddLifecycleModal = ({
154167
if (targetVersion === "current") {
155168
transition["transition_days"] = parseInt(lifecycleDays);
156169
transition["storage_class"] = storageClass;
157-
} else {
170+
} else if (expiryUnit === "days") {
158171
transition["noncurrentversion_transition_days"] =
159172
parseInt(lifecycleDays);
160173
transition["noncurrentversion_transition_storage_class"] = storageClass;
@@ -184,7 +197,6 @@ const AddLifecycleModal = ({
184197
dispatch(setModalErrorSnackMessage(errorToHandler(err)));
185198
});
186199
};
187-
188200
return (
189201
<ModalWrapper
190202
modalOpen={open}
@@ -284,6 +296,15 @@ const AddLifecycleModal = ({
284296
)}
285297

286298
<InputBox
299+
error={
300+
lifecycleDays && !isFormValid
301+
? parseInt(lifecycleDays) <= 0
302+
? `Number of ${expiryUnit} to retain must be greater than zero`
303+
: parseInt(lifecycleDays) > 2147483647
304+
? `Number of ${expiryUnit} must be less than or equal to 2147483647`
305+
: ""
306+
: ""
307+
}
287308
id="expiry_days"
288309
name="expiry_days"
289310
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
@@ -295,12 +316,38 @@ const AddLifecycleModal = ({
295316
label="After"
296317
value={lifecycleDays}
297318
overlayObject={
298-
<InputUnitMenu
299-
id={"expire-current-unit"}
300-
unitSelected={"days"}
301-
unitsList={[{ label: "Days", value: "days" }]}
302-
disabled={true}
303-
/>
319+
<Fragment>
320+
<Grid container sx={{ justifyContent: "center" }}>
321+
<InputUnitMenu
322+
id={"expire-current-unit"}
323+
unitSelected={expiryUnit}
324+
unitsList={[
325+
{ label: "Days", value: "days" },
326+
{ label: "Versions", value: "versions" },
327+
]}
328+
disabled={
329+
targetVersion !== "noncurrent" || ilmType !== "expiry"
330+
}
331+
onUnitChange={(newValue) => {
332+
setExpiryUnit(newValue);
333+
}}
334+
/>
335+
{ilmType === "expiry" && targetVersion === "noncurrent" && (
336+
<HelpTip
337+
content={
338+
<Fragment>
339+
Select to set expiry by days or newer noncurrent
340+
versions
341+
</Fragment>
342+
}
343+
placement="right"
344+
>
345+
{" "}
346+
<AlertIcon style={{ width: 15, height: 15 }} />
347+
</HelpTip>
348+
)}
349+
</Grid>
350+
</Fragment>
304351
}
305352
/>
306353

portal-ui/src/screens/Console/Buckets/BucketDetails/BucketLifecyclePanel.tsx

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ const BucketLifecyclePanel = () => {
8686
.getBucketLifecycle(bucketName)
8787
.then((res) => {
8888
const records = get(res.data, "lifecycle", []);
89-
9089
setLifecycleRecords(records || []);
9190
setLoadingLifecycle(false);
9291
})
@@ -147,7 +146,10 @@ const BucketLifecyclePanel = () => {
147146
}
148147
if (
149148
el.expiration &&
150-
(el.expiration.days > 0 || el.expiration.noncurrent_expiration_days)
149+
(el.expiration.days > 0 ||
150+
el.expiration.noncurrent_expiration_days ||
151+
(el.expiration.newer_noncurrent_expiration_versions &&
152+
el.expiration.newer_noncurrent_expiration_versions > 0))
151153
) {
152154
return <span>Expiry</span>;
153155
}
@@ -170,7 +172,10 @@ const BucketLifecyclePanel = () => {
170172
if (el.expiration) {
171173
if (el.expiration.days > 0) {
172174
return <span>Current</span>;
173-
} else if (el.expiration.noncurrent_expiration_days) {
175+
} else if (
176+
el.expiration.noncurrent_expiration_days ||
177+
el.expiration.newer_noncurrent_expiration_versions
178+
) {
174179
return <span>Non-Current</span>;
175180
}
176181
}
@@ -200,20 +205,26 @@ const BucketLifecyclePanel = () => {
200205
if (!el) {
201206
return <Fragment />;
202207
}
203-
if (el.expiration) {
204-
if (el.expiration.days > 0) {
205-
return <span>{el.expiration.days} days</span>;
206-
} else if (el.expiration.noncurrent_expiration_days) {
207-
return <span>{el.expiration.noncurrent_expiration_days} days</span>;
208-
}
209-
}
210208
if (el.transition) {
211209
if (el.transition.days > 0) {
212210
return <span>{el.transition.days} days</span>;
213211
} else if (el.transition.noncurrent_transition_days) {
214212
return <span>{el.transition.noncurrent_transition_days} days</span>;
215213
}
216214
}
215+
if (el.expiration) {
216+
if (el.expiration.days > 0) {
217+
return <span>{el.expiration.days} days</span>;
218+
} else if (el.expiration.noncurrent_expiration_days) {
219+
return <span>{el.expiration.noncurrent_expiration_days} days</span>;
220+
} else {
221+
return (
222+
<span>
223+
{el.expiration.newer_noncurrent_expiration_versions} versions
224+
</span>
225+
);
226+
}
227+
}
217228
},
218229
},
219230
{

portal-ui/src/screens/Console/Buckets/types.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ interface IExpirationLifecycle {
4242
date: string;
4343
delete_marker?: boolean;
4444
noncurrent_expiration_days?: number;
45+
newer_noncurrent_expiration_versions?: number;
4546
}
4647

4748
interface ITransitionLifecycle {

restapi/embedded_spec.go

Lines changed: 20 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

restapi/user_buckets_lifecycle.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ func getBucketLifecycle(ctx context.Context, client MinioClient, bucketName stri
9090
if err != nil {
9191
return nil, err
9292
}
93-
9493
var rules []*models.ObjectBucketLifecycle
9594

9695
for _, rule := range lifecycleList.Rules {
@@ -115,10 +114,11 @@ func getBucketLifecycle(ctx context.Context, client MinioClient, bucketName stri
115114
Status: rule.Status,
116115
Prefix: rulePrefix,
117116
Expiration: &models.ExpirationResponse{
118-
Date: rule.Expiration.Date.Format(time.RFC3339),
119-
Days: int64(rule.Expiration.Days),
120-
DeleteMarker: rule.Expiration.DeleteMarker.IsEnabled(),
121-
NoncurrentExpirationDays: int64(rule.NoncurrentVersionExpiration.NoncurrentDays),
117+
Date: rule.Expiration.Date.Format(time.RFC3339),
118+
Days: int64(rule.Expiration.Days),
119+
DeleteMarker: rule.Expiration.DeleteMarker.IsEnabled(),
120+
NoncurrentExpirationDays: int64(rule.NoncurrentVersionExpiration.NoncurrentDays),
121+
NewerNoncurrentExpirationVersions: int64(rule.NoncurrentVersionExpiration.NewerNoncurrentVersions),
122122
},
123123
Transition: &models.TransitionResponse{
124124
Date: rule.Transition.Date.Format(time.RFC3339),
@@ -178,7 +178,7 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params bucketAp
178178
switch params.Body.Type {
179179
case models.AddBucketLifecycleTypeTransition:
180180
if params.Body.TransitionDays == 0 && params.Body.NoncurrentversionTransitionDays == 0 {
181-
return errors.New("only one expiry configuration can be set (days or date)")
181+
return errors.New("you must provide a value for transition days or date")
182182
}
183183

184184
status := !params.Body.Disable
@@ -195,12 +195,13 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params bucketAp
195195
noncurrentVersionTransitionStorageClass := strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass)
196196
opts.NoncurrentVersionTransitionDays = &noncurrentVersionTransitionDays
197197
opts.NoncurrentVersionTransitionStorageClass = &noncurrentVersionTransitionStorageClass
198-
} else {
198+
} else if params.Body.TransitionDays > 0 {
199199
tdays := strconv.Itoa(int(params.Body.TransitionDays))
200200
sclass := strings.ToUpper(params.Body.StorageClass)
201201
opts.TransitionDays = &tdays
202202
opts.StorageClass = &sclass
203203
}
204+
204205
case models.AddBucketLifecycleTypeExpiry:
205206
// Verify if expiry items are set
206207
if params.Body.NoncurrentversionTransitionDays != 0 {
@@ -220,10 +221,15 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params bucketAp
220221
ExpiredObjectDeleteMarker: &params.Body.ExpiredObjectDeleteMarker,
221222
}
222223

223-
if params.Body.NoncurrentversionExpirationDays > 0 {
224+
if params.Body.NewerNoncurrentversionExpirationVersions > 0 {
225+
versions := int(params.Body.NewerNoncurrentversionExpirationVersions)
226+
opts.NewerNoncurrentExpirationVersions = &versions
227+
}
228+
switch {
229+
case params.Body.NoncurrentversionExpirationDays > 0:
224230
days := int(params.Body.NoncurrentversionExpirationDays)
225231
opts.NoncurrentVersionExpirationDays = &days
226-
} else {
232+
case params.Body.ExpiryDays > 0:
227233
days := strconv.Itoa(int(params.Body.ExpiryDays))
228234
opts.ExpiryDays = &days
229235
}

swagger.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5067,6 +5067,9 @@ definitions:
50675067
noncurrent_expiration_days:
50685068
type: integer
50695069
format: int64
5070+
newer_noncurrent_expiration_versions:
5071+
type: integer
5072+
format: int64
50705073

50715074
transitionResponse:
50725075
type: object
@@ -5154,6 +5157,11 @@ definitions:
51545157
type: integer
51555158
format: int32
51565159
default: 0
5160+
newer_noncurrentversion_expiration_versions:
5161+
description: Non required, can be set in case of expiration is enabled
5162+
type: integer
5163+
format: int32
5164+
default: 0
51575165
noncurrentversion_transition_storage_class:
51585166
description: Non required, can be set in case of transition is enabled
51595167
type: string

0 commit comments

Comments
 (0)