mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-11 23:56:53 +00:00
fix: populate tagging notification principalId and object metadata (#2342)
This commit is contained in:
@@ -817,12 +817,17 @@ pub async fn expire_transitioned_object(
|
||||
|
||||
//defer auditLogLifecycle(ctx, *oi, ILMExpiry, tags, traceFn)
|
||||
|
||||
let mut event_name = EventName::ObjectRemovedDelete;
|
||||
if oi.delete_marker {
|
||||
event_name = EventName::ObjectRemovedDeleteMarkerCreated;
|
||||
}
|
||||
let event_name = if oi.delete_marker {
|
||||
EventName::LifecycleExpirationDelete
|
||||
} else if dobj.delete_marker {
|
||||
EventName::LifecycleExpirationDeleteMarkerCreated
|
||||
} else {
|
||||
EventName::LifecycleExpirationDelete
|
||||
};
|
||||
let obj_info = ObjectInfo {
|
||||
bucket: oi.bucket.clone(),
|
||||
name: oi.name.clone(),
|
||||
size: oi.size,
|
||||
version_id: oi.version_id,
|
||||
delete_marker: oi.delete_marker,
|
||||
..Default::default()
|
||||
@@ -1230,15 +1235,12 @@ pub async fn apply_expiry_on_non_transitioned_objects(
|
||||
//let tags = LcAuditEvent::new(lc_event.clone(), src.clone()).tags();
|
||||
//tags["version-id"] = dobj.version_id;
|
||||
|
||||
let mut event_name = EventName::ObjectRemovedDelete;
|
||||
if oi.delete_marker {
|
||||
event_name = EventName::ObjectRemovedDeleteMarkerCreated;
|
||||
}
|
||||
match lc_event.action {
|
||||
IlmAction::DeleteAllVersionsAction => event_name = EventName::ObjectRemovedDeleteAllVersions,
|
||||
IlmAction::DelMarkerDeleteAllVersionsAction => event_name = EventName::LifecycleDelMarkerExpirationDelete,
|
||||
_ => (),
|
||||
}
|
||||
let event_name = match lc_event.action {
|
||||
IlmAction::DeleteAllVersionsAction | IlmAction::DelMarkerDeleteAllVersionsAction => EventName::LifecycleExpirationDelete,
|
||||
_ if oi.delete_marker => EventName::LifecycleExpirationDelete,
|
||||
_ if dobj.delete_marker => EventName::LifecycleExpirationDeleteMarkerCreated,
|
||||
_ => EventName::LifecycleExpirationDelete,
|
||||
};
|
||||
send_event(EventArgs {
|
||||
event_name: event_name.to_string(),
|
||||
bucket_name: dobj.bucket.clone(),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![allow(unused_variables)]
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -13,274 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Defines the EventName enum which represents the various S3 event types that can trigger notifications.
|
||||
//! This enum includes both specific event types (e.g., ObjectCreated:Put) and aggregate types (e.g., ObjectCreated:*). Each variant has methods to expand into its constituent event types and to compute a bitmask for efficient filtering.
|
||||
//! The EventName enum is used in the event notification system to determine which events should trigger notifications based on the configured rules.
|
||||
//!
|
||||
//! @Deprecated: This module is currently not fully implemented and serves as a placeholder for future development of the event notification system. The EventName enum and its associated methods are defined, but the actual logic for handling events and sending notifications is not yet implemented.
|
||||
//! Compatibility re-export for the legacy `rustfs_ecstore::event::name::EventName` path.
|
||||
//! The canonical event definition now lives in `rustfs_s3_common::EventName`.
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub enum EventName {
|
||||
ObjectAccessedGet,
|
||||
ObjectAccessedGetRetention,
|
||||
ObjectAccessedGetLegalHold,
|
||||
ObjectAccessedHead,
|
||||
ObjectAccessedAttributes,
|
||||
ObjectCreatedCompleteMultipartUpload,
|
||||
ObjectCreatedCopy,
|
||||
ObjectCreatedPost,
|
||||
ObjectCreatedPut,
|
||||
ObjectCreatedPutRetention,
|
||||
ObjectCreatedPutLegalHold,
|
||||
ObjectCreatedPutTagging,
|
||||
ObjectCreatedDeleteTagging,
|
||||
ObjectRemovedDelete,
|
||||
ObjectRemovedDeleteMarkerCreated,
|
||||
ObjectRemovedDeleteAllVersions,
|
||||
ObjectRemovedNoOP,
|
||||
BucketCreated,
|
||||
BucketRemoved,
|
||||
ObjectReplicationFailed,
|
||||
ObjectReplicationComplete,
|
||||
ObjectReplicationMissedThreshold,
|
||||
ObjectReplicationReplicatedAfterThreshold,
|
||||
ObjectReplicationNotTracked,
|
||||
ObjectRestorePost,
|
||||
ObjectRestoreCompleted,
|
||||
ObjectTransitionFailed,
|
||||
ObjectTransitionComplete,
|
||||
ObjectManyVersions,
|
||||
ObjectLargeVersions,
|
||||
PrefixManyFolders,
|
||||
ILMDelMarkerExpirationDelete,
|
||||
ObjectSingleTypesEnd,
|
||||
ObjectAccessedAll,
|
||||
ObjectCreatedAll,
|
||||
ObjectRemovedAll,
|
||||
ObjectReplicationAll,
|
||||
ObjectRestoreAll,
|
||||
ObjectTransitionAll,
|
||||
ObjectScannerAll,
|
||||
#[default]
|
||||
Everything,
|
||||
}
|
||||
|
||||
impl EventName {
|
||||
fn expand(&self) -> Vec<EventName> {
|
||||
match self.clone() {
|
||||
EventName::Everything => vec![
|
||||
EventName::BucketCreated,
|
||||
EventName::BucketRemoved,
|
||||
EventName::ObjectAccessedAll,
|
||||
EventName::ObjectCreatedAll,
|
||||
EventName::ObjectRemovedAll,
|
||||
EventName::ObjectManyVersions,
|
||||
EventName::ObjectLargeVersions,
|
||||
EventName::PrefixManyFolders,
|
||||
EventName::ILMDelMarkerExpirationDelete,
|
||||
EventName::ObjectReplicationAll,
|
||||
EventName::ObjectRestoreAll,
|
||||
EventName::ObjectTransitionAll,
|
||||
],
|
||||
EventName::ObjectAccessedAll => vec![
|
||||
EventName::ObjectAccessedGet,
|
||||
EventName::ObjectAccessedGetRetention,
|
||||
EventName::ObjectAccessedGetLegalHold,
|
||||
EventName::ObjectAccessedHead,
|
||||
EventName::ObjectAccessedAttributes,
|
||||
],
|
||||
EventName::ObjectCreatedAll => vec![
|
||||
EventName::ObjectCreatedCompleteMultipartUpload,
|
||||
EventName::ObjectCreatedCopy,
|
||||
EventName::ObjectCreatedPost,
|
||||
EventName::ObjectCreatedPut,
|
||||
EventName::ObjectCreatedPutRetention,
|
||||
EventName::ObjectCreatedPutLegalHold,
|
||||
EventName::ObjectCreatedPutTagging,
|
||||
EventName::ObjectCreatedDeleteTagging,
|
||||
],
|
||||
EventName::ObjectRemovedAll => vec![
|
||||
EventName::ObjectRemovedDelete,
|
||||
EventName::ObjectRemovedDeleteMarkerCreated,
|
||||
EventName::ObjectRemovedNoOP,
|
||||
EventName::ObjectRemovedDeleteAllVersions,
|
||||
],
|
||||
EventName::ObjectReplicationAll => vec![
|
||||
EventName::ObjectReplicationFailed,
|
||||
EventName::ObjectReplicationComplete,
|
||||
EventName::ObjectReplicationNotTracked,
|
||||
EventName::ObjectReplicationMissedThreshold,
|
||||
EventName::ObjectReplicationReplicatedAfterThreshold,
|
||||
],
|
||||
EventName::ObjectRestoreAll => vec![EventName::ObjectRestorePost, EventName::ObjectRestoreCompleted],
|
||||
EventName::ObjectTransitionAll => vec![EventName::ObjectTransitionFailed, EventName::ObjectTransitionComplete],
|
||||
EventName::ObjectSingleTypesEnd | EventName::ObjectScannerAll => vec![self.clone()],
|
||||
_ => vec![self.clone()],
|
||||
}
|
||||
}
|
||||
|
||||
fn mask(&self) -> u64 {
|
||||
match self {
|
||||
EventName::Everything => u64::MAX,
|
||||
EventName::BucketCreated => 1_u64 << 0,
|
||||
EventName::BucketRemoved => 1_u64 << 1,
|
||||
EventName::ObjectAccessedGet => 1_u64 << 2,
|
||||
EventName::ObjectAccessedGetRetention => 1_u64 << 3,
|
||||
EventName::ObjectAccessedGetLegalHold => 1_u64 << 4,
|
||||
EventName::ObjectAccessedHead => 1_u64 << 5,
|
||||
EventName::ObjectAccessedAttributes => 1_u64 << 6,
|
||||
EventName::ObjectCreatedCompleteMultipartUpload => 1_u64 << 7,
|
||||
EventName::ObjectCreatedCopy => 1_u64 << 8,
|
||||
EventName::ObjectCreatedPost => 1_u64 << 9,
|
||||
EventName::ObjectCreatedPut => 1_u64 << 10,
|
||||
EventName::ObjectCreatedPutRetention => 1_u64 << 11,
|
||||
EventName::ObjectCreatedPutLegalHold => 1_u64 << 12,
|
||||
EventName::ObjectCreatedPutTagging => 1_u64 << 13,
|
||||
EventName::ObjectCreatedDeleteTagging => 1_u64 << 14,
|
||||
EventName::ObjectRemovedDelete => 1_u64 << 15,
|
||||
EventName::ObjectRemovedDeleteMarkerCreated => 1_u64 << 16,
|
||||
EventName::ObjectRemovedDeleteAllVersions => 1_u64 << 17,
|
||||
EventName::ObjectRemovedNoOP => 1_u64 << 18,
|
||||
EventName::ObjectManyVersions => 1_u64 << 19,
|
||||
EventName::ObjectLargeVersions => 1_u64 << 20,
|
||||
EventName::PrefixManyFolders => 1_u64 << 21,
|
||||
EventName::ILMDelMarkerExpirationDelete => 1_u64 << 22,
|
||||
EventName::ObjectReplicationFailed => 1_u64 << 23,
|
||||
EventName::ObjectReplicationComplete => 1_u64 << 24,
|
||||
EventName::ObjectReplicationMissedThreshold => 1_u64 << 25,
|
||||
EventName::ObjectReplicationReplicatedAfterThreshold => 1_u64 << 26,
|
||||
EventName::ObjectReplicationNotTracked => 1_u64 << 27,
|
||||
EventName::ObjectRestorePost => 1_u64 << 28,
|
||||
EventName::ObjectRestoreCompleted => 1_u64 << 29,
|
||||
EventName::ObjectRestoreAll => 1_u64 << 30,
|
||||
EventName::ObjectTransitionFailed => 1_u64 << 31,
|
||||
EventName::ObjectTransitionComplete => 1_u64 << 32,
|
||||
EventName::ObjectAccessedAll => {
|
||||
EventName::ObjectAccessedGet.mask()
|
||||
| EventName::ObjectAccessedGetRetention.mask()
|
||||
| EventName::ObjectAccessedGetLegalHold.mask()
|
||||
| EventName::ObjectAccessedHead.mask()
|
||||
| EventName::ObjectAccessedAttributes.mask()
|
||||
}
|
||||
EventName::ObjectCreatedAll => {
|
||||
EventName::ObjectCreatedCompleteMultipartUpload.mask()
|
||||
| EventName::ObjectCreatedCopy.mask()
|
||||
| EventName::ObjectCreatedPost.mask()
|
||||
| EventName::ObjectCreatedPut.mask()
|
||||
| EventName::ObjectCreatedPutRetention.mask()
|
||||
| EventName::ObjectCreatedPutLegalHold.mask()
|
||||
| EventName::ObjectCreatedPutTagging.mask()
|
||||
| EventName::ObjectCreatedDeleteTagging.mask()
|
||||
}
|
||||
EventName::ObjectRemovedAll => {
|
||||
EventName::ObjectRemovedDelete.mask()
|
||||
| EventName::ObjectRemovedDeleteMarkerCreated.mask()
|
||||
| EventName::ObjectRemovedNoOP.mask()
|
||||
| EventName::ObjectRemovedDeleteAllVersions.mask()
|
||||
}
|
||||
EventName::ObjectReplicationAll => {
|
||||
EventName::ObjectReplicationFailed.mask()
|
||||
| EventName::ObjectReplicationComplete.mask()
|
||||
| EventName::ObjectReplicationMissedThreshold.mask()
|
||||
| EventName::ObjectReplicationReplicatedAfterThreshold.mask()
|
||||
| EventName::ObjectReplicationNotTracked.mask()
|
||||
}
|
||||
EventName::ObjectTransitionAll => {
|
||||
EventName::ObjectTransitionFailed.mask() | EventName::ObjectTransitionComplete.mask()
|
||||
}
|
||||
EventName::ObjectSingleTypesEnd | EventName::ObjectScannerAll => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for EventName {
|
||||
fn as_ref(&self) -> &str {
|
||||
match self {
|
||||
EventName::BucketCreated => "s3:BucketCreated:*",
|
||||
EventName::BucketRemoved => "s3:BucketRemoved:*",
|
||||
EventName::ObjectAccessedAll => "s3:ObjectAccessed:*",
|
||||
EventName::ObjectAccessedGet => "s3:ObjectAccessed:Get",
|
||||
EventName::ObjectAccessedGetRetention => "s3:ObjectAccessed:GetRetention",
|
||||
EventName::ObjectAccessedGetLegalHold => "s3:ObjectAccessed:GetLegalHold",
|
||||
EventName::ObjectAccessedHead => "s3:ObjectAccessed:Head",
|
||||
EventName::ObjectAccessedAttributes => "s3:ObjectAccessed:Attributes",
|
||||
EventName::ObjectCreatedAll => "s3:ObjectCreated:*",
|
||||
EventName::ObjectCreatedCompleteMultipartUpload => "s3:ObjectCreated:CompleteMultipartUpload",
|
||||
EventName::ObjectCreatedCopy => "s3:ObjectCreated:Copy",
|
||||
EventName::ObjectCreatedPost => "s3:ObjectCreated:Post",
|
||||
EventName::ObjectCreatedPut => "s3:ObjectCreated:Put",
|
||||
EventName::ObjectCreatedPutTagging => "s3:ObjectCreated:PutTagging",
|
||||
EventName::ObjectCreatedDeleteTagging => "s3:ObjectCreated:DeleteTagging",
|
||||
EventName::ObjectCreatedPutRetention => "s3:ObjectCreated:PutRetention",
|
||||
EventName::ObjectCreatedPutLegalHold => "s3:ObjectCreated:PutLegalHold",
|
||||
EventName::ObjectRemovedAll => "s3:ObjectRemoved:*",
|
||||
EventName::ObjectRemovedDelete => "s3:ObjectRemoved:Delete",
|
||||
EventName::ObjectRemovedDeleteMarkerCreated => "s3:ObjectRemoved:DeleteMarkerCreated",
|
||||
EventName::ObjectRemovedNoOP => "s3:ObjectRemoved:NoOP",
|
||||
EventName::ObjectRemovedDeleteAllVersions => "s3:ObjectRemoved:DeleteAllVersions",
|
||||
EventName::ILMDelMarkerExpirationDelete => "s3:LifecycleDelMarkerExpiration:Delete",
|
||||
EventName::ObjectReplicationAll => "s3:Replication:*",
|
||||
EventName::ObjectReplicationFailed => "s3:Replication:OperationFailedReplication",
|
||||
EventName::ObjectReplicationComplete => "s3:Replication:OperationCompletedReplication",
|
||||
EventName::ObjectReplicationNotTracked => "s3:Replication:OperationNotTracked",
|
||||
EventName::ObjectReplicationMissedThreshold => "s3:Replication:OperationMissedThreshold",
|
||||
EventName::ObjectReplicationReplicatedAfterThreshold => "s3:Replication:OperationReplicatedAfterThreshold",
|
||||
EventName::ObjectRestoreAll => "s3:ObjectRestore:*",
|
||||
EventName::ObjectRestorePost => "s3:ObjectRestore:Post",
|
||||
EventName::ObjectRestoreCompleted => "s3:ObjectRestore:Completed",
|
||||
EventName::ObjectTransitionAll => "s3:ObjectTransition:*",
|
||||
EventName::ObjectTransitionFailed => "s3:ObjectTransition:Failed",
|
||||
EventName::ObjectTransitionComplete => "s3:ObjectTransition:Complete",
|
||||
EventName::ObjectManyVersions => "s3:Scanner:ManyVersions",
|
||||
EventName::ObjectLargeVersions => "s3:Scanner:LargeVersions",
|
||||
EventName::PrefixManyFolders => "s3:Scanner:BigPrefix",
|
||||
_ => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for EventName {
|
||||
fn from(s: &str) -> Self {
|
||||
match s {
|
||||
"s3:BucketCreated:*" => EventName::BucketCreated,
|
||||
"s3:BucketRemoved:*" => EventName::BucketRemoved,
|
||||
"s3:ObjectAccessed:*" => EventName::ObjectAccessedAll,
|
||||
"s3:ObjectAccessed:Get" => EventName::ObjectAccessedGet,
|
||||
"s3:ObjectAccessed:GetRetention" => EventName::ObjectAccessedGetRetention,
|
||||
"s3:ObjectAccessed:GetLegalHold" => EventName::ObjectAccessedGetLegalHold,
|
||||
"s3:ObjectAccessed:Head" => EventName::ObjectAccessedHead,
|
||||
"s3:ObjectAccessed:Attributes" => EventName::ObjectAccessedAttributes,
|
||||
"s3:ObjectCreated:*" => EventName::ObjectCreatedAll,
|
||||
"s3:ObjectCreated:CompleteMultipartUpload" => EventName::ObjectCreatedCompleteMultipartUpload,
|
||||
"s3:ObjectCreated:Copy" => EventName::ObjectCreatedCopy,
|
||||
"s3:ObjectCreated:Post" => EventName::ObjectCreatedPost,
|
||||
"s3:ObjectCreated:Put" => EventName::ObjectCreatedPut,
|
||||
"s3:ObjectCreated:PutRetention" => EventName::ObjectCreatedPutRetention,
|
||||
"s3:ObjectCreated:PutLegalHold" => EventName::ObjectCreatedPutLegalHold,
|
||||
"s3:ObjectCreated:PutTagging" => EventName::ObjectCreatedPutTagging,
|
||||
"s3:ObjectCreated:DeleteTagging" => EventName::ObjectCreatedDeleteTagging,
|
||||
"s3:ObjectRemoved:*" => EventName::ObjectRemovedAll,
|
||||
"s3:ObjectRemoved:Delete" => EventName::ObjectRemovedDelete,
|
||||
"s3:ObjectRemoved:DeleteMarkerCreated" => EventName::ObjectRemovedDeleteMarkerCreated,
|
||||
"s3:ObjectRemoved:NoOP" => EventName::ObjectRemovedNoOP,
|
||||
"s3:ObjectRemoved:DeleteAllVersions" => EventName::ObjectRemovedDeleteAllVersions,
|
||||
"s3:LifecycleDelMarkerExpiration:Delete" => EventName::ILMDelMarkerExpirationDelete,
|
||||
"s3:Replication:*" => EventName::ObjectReplicationAll,
|
||||
"s3:Replication:OperationFailedReplication" => EventName::ObjectReplicationFailed,
|
||||
"s3:Replication:OperationCompletedReplication" => EventName::ObjectReplicationComplete,
|
||||
"s3:Replication:OperationMissedThreshold" => EventName::ObjectReplicationMissedThreshold,
|
||||
"s3:Replication:OperationReplicatedAfterThreshold" => EventName::ObjectReplicationReplicatedAfterThreshold,
|
||||
"s3:Replication:OperationNotTracked" => EventName::ObjectReplicationNotTracked,
|
||||
"s3:ObjectRestore:*" => EventName::ObjectRestoreAll,
|
||||
"s3:ObjectRestore:Post" => EventName::ObjectRestorePost,
|
||||
"s3:ObjectRestore:Completed" => EventName::ObjectRestoreCompleted,
|
||||
"s3:ObjectTransition:Failed" => EventName::ObjectTransitionFailed,
|
||||
"s3:ObjectTransition:Complete" => EventName::ObjectTransitionComplete,
|
||||
"s3:ObjectTransition:*" => EventName::ObjectTransitionAll,
|
||||
"s3:Scanner:ManyVersions" => EventName::ObjectManyVersions,
|
||||
"s3:Scanner:LargeVersions" => EventName::ObjectLargeVersions,
|
||||
"s3:Scanner:BigPrefix" => EventName::PrefixManyFolders,
|
||||
_ => EventName::Everything,
|
||||
}
|
||||
}
|
||||
}
|
||||
pub use rustfs_s3_common::EventName;
|
||||
|
||||
@@ -1882,12 +1882,19 @@ impl ObjectOperations for SetDisks {
|
||||
fi.transitioned_objname = dest_obj;
|
||||
fi.transition_tier = opts.transition.tier.clone();
|
||||
fi.transition_version_id = if rv.is_empty() { None } else { Some(Uuid::parse_str(&rv)?) };
|
||||
let mut event_name = EventName::ObjectTransitionComplete.as_str();
|
||||
let event_name = EventName::LifecycleTransition.as_str();
|
||||
let mut should_notify_transition = true;
|
||||
|
||||
let disks = self.get_disks(0, 0).await?;
|
||||
|
||||
if let Err(err) = self.delete_object_version(bucket, object, &fi, false).await {
|
||||
event_name = EventName::ObjectTransitionFailed.as_str();
|
||||
should_notify_transition = false;
|
||||
warn!(
|
||||
bucket = bucket,
|
||||
object = object,
|
||||
error = ?err,
|
||||
"transition completed on remote tier but source cleanup failed; skipping external lifecycle transition notification"
|
||||
);
|
||||
}
|
||||
|
||||
for disk in disks.iter() {
|
||||
@@ -1898,15 +1905,17 @@ impl ObjectOperations for SetDisks {
|
||||
break;
|
||||
}
|
||||
|
||||
let obj_info = ObjectInfo::from_file_info(&fi, bucket, object, opts.versioned || opts.version_suspended);
|
||||
send_event(EventArgs {
|
||||
event_name: event_name.to_string(),
|
||||
bucket_name: bucket.to_string(),
|
||||
object: obj_info,
|
||||
user_agent: "Internal: [ILM-Transition]".to_string(),
|
||||
host: GLOBAL_LocalNodeName.to_string(),
|
||||
..Default::default()
|
||||
});
|
||||
if should_notify_transition {
|
||||
let obj_info = ObjectInfo::from_file_info(&fi, bucket, object, opts.versioned || opts.version_suspended);
|
||||
send_event(EventArgs {
|
||||
event_name: event_name.to_string(),
|
||||
bucket_name: bucket.to_string(),
|
||||
object: obj_info,
|
||||
user_agent: "Internal: [ILM-Transition]".to_string(),
|
||||
host: GLOBAL_LocalNodeName.to_string(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
//let tags = opts.lifecycle_audit_event.tags();
|
||||
//auditLogLifecycle(ctx, objInfo, ILMTransition, tags, traceFn)
|
||||
Ok(())
|
||||
@@ -1961,10 +1970,19 @@ impl ObjectOperations for SetDisks {
|
||||
false,
|
||||
)?;
|
||||
let mut p_reader = PutObjReader::new(hash_reader);
|
||||
return if let Err(err) = self_.clone().put_object(bucket, object, &mut p_reader, &ropts).await {
|
||||
set_restore_header_fn(&mut oi, Some(to_object_err(err, vec![bucket, object]))).await
|
||||
} else {
|
||||
Ok(())
|
||||
return match self_.clone().put_object(bucket, object, &mut p_reader, &ropts).await {
|
||||
Ok(restored_info) => {
|
||||
send_event(EventArgs {
|
||||
event_name: EventName::ObjectRestoreCompleted.as_str().to_string(),
|
||||
bucket_name: bucket.to_string(),
|
||||
object: restored_info,
|
||||
user_agent: "Internal: [Restore-Completed]".to_string(),
|
||||
host: GLOBAL_LocalNodeName.to_string(),
|
||||
..Default::default()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
Err(err) => set_restore_header_fn(&mut oi, Some(to_object_err(err, vec![bucket, object]))).await,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2055,7 +2073,7 @@ impl ObjectOperations for SetDisks {
|
||||
checksum_crc64nvme: None,
|
||||
});
|
||||
}
|
||||
if let Err(err) = self_
|
||||
let restored_info = match self_
|
||||
.clone()
|
||||
.complete_multipart_upload(
|
||||
bucket,
|
||||
@@ -2069,8 +2087,17 @@ impl ObjectOperations for SetDisks {
|
||||
)
|
||||
.await
|
||||
{
|
||||
return set_restore_header_fn(&mut oi, Some(err)).await;
|
||||
}
|
||||
Ok(info) => info,
|
||||
Err(err) => return set_restore_header_fn(&mut oi, Some(err)).await,
|
||||
};
|
||||
send_event(EventArgs {
|
||||
event_name: EventName::ObjectRestoreCompleted.as_str().to_string(),
|
||||
bucket_name: bucket.to_string(),
|
||||
object: restored_info,
|
||||
user_agent: "Internal: [Restore-Completed]".to_string(),
|
||||
host: GLOBAL_LocalNodeName.to_string(),
|
||||
..Default::default()
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
axum = { workspace = true }
|
||||
rustfs-utils = { workspace = true, features = ["path", "sys"] }
|
||||
serde_json = { workspace = true }
|
||||
time = { workspace = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
+117
-3
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use chrono::{DateTime, SecondsFormat, Utc};
|
||||
use hashbrown::HashMap;
|
||||
use rustfs_s3_common::EventName;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -90,6 +90,21 @@ pub struct Source {
|
||||
pub user_agent: String,
|
||||
}
|
||||
|
||||
/// Additional data included for restore-completed events.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct GlacierEventData {
|
||||
pub restore_event_data: RestoreEventData,
|
||||
}
|
||||
|
||||
/// Restore-specific event attributes for `s3:ObjectRestore:Completed`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RestoreEventData {
|
||||
pub lifecycle_restoration_expiry_time: String,
|
||||
pub lifecycle_restore_storage_class: String,
|
||||
}
|
||||
|
||||
/// Represents a storage event
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@@ -112,11 +127,33 @@ pub struct Event {
|
||||
pub response_elements: HashMap<String, String>,
|
||||
/// Metadata about the event
|
||||
pub s3: Metadata,
|
||||
/// Additional restore event data when present.
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub glacier_event_data: Option<GlacierEventData>,
|
||||
/// Information about the source of the event
|
||||
pub source: Source,
|
||||
}
|
||||
|
||||
impl Event {
|
||||
fn event_version_for(event_name: EventName) -> &'static str {
|
||||
match event_name {
|
||||
EventName::ObjectReplicationFailed
|
||||
| EventName::ObjectReplicationComplete
|
||||
| EventName::ObjectReplicationMissedThreshold
|
||||
| EventName::ObjectReplicationReplicatedAfterThreshold
|
||||
| EventName::ObjectReplicationNotTracked => "2.2",
|
||||
EventName::ObjectRestoreCompleted
|
||||
| EventName::ObjectAclPut
|
||||
| EventName::ObjectTaggingPut
|
||||
| EventName::ObjectTaggingDelete
|
||||
| EventName::LifecycleExpirationDelete
|
||||
| EventName::LifecycleExpirationDeleteMarkerCreated
|
||||
| EventName::LifecycleTransition
|
||||
| EventName::IntelligentTiering => "2.3",
|
||||
_ => "2.1",
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a test event for a given bucket and object
|
||||
pub fn new_test_event(bucket: &str, key: &str, event_name: EventName) -> Self {
|
||||
let mut user_metadata = HashMap::new();
|
||||
@@ -139,7 +176,7 @@ impl Event {
|
||||
user_metadata.insert("x-request-time".to_string(), Utc::now().to_rfc3339());
|
||||
|
||||
Event {
|
||||
event_version: "2.1".to_string(),
|
||||
event_version: Self::event_version_for(event_name).to_string(),
|
||||
event_source: "rustfs:s3".to_string(),
|
||||
aws_region: "us-east-1".to_string(),
|
||||
event_time: Utc::now(),
|
||||
@@ -169,6 +206,7 @@ impl Event {
|
||||
sequencer: "0055AED6DCD90281E5".to_string(),
|
||||
},
|
||||
},
|
||||
glacier_event_data: None,
|
||||
source: Source {
|
||||
host: "127.0.0.1".to_string(),
|
||||
port: "9000".to_string(),
|
||||
@@ -237,8 +275,25 @@ impl Event {
|
||||
s3_metadata.object.user_metadata = Some(user_metadata);
|
||||
}
|
||||
|
||||
let glacier_event_data = if args.event_name == EventName::ObjectRestoreCompleted {
|
||||
args.object.restore_expires.and_then(|expiry| {
|
||||
let expiry_time = DateTime::<Utc>::from_timestamp(expiry.unix_timestamp(), expiry.nanosecond())?;
|
||||
let storage_class = args.object.storage_class.clone().or_else(|| {
|
||||
(!args.object.transitioned_object.tier.is_empty()).then_some(args.object.transitioned_object.tier.clone())
|
||||
})?;
|
||||
Some(GlacierEventData {
|
||||
restore_event_data: RestoreEventData {
|
||||
lifecycle_restoration_expiry_time: expiry_time.to_rfc3339_opts(SecondsFormat::Millis, true),
|
||||
lifecycle_restore_storage_class: storage_class,
|
||||
},
|
||||
})
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Self {
|
||||
event_version: "2.1".to_string(),
|
||||
event_version: Self::event_version_for(args.event_name).to_string(),
|
||||
event_source: "rustfs:s3".to_string(),
|
||||
aws_region: args.req_params.get("region").cloned().unwrap_or_default(),
|
||||
event_time: event_time.and_utc(),
|
||||
@@ -247,6 +302,7 @@ impl Event {
|
||||
request_parameters: args.req_params,
|
||||
response_elements: resp_elements,
|
||||
s3: s3_metadata,
|
||||
glacier_event_data,
|
||||
source: Source {
|
||||
host: args.host,
|
||||
port: if args.port == 0 {
|
||||
@@ -410,3 +466,61 @@ impl EventArgsBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn new_test_event_uses_aws_compatible_event_versions() {
|
||||
let acl_event = Event::new_test_event("bucket", "key", EventName::ObjectAclPut);
|
||||
assert_eq!(acl_event.event_version, "2.3");
|
||||
|
||||
let tagging_event = Event::new_test_event("bucket", "key", EventName::ObjectTaggingPut);
|
||||
assert_eq!(tagging_event.event_version, "2.3");
|
||||
|
||||
let lifecycle_event = Event::new_test_event("bucket", "key", EventName::LifecycleExpirationDelete);
|
||||
assert_eq!(lifecycle_event.event_version, "2.3");
|
||||
|
||||
let put_event = Event::new_test_event("bucket", "key", EventName::ObjectCreatedPut);
|
||||
assert_eq!(put_event.event_version, "2.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn event_new_uses_aws_compatible_event_versions() {
|
||||
let args = EventArgsBuilder::new(
|
||||
EventName::LifecycleTransition,
|
||||
"bucket",
|
||||
rustfs_ecstore::store_api::ObjectInfo {
|
||||
bucket: "bucket".to_string(),
|
||||
name: "key".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.build();
|
||||
let event = Event::new(args);
|
||||
assert_eq!(event.event_version, "2.3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn object_restore_completed_includes_glacier_event_data() {
|
||||
let args = EventArgsBuilder::new(
|
||||
EventName::ObjectRestoreCompleted,
|
||||
"bucket",
|
||||
rustfs_ecstore::store_api::ObjectInfo {
|
||||
bucket: "bucket".to_string(),
|
||||
name: "key".to_string(),
|
||||
restore_expires: Some(time::OffsetDateTime::from_unix_timestamp(1_700_000_000).unwrap()),
|
||||
storage_class: Some("GLACIER".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.build();
|
||||
let event = Event::new(args);
|
||||
|
||||
assert_eq!(event.event_version, "2.3");
|
||||
let glacier = event.glacier_event_data.expect("glacier event data should be present");
|
||||
assert_eq!(glacier.restore_event_data.lifecycle_restoration_expiry_time, "2023-11-14T22:13:20.000Z");
|
||||
assert_eq!(glacier.restore_event_data.lifecycle_restore_storage_class, "GLACIER");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,16 +417,12 @@ mod integration_tests {
|
||||
|
||||
let rules_map = config.get_rules_map();
|
||||
|
||||
// ObjectCreated:* should be expanded to all ObjectCreated events
|
||||
// AWS ObjectCreated:* should only include object creation operations.
|
||||
let event_types = [
|
||||
EventName::ObjectCreatedPut,
|
||||
EventName::ObjectCreatedPost,
|
||||
EventName::ObjectCreatedCopy,
|
||||
EventName::ObjectCreatedCompleteMultipartUpload,
|
||||
EventName::ObjectCreatedPutRetention,
|
||||
EventName::ObjectCreatedPutLegalHold,
|
||||
EventName::ObjectCreatedPutTagging,
|
||||
EventName::ObjectCreatedDeleteTagging,
|
||||
];
|
||||
|
||||
for event_type in event_types {
|
||||
@@ -436,5 +432,8 @@ mod integration_tests {
|
||||
let targets = rules_map.match_rules(event_type, "data/file.csv");
|
||||
assert!(!targets.is_empty(), "Event {:?} should match", event_type);
|
||||
}
|
||||
|
||||
assert!(!rules_map.has_subscriber(&EventName::ObjectTaggingPut));
|
||||
assert!(!rules_map.has_subscriber(&EventName::ObjectTaggingDelete));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ impl std::error::Error for ParseEventNameError {}
|
||||
/// Based on AWS S3 event type and includes RustFS extension.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
|
||||
pub enum EventName {
|
||||
// Single event type (values are 1-32 for compatible mask logic)
|
||||
// Single event type (values are sequential for compatible mask logic)
|
||||
ObjectAccessedGet = 1,
|
||||
ObjectAccessedGetRetention = 2,
|
||||
ObjectAccessedGetLegalHold = 3,
|
||||
@@ -42,8 +42,8 @@ pub enum EventName {
|
||||
ObjectCreatedPut = 9,
|
||||
ObjectCreatedPutRetention = 10,
|
||||
ObjectCreatedPutLegalHold = 11,
|
||||
ObjectCreatedPutTagging = 12,
|
||||
ObjectCreatedDeleteTagging = 13,
|
||||
ObjectTaggingPut = 12,
|
||||
ObjectTaggingDelete = 13,
|
||||
ObjectRemovedDelete = 14,
|
||||
ObjectRemovedDeleteMarkerCreated = 15,
|
||||
ObjectRemovedDeleteAllVersions = 16,
|
||||
@@ -63,6 +63,11 @@ pub enum EventName {
|
||||
ScannerLargeVersions = 30, // ObjectLargeVersions corresponding to Go
|
||||
ScannerBigPrefix = 31, // PrefixManyFolders corresponding to Go
|
||||
LifecycleDelMarkerExpirationDelete = 32, // ILMDelMarkerExpirationDelete corresponding to Go
|
||||
ObjectAclPut = 33,
|
||||
LifecycleExpirationDelete = 34,
|
||||
LifecycleExpirationDeleteMarkerCreated = 35,
|
||||
LifecycleTransition = 36,
|
||||
IntelligentTiering = 37,
|
||||
|
||||
// Compound "All" event type (no sequential value for mask)
|
||||
ObjectAccessedAll,
|
||||
@@ -70,6 +75,8 @@ pub enum EventName {
|
||||
ObjectRemovedAll,
|
||||
ObjectReplicationAll,
|
||||
ObjectRestoreAll,
|
||||
ObjectTaggingAll,
|
||||
LifecycleExpirationAll,
|
||||
ObjectTransitionAll,
|
||||
ObjectScannerAll, // New, from Go
|
||||
#[default]
|
||||
@@ -94,8 +101,8 @@ const SINGLE_EVENT_NAMES_IN_ORDER: [EventName; 32] = [
|
||||
EventName::ObjectCreatedPut,
|
||||
EventName::ObjectCreatedPutRetention,
|
||||
EventName::ObjectCreatedPutLegalHold,
|
||||
EventName::ObjectCreatedPutTagging,
|
||||
EventName::ObjectCreatedDeleteTagging,
|
||||
EventName::ObjectTaggingPut,
|
||||
EventName::ObjectTaggingDelete,
|
||||
EventName::ObjectRemovedDelete,
|
||||
EventName::ObjectRemovedDeleteMarkerCreated,
|
||||
EventName::ObjectRemovedDeleteAllVersions,
|
||||
@@ -117,7 +124,15 @@ const SINGLE_EVENT_NAMES_IN_ORDER: [EventName; 32] = [
|
||||
EventName::LifecycleDelMarkerExpirationDelete,
|
||||
];
|
||||
|
||||
const LAST_SINGLE_TYPE_VALUE: u32 = EventName::LifecycleDelMarkerExpirationDelete as u32;
|
||||
const SINGLE_AWS_AND_EXTENSION_EVENTS_AFTER_COMPAT: [EventName; 5] = [
|
||||
EventName::ObjectAclPut,
|
||||
EventName::LifecycleExpirationDelete,
|
||||
EventName::LifecycleExpirationDeleteMarkerCreated,
|
||||
EventName::LifecycleTransition,
|
||||
EventName::IntelligentTiering,
|
||||
];
|
||||
|
||||
const LAST_SINGLE_TYPE_VALUE: u32 = EventName::IntelligentTiering as u32;
|
||||
|
||||
impl EventName {
|
||||
/// The parsed string is EventName.
|
||||
@@ -138,14 +153,21 @@ impl EventName {
|
||||
"s3:ObjectCreated:Put" => Ok(EventName::ObjectCreatedPut),
|
||||
"s3:ObjectCreated:PutRetention" => Ok(EventName::ObjectCreatedPutRetention),
|
||||
"s3:ObjectCreated:PutLegalHold" => Ok(EventName::ObjectCreatedPutLegalHold),
|
||||
"s3:ObjectCreated:PutTagging" => Ok(EventName::ObjectCreatedPutTagging),
|
||||
"s3:ObjectCreated:DeleteTagging" => Ok(EventName::ObjectCreatedDeleteTagging),
|
||||
"s3:ObjectCreated:PutTagging" => Ok(EventName::ObjectTaggingPut),
|
||||
"s3:ObjectCreated:DeleteTagging" => Ok(EventName::ObjectTaggingDelete),
|
||||
"s3:ObjectTagging:*" => Ok(EventName::ObjectTaggingAll),
|
||||
"s3:ObjectTagging:Put" => Ok(EventName::ObjectTaggingPut),
|
||||
"s3:ObjectTagging:Delete" => Ok(EventName::ObjectTaggingDelete),
|
||||
"s3:ObjectAcl:Put" => Ok(EventName::ObjectAclPut),
|
||||
"s3:ObjectRemoved:*" => Ok(EventName::ObjectRemovedAll),
|
||||
"s3:ObjectRemoved:Delete" => Ok(EventName::ObjectRemovedDelete),
|
||||
"s3:ObjectRemoved:DeleteMarkerCreated" => Ok(EventName::ObjectRemovedDeleteMarkerCreated),
|
||||
"s3:ObjectRemoved:NoOP" => Ok(EventName::ObjectRemovedNoOP),
|
||||
"s3:ObjectRemoved:DeleteAllVersions" => Ok(EventName::ObjectRemovedDeleteAllVersions),
|
||||
"s3:LifecycleDelMarkerExpiration:Delete" => Ok(EventName::LifecycleDelMarkerExpirationDelete),
|
||||
"s3:LifecycleDelMarkerExpiration:Delete" => Ok(EventName::LifecycleExpirationDeleteMarkerCreated),
|
||||
"s3:LifecycleExpiration:*" => Ok(EventName::LifecycleExpirationAll),
|
||||
"s3:LifecycleExpiration:Delete" => Ok(EventName::LifecycleExpirationDelete),
|
||||
"s3:LifecycleExpiration:DeleteMarkerCreated" => Ok(EventName::LifecycleExpirationDeleteMarkerCreated),
|
||||
"s3:Replication:*" => Ok(EventName::ObjectReplicationAll),
|
||||
"s3:Replication:OperationFailedReplication" => Ok(EventName::ObjectReplicationFailed),
|
||||
"s3:Replication:OperationCompletedReplication" => Ok(EventName::ObjectReplicationComplete),
|
||||
@@ -156,8 +178,10 @@ impl EventName {
|
||||
"s3:ObjectRestore:Post" => Ok(EventName::ObjectRestorePost),
|
||||
"s3:ObjectRestore:Completed" => Ok(EventName::ObjectRestoreCompleted),
|
||||
"s3:ObjectTransition:Failed" => Ok(EventName::ObjectTransitionFailed),
|
||||
"s3:ObjectTransition:Complete" => Ok(EventName::ObjectTransitionComplete),
|
||||
"s3:ObjectTransition:Complete" => Ok(EventName::LifecycleTransition),
|
||||
"s3:ObjectTransition:*" => Ok(EventName::ObjectTransitionAll),
|
||||
"s3:LifecycleTransition" => Ok(EventName::LifecycleTransition),
|
||||
"s3:IntelligentTiering" => Ok(EventName::IntelligentTiering),
|
||||
"s3:Scanner:ManyVersions" => Ok(EventName::ScannerManyVersions),
|
||||
"s3:Scanner:LargeVersions" => Ok(EventName::ScannerLargeVersions),
|
||||
"s3:Scanner:BigPrefix" => Ok(EventName::ScannerBigPrefix),
|
||||
@@ -182,16 +206,21 @@ impl EventName {
|
||||
EventName::ObjectCreatedCopy => "s3:ObjectCreated:Copy",
|
||||
EventName::ObjectCreatedPost => "s3:ObjectCreated:Post",
|
||||
EventName::ObjectCreatedPut => "s3:ObjectCreated:Put",
|
||||
EventName::ObjectCreatedPutTagging => "s3:ObjectCreated:PutTagging",
|
||||
EventName::ObjectCreatedDeleteTagging => "s3:ObjectCreated:DeleteTagging",
|
||||
EventName::ObjectCreatedPutRetention => "s3:ObjectCreated:PutRetention",
|
||||
EventName::ObjectCreatedPutLegalHold => "s3:ObjectCreated:PutLegalHold",
|
||||
EventName::ObjectTaggingAll => "s3:ObjectTagging:*",
|
||||
EventName::ObjectTaggingPut => "s3:ObjectTagging:Put",
|
||||
EventName::ObjectTaggingDelete => "s3:ObjectTagging:Delete",
|
||||
EventName::ObjectAclPut => "s3:ObjectAcl:Put",
|
||||
EventName::ObjectRemovedAll => "s3:ObjectRemoved:*",
|
||||
EventName::ObjectRemovedDelete => "s3:ObjectRemoved:Delete",
|
||||
EventName::ObjectRemovedDeleteMarkerCreated => "s3:ObjectRemoved:DeleteMarkerCreated",
|
||||
EventName::ObjectRemovedNoOP => "s3:ObjectRemoved:NoOP",
|
||||
EventName::ObjectRemovedDeleteAllVersions => "s3:ObjectRemoved:DeleteAllVersions",
|
||||
EventName::LifecycleDelMarkerExpirationDelete => "s3:LifecycleDelMarkerExpiration:Delete",
|
||||
EventName::LifecycleExpirationAll => "s3:LifecycleExpiration:*",
|
||||
EventName::LifecycleExpirationDelete => "s3:LifecycleExpiration:Delete",
|
||||
EventName::LifecycleExpirationDeleteMarkerCreated => "s3:LifecycleExpiration:DeleteMarkerCreated",
|
||||
EventName::ObjectReplicationAll => "s3:Replication:*",
|
||||
EventName::ObjectReplicationFailed => "s3:Replication:OperationFailedReplication",
|
||||
EventName::ObjectReplicationComplete => "s3:Replication:OperationCompletedReplication",
|
||||
@@ -204,6 +233,8 @@ impl EventName {
|
||||
EventName::ObjectTransitionAll => "s3:ObjectTransition:*",
|
||||
EventName::ObjectTransitionFailed => "s3:ObjectTransition:Failed",
|
||||
EventName::ObjectTransitionComplete => "s3:ObjectTransition:Complete",
|
||||
EventName::LifecycleTransition => "s3:LifecycleTransition",
|
||||
EventName::IntelligentTiering => "s3:IntelligentTiering",
|
||||
EventName::ScannerManyVersions => "s3:Scanner:ManyVersions",
|
||||
EventName::ScannerLargeVersions => "s3:Scanner:LargeVersions",
|
||||
EventName::ScannerBigPrefix => "s3:Scanner:BigPrefix",
|
||||
@@ -231,17 +262,9 @@ impl EventName {
|
||||
EventName::ObjectCreatedCopy,
|
||||
EventName::ObjectCreatedPost,
|
||||
EventName::ObjectCreatedPut,
|
||||
EventName::ObjectCreatedPutRetention,
|
||||
EventName::ObjectCreatedPutLegalHold,
|
||||
EventName::ObjectCreatedPutTagging,
|
||||
EventName::ObjectCreatedDeleteTagging,
|
||||
],
|
||||
EventName::ObjectRemovedAll => vec![
|
||||
EventName::ObjectRemovedDelete,
|
||||
EventName::ObjectRemovedDeleteMarkerCreated,
|
||||
EventName::ObjectRemovedNoOP,
|
||||
EventName::ObjectRemovedDeleteAllVersions,
|
||||
],
|
||||
EventName::ObjectTaggingAll => vec![EventName::ObjectTaggingPut, EventName::ObjectTaggingDelete],
|
||||
EventName::ObjectRemovedAll => vec![EventName::ObjectRemovedDelete, EventName::ObjectRemovedDeleteMarkerCreated],
|
||||
EventName::ObjectReplicationAll => vec![
|
||||
EventName::ObjectReplicationFailed,
|
||||
EventName::ObjectReplicationComplete,
|
||||
@@ -250,7 +273,15 @@ impl EventName {
|
||||
EventName::ObjectReplicationReplicatedAfterThreshold,
|
||||
],
|
||||
EventName::ObjectRestoreAll => vec![EventName::ObjectRestorePost, EventName::ObjectRestoreCompleted],
|
||||
EventName::ObjectTransitionAll => vec![EventName::ObjectTransitionFailed, EventName::ObjectTransitionComplete],
|
||||
EventName::LifecycleExpirationAll => vec![
|
||||
EventName::LifecycleExpirationDelete,
|
||||
EventName::LifecycleExpirationDeleteMarkerCreated,
|
||||
],
|
||||
EventName::ObjectTransitionAll => vec![
|
||||
EventName::ObjectTransitionFailed,
|
||||
EventName::ObjectTransitionComplete,
|
||||
EventName::LifecycleTransition,
|
||||
],
|
||||
EventName::ObjectScannerAll => vec![
|
||||
// New
|
||||
EventName::ScannerManyVersions,
|
||||
@@ -259,7 +290,9 @@ impl EventName {
|
||||
],
|
||||
EventName::Everything => {
|
||||
// New
|
||||
SINGLE_EVENT_NAMES_IN_ORDER.to_vec()
|
||||
let mut all = SINGLE_EVENT_NAMES_IN_ORDER.to_vec();
|
||||
all.extend(SINGLE_AWS_AND_EXTENSION_EVENTS_AFTER_COMPAT);
|
||||
all
|
||||
}
|
||||
// A single type returns to itself directly
|
||||
_ => vec![*self],
|
||||
@@ -299,8 +332,9 @@ impl EventName {
|
||||
EventName::ObjectCreatedPut => Some(S3Operation::PutObject),
|
||||
EventName::ObjectCreatedPutRetention => Some(S3Operation::PutObjectRetention),
|
||||
EventName::ObjectCreatedPutLegalHold => Some(S3Operation::PutObjectLegalHold),
|
||||
EventName::ObjectCreatedPutTagging => Some(S3Operation::PutObjectTagging),
|
||||
EventName::ObjectCreatedDeleteTagging => Some(S3Operation::DeleteObjectTagging),
|
||||
EventName::ObjectTaggingPut => Some(S3Operation::PutObjectTagging),
|
||||
EventName::ObjectTaggingDelete => Some(S3Operation::DeleteObjectTagging),
|
||||
EventName::ObjectAclPut => Some(S3Operation::PutObjectAcl),
|
||||
EventName::ObjectRemovedDelete => Some(S3Operation::DeleteObject),
|
||||
EventName::ObjectRemovedDeleteMarkerCreated => Some(S3Operation::DeleteObject),
|
||||
EventName::ObjectRemovedDeleteAllVersions => Some(S3Operation::DeleteObject),
|
||||
@@ -497,16 +531,17 @@ impl S3Operation {
|
||||
Self::DeleteBucket => Some(EventName::BucketRemoved),
|
||||
Self::DeleteObject => Some(EventName::ObjectRemovedDelete),
|
||||
Self::DeleteObjects => Some(EventName::ObjectRemovedDeleteObjects),
|
||||
Self::DeleteObjectTagging => Some(EventName::ObjectCreatedDeleteTagging),
|
||||
Self::DeleteObjectTagging => Some(EventName::ObjectTaggingDelete),
|
||||
Self::GetObject => Some(EventName::ObjectAccessedGet),
|
||||
Self::GetObjectAttributes => Some(EventName::ObjectAccessedAttributes),
|
||||
Self::GetObjectLegalHold => Some(EventName::ObjectAccessedGetLegalHold),
|
||||
Self::GetObjectRetention => Some(EventName::ObjectAccessedGetRetention),
|
||||
Self::HeadObject => Some(EventName::ObjectAccessedHead),
|
||||
Self::PutObject => Some(EventName::ObjectCreatedPut),
|
||||
Self::PutObjectAcl => Some(EventName::ObjectAclPut),
|
||||
Self::PutObjectLegalHold => Some(EventName::ObjectCreatedPutLegalHold),
|
||||
Self::PutObjectRetention => Some(EventName::ObjectCreatedPutRetention),
|
||||
Self::PutObjectTagging => Some(EventName::ObjectCreatedPutTagging),
|
||||
Self::PutObjectTagging => Some(EventName::ObjectTaggingPut),
|
||||
Self::RestoreObject => Some(EventName::ObjectRestorePost),
|
||||
Self::SelectObjectContent => Some(EventName::ObjectAccessedGet),
|
||||
Self::AbortMultipartUpload => Some(EventName::ObjectRemovedAbortMultipartUpload),
|
||||
@@ -541,6 +576,10 @@ mod tests {
|
||||
event: EventName::ObjectCreatedPut,
|
||||
serialized_str: "\"s3:ObjectCreated:Put\"",
|
||||
},
|
||||
TestCase {
|
||||
event: EventName::ObjectTaggingPut,
|
||||
serialized_str: "\"s3:ObjectTagging:Put\"",
|
||||
},
|
||||
];
|
||||
|
||||
for case in &test_cases {
|
||||
@@ -574,6 +613,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_s3_operation_to_event_name() {
|
||||
assert_eq!(S3Operation::PutObject.to_event_name(), Some(EventName::ObjectCreatedPut));
|
||||
assert_eq!(S3Operation::PutObjectAcl.to_event_name(), Some(EventName::ObjectAclPut));
|
||||
assert_eq!(S3Operation::PutObjectTagging.to_event_name(), Some(EventName::ObjectTaggingPut));
|
||||
assert_eq!(S3Operation::DeleteObjectTagging.to_event_name(), Some(EventName::ObjectTaggingDelete));
|
||||
assert_eq!(S3Operation::GetObject.to_event_name(), Some(EventName::ObjectAccessedGet));
|
||||
assert_eq!(S3Operation::ListBuckets.to_event_name(), None);
|
||||
assert_eq!(S3Operation::RestoreObject.to_event_name(), Some(EventName::ObjectRestorePost));
|
||||
@@ -587,6 +629,9 @@ mod tests {
|
||||
#[test]
|
||||
fn test_event_name_to_s3_operation() {
|
||||
assert_eq!(EventName::ObjectCreatedPut.to_s3_operation(), Some(S3Operation::PutObject));
|
||||
assert_eq!(EventName::ObjectAclPut.to_s3_operation(), Some(S3Operation::PutObjectAcl));
|
||||
assert_eq!(EventName::ObjectTaggingPut.to_s3_operation(), Some(S3Operation::PutObjectTagging));
|
||||
assert_eq!(EventName::ObjectTaggingDelete.to_s3_operation(), Some(S3Operation::DeleteObjectTagging));
|
||||
assert_eq!(EventName::ObjectAccessedGet.to_s3_operation(), Some(S3Operation::GetObject));
|
||||
assert_eq!(EventName::BucketCreated.to_s3_operation(), Some(S3Operation::CreateBucket));
|
||||
assert_eq!(EventName::Everything.to_s3_operation(), None);
|
||||
@@ -597,4 +642,32 @@ mod tests {
|
||||
Some(S3Operation::AbortMultipartUpload)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_event_name_aliases_parse_to_aws_compatible_variants() {
|
||||
assert_eq!(EventName::parse("s3:ObjectCreated:PutTagging").unwrap(), EventName::ObjectTaggingPut);
|
||||
assert_eq!(
|
||||
EventName::parse("s3:ObjectCreated:DeleteTagging").unwrap(),
|
||||
EventName::ObjectTaggingDelete
|
||||
);
|
||||
assert_eq!(EventName::parse("s3:ObjectTransition:Complete").unwrap(), EventName::LifecycleTransition);
|
||||
assert_eq!(
|
||||
EventName::parse("s3:LifecycleDelMarkerExpiration:Delete").unwrap(),
|
||||
EventName::LifecycleExpirationDeleteMarkerCreated
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_object_created_all_expansion_matches_aws_scope() {
|
||||
let expanded = EventName::ObjectCreatedAll.expand();
|
||||
assert_eq!(
|
||||
expanded,
|
||||
vec![
|
||||
EventName::ObjectCreatedCompleteMultipartUpload,
|
||||
EventName::ObjectCreatedCopy,
|
||||
EventName::ObjectCreatedPost,
|
||||
EventName::ObjectCreatedPut,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user