diff --git a/cmd/event-notification.go b/cmd/event-notification.go index cba7e4ab2..9f56c4968 100644 --- a/cmd/event-notification.go +++ b/cmd/event-notification.go @@ -225,7 +225,11 @@ func (args eventArgs) ToEvent(escape bool) event.Event { }, } - if args.EventName != event.ObjectRemovedDelete && args.EventName != event.ObjectRemovedDeleteMarkerCreated { + isRemovedEvent := args.EventName == event.ObjectRemovedDelete || + args.EventName == event.ObjectRemovedDeleteMarkerCreated || + args.EventName == event.ObjectRemovedNoOP + + if !isRemovedEvent { newEvent.S3.Object.ETag = args.Object.ETag newEvent.S3.Object.Size = args.Object.Size newEvent.S3.Object.ContentType = args.Object.ContentType diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index 4cfbc1316..5db412d92 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -2891,6 +2891,18 @@ func (api objectAPIHandlers) DeleteObjectHandler(w http.ResponseWriter, r *http. return } if isErrObjectNotFound(err) || isErrVersionNotFound(err) { + // Send an event when the object is not found + objInfo.Name = object + objInfo.VersionID = opts.VersionID + sendEvent(eventArgs{ + EventName: event.ObjectRemovedNoOP, + BucketName: bucket, + Object: objInfo, + ReqParams: extractReqParams(r), + RespElements: extractRespElements(w), + UserAgent: r.UserAgent(), + Host: handlers.GetSourceIP(r), + }) writeSuccessNoContent(w) return } diff --git a/internal/event/name.go b/internal/event/name.go index 966c7e7b0..3f13cad82 100644 --- a/internal/event/name.go +++ b/internal/event/name.go @@ -47,6 +47,7 @@ const ( ObjectCreatedDeleteTagging ObjectRemovedDelete ObjectRemovedDeleteMarkerCreated + ObjectRemovedNoOP BucketCreated BucketRemoved ObjectReplicationFailed @@ -98,6 +99,7 @@ func (name Name) Expand() []Name { return []Name{ ObjectRemovedDelete, ObjectRemovedDeleteMarkerCreated, + ObjectRemovedNoOP, } case ObjectReplicationAll: return []Name{ @@ -189,6 +191,8 @@ func (name Name) String() string { return "s3:ObjectRemoved:Delete" case ObjectRemovedDeleteMarkerCreated: return "s3:ObjectRemoved:DeleteMarkerCreated" + case ObjectRemovedNoOP: + return "s3:ObjectRemoved:NoOP" case ObjectReplicationAll: return "s3:Replication:*" case ObjectReplicationFailed: @@ -307,6 +311,8 @@ func ParseName(s string) (Name, error) { return ObjectRemovedDelete, nil case "s3:ObjectRemoved:DeleteMarkerCreated": return ObjectRemovedDeleteMarkerCreated, nil + case "s3:ObjectRemoved:NoOP": + return ObjectRemovedNoOP, nil case "s3:Replication:*": return ObjectReplicationAll, nil case "s3:Replication:OperationFailedReplication": diff --git a/internal/event/name_test.go b/internal/event/name_test.go index 0e0f748b6..130ff7036 100644 --- a/internal/event/name_test.go +++ b/internal/event/name_test.go @@ -36,7 +36,7 @@ func TestNameExpand(t *testing.T) { ObjectCreatedCompleteMultipartUpload, ObjectCreatedCopy, ObjectCreatedPost, ObjectCreatedPut, ObjectCreatedPutRetention, ObjectCreatedPutLegalHold, ObjectCreatedPutTagging, ObjectCreatedDeleteTagging, }}, - {ObjectRemovedAll, []Name{ObjectRemovedDelete, ObjectRemovedDeleteMarkerCreated}}, + {ObjectRemovedAll, []Name{ObjectRemovedDelete, ObjectRemovedDeleteMarkerCreated, ObjectRemovedNoOP}}, {ObjectAccessedHead, []Name{ObjectAccessedHead}}, } @@ -68,6 +68,7 @@ func TestNameString(t *testing.T) { {ObjectCreatedPut, "s3:ObjectCreated:Put"}, {ObjectRemovedAll, "s3:ObjectRemoved:*"}, {ObjectRemovedDelete, "s3:ObjectRemoved:Delete"}, + {ObjectRemovedNoOP, "s3:ObjectRemoved:NoOP"}, {ObjectCreatedPutRetention, "s3:ObjectCreated:PutRetention"}, {ObjectCreatedPutLegalHold, "s3:ObjectCreated:PutLegalHold"}, {ObjectAccessedGetRetention, "s3:ObjectAccessed:GetRetention"}, @@ -95,6 +96,7 @@ func TestNameMarshalXML(t *testing.T) { }{ {ObjectAccessedAll, []byte("s3:ObjectAccessed:*"), false}, {ObjectRemovedDelete, []byte("s3:ObjectRemoved:Delete"), false}, + {ObjectRemovedNoOP, []byte("s3:ObjectRemoved:NoOP"), false}, {blankName, []byte(""), false}, } @@ -124,6 +126,7 @@ func TestNameUnmarshalXML(t *testing.T) { }{ {[]byte("s3:ObjectAccessed:*"), ObjectAccessedAll, false}, {[]byte("s3:ObjectRemoved:Delete"), ObjectRemovedDelete, false}, + {[]byte("s3:ObjectRemoved:NoOP"), ObjectRemovedNoOP, false}, {[]byte(""), blankName, true}, } @@ -154,6 +157,7 @@ func TestNameMarshalJSON(t *testing.T) { }{ {ObjectAccessedAll, []byte(`"s3:ObjectAccessed:*"`), false}, {ObjectRemovedDelete, []byte(`"s3:ObjectRemoved:Delete"`), false}, + {ObjectRemovedNoOP, []byte(`"s3:ObjectRemoved:NoOP"`), false}, {blankName, []byte(`""`), false}, } @@ -183,6 +187,7 @@ func TestNameUnmarshalJSON(t *testing.T) { }{ {[]byte(`"s3:ObjectAccessed:*"`), ObjectAccessedAll, false}, {[]byte(`"s3:ObjectRemoved:Delete"`), ObjectRemovedDelete, false}, + {[]byte(`"s3:ObjectRemoved:NoOP"`), ObjectRemovedNoOP, false}, {[]byte(`""`), blankName, true}, } @@ -213,6 +218,7 @@ func TestParseName(t *testing.T) { }{ {"s3:ObjectAccessed:*", ObjectAccessedAll, false}, {"s3:ObjectRemoved:Delete", ObjectRemovedDelete, false}, + {"s3:ObjectRemoved:NoOP", ObjectRemovedNoOP, false}, {"", blankName, true}, }