feat(storage): integrate S3Operation into OperationHelper for unified metrics and audit (#2103)

This commit is contained in:
houseme
2026-03-08 17:57:33 +08:00
committed by GitHub
parent 8e4a1ef917
commit 60aa47bf61
39 changed files with 574 additions and 357 deletions
+1
View File
@@ -62,6 +62,7 @@ rustfs-policy = { workspace = true }
rustfs-protocols = { workspace = true }
rustfs-protos = { workspace = true }
rustfs-rio.workspace = true
rustfs-s3-common = { workspace = true }
rustfs-s3select-api = { workspace = true }
rustfs-s3select-query = { workspace = true }
rustfs-targets = { workspace = true }
+3 -2
View File
@@ -46,6 +46,7 @@ use rustfs_policy::policy::{
action::{Action, S3Action},
{BucketPolicy, BucketPolicyArgs, Effect, Validator},
};
use rustfs_s3_common::S3Operation;
use rustfs_targets::{
EventName,
arn::{ARN, TargetIDError},
@@ -145,7 +146,7 @@ impl DefaultBucketUsecase {
let _ = context.object_store();
}
let helper = OperationHelper::new(&req, EventName::BucketCreated, "s3:CreateBucket");
let helper = OperationHelper::new(&req, EventName::BucketCreated, S3Operation::CreateBucket);
let requester_id = match req_info_ref(&req) {
Ok(r) => r.cred.as_ref().map(|c| c.access_key.clone()),
Err(_) => {
@@ -239,7 +240,7 @@ impl DefaultBucketUsecase {
let _ = context.object_store();
}
let helper = OperationHelper::new(&req, EventName::BucketRemoved, "s3:DeleteBucket");
let helper = OperationHelper::new(&req, EventName::BucketRemoved, S3Operation::DeleteBucket);
let input = req.input.clone();
let Some(store) = new_object_layer_fn() else {
+7 -3
View File
@@ -43,6 +43,7 @@ use rustfs_ecstore::store_api::{CompletePart, HTTPRangeSpec, MultipartUploadResu
use rustfs_ecstore::store_api::{MultipartOperations, ObjectOperations};
use rustfs_filemeta::{ReplicationStatusType, ReplicationType};
use rustfs_rio::{CompressReader, HashReader, Reader, WarpReader};
use rustfs_s3_common::S3Operation;
use rustfs_targets::EventName;
use rustfs_utils::CompressionAlgorithm;
use rustfs_utils::http::{
@@ -145,8 +146,11 @@ impl DefaultMultipartUsecase {
let _ = context.object_store();
}
let mut helper =
OperationHelper::new(&req, EventName::ObjectCreatedCompleteMultipartUpload, "s3:CompleteMultipartUpload");
let mut helper = OperationHelper::new(
&req,
EventName::ObjectCreatedCompleteMultipartUpload,
S3Operation::CompleteMultipartUpload,
);
let input = req.input;
let CompleteMultipartUploadInput {
multipart_upload,
@@ -425,7 +429,7 @@ impl DefaultMultipartUsecase {
let _ = context.object_store();
}
let helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, "s3:CreateMultipartUpload");
let helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, S3Operation::CreateMultipartUpload);
let CreateMultipartUploadInput {
bucket,
key,
+15 -14
View File
@@ -74,6 +74,7 @@ use rustfs_filemeta::{
use rustfs_notify::EventArgsBuilder;
use rustfs_policy::policy::action::{Action, S3Action};
use rustfs_rio::{CompressReader, EtagReader, HashReader, Reader, WarpReader};
use rustfs_s3_common::S3Operation;
use rustfs_s3select_api::{
object_store::bytes_stream,
query::{Context, Query},
@@ -266,7 +267,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, "s3:PutObject");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, S3Operation::PutObject);
if req
.headers
.get("X-Amz-Meta-Snowball-Auto-Extract")
@@ -614,7 +615,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutLegalHold, "s3:PutObjectLegalHold");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutLegalHold, S3Operation::PutObjectLegalHold);
let PutObjectLegalHoldInput {
bucket,
key,
@@ -743,7 +744,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutRetention, "s3:PutObjectRetention");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutRetention, S3Operation::PutObjectRetention);
let PutObjectRetentionInput {
bucket,
key,
@@ -835,7 +836,7 @@ impl DefaultObjectUsecase {
}
let start_time = std::time::Instant::now();
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutTagging, "s3:PutObjectTagging");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedPutTagging, S3Operation::PutObjectTagging);
let PutObjectTaggingInput {
bucket,
key: object,
@@ -944,7 +945,7 @@ impl DefaultObjectUsecase {
debug!("GetObject request started with {} concurrent requests", concurrent_requests);
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGet, "s3:GetObject");
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGet, S3Operation::GetObject);
// mc get 3
let GetObjectInput {
@@ -1524,7 +1525,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedAttributes, "s3:GetObjectAttributes");
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedAttributes, S3Operation::GetObjectAttributes);
let GetObjectAttributesInput {
bucket,
key,
@@ -1756,7 +1757,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGetLegalHold, "s3:GetObjectLegalHold");
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGetLegalHold, S3Operation::GetObjectLegalHold);
let GetObjectLegalHoldInput {
bucket, key, version_id, ..
} = req.input.clone();
@@ -1847,7 +1848,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGetRetention, "s3:GetObjectRetention");
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedGetRetention, S3Operation::GetObjectRetention);
let GetObjectRetentionInput {
bucket, key, version_id, ..
} = req.input.clone();
@@ -1941,7 +1942,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedCopy, "s3:CopyObject");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedCopy, S3Operation::CopyObject);
let CopyObjectInput {
copy_source,
bucket,
@@ -2237,7 +2238,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let helper = OperationHelper::new(&req, EventName::ObjectRemovedDelete, "s3:DeleteObjects").suppress_event();
let helper = OperationHelper::new(&req, EventName::ObjectRemovedDelete, S3Operation::DeleteObjects).suppress_event();
let (bucket, delete) = {
let bucket = req.input.bucket.clone();
let delete = req.input.delete.clone();
@@ -2538,7 +2539,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectRemovedDelete, "s3:DeleteObject");
let mut helper = OperationHelper::new(&req, EventName::ObjectRemovedDelete, S3Operation::DeleteObject);
let DeleteObjectInput {
bucket, key, version_id, ..
} = req.input.clone();
@@ -2722,7 +2723,7 @@ impl DefaultObjectUsecase {
}
let start_time = std::time::Instant::now();
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedDeleteTagging, "s3:DeleteObjectTagging");
let mut helper = OperationHelper::new(&req, EventName::ObjectCreatedDeleteTagging, S3Operation::DeleteObjectTagging);
let DeleteObjectTaggingInput {
bucket,
key: object,
@@ -2776,7 +2777,7 @@ impl DefaultObjectUsecase {
let _ = context.object_store();
}
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedHead, "s3:HeadObject");
let mut helper = OperationHelper::new(&req, EventName::ObjectAccessedHead, S3Operation::HeadObject);
// mc get 2
let HeadObjectInput {
bucket,
@@ -3352,7 +3353,7 @@ impl DefaultObjectUsecase {
#[instrument(level = "debug", skip(self, req))]
pub async fn execute_put_object_extract(&self, req: S3Request<PutObjectInput>) -> S3Result<S3Response<PutObjectOutput>> {
let helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, "s3:PutObject").suppress_event();
let helper = OperationHelper::new(&req, EventName::ObjectCreatedPut, S3Operation::PutObject).suppress_event();
let input = req.input;
let PutObjectInput {
+2 -41
View File
@@ -15,13 +15,13 @@
use crate::app::bucket_usecase::DefaultBucketUsecase;
use crate::app::multipart_usecase::DefaultMultipartUsecase;
use crate::app::object_usecase::DefaultObjectUsecase;
use crate::storage::s3_metrics::{S3Operation, record_s3_op};
use rustfs_ecstore::{
bucket::tagging::decode_tags_to_map,
error::{is_err_bucket_not_found, is_err_object_not_found, is_err_version_not_found},
new_object_layer_fn,
store_api::{BucketOperations, BucketOptions, ObjectOperations, ObjectOptions},
};
use rustfs_s3_common::{S3Operation, record_s3_op};
use s3s::{S3, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, dto::*, s3_error};
use std::{fmt::Debug, sync::LazyLock};
use tokio::io::{AsyncRead, AsyncSeek};
@@ -98,7 +98,7 @@ impl AsyncSeek for InMemoryAsyncReader {
impl FS {
pub fn new() -> Self {
crate::storage::s3_metrics::init_s3_metrics();
rustfs_s3_common::init_s3_metrics();
Self {}
}
@@ -190,7 +190,6 @@ impl S3 for FS {
&self,
req: S3Request<AbortMultipartUploadInput>,
) -> S3Result<S3Response<AbortMultipartUploadOutput>> {
record_s3_op(S3Operation::AbortMultipartUpload, &req.input.bucket);
let usecase = DefaultMultipartUsecase::from_global();
usecase.execute_abort_multipart_upload(req).await
}
@@ -200,7 +199,6 @@ impl S3 for FS {
&self,
req: S3Request<CompleteMultipartUploadInput>,
) -> S3Result<S3Response<CompleteMultipartUploadOutput>> {
record_s3_op(S3Operation::CompleteMultipartUpload, &req.input.bucket);
let usecase = DefaultMultipartUsecase::from_global();
usecase.execute_complete_multipart_upload(req).await
}
@@ -208,7 +206,6 @@ impl S3 for FS {
/// Copy an object from one location to another
#[instrument(level = "debug", skip(self, req))]
async fn copy_object(&self, req: S3Request<CopyObjectInput>) -> S3Result<S3Response<CopyObjectOutput>> {
record_s3_op(S3Operation::CopyObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_copy_object(req).await
}
@@ -219,7 +216,6 @@ impl S3 for FS {
fields(start_time=?time::OffsetDateTime::now_utc())
)]
async fn create_bucket(&self, req: S3Request<CreateBucketInput>) -> S3Result<S3Response<CreateBucketOutput>> {
record_s3_op(S3Operation::CreateBucket, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_create_bucket(req).await
}
@@ -229,7 +225,6 @@ impl S3 for FS {
&self,
req: S3Request<CreateMultipartUploadInput>,
) -> S3Result<S3Response<CreateMultipartUploadOutput>> {
record_s3_op(S3Operation::CreateMultipartUpload, &req.input.bucket);
let usecase = DefaultMultipartUsecase::from_global();
usecase.execute_create_multipart_upload(req).await
}
@@ -237,14 +232,12 @@ impl S3 for FS {
/// Delete a bucket
#[instrument(level = "debug", skip(self, req))]
async fn delete_bucket(&self, req: S3Request<DeleteBucketInput>) -> S3Result<S3Response<DeleteBucketOutput>> {
record_s3_op(S3Operation::DeleteBucket, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket(req).await
}
#[instrument(level = "debug", skip(self))]
async fn delete_bucket_cors(&self, req: S3Request<DeleteBucketCorsInput>) -> S3Result<S3Response<DeleteBucketCorsOutput>> {
record_s3_op(S3Operation::DeleteBucketCors, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_cors(req).await
}
@@ -253,7 +246,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketEncryptionInput>,
) -> S3Result<S3Response<DeleteBucketEncryptionOutput>> {
record_s3_op(S3Operation::DeleteBucketEncryption, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_encryption(req).await
}
@@ -263,7 +255,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketLifecycleInput>,
) -> S3Result<S3Response<DeleteBucketLifecycleOutput>> {
record_s3_op(S3Operation::DeleteBucketLifecycle, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_lifecycle(req).await
}
@@ -272,7 +263,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketPolicyInput>,
) -> S3Result<S3Response<DeleteBucketPolicyOutput>> {
record_s3_op(S3Operation::DeleteBucketPolicy, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_policy(req).await
}
@@ -281,7 +271,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketReplicationInput>,
) -> S3Result<S3Response<DeleteBucketReplicationOutput>> {
record_s3_op(S3Operation::DeleteBucketReplication, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_replication(req).await
}
@@ -291,7 +280,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteBucketTaggingInput>,
) -> S3Result<S3Response<DeleteBucketTaggingOutput>> {
record_s3_op(S3Operation::DeleteBucketTagging, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_bucket_tagging(req).await
}
@@ -301,7 +289,6 @@ impl S3 for FS {
&self,
req: S3Request<DeletePublicAccessBlockInput>,
) -> S3Result<S3Response<DeletePublicAccessBlockOutput>> {
record_s3_op(S3Operation::DeletePublicAccessBlock, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_delete_public_access_block(req).await
}
@@ -309,7 +296,6 @@ impl S3 for FS {
/// Delete an object
#[instrument(level = "debug", skip(self, req))]
async fn delete_object(&self, req: S3Request<DeleteObjectInput>) -> S3Result<S3Response<DeleteObjectOutput>> {
record_s3_op(S3Operation::DeleteObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_delete_object(req).await
}
@@ -319,7 +305,6 @@ impl S3 for FS {
&self,
req: S3Request<DeleteObjectTaggingInput>,
) -> S3Result<S3Response<DeleteObjectTaggingOutput>> {
record_s3_op(S3Operation::DeleteObjectTagging, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_delete_object_tagging(req).await
}
@@ -327,7 +312,6 @@ impl S3 for FS {
/// Delete multiple objects
#[instrument(level = "debug", skip(self, req))]
async fn delete_objects(&self, req: S3Request<DeleteObjectsInput>) -> S3Result<S3Response<DeleteObjectsOutput>> {
record_s3_op(S3Operation::DeleteObjects, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_delete_objects(req).await
}
@@ -439,7 +423,6 @@ impl S3 for FS {
fields(start_time=?time::OffsetDateTime::now_utc())
)]
async fn get_object(&self, req: S3Request<GetObjectInput>) -> S3Result<S3Response<GetObjectOutput>> {
record_s3_op(S3Operation::GetObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_get_object(req).await
}
@@ -454,7 +437,6 @@ impl S3 for FS {
&self,
req: S3Request<GetObjectAttributesInput>,
) -> S3Result<S3Response<GetObjectAttributesOutput>> {
record_s3_op(S3Operation::GetObjectAttributes, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_get_object_attributes(req).await
}
@@ -463,7 +445,6 @@ impl S3 for FS {
&self,
req: S3Request<GetObjectLegalHoldInput>,
) -> S3Result<S3Response<GetObjectLegalHoldOutput>> {
record_s3_op(S3Operation::GetObjectLegalHold, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_get_object_legal_hold(req).await
}
@@ -482,7 +463,6 @@ impl S3 for FS {
&self,
req: S3Request<GetObjectRetentionInput>,
) -> S3Result<S3Response<GetObjectRetentionOutput>> {
record_s3_op(S3Operation::GetObjectRetention, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_get_object_retention(req).await
}
@@ -505,14 +485,12 @@ impl S3 for FS {
#[instrument(level = "debug", skip(self, req))]
async fn head_bucket(&self, req: S3Request<HeadBucketInput>) -> S3Result<S3Response<HeadBucketOutput>> {
record_s3_op(S3Operation::HeadBucket, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_head_bucket(req).await
}
#[instrument(level = "debug", skip(self, req))]
async fn head_object(&self, req: S3Request<HeadObjectInput>) -> S3Result<S3Response<HeadObjectOutput>> {
record_s3_op(S3Operation::HeadObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_head_object(req).await
}
@@ -565,14 +543,12 @@ impl S3 for FS {
}
async fn put_bucket_acl(&self, req: S3Request<PutBucketAclInput>) -> S3Result<S3Response<PutBucketAclOutput>> {
record_s3_op(S3Operation::PutBucketAcl, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_acl(req).await
}
#[instrument(level = "debug", skip(self))]
async fn put_bucket_cors(&self, req: S3Request<PutBucketCorsInput>) -> S3Result<S3Response<PutBucketCorsOutput>> {
record_s3_op(S3Operation::PutBucketCors, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_cors(req).await
}
@@ -605,7 +581,6 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketEncryptionInput>,
) -> S3Result<S3Response<PutBucketEncryptionOutput>> {
record_s3_op(S3Operation::PutBucketEncryption, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_encryption(req).await
}
@@ -615,7 +590,6 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketLifecycleConfigurationInput>,
) -> S3Result<S3Response<PutBucketLifecycleConfigurationOutput>> {
record_s3_op(S3Operation::PutBucketLifecycleConfiguration, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_lifecycle_configuration(req).await
}
@@ -624,13 +598,11 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketNotificationConfigurationInput>,
) -> S3Result<S3Response<PutBucketNotificationConfigurationOutput>> {
record_s3_op(S3Operation::PutBucketNotificationConfiguration, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_notification_configuration(req).await
}
async fn put_bucket_policy(&self, req: S3Request<PutBucketPolicyInput>) -> S3Result<S3Response<PutBucketPolicyOutput>> {
record_s3_op(S3Operation::PutBucketPolicy, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_policy(req).await
}
@@ -639,7 +611,6 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketReplicationInput>,
) -> S3Result<S3Response<PutBucketReplicationOutput>> {
record_s3_op(S3Operation::PutBucketReplication, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_replication(req).await
}
@@ -649,14 +620,12 @@ impl S3 for FS {
&self,
req: S3Request<PutPublicAccessBlockInput>,
) -> S3Result<S3Response<PutPublicAccessBlockOutput>> {
record_s3_op(S3Operation::PutPublicAccessBlock, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_public_access_block(req).await
}
#[instrument(level = "debug", skip(self))]
async fn put_bucket_tagging(&self, req: S3Request<PutBucketTaggingInput>) -> S3Result<S3Response<PutBucketTaggingOutput>> {
record_s3_op(S3Operation::PutBucketTagging, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_tagging(req).await
}
@@ -666,14 +635,12 @@ impl S3 for FS {
&self,
req: S3Request<PutBucketVersioningInput>,
) -> S3Result<S3Response<PutBucketVersioningOutput>> {
record_s3_op(S3Operation::PutBucketVersioning, &req.input.bucket);
let usecase = DefaultBucketUsecase::from_global();
usecase.execute_put_bucket_versioning(req).await
}
#[instrument(level = "debug", skip(self, req))]
async fn put_object(&self, req: S3Request<PutObjectInput>) -> S3Result<S3Response<PutObjectOutput>> {
record_s3_op(S3Operation::PutObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_put_object(self, req).await
}
@@ -688,7 +655,6 @@ impl S3 for FS {
&self,
req: S3Request<PutObjectLegalHoldInput>,
) -> S3Result<S3Response<PutObjectLegalHoldOutput>> {
record_s3_op(S3Operation::PutObjectLegalHold, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_put_object_legal_hold(req).await
}
@@ -698,7 +664,6 @@ impl S3 for FS {
&self,
req: S3Request<PutObjectLockConfigurationInput>,
) -> S3Result<S3Response<PutObjectLockConfigurationOutput>> {
record_s3_op(S3Operation::PutObjectLockConfiguration, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_put_object_lock_configuration(req).await
}
@@ -707,20 +672,17 @@ impl S3 for FS {
&self,
req: S3Request<PutObjectRetentionInput>,
) -> S3Result<S3Response<PutObjectRetentionOutput>> {
record_s3_op(S3Operation::PutObjectRetention, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_put_object_retention(req).await
}
#[instrument(level = "debug", skip(self, req))]
async fn put_object_tagging(&self, req: S3Request<PutObjectTaggingInput>) -> S3Result<S3Response<PutObjectTaggingOutput>> {
record_s3_op(S3Operation::PutObjectTagging, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_put_object_tagging(req).await
}
async fn restore_object(&self, req: S3Request<RestoreObjectInput>) -> S3Result<S3Response<RestoreObjectOutput>> {
record_s3_op(S3Operation::RestoreObject, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_restore_object(req).await
}
@@ -729,7 +691,6 @@ impl S3 for FS {
&self,
req: S3Request<SelectObjectContentInput>,
) -> S3Result<S3Response<SelectObjectContentOutput>> {
record_s3_op(S3Operation::SelectObjectContent, &req.input.bucket);
let usecase = DefaultObjectUsecase::from_global();
usecase.execute_select_object_content(req).await
}
+8 -2
View File
@@ -19,7 +19,8 @@ use rustfs_audit::{
};
use rustfs_ecstore::store_api::ObjectInfo;
use rustfs_notify::{EventArgsBuilder, notifier_global};
use rustfs_targets::EventName;
use rustfs_s3_common::record_s3_op;
use rustfs_s3_common::{EventName, S3Operation};
use rustfs_utils::{
extract_params_header, extract_req_params, extract_resp_elements, get_request_host, get_request_port, get_request_user_agent,
};
@@ -54,7 +55,7 @@ pub struct OperationHelper {
impl OperationHelper {
/// Create a new OperationHelper for S3 requests.
pub fn new(req: &S3Request<impl Send + Sync>, event: EventName, trigger: &'static str) -> Self {
pub fn new(req: &S3Request<impl Send + Sync>, event: EventName, op: S3Operation) -> Self {
// Parse path -> bucket/object
let path = req.uri.path().trim_start_matches('/');
let mut segs = path.splitn(2, '/');
@@ -70,6 +71,11 @@ impl OperationHelper {
.unwrap_or("")
.to_string();
let trigger = op.as_str();
let bucket_label = if bucket.is_empty() { "*" } else { &bucket };
record_s3_op(op, bucket_label);
// Initialize audit builder
let mut api_builder = ApiDetailsBuilder::new().name(trigger);
if !bucket.is_empty() {
-1
View File
@@ -21,7 +21,6 @@ pub mod options;
pub(crate) mod readers;
pub mod rpc;
pub(crate) mod s3_api;
pub(crate) mod s3_metrics;
mod sse;
pub mod tonic_service;
-174
View File
@@ -1,174 +0,0 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use metrics::{counter, describe_counter};
use std::sync::OnceLock;
const S3_OPS_METRIC: &str = "rustfs_s3_operations_total";
#[derive(Clone, Copy)]
pub enum S3Operation {
AbortMultipartUpload,
CompleteMultipartUpload,
CopyObject,
CreateBucket,
CreateMultipartUpload,
DeleteBucket,
DeleteBucketCors,
DeleteBucketEncryption,
DeleteBucketLifecycle,
DeleteBucketPolicy,
DeleteBucketReplication,
DeleteBucketTagging,
DeleteObject,
DeleteObjectTagging,
DeleteObjects,
DeletePublicAccessBlock,
GetBucketAcl,
GetBucketCors,
GetBucketEncryption,
GetBucketLifecycleConfiguration,
GetBucketLocation,
GetBucketLogging,
GetBucketNotificationConfiguration,
GetBucketPolicy,
GetBucketPolicyStatus,
GetBucketReplication,
GetBucketTagging,
GetBucketVersioning,
GetObject,
GetObjectAcl,
GetObjectAttributes,
GetObjectLegalHold,
GetObjectLockConfiguration,
GetObjectRetention,
GetObjectTagging,
GetObjectTorrent,
GetPublicAccessBlock,
HeadBucket,
HeadObject,
ListBuckets,
ListMultipartUploads,
ListObjectVersions,
ListObjects,
ListObjectsV2,
ListParts,
PutBucketAcl,
PutBucketCors,
PutBucketEncryption,
PutBucketLifecycleConfiguration,
PutBucketLogging,
PutBucketNotificationConfiguration,
PutBucketPolicy,
PutBucketReplication,
PutBucketTagging,
PutBucketVersioning,
PutObject,
PutObjectAcl,
PutObjectLegalHold,
PutObjectLockConfiguration,
PutObjectRetention,
PutObjectTagging,
PutPublicAccessBlock,
RestoreObject,
SelectObjectContent,
UploadPart,
UploadPartCopy,
}
impl S3Operation {
pub fn as_str(self) -> &'static str {
match self {
Self::AbortMultipartUpload => "AbortMultipartUpload",
Self::CompleteMultipartUpload => "CompleteMultipartUpload",
Self::CopyObject => "CopyObject",
Self::CreateBucket => "CreateBucket",
Self::CreateMultipartUpload => "CreateMultipartUpload",
Self::DeleteBucket => "DeleteBucket",
Self::DeleteBucketCors => "DeleteBucketCors",
Self::DeleteBucketEncryption => "DeleteBucketEncryption",
Self::DeleteBucketLifecycle => "DeleteBucketLifecycle",
Self::DeleteBucketPolicy => "DeleteBucketPolicy",
Self::DeleteBucketReplication => "DeleteBucketReplication",
Self::DeleteBucketTagging => "DeleteBucketTagging",
Self::DeleteObject => "DeleteObject",
Self::DeleteObjectTagging => "DeleteObjectTagging",
Self::DeleteObjects => "DeleteObjects",
Self::DeletePublicAccessBlock => "DeletePublicAccessBlock",
Self::GetBucketAcl => "GetBucketAcl",
Self::GetBucketCors => "GetBucketCors",
Self::GetBucketEncryption => "GetBucketEncryption",
Self::GetBucketLifecycleConfiguration => "GetBucketLifecycleConfiguration",
Self::GetBucketLocation => "GetBucketLocation",
Self::GetBucketLogging => "GetBucketLogging",
Self::GetBucketNotificationConfiguration => "GetBucketNotificationConfiguration",
Self::GetBucketPolicy => "GetBucketPolicy",
Self::GetBucketPolicyStatus => "GetBucketPolicyStatus",
Self::GetBucketReplication => "GetBucketReplication",
Self::GetBucketTagging => "GetBucketTagging",
Self::GetBucketVersioning => "GetBucketVersioning",
Self::GetObject => "GetObject",
Self::GetObjectAcl => "GetObjectAcl",
Self::GetObjectAttributes => "GetObjectAttributes",
Self::GetObjectLegalHold => "GetObjectLegalHold",
Self::GetObjectLockConfiguration => "GetObjectLockConfiguration",
Self::GetObjectRetention => "GetObjectRetention",
Self::GetObjectTagging => "GetObjectTagging",
Self::GetObjectTorrent => "GetObjectTorrent",
Self::GetPublicAccessBlock => "GetPublicAccessBlock",
Self::HeadBucket => "HeadBucket",
Self::HeadObject => "HeadObject",
Self::ListBuckets => "ListBuckets",
Self::ListMultipartUploads => "ListMultipartUploads",
Self::ListObjectVersions => "ListObjectVersions",
Self::ListObjects => "ListObjects",
Self::ListObjectsV2 => "ListObjectsV2",
Self::ListParts => "ListParts",
Self::PutBucketAcl => "PutBucketAcl",
Self::PutBucketCors => "PutBucketCors",
Self::PutBucketEncryption => "PutBucketEncryption",
Self::PutBucketLifecycleConfiguration => "PutBucketLifecycleConfiguration",
Self::PutBucketLogging => "PutBucketLogging",
Self::PutBucketNotificationConfiguration => "PutBucketNotificationConfiguration",
Self::PutBucketPolicy => "PutBucketPolicy",
Self::PutBucketReplication => "PutBucketReplication",
Self::PutBucketTagging => "PutBucketTagging",
Self::PutBucketVersioning => "PutBucketVersioning",
Self::PutObject => "PutObject",
Self::PutObjectAcl => "PutObjectAcl",
Self::PutObjectLegalHold => "PutObjectLegalHold",
Self::PutObjectLockConfiguration => "PutObjectLockConfiguration",
Self::PutObjectRetention => "PutObjectRetention",
Self::PutObjectTagging => "PutObjectTagging",
Self::PutPublicAccessBlock => "PutPublicAccessBlock",
Self::RestoreObject => "RestoreObject",
Self::SelectObjectContent => "SelectObjectContent",
Self::UploadPart => "UploadPart",
Self::UploadPartCopy => "UploadPartCopy",
}
}
}
pub fn record_s3_op(op: S3Operation, bucket: &str) {
counter!(S3_OPS_METRIC, "op" => op.as_str(), "bucket" => bucket.to_owned()).increment(1);
}
/// One-time registration of indicator meta information
/// This function ensures that metric descriptors are registered only once.
pub fn init_s3_metrics() {
static METRICS_DESC_INIT: OnceLock<()> = OnceLock::new();
METRICS_DESC_INIT.get_or_init(|| {
describe_counter!(S3_OPS_METRIC, "Total number of S3 API operations handled");
});
}