Implemented edit lifecycle API (#1533)

Signed-off-by: Benjamin Perez <benjamin@bexsoft.net>
This commit is contained in:
Alex
2022-02-09 13:30:22 -07:00
committed by GitHub
parent 2ffc28a834
commit c8fdadde39
5 changed files with 305 additions and 5 deletions

View File

@@ -34,11 +34,35 @@ import (
// swagger:model updateBucketLifecycle
type UpdateBucketLifecycle struct {
// disable
// Non required, toggle to disable or enable rule
Disable bool `json:"disable,omitempty"`
// tags
// Non required, toggle to disable or enable rule
ExpiredObjectDeleteMarker bool `json:"expired_object_delete_marker,omitempty"`
// Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM
ExpiryDays int32 `json:"expiry_days,omitempty"`
// Non required, can be set in case of expiration is enabled
NoncurrentversionExpirationDays int32 `json:"noncurrentversion_expiration_days,omitempty"`
// Non required, can be set in case of transition is enabled
NoncurrentversionTransitionDays int32 `json:"noncurrentversion_transition_days,omitempty"`
// Non required, can be set in case of transition is enabled
NoncurrentversionTransitionStorageClass string `json:"noncurrentversion_transition_storage_class,omitempty"`
// Non required field, it matches a prefix to perform ILM operations on it
Prefix string `json:"prefix,omitempty"`
// Required only in case of transition is set. it refers to a tier
StorageClass string `json:"storage_class,omitempty"`
// Non required field, tags to match ILM files
Tags string `json:"tags,omitempty"`
// Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM
TransitionDays int32 `json:"transition_days,omitempty"`
}
// Validate validates this update bucket lifecycle

View File

@@ -5956,10 +5956,52 @@ func init() {
"type": "object",
"properties": {
"disable": {
"description": "Non required, toggle to disable or enable rule",
"type": "boolean"
},
"tags": {
"expired_object_delete_marker": {
"description": "Non required, toggle to disable or enable rule",
"type": "boolean"
},
"expiry_days": {
"description": "Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_expiration_days": {
"description": "Non required, can be set in case of expiration is enabled",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_transition_days": {
"description": "Non required, can be set in case of transition is enabled",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_transition_storage_class": {
"description": "Non required, can be set in case of transition is enabled",
"type": "string"
},
"prefix": {
"description": "Non required field, it matches a prefix to perform ILM operations on it",
"type": "string"
},
"storage_class": {
"description": "Required only in case of transition is set. it refers to a tier",
"type": "string"
},
"tags": {
"description": "Non required field, tags to match ILM files",
"type": "string"
},
"transition_days": {
"description": "Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM",
"type": "integer",
"format": "int32",
"default": 0
}
}
},
@@ -12183,10 +12225,52 @@ func init() {
"type": "object",
"properties": {
"disable": {
"description": "Non required, toggle to disable or enable rule",
"type": "boolean"
},
"tags": {
"expired_object_delete_marker": {
"description": "Non required, toggle to disable or enable rule",
"type": "boolean"
},
"expiry_days": {
"description": "Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_expiration_days": {
"description": "Non required, can be set in case of expiration is enabled",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_transition_days": {
"description": "Non required, can be set in case of transition is enabled",
"type": "integer",
"format": "int32",
"default": 0
},
"noncurrentversion_transition_storage_class": {
"description": "Non required, can be set in case of transition is enabled",
"type": "string"
},
"prefix": {
"description": "Non required field, it matches a prefix to perform ILM operations on it",
"type": "string"
},
"storage_class": {
"description": "Required only in case of transition is set. it refers to a tier",
"type": "string"
},
"tags": {
"description": "Non required field, tags to match ILM files",
"type": "string"
},
"transition_days": {
"description": "Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM",
"type": "integer",
"format": "int32",
"default": 0
}
}
},

View File

@@ -53,6 +53,14 @@ func registerBucketsLifecycleHandlers(api *operations.ConsoleAPI) {
}
return user_api.NewAddBucketLifecycleCreated()
})
api.UserAPIUpdateBucketLifecycleHandler = user_api.UpdateBucketLifecycleHandlerFunc(func(params user_api.UpdateBucketLifecycleParams, session *models.Principal) middleware.Responder {
err := getEditBucketLifecycleRule(session, params)
if err != nil {
user_api.NewUpdateBucketLifecycleDefault(int(err.Code)).WithPayload(err)
}
return user_api.NewUpdateBucketLifecycleOK()
})
}
// getBucketLifecycle() gets lifecycle lists for a bucket from MinIO API and returns their implementations
@@ -224,7 +232,7 @@ func addBucketLifecycle(ctx context.Context, client MinioClient, params user_api
return client.setBucketLifecycle(ctx, params.BucketName, lfcCfg)
}
// getAddBucketLifecycleResponse returns the respose of adding a bucket lifecycle response
// getAddBucketLifecycleResponse returns the response of adding a bucket lifecycle response
func getAddBucketLifecycleResponse(session *models.Principal, params user_api.AddBucketLifecycleParams) *models.Error {
ctx := context.Background()
mClient, err := newMinioClient(session)
@@ -242,3 +250,91 @@ func getAddBucketLifecycleResponse(session *models.Principal, params user_api.Ad
return nil
}
// addBucketLifecycle gets lifecycle lists for a bucket from MinIO API and returns their implementations
func editBucketLifecycle(ctx context.Context, client MinioClient, params user_api.UpdateBucketLifecycleParams) error {
// Configuration that is already set.
lfcCfg, err := client.getLifecycleRules(ctx, params.BucketName)
if err != nil {
if e := err; minio.ToErrorResponse(e).Code == "NoSuchLifecycleConfiguration" {
lfcCfg = lifecycle.NewConfiguration()
} else {
return err
}
}
id := params.LifecycleID
opts := ilm.LifecycleOptions{}
// Verify if transition items are set
if params.Body.ExpiryDays == 0 && params.Body.TransitionDays != 0 {
if params.Body.NoncurrentversionExpirationDays != 0 {
return errors.New("non current version expiration days cannot be set when transition is being configured")
}
opts = ilm.LifecycleOptions{
ID: id,
Prefix: params.Body.Prefix,
Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags,
TransitionDays: strconv.Itoa(int(params.Body.TransitionDays)),
StorageClass: strings.ToUpper(params.Body.StorageClass),
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
NoncurrentVersionTransitionDays: int(params.Body.NoncurrentversionTransitionDays),
NoncurrentVersionTransitionStorageClass: strings.ToUpper(params.Body.NoncurrentversionTransitionStorageClass),
}
} else if params.Body.TransitionDays == 0 && params.Body.ExpiryDays != 0 { // Verify if expiry configuration is set
if params.Body.NoncurrentversionTransitionDays != 0 {
return errors.New("non current version Transition Days cannot be set when expiry is being configured")
}
if params.Body.NoncurrentversionTransitionStorageClass != "" {
return errors.New("non current version Transition Storage Class cannot be set when expiry is being configured")
}
opts = ilm.LifecycleOptions{
ID: id,
Prefix: params.Body.Prefix,
Status: !params.Body.Disable,
IsTagsSet: params.Body.Tags != "",
Tags: params.Body.Tags,
ExpiryDays: strconv.Itoa(int(params.Body.ExpiryDays)),
ExpiredObjectDeleteMarker: params.Body.ExpiredObjectDeleteMarker,
NoncurrentVersionExpirationDays: int(params.Body.NoncurrentversionExpirationDays),
}
} else {
// Non set, we return error
return errors.New("transition and expiry cannot be set for the same rule")
}
var err2 *probe.Error
lfcCfg, err2 = opts.ToConfig(lfcCfg)
if err2.ToGoError() != nil {
return err2.ToGoError()
}
return client.setBucketLifecycle(ctx, params.BucketName, lfcCfg)
}
// getEditBucketLifecycleRule returns the response of bucket lyfecycle tier edit
func getEditBucketLifecycleRule(session *models.Principal, params user_api.UpdateBucketLifecycleParams) *models.Error {
ctx := context.Background()
mClient, err := newMinioClient(session)
if err != nil {
return prepareError(err)
}
// create a minioClient interface implementation
// defining the client to be used
minioClient := minioClient{client: mClient}
err = editBucketLifecycle(ctx, minioClient, params)
if err != nil {
return prepareError(err)
}
return nil
}

View File

@@ -198,3 +198,65 @@ func TestSetLifecycleRule(t *testing.T) {
assert.Equal(errors.New("error setting lifecycle"), err2, fmt.Sprintf("Failed on %s: Error returned", function))
}
func TestUpdateLifecycleRule(t *testing.T) {
assert := assert.New(t)
// mock minIO client
minClient := minioClientMock{}
function := "editBucketLifecycle()"
ctx := context.Background()
// Test-1 : editBucketLifecycle() get list of events for a particular bucket only one config (get lifecycle mock)
// mock create request
mockLifecycle := lifecycle.Configuration{
Rules: []lifecycle.Rule{
{
ID: "TESTRULE",
Expiration: lifecycle.Expiration{Days: 15},
Status: "Enabled",
RuleFilter: lifecycle.Filter{Tag: lifecycle.Tag{Key: "tag1", Value: "val1"}, And: lifecycle.And{Prefix: "prefix1"}},
},
},
}
minioGetLifecycleRulesMock = func(ctx context.Context, bucketName string) (lifecycle *lifecycle.Configuration, err error) {
return &mockLifecycle, nil
}
// Test-2 : editBucketLifecycle() Update lifecycle rule
editMock := user_api.UpdateBucketLifecycleParams{
BucketName: "testBucket",
Body: &models.UpdateBucketLifecycle{
Disable: false,
ExpiredObjectDeleteMarker: false,
ExpiryDays: int32(16),
NoncurrentversionExpirationDays: 0,
NoncurrentversionTransitionDays: 0,
NoncurrentversionTransitionStorageClass: "",
Prefix: "pref1",
StorageClass: "",
Tags: "",
TransitionDays: 0,
},
}
minioSetBucketLifecycleMock = func(ctx context.Context, bucketName string, config *lifecycle.Configuration) error {
return nil
}
err := editBucketLifecycle(ctx, minClient, editMock)
assert.Equal(nil, err, fmt.Sprintf("Failed on %s: Error returned", function))
// Test-3 : editBucketLifecycle() returns error
minioSetBucketLifecycleMock = func(ctx context.Context, bucketName string, config *lifecycle.Configuration) error {
return errors.New("error setting lifecycle")
}
err2 := editBucketLifecycle(ctx, minClient, editMock)
assert.Equal(errors.New("error setting lifecycle"), err2, fmt.Sprintf("Failed on %s: Error returned", function))
}

View File

@@ -3906,10 +3906,44 @@ definitions:
updateBucketLifecycle:
type: object
properties:
prefix:
description: Non required field, it matches a prefix to perform ILM operations on it
type: string
tags:
description: Non required field, tags to match ILM files
type: string
expiry_days:
description: Required in case of expiry_date or transition fields are not set. it defines an expiry days for ILM
type: integer
format: int32
default: 0
transition_days:
description: Required in case of transition_date or expiry fields are not set. it defines a transition days for ILM
type: integer
format: int32
default: 0
storage_class:
description: Required only in case of transition is set. it refers to a tier
type: string
disable:
description: Non required, toggle to disable or enable rule
type: boolean
expired_object_delete_marker:
description: Non required, toggle to disable or enable rule
type: boolean
noncurrentversion_expiration_days:
description: Non required, can be set in case of expiration is enabled
type: integer
format: int32
default: 0
noncurrentversion_transition_days:
description: Non required, can be set in case of transition is enabled
type: integer
format: int32
default: 0
noncurrentversion_transition_storage_class:
description: Non required, can be set in case of transition is enabled
type: string
prefixAccessPair:
type: object