diff --git a/internal/bucket/lifecycle/lifecycle.go b/internal/bucket/lifecycle/lifecycle.go
index f0873f801..8adc9ed14 100644
--- a/internal/bucket/lifecycle/lifecycle.go
+++ b/internal/bucket/lifecycle/lifecycle.go
@@ -287,12 +287,23 @@ func (lc Lifecycle) ComputeAction(obj ObjectOpts) Action {
return action
}
for _, rule := range lc.FilterActionableRules(obj) {
- if obj.ExpiredObjectDeleteMarker() && rule.Expiration.DeleteMarker.val {
- // Indicates whether MinIO will remove a delete marker with no noncurrent versions.
- // Only latest marker is removed. If set to true, the delete marker will be expired;
- // if set to false the policy takes no action. This cannot be specified with Days or
- // Date in a Lifecycle Expiration Policy.
- return DeleteVersionAction
+ if obj.ExpiredObjectDeleteMarker() {
+ if rule.Expiration.DeleteMarker.val {
+ // Indicates whether MinIO will remove a delete marker with no noncurrent versions.
+ // Only latest marker is removed. If set to true, the delete marker will be expired;
+ // if set to false the policy takes no action. This cannot be specified with Days or
+ // Date in a Lifecycle Expiration Policy.
+ return DeleteVersionAction
+ }
+
+ if !rule.Expiration.IsDaysNull() {
+ // Specifying the Days tag will automatically perform ExpiredObjectDeleteMarker cleanup
+ // once delete markers are old enough to satisfy the age criteria.
+ // https://docs.aws.amazon.com/AmazonS3/latest/userguide/lifecycle-configuration-examples.html
+ if time.Now().After(ExpectedExpiryTime(obj.ModTime, int(rule.Expiration.Days))) {
+ return DeleteVersionAction
+ }
+ }
}
if !rule.NoncurrentVersionExpiration.IsDaysNull() {
@@ -303,17 +314,6 @@ func (lc Lifecycle) ComputeAction(obj ObjectOpts) Action {
return DeleteVersionAction
}
}
-
- if obj.VersionID != "" && obj.ExpiredObjectDeleteMarker() {
- // From https: //docs.aws.amazon.com/AmazonS3/latest/dev/lifecycle-configuration-examples.html :
- // The NoncurrentVersionExpiration action in the same Lifecycle configuration removes noncurrent objects X days
- // after they become noncurrent. Thus, in this example, all object versions are permanently removed X days after
- // object creation. You will have expired object delete markers, but Amazon S3 detects and removes the expired
- // object delete markers for you.
- if time.Now().After(ExpectedExpiryTime(obj.ModTime, int(rule.NoncurrentVersionExpiration.NoncurrentDays))) {
- return DeleteVersionAction
- }
- }
}
if !rule.NoncurrentVersionTransition.IsDaysNull() {
diff --git a/internal/bucket/lifecycle/lifecycle_test.go b/internal/bucket/lifecycle/lifecycle_test.go
index 6df8afbcb..700ca4a41 100644
--- a/internal/bucket/lifecycle/lifecycle_test.go
+++ b/internal/bucket/lifecycle/lifecycle_test.go
@@ -210,11 +210,12 @@ func TestExpectedExpiryTime(t *testing.T) {
func TestComputeActions(t *testing.T) {
testCases := []struct {
- inputConfig string
- objectName string
- objectTags string
- objectModTime time.Time
- expectedAction Action
+ inputConfig string
+ objectName string
+ objectTags string
+ objectModTime time.Time
+ isExpiredDelMarker bool
+ expectedAction Action
}{
// Empty object name (unexpected case) should always return NoneAction
{
@@ -355,6 +356,30 @@ func TestComputeActions(t *testing.T) {
objectModTime: time.Now().UTC().Add(-24 * time.Hour), // Created 1 day ago
expectedAction: DeleteAction,
},
+ // Should delete expired delete marker right away
+ {
+ inputConfig: `trueEnabled`,
+ objectName: "foodir/fooobject",
+ objectModTime: time.Now().UTC().Add(-1 * time.Hour), // Created one hour ago
+ isExpiredDelMarker: true,
+ expectedAction: DeleteVersionAction,
+ },
+ // Should not delete expired marker if its time has not come yet
+ {
+ inputConfig: `Enabled1`,
+ objectName: "foodir/fooobject",
+ objectModTime: time.Now().UTC().Add(-12 * time.Hour), // Created 12 hours ago
+ isExpiredDelMarker: true,
+ expectedAction: NoneAction,
+ },
+ // Should delete expired marker since its time has come
+ {
+ inputConfig: `Enabled1`,
+ objectName: "foodir/fooobject",
+ objectModTime: time.Now().UTC().Add(-10 * 24 * time.Hour), // Created 10 days ago
+ isExpiredDelMarker: true,
+ expectedAction: DeleteVersionAction,
+ },
}
for _, tc := range testCases {
@@ -365,10 +390,12 @@ func TestComputeActions(t *testing.T) {
t.Fatalf("Got unexpected error: %v", err)
}
if resultAction := lc.ComputeAction(ObjectOpts{
- Name: tc.objectName,
- UserTags: tc.objectTags,
- ModTime: tc.objectModTime,
- IsLatest: true,
+ Name: tc.objectName,
+ UserTags: tc.objectTags,
+ ModTime: tc.objectModTime,
+ DeleteMarker: tc.isExpiredDelMarker,
+ NumVersions: 1,
+ IsLatest: true,
}); resultAction != tc.expectedAction {
t.Fatalf("Expected action: `%v`, got: `%v`", tc.expectedAction, resultAction)
}