Feature/bucket event notification (#365)

* add tracing instrument

* fix rebalance/decom

* modify Telemetry filter order

* feat: improve address binding and port handling mechanism (#366)

* feat: improve address binding and port handling mechanism

1. Add support for ":port" format to enable dual-stack binding (IPv4/IPv6)
2. Implement automatic port allocation when port 0 is specified
3. Optimize server startup process with unified address resolution
4. Enhance error handling and logging for address resolution
5. Improve graceful shutdown with signal listening
6. Clean up commented code in console.rs

Files:
- ecstore/src/utils/net.rs
- rustfs/src/console.rs
- rustfs/src/main.rs

Branch: feature/server-and-console-port

* improve code for console

* improve code

* improve code for console and net.rs

* Update rustfs/src/main.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update rustfs/src/utils/mod.rs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* upgrade config file

* modify

* fix readme

Signed-off-by: junxiang Mu <1948535941@qq.com>

* improve readme.md

* improve code for readme.md
add chinese readme.md

* Implement Storage Service Event Notification System

Added event notification capability to the storage module, enabling the storage service to publish object operation events. Key changes include:

1. Created `event_notifier` module providing core functionality:
   - `create_metadata()` - Creates event metadata objects with default configuration ID
   - `send_event()` - Asynchronously sends event notifications with error handling

2. Integrated the `rustfs_event_notifier` library:
   - Supports object creation, deletion, and access events
   - Provides event metadata building and management
   - Includes proper error propagation

These changes enable the system to trigger notifications when storage operations occur, facilitating auditing, monitoring, and integration with other systems.

* fix

---------

Signed-off-by: junxiang Mu <1948535941@qq.com>
Co-authored-by: weisd <im@weisd.in>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: junxiang Mu <1948535941@qq.com>
This commit is contained in:
houseme
2025-04-30 00:31:55 +08:00
committed by GitHub
parent 08f7de2e33
commit 01d5383ce3
11 changed files with 230 additions and 3 deletions
+1
View File
@@ -20,6 +20,7 @@ pub(crate) struct ReqInfo {
pub version_id: Option<String>,
}
/// Authorizes the request based on the action and credentials.
pub async fn authorize_request<T>(req: &mut S3Request<T>, action: Action) -> S3Result<()> {
let req_info = req.extensions.get_mut::<ReqInfo>().expect("ReqInfo not found");
+6
View File
@@ -141,6 +141,7 @@ impl S3 for FS {
Ok(S3Response::new(output))
}
/// Copy an object from one location to another
#[tracing::instrument(level = "debug", skip(self, req))]
async fn copy_object(&self, req: S3Request<CopyObjectInput>) -> S3Result<S3Response<CopyObjectOutput>> {
let CopyObjectInput {
@@ -227,6 +228,7 @@ impl S3 for FS {
Ok(S3Response::new(output))
}
/// Delete a bucket
#[tracing::instrument(level = "debug", skip(self, req))]
async fn delete_bucket(&self, req: S3Request<DeleteBucketInput>) -> S3Result<S3Response<DeleteBucketOutput>> {
let input = req.input;
@@ -249,6 +251,7 @@ impl S3 for FS {
Ok(S3Response::new(DeleteBucketOutput {}))
}
/// Delete an object
#[tracing::instrument(level = "debug", skip(self, req))]
async fn delete_object(&self, req: S3Request<DeleteObjectInput>) -> S3Result<S3Response<DeleteObjectOutput>> {
let DeleteObjectInput {
@@ -308,6 +311,7 @@ impl S3 for FS {
Ok(S3Response::new(output))
}
/// Delete multiple objects
#[tracing::instrument(level = "debug", skip(self, req))]
async fn delete_objects(&self, req: S3Request<DeleteObjectsInput>) -> S3Result<S3Response<DeleteObjectsOutput>> {
// info!("delete_objects args {:?}", req.input);
@@ -367,6 +371,7 @@ impl S3 for FS {
Ok(S3Response::new(output))
}
/// Get bucket location
#[tracing::instrument(level = "debug", skip(self, req))]
async fn get_bucket_location(&self, req: S3Request<GetBucketLocationInput>) -> S3Result<S3Response<GetBucketLocationOutput>> {
// mc get 1
@@ -385,6 +390,7 @@ impl S3 for FS {
Ok(S3Response::new(output))
}
/// Get bucket notification
#[tracing::instrument(
level = "debug",
skip(self, req),
+17
View File
@@ -0,0 +1,17 @@
use rustfs_event_notifier::{Event, Metadata};
/// Create a new metadata object
#[allow(dead_code)]
pub(crate) fn create_metadata() -> Metadata {
// Create a new metadata object
let mut metadata = Metadata::new();
metadata.set_configuration_id("test-config".to_string());
// Return the created metadata object
metadata
}
/// Create a new event object
#[allow(dead_code)]
pub(crate) async fn send_event(event: Event) -> Result<(), Box<dyn std::error::Error>> {
rustfs_event_notifier::send_event(event).await.map_err(|e| e.into())
}
+1
View File
@@ -1,4 +1,5 @@
pub mod access;
pub mod ecfs;
pub mod error;
mod event_notifier;
pub mod options;
+9
View File
@@ -8,6 +8,7 @@ use lazy_static::lazy_static;
use std::collections::HashMap;
use uuid::Uuid;
/// Creates options for deleting an object in a bucket.
pub async fn del_opts(
bucket: &str,
object: &str,
@@ -56,6 +57,7 @@ pub async fn del_opts(
Ok(opts)
}
/// Creates options for getting an object from a bucket.
pub async fn get_opts(
bucket: &str,
object: &str,
@@ -105,6 +107,7 @@ pub async fn get_opts(
Ok(opts)
}
/// Creates options for putting an object in a bucket.
pub async fn put_opts(
bucket: &str,
object: &str,
@@ -151,6 +154,7 @@ pub async fn put_opts(
Ok(opts)
}
/// Creates options for copying an object in a bucket.
pub async fn copy_dst_opts(
bucket: &str,
object: &str,
@@ -172,6 +176,7 @@ pub fn put_opts_from_headers(
get_default_opts(headers, metadata, false)
}
/// Creates default options for getting an object from a bucket.
pub fn get_default_opts(
_headers: &HeaderMap<HeaderValue>,
metadata: Option<HashMap<String, String>>,
@@ -183,6 +188,7 @@ pub fn get_default_opts(
})
}
/// Extracts metadata from headers and returns it as a HashMap.
pub fn extract_metadata(headers: &HeaderMap<HeaderValue>) -> HashMap<String, String> {
let mut metadata = HashMap::new();
@@ -191,6 +197,7 @@ pub fn extract_metadata(headers: &HeaderMap<HeaderValue>) -> HashMap<String, Str
metadata
}
/// Extracts metadata from headers and returns it as a HashMap.
pub fn extract_metadata_from_mime(headers: &HeaderMap<HeaderValue>, metadata: &mut HashMap<String, String>) {
for (k, v) in headers.iter() {
if let Some(key) = k.as_str().strip_prefix("x-amz-meta-") {
@@ -219,7 +226,9 @@ pub fn extract_metadata_from_mime(headers: &HeaderMap<HeaderValue>, metadata: &m
metadata.insert("content-type".to_owned(), "binary/octet-stream".to_owned());
}
}
lazy_static! {
/// List of supported headers.
static ref SUPPORTED_HEADERS: Vec<&'static str> = vec![
"content-type",
"cache-control",