mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-06 13:27:43 +00:00
feat(storage): integrate S3Operation into OperationHelper for unified metrics and audit (#2103)
This commit is contained in:
@@ -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 }
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user