From 209e6d00c6c36c641c11fede4fca79cc77c40f63 Mon Sep 17 00:00:00 2001 From: Krishnan Parthasarathi Date: Wed, 21 Jul 2021 19:12:44 -0700 Subject: [PATCH] Use ObjectInfo.ToLifecycleOpts instead of literal values (#12772) Promote getLifecycleTransitionTier to a method on lifecycle.Lifecycle. --- cmd/bucket-lifecycle-handlers.go | 2 +- cmd/bucket-lifecycle.go | 24 ++----------- cmd/bucket-lifecycle_test.go | 40 +-------------------- cmd/data-scanner.go | 33 ++--------------- internal/bucket/lifecycle/lifecycle.go | 13 +++++++ internal/bucket/lifecycle/lifecycle_test.go | 37 +++++++++++++++++++ 6 files changed, 57 insertions(+), 92 deletions(-) diff --git a/cmd/bucket-lifecycle-handlers.go b/cmd/bucket-lifecycle-handlers.go index 5eafcb6cb..a1673324b 100644 --- a/cmd/bucket-lifecycle-handlers.go +++ b/cmd/bucket-lifecycle-handlers.go @@ -80,7 +80,7 @@ func (api objectAPIHandlers) PutBucketLifecycleHandler(w http.ResponseWriter, r } // Validate the transition storage ARNs - if err = validateTransitionTier(ctx, bucketLifecycle); err != nil { + if err = validateTransitionTier(bucketLifecycle); err != nil { writeErrorResponse(ctx, w, toAPIError(ctx, err), r.URL) return } diff --git a/cmd/bucket-lifecycle.go b/cmd/bucket-lifecycle.go index 8bafd7b7a..fd3b991db 100644 --- a/cmd/bucket-lifecycle.go +++ b/cmd/bucket-lifecycle.go @@ -180,8 +180,8 @@ func initBackgroundTransition(ctx context.Context, objectAPI ObjectLayer) { var errInvalidStorageClass = errors.New("invalid storage class") -func validateTransitionTier(ctx context.Context, lfc *lifecycle.Lifecycle) error { - for _, rule := range lfc.Rules { +func validateTransitionTier(lc *lifecycle.Lifecycle) error { + for _, rule := range lc.Rules { if rule.Transition.StorageClass == "" { continue } @@ -288,15 +288,10 @@ func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo) if err != nil { return err } - lcOpts := lifecycle.ObjectOpts{ - Name: oi.Name, - UserTags: oi.UserTags, - } - tierName := getLifeCycleTransitionTier(ctx, lc, oi.Bucket, lcOpts) opts := ObjectOptions{ Transition: TransitionOptions{ Status: lifecycle.TransitionPending, - Tier: tierName, + Tier: lc.TransitionTier(oi.ToLifecycleOpts()), ETag: oi.ETag, }, VersionID: oi.VersionID, @@ -306,19 +301,6 @@ func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo) return objectAPI.TransitionObject(ctx, oi.Bucket, oi.Name, opts) } -// getLifeCycleTransitionTier returns storage class for transition target -func getLifeCycleTransitionTier(ctx context.Context, lc *lifecycle.Lifecycle, bucket string, obj lifecycle.ObjectOpts) string { - for _, rule := range lc.FilterActionableRules(obj) { - if obj.IsLatest && rule.Transition.StorageClass != "" { - return rule.Transition.StorageClass - } - if !obj.IsLatest && rule.NoncurrentVersionTransition.StorageClass != "" { - return rule.NoncurrentVersionTransition.StorageClass - } - } - return "" -} - // getTransitionedObjectReader returns a reader from the transitioned tier. func getTransitionedObjectReader(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, oi ObjectInfo, opts ObjectOptions) (gr *GetObjectReader, err error) { tgtClient, err := globalTierConfigMgr.getDriver(oi.TransitionTier) diff --git a/cmd/bucket-lifecycle_test.go b/cmd/bucket-lifecycle_test.go index feda1efee..0577834d4 100644 --- a/cmd/bucket-lifecycle_test.go +++ b/cmd/bucket-lifecycle_test.go @@ -19,7 +19,6 @@ package cmd import ( "bytes" - "context" "net/http" "testing" "time" @@ -240,46 +239,9 @@ func TestValidateTransitionTier(t *testing.T) { t.Fatalf("Test %d: Failed to parse lifecycle config %v", i+1, err) } - err = validateTransitionTier(context.Background(), lc) + err = validateTransitionTier(lc) if err != tc.expectedErr { t.Fatalf("Test %d: Expected %v but got %v", i+1, tc.expectedErr, err) } } } - -func TestGetLifecycleTransitionTier(t *testing.T) { - lc := lifecycle.Lifecycle{ - Rules: []lifecycle.Rule{ - { - ID: "rule-1", - Status: "Enabled", - Transition: lifecycle.Transition{ - Days: lifecycle.TransitionDays(3), - StorageClass: "TIER-1", - }, - }, - { - ID: "rule-2", - Status: "Enabled", - NoncurrentVersionTransition: lifecycle.NoncurrentVersionTransition{ - NoncurrentDays: lifecycle.ExpirationDays(3), - StorageClass: "TIER-2", - }, - }, - }, - } - - obj1 := lifecycle.ObjectOpts{ - Name: "obj1", - IsLatest: true, - } - obj2 := lifecycle.ObjectOpts{ - Name: "obj2", - } - if got := getLifeCycleTransitionTier(context.TODO(), &lc, "bucket", obj1); got != "TIER-1" { - t.Fatalf("Expected TIER-1 but got %s", got) - } - if got := getLifeCycleTransitionTier(context.TODO(), &lc, "bucket", obj2); got != "TIER-2" { - t.Fatalf("Expected TIER-2 but got %s", got) - } -} diff --git a/cmd/data-scanner.go b/cmd/data-scanner.go index 213ab177e..68946880e 100644 --- a/cmd/data-scanner.go +++ b/cmd/data-scanner.go @@ -1020,22 +1020,7 @@ func (i *scannerItem) applyActions(ctx context.Context, o ObjectLayer, meta acti } func evalActionFromLifecycle(ctx context.Context, lc lifecycle.Lifecycle, obj ObjectInfo, debug bool) (action lifecycle.Action) { - lcOpts := lifecycle.ObjectOpts{ - Name: obj.Name, - UserTags: obj.UserTags, - ModTime: obj.ModTime, - VersionID: obj.VersionID, - DeleteMarker: obj.DeleteMarker, - IsLatest: obj.IsLatest, - NumVersions: obj.NumVersions, - SuccessorModTime: obj.SuccessorModTime, - RestoreOngoing: obj.RestoreOngoing, - RestoreExpires: obj.RestoreExpires, - TransitionStatus: obj.TransitionStatus, - RemoteTiersImmediately: globalDebugRemoteTiersImmediately, - } - - action = lc.ComputeAction(lcOpts) + action = lc.ComputeAction(obj.ToLifecycleOpts()) if debug { console.Debugf(applyActionsLogPrefix+" lifecycle: Secondary scan: %v\n", action) } @@ -1086,25 +1071,11 @@ func applyTransitionAction(ctx context.Context, action lifecycle.Action, objLaye } func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, restoredObject bool) bool { - lcOpts := lifecycle.ObjectOpts{ - Name: obj.Name, - UserTags: obj.UserTags, - ModTime: obj.ModTime, - VersionID: obj.VersionID, - DeleteMarker: obj.DeleteMarker, - IsLatest: obj.IsLatest, - NumVersions: obj.NumVersions, - SuccessorModTime: obj.SuccessorModTime, - RestoreOngoing: obj.RestoreOngoing, - RestoreExpires: obj.RestoreExpires, - TransitionStatus: obj.TransitionStatus, - } - action := expireObj if restoredObject { action = expireRestoredObj } - if err := expireTransitionedObject(ctx, objLayer, &obj, lcOpts, action); err != nil { + if err := expireTransitionedObject(ctx, objLayer, &obj, obj.ToLifecycleOpts(), action); err != nil { if isErrObjectNotFound(err) || isErrVersionNotFound(err) { return false } diff --git a/internal/bucket/lifecycle/lifecycle.go b/internal/bucket/lifecycle/lifecycle.go index 78f050eed..f0873f801 100644 --- a/internal/bucket/lifecycle/lifecycle.go +++ b/internal/bucket/lifecycle/lifecycle.go @@ -476,3 +476,16 @@ func (lc Lifecycle) SetPredictionHeaders(w http.ResponseWriter, obj ObjectOpts) } } } + +// TransitionTier returns remote tier that applies to obj per ILM rules. +func (lc Lifecycle) TransitionTier(obj ObjectOpts) string { + for _, rule := range lc.FilterActionableRules(obj) { + if obj.IsLatest && rule.Transition.StorageClass != "" { + return rule.Transition.StorageClass + } + if !obj.IsLatest && rule.NoncurrentVersionTransition.StorageClass != "" { + return rule.NoncurrentVersionTransition.StorageClass + } + } + return "" +} diff --git a/internal/bucket/lifecycle/lifecycle_test.go b/internal/bucket/lifecycle/lifecycle_test.go index 92cbe9e8c..6df8afbcb 100644 --- a/internal/bucket/lifecycle/lifecycle_test.go +++ b/internal/bucket/lifecycle/lifecycle_test.go @@ -516,3 +516,40 @@ func TestSetPredictionHeaders(t *testing.T) { } } } + +func TestTransitionTier(t *testing.T) { + lc := Lifecycle{ + Rules: []Rule{ + { + ID: "rule-1", + Status: "Enabled", + Transition: Transition{ + Days: TransitionDays(3), + StorageClass: "TIER-1", + }, + }, + { + ID: "rule-2", + Status: "Enabled", + NoncurrentVersionTransition: NoncurrentVersionTransition{ + NoncurrentDays: ExpirationDays(3), + StorageClass: "TIER-2", + }, + }, + }, + } + + obj1 := ObjectOpts{ + Name: "obj1", + IsLatest: true, + } + obj2 := ObjectOpts{ + Name: "obj2", + } + if got := lc.TransitionTier(obj1); got != "TIER-1" { + t.Fatalf("Expected TIER-1 but got %s", got) + } + if got := lc.TransitionTier(obj2); got != "TIER-2" { + t.Fatalf("Expected TIER-2 but got %s", got) + } +}