fix: immediate tiering for NoncurrentVersionTransition (#13464)

This commit is contained in:
Krishnan Parthasarathi 2021-10-18 19:24:30 -05:00 committed by GitHub
parent 221ef78faa
commit 45d145a823
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 15 deletions

View File

@ -316,10 +316,9 @@ func (lc Lifecycle) ComputeAction(obj ObjectOpts) Action {
if obj.VersionID != "" && !obj.IsLatest && !obj.SuccessorModTime.IsZero() && !obj.DeleteMarker && obj.TransitionStatus != TransitionComplete { if obj.VersionID != "" && !obj.IsLatest && !obj.SuccessorModTime.IsZero() && !obj.DeleteMarker && obj.TransitionStatus != TransitionComplete {
// Non current versions should be transitioned if their age exceeds non current days configuration // Non current versions should be transitioned if their age exceeds non current days configuration
// https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#intro-lifecycle-rules-actions // https://docs.aws.amazon.com/AmazonS3/latest/dev/intro-lifecycle-rules.html#intro-lifecycle-rules-actions
if time.Now().After(ExpectedExpiryTime(obj.SuccessorModTime, int(rule.NoncurrentVersionTransition.NoncurrentDays))) { if due, ok := rule.NoncurrentVersionTransition.NextDue(obj); ok && time.Now().UTC().After(due) {
return TransitionVersionAction return TransitionVersionAction
} }
} }
} }

View File

@ -27,6 +27,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/google/uuid"
xhttp "github.com/minio/minio/internal/http" xhttp "github.com/minio/minio/internal/http"
) )
@ -216,12 +217,15 @@ func TestExpectedExpiryTime(t *testing.T) {
func TestComputeActions(t *testing.T) { func TestComputeActions(t *testing.T) {
testCases := []struct { testCases := []struct {
inputConfig string inputConfig string
objectName string objectName string
objectTags string objectTags string
objectModTime time.Time objectModTime time.Time
isExpiredDelMarker bool isExpiredDelMarker bool
expectedAction Action expectedAction Action
isNoncurrent bool
objectSuccessorModTime time.Time
versionID string
}{ }{
// Empty object name (unexpected case) should always return NoneAction // Empty object name (unexpected case) should always return NoneAction
{ {
@ -386,13 +390,23 @@ func TestComputeActions(t *testing.T) {
isExpiredDelMarker: true, isExpiredDelMarker: true,
expectedAction: DeleteVersionAction, expectedAction: DeleteVersionAction,
}, },
// Should not delete expired marker if its time has not come yet // Should transition immediately when Transition days is zero
{ {
inputConfig: `<BucketLifecycleConfiguration><Rule><Filter></Filter><Status>Enabled</Status><Transition><Days>0</Days><StorageClass>S3TIER-1</StorageClass></Transition></Rule></BucketLifecycleConfiguration>`, inputConfig: `<BucketLifecycleConfiguration><Rule><Filter></Filter><Status>Enabled</Status><Transition><Days>0</Days><StorageClass>S3TIER-1</StorageClass></Transition></Rule></BucketLifecycleConfiguration>`,
objectName: "foodir/fooobject", objectName: "foodir/fooobject",
objectModTime: time.Now().UTC(), // Created now objectModTime: time.Now().UTC(), // Created now
expectedAction: TransitionAction, expectedAction: TransitionAction,
}, },
// Should transition immediately when NoncurrentVersion Transition days is zero
{
inputConfig: `<BucketLifecycleConfiguration><Rule><Filter></Filter><Status>Enabled</Status><NoncurrentVersionTransition><NoncurrentDays>0</NoncurrentDays><StorageClass>S3TIER-1</StorageClass></NoncurrentVersionTransition></Rule></BucketLifecycleConfiguration>`,
objectName: "foodir/fooobject",
objectModTime: time.Now().UTC(), // Created now
expectedAction: TransitionVersionAction,
isNoncurrent: true,
objectSuccessorModTime: time.Now().UTC(),
versionID: uuid.New().String(),
},
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -403,12 +417,14 @@ func TestComputeActions(t *testing.T) {
t.Fatalf("Got unexpected error: %v", err) t.Fatalf("Got unexpected error: %v", err)
} }
if resultAction := lc.ComputeAction(ObjectOpts{ if resultAction := lc.ComputeAction(ObjectOpts{
Name: tc.objectName, Name: tc.objectName,
UserTags: tc.objectTags, UserTags: tc.objectTags,
ModTime: tc.objectModTime, ModTime: tc.objectModTime,
DeleteMarker: tc.isExpiredDelMarker, DeleteMarker: tc.isExpiredDelMarker,
NumVersions: 1, NumVersions: 1,
IsLatest: true, IsLatest: !tc.isNoncurrent,
SuccessorModTime: tc.objectSuccessorModTime,
VersionID: tc.versionID,
}); resultAction != tc.expectedAction { }); resultAction != tc.expectedAction {
t.Fatalf("Expected action: `%v`, got: `%v`", tc.expectedAction, resultAction) t.Fatalf("Expected action: `%v`, got: `%v`", tc.expectedAction, resultAction)
} }