lc: Apply DeleteAction correctly to objects (#11471)

When lifecycle decides to Delete an object and not a version in a
versioned bucket, the code should create a delete marker and not
removing the scanned version.

This commit fixes the issue.
This commit is contained in:
Anis Elleuch 2021-02-07 01:10:33 +01:00 committed by GitHub
parent 97fe57bba9
commit 275f7a63e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 15 deletions

View File

@ -65,13 +65,18 @@ func NewLifecycleSys() *LifecycleSys {
return &LifecycleSys{} return &LifecycleSys{}
} }
type expiryState struct { type expiryTask struct {
expiryCh chan ObjectInfo objInfo ObjectInfo
versionExpiry bool
} }
func (es *expiryState) queueExpiryTask(oi ObjectInfo) { type expiryState struct {
expiryCh chan expiryTask
}
func (es *expiryState) queueExpiryTask(oi ObjectInfo, rmVersion bool) {
select { select {
case es.expiryCh <- oi: case es.expiryCh <- expiryTask{objInfo: oi, versionExpiry: rmVersion}:
default: default:
} }
} }
@ -82,7 +87,7 @@ var (
func newExpiryState() *expiryState { func newExpiryState() *expiryState {
es := &expiryState{ es := &expiryState{
expiryCh: make(chan ObjectInfo, 10000), expiryCh: make(chan expiryTask, 10000),
} }
go func() { go func() {
<-GlobalContext.Done() <-GlobalContext.Done()
@ -94,8 +99,8 @@ func newExpiryState() *expiryState {
func initBackgroundExpiry(ctx context.Context, objectAPI ObjectLayer) { func initBackgroundExpiry(ctx context.Context, objectAPI ObjectLayer) {
globalExpiryState = newExpiryState() globalExpiryState = newExpiryState()
go func() { go func() {
for oi := range globalExpiryState.expiryCh { for t := range globalExpiryState.expiryCh {
applyExpiryRule(ctx, objectAPI, oi, false) applyExpiryRule(ctx, objectAPI, t.objInfo, false, t.versionExpiry)
} }
}() }()
} }

View File

@ -994,10 +994,12 @@ func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer,
return true return true
} }
func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo) bool { func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, applyOnVersion bool) bool {
opts := ObjectOptions{} opts := ObjectOptions{}
if applyOnVersion {
opts.VersionID = obj.VersionID opts.VersionID = obj.VersionID
}
if opts.VersionID == "" { if opts.VersionID == "" {
opts.Versioned = globalBucketVersioningSys.Enabled(obj.Bucket) opts.Versioned = globalBucketVersioningSys.Enabled(obj.Bucket)
} }
@ -1029,20 +1031,20 @@ func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLay
} }
// Apply object, object version, restored object or restored object version action on the given object // Apply object, object version, restored object or restored object version action on the given object
func applyExpiryRule(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, restoredObject bool) bool { func applyExpiryRule(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, restoredObject, applyOnVersion bool) bool {
if obj.TransitionStatus != "" { if obj.TransitionStatus != "" {
return applyExpiryOnTransitionedObject(ctx, objLayer, obj, restoredObject) return applyExpiryOnTransitionedObject(ctx, objLayer, obj, restoredObject)
} }
return applyExpiryOnNonTransitionedObjects(ctx, objLayer, obj) return applyExpiryOnNonTransitionedObjects(ctx, objLayer, obj, applyOnVersion)
} }
// Perform actions (removal of transitioning of objects), return true the action is successfully performed // Perform actions (removal of transitioning of objects), return true the action is successfully performed
func applyLifecycleAction(ctx context.Context, action lifecycle.Action, objLayer ObjectLayer, obj ObjectInfo) (success bool) { func applyLifecycleAction(ctx context.Context, action lifecycle.Action, objLayer ObjectLayer, obj ObjectInfo) (success bool) {
switch action { switch action {
case lifecycle.DeleteVersionAction, lifecycle.DeleteAction: case lifecycle.DeleteVersionAction, lifecycle.DeleteAction:
success = applyExpiryRule(ctx, objLayer, obj, false) success = applyExpiryRule(ctx, objLayer, obj, false, action == lifecycle.DeleteVersionAction)
case lifecycle.DeleteRestoredAction, lifecycle.DeleteRestoredVersionAction: case lifecycle.DeleteRestoredAction, lifecycle.DeleteRestoredVersionAction:
success = applyExpiryRule(ctx, objLayer, obj, true) success = applyExpiryRule(ctx, objLayer, obj, true, action == lifecycle.DeleteRestoredVersionAction)
case lifecycle.TransitionAction, lifecycle.TransitionVersionAction: case lifecycle.TransitionAction, lifecycle.TransitionVersionAction:
success = applyTransitionAction(ctx, action, objLayer, obj) success = applyTransitionAction(ctx, action, objLayer, obj)
} }

View File

@ -433,7 +433,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req
if lc, err := globalLifecycleSys.Get(bucket); err == nil { if lc, err := globalLifecycleSys.Get(bucket); err == nil {
action := evalActionFromLifecycle(ctx, *lc, objInfo, false) action := evalActionFromLifecycle(ctx, *lc, objInfo, false)
if action == lifecycle.DeleteAction || action == lifecycle.DeleteVersionAction { if action == lifecycle.DeleteAction || action == lifecycle.DeleteVersionAction {
globalExpiryState.queueExpiryTask(objInfo) globalExpiryState.queueExpiryTask(objInfo, action == lifecycle.DeleteVersionAction)
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey)) writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey))
return return
} }
@ -600,7 +600,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re
if lc, err := globalLifecycleSys.Get(bucket); err == nil { if lc, err := globalLifecycleSys.Get(bucket); err == nil {
action := evalActionFromLifecycle(ctx, *lc, objInfo, false) action := evalActionFromLifecycle(ctx, *lc, objInfo, false)
if action == lifecycle.DeleteAction || action == lifecycle.DeleteVersionAction { if action == lifecycle.DeleteAction || action == lifecycle.DeleteVersionAction {
globalExpiryState.queueExpiryTask(objInfo) globalExpiryState.queueExpiryTask(objInfo, action == lifecycle.DeleteVersionAction)
writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey)) writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey))
return return
} }