From 3e128c116ed1451c40e9140fb41af838e31967b0 Mon Sep 17 00:00:00 2001 From: Krishnan Parthasarathi Date: Mon, 22 May 2023 15:28:56 -0700 Subject: [PATCH] Add lifecycle event source to audit log tags (#17248) --- cmd/bucket-lifecycle-audit.go | 88 ++++++++++++++++++++++++++++ cmd/bucket-lifecycle.go | 70 +++++++--------------- cmd/data-scanner.go | 26 ++++---- cmd/erasure-object.go | 2 +- cmd/erasure-server-pool-decom.go | 8 +-- cmd/erasure-server-pool-rebalance.go | 2 +- cmd/erasure-server-pool.go | 2 +- cmd/lceventsrc_string.go | 32 ++++++++++ cmd/metacache-server-pool.go | 2 +- cmd/object-api-interface.go | 17 +++--- cmd/object-handlers-common.go | 3 +- cmd/object-handlers.go | 8 +-- cmd/object-multipart-handlers.go | 2 +- 13 files changed, 176 insertions(+), 86 deletions(-) create mode 100644 cmd/bucket-lifecycle-audit.go create mode 100644 cmd/lceventsrc_string.go diff --git a/cmd/bucket-lifecycle-audit.go b/cmd/bucket-lifecycle-audit.go new file mode 100644 index 000000000..1895b90e8 --- /dev/null +++ b/cmd/bucket-lifecycle-audit.go @@ -0,0 +1,88 @@ +// Copyright (c) 2023 MinIO, Inc. +// +// This file is part of MinIO Object Storage stack +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package cmd + +import "github.com/minio/minio/internal/bucket/lifecycle" + +//go:generate stringer -type lcEventSrc -trimprefix lcEventSrc_ $GOFILE +type lcEventSrc uint8 + +//revive:disable:var-naming Underscores is used here to indicate where common prefix ends and the enumeration name begins +const ( + lcEventSrc_None lcEventSrc = iota + lcEventSrc_Scanner + lcEventSrc_Decom + lcEventSrc_Rebal + lcEventSrc_s3HeadObject + lcEventSrc_s3GetObject + lcEventSrc_s3ListObjects + lcEventSrc_s3PutObject + lcEventSrc_s3CopyObject + lcEventSrc_s3CompleteMultipartUpload +) + +//revive:enable:var-naming +type lcAuditEvent struct { + lifecycle.Event + source lcEventSrc +} + +func (lae lcAuditEvent) Tags() map[string]interface{} { + event := lae.Event + src := lae.source + const ( + ilmSrc = "ilm-src" + ilmAction = "ilm-action" + ilmDue = "ilm-due" + ilmRuleID = "ilm-rule-id" + ilmTier = "ilm-tier" + ilmNewerNoncurrentVersions = "ilm-newer-noncurrent-versions" + ilmNoncurrentDays = "ilm-noncurrent-days" + ) + tags := make(map[string]interface{}, 5) + if src > lcEventSrc_None { + tags[ilmSrc] = src.String() + } + tags[ilmAction] = event.Action.String() + tags[ilmRuleID] = event.RuleID + + if !event.Due.IsZero() { + tags[ilmDue] = event.Due + } + + // rule with Transition/NoncurrentVersionTransition in effect + if event.StorageClass != "" { + tags[ilmTier] = event.StorageClass + } + + // rule with NewernoncurrentVersions in effect + if event.NewerNoncurrentVersions > 0 { + tags[ilmNewerNoncurrentVersions] = event.NewerNoncurrentVersions + } + if event.NoncurrentDays > 0 { + tags[ilmNoncurrentDays] = event.NoncurrentDays + } + return tags +} + +func newLifecycleAuditEvent(src lcEventSrc, event lifecycle.Event) lcAuditEvent { + return lcAuditEvent{ + Event: event, + source: src, + } +} diff --git a/cmd/bucket-lifecycle.go b/cmd/bucket-lifecycle.go index 4f4cbdda4..a6807f00d 100644 --- a/cmd/bucket-lifecycle.go +++ b/cmd/bucket-lifecycle.go @@ -98,6 +98,7 @@ func (sys *LifecycleSys) trace(oi ObjectInfo) func(event string) { type expiryTask struct { objInfo ObjectInfo event lifecycle.Event + src lcEventSrc } type expiryState struct { @@ -120,11 +121,11 @@ func (es *expiryState) close() { } // enqueueByDays enqueues object versions expired by days for expiry. -func (es *expiryState) enqueueByDays(oi ObjectInfo, event lifecycle.Event) { +func (es *expiryState) enqueueByDays(oi ObjectInfo, event lifecycle.Event, src lcEventSrc) { select { case <-GlobalContext.Done(): es.close() - case es.byDaysCh <- expiryTask{objInfo: oi, event: event}: + case es.byDaysCh <- expiryTask{objInfo: oi, event: event, src: src}: default: } } @@ -172,9 +173,9 @@ func initBackgroundExpiry(ctx context.Context, objectAPI ObjectLayer) { go func(t expiryTask) { defer ewk.Give() if t.objInfo.TransitionedObject.Status != "" { - applyExpiryOnTransitionedObject(ctx, objectAPI, t.objInfo, t.event) + applyExpiryOnTransitionedObject(ctx, objectAPI, t.objInfo, t.event, t.src) } else { - applyExpiryOnNonTransitionedObjects(ctx, objectAPI, t.objInfo, t.event) + applyExpiryOnNonTransitionedObjects(ctx, objectAPI, t.objInfo, t.event, t.src) } }(t) } @@ -202,6 +203,7 @@ type newerNoncurrentTask struct { type transitionTask struct { objInfo ObjectInfo + src lcEventSrc event lifecycle.Event } @@ -220,10 +222,10 @@ type transitionState struct { lastDayStats map[string]*lastDayTierStats } -func (t *transitionState) queueTransitionTask(oi ObjectInfo, event lifecycle.Event) { +func (t *transitionState) queueTransitionTask(oi ObjectInfo, event lifecycle.Event, src lcEventSrc) { select { case <-t.ctx.Done(): - case t.transitionCh <- transitionTask{objInfo: oi, event: event}: + case t.transitionCh <- transitionTask{objInfo: oi, event: event, src: src}: default: } } @@ -276,7 +278,7 @@ func (t *transitionState) worker(objectAPI ObjectLayer) { return } atomic.AddInt32(&t.activeTasks, 1) - if err := transitionObject(t.ctx, objectAPI, task.objInfo, task.event); err != nil { + if err := transitionObject(t.ctx, objectAPI, task.objInfo, newLifecycleAuditEvent(task.src, task.event)); err != nil { logger.LogIf(t.ctx, fmt.Errorf("Transition to %s failed for %s/%s version:%s with %w", task.event.StorageClass, task.objInfo.Bucket, task.objInfo.Name, task.objInfo.VersionID, err)) } else { @@ -358,11 +360,11 @@ func validateTransitionTier(lc *lifecycle.Lifecycle) error { // enqueueTransitionImmediate enqueues obj for transition if eligible. // This is to be called after a successful upload of an object (version). -func enqueueTransitionImmediate(obj ObjectInfo) { +func enqueueTransitionImmediate(obj ObjectInfo, src lcEventSrc) { if lc, err := globalLifecycleSys.Get(obj.Bucket); err == nil { switch event := lc.Eval(obj.ToLifecycleOpts()); event.Action { case lifecycle.TransitionAction, lifecycle.TransitionVersionAction: - globalTransitionState.queueTransitionTask(obj, event) + globalTransitionState.queueTransitionTask(obj, event, src) } } } @@ -372,13 +374,13 @@ func enqueueTransitionImmediate(obj ObjectInfo) { // // 1. when a restored (via PostRestoreObject API) object expires. // 2. when a transitioned object expires (based on an ILM rule). -func expireTransitionedObject(ctx context.Context, objectAPI ObjectLayer, oi *ObjectInfo, lcOpts lifecycle.ObjectOpts, lcEvent lifecycle.Event) error { +func expireTransitionedObject(ctx context.Context, objectAPI ObjectLayer, oi *ObjectInfo, lcOpts lifecycle.ObjectOpts, lcEvent lifecycle.Event, src lcEventSrc) error { traceFn := globalLifecycleSys.trace(*oi) var opts ObjectOptions opts.Versioned = globalBucketVersioningSys.PrefixEnabled(oi.Bucket, oi.Name) opts.VersionID = lcOpts.VersionID opts.Expiration = ExpirationOptions{Expire: true} - tags := auditLifecycleTags(lcEvent) + tags := newLifecycleAuditEvent(src, lcEvent).Tags() if lcEvent.Action.DeleteRestored() { // delete locally restored copy of object or object version // from the source, while leaving metadata behind. The data on @@ -449,18 +451,18 @@ func genTransitionObjName(bucket string) (string, error) { // storage specified by the transition ARN, the metadata is left behind on source cluster and original content // is moved to the transition tier. Note that in the case of encrypted objects, entire encrypted stream is moved // to the transition tier without decrypting or re-encrypting. -func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo, lcEvent lifecycle.Event) error { +func transitionObject(ctx context.Context, objectAPI ObjectLayer, oi ObjectInfo, lae lcAuditEvent) error { opts := ObjectOptions{ Transition: TransitionOptions{ Status: lifecycle.TransitionPending, - Tier: lcEvent.StorageClass, + Tier: lae.StorageClass, ETag: oi.ETag, }, - LifecycleEvent: lcEvent, - VersionID: oi.VersionID, - Versioned: globalBucketVersioningSys.PrefixEnabled(oi.Bucket, oi.Name), - VersionSuspended: globalBucketVersioningSys.PrefixSuspended(oi.Bucket, oi.Name), - MTime: oi.ModTime, + LifecycleAuditEvent: lae, + VersionID: oi.VersionID, + Versioned: globalBucketVersioningSys.PrefixEnabled(oi.Bucket, oi.Name), + VersionSuspended: globalBucketVersioningSys.PrefixSuspended(oi.Bucket, oi.Name), + MTime: oi.ModTime, } return objectAPI.TransitionObject(ctx, oi.Bucket, oi.Name, opts) } @@ -868,35 +870,3 @@ func (oi ObjectInfo) ToLifecycleOpts() lifecycle.ObjectOpts { TransitionStatus: oi.TransitionedObject.Status, } } - -func auditLifecycleTags(event lifecycle.Event) map[string]interface{} { - const ( - ilmAction = "ilm-action" - ilmDue = "ilm-due" - ilmRuleID = "ilm-rule-id" - ilmTier = "ilm-tier" - ilmNewerNoncurrentVersions = "ilm-newer-noncurrent-versions" - ilmNoncurrentDays = "ilm-noncurrent-days" - ) - tags := make(map[string]interface{}, 4) - tags[ilmAction] = event.Action.String() - tags[ilmRuleID] = event.RuleID - - if !event.Due.IsZero() { - tags[ilmDue] = event.Due - } - - // rule with Transition/NoncurrentVersionTransition in effect - if event.StorageClass != "" { - tags[ilmTier] = event.StorageClass - } - - // rule with NewernoncurrentVersions in effect - if event.NewerNoncurrentVersions > 0 { - tags[ilmNewerNoncurrentVersions] = event.NewerNoncurrentVersions - } - if event.NoncurrentDays > 0 { - tags[ilmNoncurrentDays] = event.NoncurrentDays - } - return tags -} diff --git a/cmd/data-scanner.go b/cmd/data-scanner.go index af116cbb9..c45320ceb 100644 --- a/cmd/data-scanner.go +++ b/cmd/data-scanner.go @@ -945,9 +945,9 @@ func (i *scannerItem) applyLifecycle(ctx context.Context, o ObjectLayer, oi Obje switch lcEvt.Action { case lifecycle.DeleteAction, lifecycle.DeleteVersionAction, lifecycle.DeleteRestoredAction, lifecycle.DeleteRestoredVersionAction: - return applyLifecycleAction(lcEvt, oi), 0 + return applyLifecycleAction(lcEvt, lcEventSrc_Scanner, oi), 0 case lifecycle.TransitionAction, lifecycle.TransitionVersionAction: - return applyLifecycleAction(lcEvt, oi), size + return applyLifecycleAction(lcEvt, lcEventSrc_Scanner, oi), size default: // No action. return false, size @@ -1154,16 +1154,16 @@ func evalActionFromLifecycle(ctx context.Context, lc lifecycle.Lifecycle, lr loc return event } -func applyTransitionRule(event lifecycle.Event, obj ObjectInfo) bool { +func applyTransitionRule(event lifecycle.Event, src lcEventSrc, obj ObjectInfo) bool { if obj.DeleteMarker { return false } - globalTransitionState.queueTransitionTask(obj, event) + globalTransitionState.queueTransitionTask(obj, event, src) return true } -func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, lcEvent lifecycle.Event) bool { - if err := expireTransitionedObject(ctx, objLayer, &obj, obj.ToLifecycleOpts(), lcEvent); err != nil { +func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, lcEvent lifecycle.Event, src lcEventSrc) bool { + if err := expireTransitionedObject(ctx, objLayer, &obj, obj.ToLifecycleOpts(), lcEvent, src); err != nil { if isErrObjectNotFound(err) || isErrVersionNotFound(err) { return false } @@ -1174,7 +1174,7 @@ func applyExpiryOnTransitionedObject(ctx context.Context, objLayer ObjectLayer, return true } -func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, lcEvent lifecycle.Event) bool { +func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLayer, obj ObjectInfo, lcEvent lifecycle.Event, src lcEventSrc) bool { traceFn := globalLifecycleSys.trace(obj) opts := ObjectOptions{ Expiration: ExpirationOptions{Expire: true}, @@ -1198,7 +1198,7 @@ func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLay return false } - tags := auditLifecycleTags(lcEvent) + tags := newLifecycleAuditEvent(src, lcEvent).Tags() // Send audit for the lifecycle delete operation auditLogLifecycle(ctx, obj, ILMExpiry, tags, traceFn) @@ -1220,19 +1220,19 @@ func applyExpiryOnNonTransitionedObjects(ctx context.Context, objLayer ObjectLay } // Apply object, object version, restored object or restored object version action on the given object -func applyExpiryRule(event lifecycle.Event, obj ObjectInfo) bool { - globalExpiryState.enqueueByDays(obj, event) +func applyExpiryRule(event lifecycle.Event, src lcEventSrc, obj ObjectInfo) bool { + globalExpiryState.enqueueByDays(obj, event, src) return true } // Perform actions (removal or transitioning of objects), return true the action is successfully performed -func applyLifecycleAction(event lifecycle.Event, obj ObjectInfo) (success bool) { +func applyLifecycleAction(event lifecycle.Event, src lcEventSrc, obj ObjectInfo) (success bool) { switch action := event.Action; action { case lifecycle.DeleteVersionAction, lifecycle.DeleteAction, lifecycle.DeleteRestoredAction, lifecycle.DeleteRestoredVersionAction: - success = applyExpiryRule(event, obj) + success = applyExpiryRule(event, src, obj) case lifecycle.TransitionAction, lifecycle.TransitionVersionAction: - success = applyTransitionRule(event, obj) + success = applyTransitionRule(event, src, obj) } return } diff --git a/cmd/erasure-object.go b/cmd/erasure-object.go index ad8b4ae0c..ae5648c59 100644 --- a/cmd/erasure-object.go +++ b/cmd/erasure-object.go @@ -2004,7 +2004,7 @@ func (er erasureObjects) TransitionObject(ctx context.Context, bucket, object st UserAgent: "Internal: [ILM-Transition]", Host: globalLocalNodeName, }) - tags := auditLifecycleTags(opts.LifecycleEvent) + tags := opts.LifecycleAuditEvent.Tags() auditLogLifecycle(ctx, objInfo, ILMTransition, tags, traceFn) return err } diff --git a/cmd/erasure-server-pool-decom.go b/cmd/erasure-server-pool-decom.go index df545d6d2..2acd0e211 100644 --- a/cmd/erasure-server-pool-decom.go +++ b/cmd/erasure-server-pool-decom.go @@ -694,10 +694,10 @@ func (z *erasureServerPools) decommissionPool(ctx context.Context, idx int, pool evt := evalActionFromLifecycle(ctx, *lc, lr, objInfo) switch { case evt.Action.DeleteRestored(): // if restored copy has expired,delete it synchronously - applyExpiryOnTransitionedObject(ctx, z, objInfo, evt) + applyExpiryOnTransitionedObject(ctx, z, objInfo, evt, lcEventSrc_Decom) return false case evt.Action.Delete(): - globalExpiryState.enqueueByDays(objInfo, evt) + globalExpiryState.enqueueByDays(objInfo, evt, lcEventSrc_Decom) return true default: return false @@ -974,10 +974,10 @@ func (z *erasureServerPools) checkAfterDecom(ctx context.Context, idx int) error evt := evalActionFromLifecycle(ctx, *lc, lr, objInfo) switch { case evt.Action.DeleteRestored(): // if restored copy has expired,delete it synchronously - applyExpiryOnTransitionedObject(ctx, z, objInfo, evt) + applyExpiryOnTransitionedObject(ctx, z, objInfo, evt, lcEventSrc_Decom) return false case evt.Action.Delete(): - globalExpiryState.enqueueByDays(objInfo, evt) + globalExpiryState.enqueueByDays(objInfo, evt, lcEventSrc_Decom) return true default: return false diff --git a/cmd/erasure-server-pool-rebalance.go b/cmd/erasure-server-pool-rebalance.go index b41c5b47b..9248855af 100644 --- a/cmd/erasure-server-pool-rebalance.go +++ b/cmd/erasure-server-pool-rebalance.go @@ -466,7 +466,7 @@ func (z *erasureServerPools) rebalanceBucket(ctx context.Context, bucket string, evt := evalActionFromLifecycle(ctx, *lc, lr, objInfo) if evt.Action.Delete() { - globalExpiryState.enqueueByDays(objInfo, evt) + globalExpiryState.enqueueByDays(objInfo, evt, lcEventSrc_Rebal) return true } diff --git a/cmd/erasure-server-pool.go b/cmd/erasure-server-pool.go index 586cd0bdb..279cafeb8 100644 --- a/cmd/erasure-server-pool.go +++ b/cmd/erasure-server-pool.go @@ -1320,7 +1320,7 @@ func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, ma if opts.Lifecycle != nil { evt := evalActionFromLifecycle(ctx, *opts.Lifecycle, opts.Retention, objInfo) if evt.Action.Delete() { - globalExpiryState.enqueueByDays(objInfo, evt) + globalExpiryState.enqueueByDays(objInfo, evt, lcEventSrc_s3ListObjects) if !evt.Action.DeleteRestored() { // Skip entry if ILM action was DeleteVersionAction or DeleteAction return loi, nil diff --git a/cmd/lceventsrc_string.go b/cmd/lceventsrc_string.go new file mode 100644 index 000000000..e88d10b3b --- /dev/null +++ b/cmd/lceventsrc_string.go @@ -0,0 +1,32 @@ +// Code generated by "stringer -type lcEventSrc -trimprefix lcEventSrc_ bucket-lifecycle-audit.go"; DO NOT EDIT. + +package cmd + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[lcEventSrc_None-0] + _ = x[lcEventSrc_Scanner-1] + _ = x[lcEventSrc_Decom-2] + _ = x[lcEventSrc_Rebal-3] + _ = x[lcEventSrc_s3HeadObject-4] + _ = x[lcEventSrc_s3GetObject-5] + _ = x[lcEventSrc_s3ListObjects-6] + _ = x[lcEventSrc_s3PutObject-7] + _ = x[lcEventSrc_s3CopyObject-8] + _ = x[lcEventSrc_s3CompleteMultipartUpload-9] +} + +const _lcEventSrc_name = "NoneScannerDecomRebals3HeadObjects3GetObjects3ListObjectss3PutObjects3CopyObjects3CompleteMultipartUpload" + +var _lcEventSrc_index = [...]uint8{0, 4, 11, 16, 21, 33, 44, 57, 68, 80, 105} + +func (i lcEventSrc) String() string { + if i >= lcEventSrc(len(_lcEventSrc_index)-1) { + return "lcEventSrc(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _lcEventSrc_name[_lcEventSrc_index[i]:_lcEventSrc_index[i+1]] +} diff --git a/cmd/metacache-server-pool.go b/cmd/metacache-server-pool.go index 4c449588c..014ca526b 100644 --- a/cmd/metacache-server-pool.go +++ b/cmd/metacache-server-pool.go @@ -395,7 +395,7 @@ func applyBucketActions(ctx context.Context, o listPathOptions, in <-chan metaCa if o.Lifecycle != nil { evt := evalActionFromLifecycle(ctx, *o.Lifecycle, o.Retention, objInfo) if evt.Action.Delete() { - globalExpiryState.enqueueByDays(objInfo, evt) + globalExpiryState.enqueueByDays(objInfo, evt, lcEventSrc_s3ListObjects) if !evt.Action.DeleteRestored() { continue } // queue version for replication upon expired restored copies if needed. diff --git a/cmd/object-api-interface.go b/cmd/object-api-interface.go index f1a9271f4..ece68da71 100644 --- a/cmd/object-api-interface.go +++ b/cmd/object-api-interface.go @@ -28,7 +28,6 @@ import ( "github.com/minio/minio-go/v7/pkg/tags" "github.com/minio/minio/internal/hash" - "github.com/minio/minio/internal/bucket/lifecycle" "github.com/minio/minio/internal/bucket/replication" xioutil "github.com/minio/minio/internal/ioutil" ) @@ -54,14 +53,14 @@ type ObjectOptions struct { DeleteMarker bool // Is only set in DELETE operations for delete marker replication CheckDMReplicationReady bool // Is delete marker ready to be replicated - set only during HEAD - UserDefined map[string]string // only set in case of POST/PUT operations - PartNumber int // only useful in case of GetObject/HeadObject - CheckPrecondFn CheckPreconditionFn // only set during GetObject/HeadObject/CopyObjectPart preconditional valuation - EvalMetadataFn EvalMetadataFn // only set for retention settings, meant to be used only when updating metadata in-place. - DeleteReplication ReplicationState // Represents internal replication state needed for Delete replication - Transition TransitionOptions - Expiration ExpirationOptions - LifecycleEvent lifecycle.Event + UserDefined map[string]string // only set in case of POST/PUT operations + PartNumber int // only useful in case of GetObject/HeadObject + CheckPrecondFn CheckPreconditionFn // only set during GetObject/HeadObject/CopyObjectPart preconditional valuation + EvalMetadataFn EvalMetadataFn // only set for retention settings, meant to be used only when updating metadata in-place. + DeleteReplication ReplicationState // Represents internal replication state needed for Delete replication + Transition TransitionOptions + Expiration ExpirationOptions + LifecycleAuditEvent lcAuditEvent WantChecksum *hash.Checksum // x-amz-checksum-XXX checksum sent to PutObject/ CompleteMultipartUpload. diff --git a/cmd/object-handlers-common.go b/cmd/object-handlers-common.go index bcec5f300..ad03156d8 100644 --- a/cmd/object-handlers-common.go +++ b/cmd/object-handlers-common.go @@ -374,7 +374,8 @@ func deleteObjectVersions(ctx context.Context, o ObjectLayer, bucket string, toD VersionID: dobj.VersionID, } traceFn := globalLifecycleSys.trace(oi) - tags := auditLifecycleTags(lcEvent) + // Note: NewerNoncurrentVersions action is performed only scanner today + tags := newLifecycleAuditEvent(lcEventSrc_Scanner, lcEvent).Tags() // Send audit for the lifecycle delete operation auditLogLifecycle( diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index e81b6649f..fb1fc51b4 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -479,7 +479,7 @@ func (api objectAPIHandlers) getObjectHandler(ctx context.Context, objectAPI Obj event := evalActionFromLifecycle(ctx, *lc, rcfg, objInfo) if event.Action.Delete() { // apply whatever the expiry rule is. - applyExpiryRule(event, objInfo) + applyExpiryRule(event, lcEventSrc_s3GetObject, objInfo) if !event.Action.DeleteRestored() { // If the ILM action is not on restored object return error. writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey)) @@ -733,7 +733,7 @@ func (api objectAPIHandlers) headObjectHandler(ctx context.Context, objectAPI Ob event := evalActionFromLifecycle(ctx, *lc, rcfg, objInfo) if event.Action.Delete() { // apply whatever the expiry rule is. - applyExpiryRule(event, objInfo) + applyExpiryRule(event, lcEventSrc_s3HeadObject, objInfo) if !event.Action.DeleteRestored() { // If the ILM action is not on restored object return error. writeErrorResponseHeadersOnly(w, errorCodes.ToAPIErr(ErrNoSuchKey)) @@ -1560,7 +1560,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if !remoteCallRequired && !globalTierConfigMgr.Empty() { // Schedule object for immediate transition if eligible. objInfo.ETag = origETag - enqueueTransitionImmediate(objInfo) + enqueueTransitionImmediate(objInfo, lcEventSrc_s3CopyObject) // Remove the transitioned object whose object version is being overwritten. logger.LogIf(ctx, os.Sweep()) } @@ -1937,7 +1937,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req if !globalTierConfigMgr.Empty() { // Schedule object for immediate transition if eligible. objInfo.ETag = origETag - enqueueTransitionImmediate(objInfo) + enqueueTransitionImmediate(objInfo, lcEventSrc_s3PutObject) logger.LogIf(ctx, os.Sweep()) } } diff --git a/cmd/object-multipart-handlers.go b/cmd/object-multipart-handlers.go index e4331848a..6cf110cb1 100644 --- a/cmd/object-multipart-handlers.go +++ b/cmd/object-multipart-handlers.go @@ -1055,7 +1055,7 @@ func (api objectAPIHandlers) CompleteMultipartUploadHandler(w http.ResponseWrite // Remove the transitioned object whose object version is being overwritten. if !globalTierConfigMgr.Empty() { // Schedule object for immediate transition if eligible. - enqueueTransitionImmediate(objInfo) + enqueueTransitionImmediate(objInfo, lcEventSrc_s3CompleteMultipartUpload) logger.LogIf(ctx, os.Sweep()) } }