lifecycle: Expiry should not delete versions (#9972)

Currently, lifecycle expiry is deleting all object versions which is not
correct, unless noncurrent versions field is specified.

Also, only delete the delete marker if it is the only version of the
given object.
This commit is contained in:
Anis Elleuch 2020-07-05 04:56:02 +01:00 committed by GitHub
parent c087a05b43
commit d4af132fc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 11 deletions

View File

@ -511,6 +511,7 @@ func (i *crawlItem) transformMetaDir() {
type actionMeta struct {
oi ObjectInfo
trustOI bool // Set true if oi can be trusted and has been read with quorum.
numVersions int // The number of versions of this object
}
// applyActions will apply lifecycle checks on to a scanned item.
@ -535,12 +536,13 @@ func (i *crawlItem) applyActions(ctx context.Context, o ObjectLayer, meta action
VersionID: meta.oi.VersionID,
DeleteMarker: meta.oi.DeleteMarker,
IsLatest: meta.oi.IsLatest,
NumVersions: meta.numVersions,
})
if i.debug {
logger.Info(color.Green("applyActions:")+" lifecycle: %q, Initial scan: %v", i.objectPath(), action)
}
switch action {
case lifecycle.DeleteAction:
case lifecycle.DeleteAction, lifecycle.DeleteVersionAction:
default:
// No action.
return size
@ -586,14 +588,22 @@ func (i *crawlItem) applyActions(ctx context.Context, o ObjectLayer, meta action
}
versionID = obj.VersionID
switch action {
case lifecycle.DeleteAction:
case lifecycle.DeleteAction, lifecycle.DeleteVersionAction:
default:
// No action.
return size
}
}
obj, err := o.DeleteObject(ctx, i.bucket, i.objectPath(), ObjectOptions{VersionID: versionID})
opts := ObjectOptions{}
switch action {
case lifecycle.DeleteVersionAction:
opts.VersionID = versionID
case lifecycle.DeleteAction:
opts.Versioned = globalBucketVersioningSys.Enabled(i.bucket)
}
obj, err := o.DeleteObject(ctx, i.bucket, i.objectPath(), opts)
if err != nil {
// Assume it is still there.
logger.LogIf(ctx, err)

View File

@ -408,7 +408,7 @@ func (s *xlStorage) CrawlAndGetDataUsage(ctx context.Context, cache dataUsageCac
var totalSize int64
for _, version := range fivs.Versions {
size := item.applyActions(ctx, objAPI, actionMeta{oi: version.ToObjectInfo(item.bucket, item.objectPath())})
size := item.applyActions(ctx, objAPI, actionMeta{numVersions: len(fivs.Versions), oi: version.ToObjectInfo(item.bucket, item.objectPath())})
if !version.Deleted {
totalSize += size
}

View File

@ -40,6 +40,8 @@ const (
NoneAction Action = iota
// DeleteAction means the object needs to be removed after evaluting lifecycle rules
DeleteAction
// DeleteVersionAction deletes a particular version
DeleteVersionAction
)
// Lifecycle - Configuration for bucket lifecycle.
@ -176,6 +178,7 @@ type ObjectOpts struct {
VersionID string
IsLatest bool
DeleteMarker bool
NumVersions int
}
// ComputeAction returns the action to perform by evaluating all lifecycle rules
@ -187,27 +190,28 @@ func (lc Lifecycle) ComputeAction(obj ObjectOpts) Action {
}
for _, rule := range lc.FilterActionableRules(obj) {
if obj.DeleteMarker && obj.IsLatest && bool(rule.Expiration.DeleteMarker) {
if obj.DeleteMarker && obj.NumVersions == 1 && bool(rule.Expiration.DeleteMarker) {
// 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 DeleteAction
return DeleteVersionAction
}
if !rule.NoncurrentVersionExpiration.IsDaysNull() {
if obj.VersionID != "" && !obj.IsLatest {
// Non current versions should be deleted.
if time.Now().After(expectedExpiryTime(obj.ModTime, rule.NoncurrentVersionExpiration.NoncurrentDays)) {
return DeleteAction
return DeleteVersionAction
}
return NoneAction
}
return NoneAction
}
// All other expiration only applies to latest versions.
if obj.IsLatest {
// All other expiration only applies to latest versions
// (except if this is a delete marker)
if obj.IsLatest && !obj.DeleteMarker {
switch {
case !rule.Expiration.IsDateNull():
if time.Now().UTC().After(rule.Expiration.Date.Time) {