mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 23:47:28 +00:00
refactor(storage): extract ACL response builders into s3_api (#1880)
This commit is contained in:
@@ -23,11 +23,11 @@ use crate::storage::head_prefix::{head_prefix_not_found_message, probe_prefix_ha
|
|||||||
use crate::storage::helper::OperationHelper;
|
use crate::storage::helper::OperationHelper;
|
||||||
use crate::storage::options::{filter_object_metadata, get_content_sha256};
|
use crate::storage::options::{filter_object_metadata, get_content_sha256};
|
||||||
use crate::storage::readers::InMemoryAsyncReader;
|
use crate::storage::readers::InMemoryAsyncReader;
|
||||||
|
use crate::storage::s3_api::acl::{build_get_bucket_acl_output, build_get_object_acl_output};
|
||||||
use crate::storage::s3_api::bucket::{
|
use crate::storage::s3_api::bucket::{
|
||||||
build_list_buckets_output, build_list_object_versions_output, build_list_objects_output, build_list_objects_v2_output,
|
build_list_buckets_output, build_list_object_versions_output, build_list_objects_output, build_list_objects_v2_output,
|
||||||
parse_list_object_versions_params, parse_list_objects_v2_params,
|
parse_list_object_versions_params, parse_list_objects_v2_params,
|
||||||
};
|
};
|
||||||
use crate::storage::s3_api::common::rustfs_owner;
|
|
||||||
use crate::storage::s3_api::multipart::{
|
use crate::storage::s3_api::multipart::{
|
||||||
build_list_multipart_uploads_output, build_list_parts_output, parse_list_multipart_uploads_params, parse_list_parts_params,
|
build_list_multipart_uploads_output, build_list_parts_output, parse_list_multipart_uploads_params, parse_list_parts_params,
|
||||||
};
|
};
|
||||||
@@ -148,13 +148,7 @@ use s3s::header::{X_AMZ_RESTORE, X_AMZ_RESTORE_OUTPUT_PATH};
|
|||||||
use s3s::{S3, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, dto::*, s3_error};
|
use s3s::{S3, S3Error, S3ErrorCode, S3Request, S3Response, S3Result, dto::*, s3_error};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::{
|
use std::{collections::HashMap, fmt::Debug, path::Path, str::FromStr, sync::Arc};
|
||||||
collections::HashMap,
|
|
||||||
fmt::Debug,
|
|
||||||
path::Path,
|
|
||||||
str::FromStr,
|
|
||||||
sync::{Arc, LazyLock},
|
|
||||||
};
|
|
||||||
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
@@ -174,9 +168,6 @@ macro_rules! try_ {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shared owner metadata source for S3 response compatibility.
|
|
||||||
pub(crate) static RUSTFS_OWNER: LazyLock<Owner> = LazyLock::new(rustfs_owner);
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FS {
|
pub struct FS {
|
||||||
// pub store: ECStore,
|
// pub store: ECStore,
|
||||||
@@ -1957,21 +1948,7 @@ impl S3 for FS {
|
|||||||
.await
|
.await
|
||||||
.map_err(ApiError::from)?;
|
.map_err(ApiError::from)?;
|
||||||
|
|
||||||
let grants = vec![Grant {
|
Ok(s3_response(build_get_bucket_acl_output()))
|
||||||
grantee: Some(Grantee {
|
|
||||||
type_: Type::from_static(Type::CANONICAL_USER),
|
|
||||||
display_name: None,
|
|
||||||
email_address: None,
|
|
||||||
id: None,
|
|
||||||
uri: None,
|
|
||||||
}),
|
|
||||||
permission: Some(Permission::from_static(Permission::FULL_CONTROL)),
|
|
||||||
}];
|
|
||||||
|
|
||||||
Ok(s3_response(GetBucketAclOutput {
|
|
||||||
grants: Some(grants),
|
|
||||||
owner: Some(RUSTFS_OWNER.to_owned()),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
@@ -2900,22 +2877,7 @@ impl S3 for FS {
|
|||||||
return Err(S3Error::with_message(S3ErrorCode::InternalError, format!("{e}")));
|
return Err(S3Error::with_message(S3ErrorCode::InternalError, format!("{e}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
let grants = vec![Grant {
|
Ok(s3_response(build_get_object_acl_output()))
|
||||||
grantee: Some(Grantee {
|
|
||||||
type_: Type::from_static(Type::CANONICAL_USER),
|
|
||||||
display_name: None,
|
|
||||||
email_address: None,
|
|
||||||
id: None,
|
|
||||||
uri: None,
|
|
||||||
}),
|
|
||||||
permission: Some(Permission::from_static(Permission::FULL_CONTROL)),
|
|
||||||
}];
|
|
||||||
|
|
||||||
Ok(s3_response(GetObjectAclOutput {
|
|
||||||
grants: Some(grants),
|
|
||||||
owner: Some(RUSTFS_OWNER.to_owned()),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_object_attributes(
|
async fn get_object_attributes(
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::config::workload_profiles::WorkloadProfile;
|
use crate::config::workload_profiles::WorkloadProfile;
|
||||||
use crate::storage::ecfs::FS;
|
use crate::storage::ecfs::FS;
|
||||||
use crate::storage::ecfs::RUSTFS_OWNER;
|
use crate::storage::s3_api::common::rustfs_owner;
|
||||||
use crate::storage::{
|
use crate::storage::{
|
||||||
apply_cors_headers, check_preconditions, get_adaptive_buffer_size_with_profile, get_buffer_size_opt_in, is_etag_equal,
|
apply_cors_headers, check_preconditions, get_adaptive_buffer_size_with_profile, get_buffer_size_opt_in, is_etag_equal,
|
||||||
matches_origin_pattern, parse_etag, parse_object_lock_legal_hold, parse_object_lock_retention,
|
matches_origin_pattern, parse_etag, parse_object_lock_legal_hold, parse_object_lock_retention,
|
||||||
@@ -67,11 +67,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rustfs_owner_constant() {
|
fn test_rustfs_owner_helper() {
|
||||||
// Test that RUSTFS_OWNER constant is properly defined
|
// Test that rustfs owner metadata remains stable for S3 compatibility.
|
||||||
assert!(!RUSTFS_OWNER.display_name.as_ref().unwrap().is_empty());
|
let owner = rustfs_owner();
|
||||||
assert!(!RUSTFS_OWNER.id.as_ref().unwrap().is_empty());
|
assert!(!owner.display_name.as_ref().unwrap().is_empty());
|
||||||
assert_eq!(RUSTFS_OWNER.display_name.as_ref().unwrap(), "rustfs");
|
assert!(!owner.id.as_ref().unwrap().is_empty());
|
||||||
|
assert_eq!(owner.display_name.as_ref().unwrap(), "rustfs");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Most S3 API methods require complex setup with global state, storage backend,
|
// Note: Most S3 API methods require complex setup with global state, storage backend,
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// 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 crate::storage::s3_api::common::rustfs_owner;
|
||||||
|
use s3s::dto::{GetBucketAclOutput, GetObjectAclOutput, Grant, Grantee, Permission, Type};
|
||||||
|
|
||||||
|
fn full_control_grants() -> Vec<Grant> {
|
||||||
|
vec![Grant {
|
||||||
|
grantee: Some(Grantee {
|
||||||
|
type_: Type::from_static(Type::CANONICAL_USER),
|
||||||
|
display_name: None,
|
||||||
|
email_address: None,
|
||||||
|
id: None,
|
||||||
|
uri: None,
|
||||||
|
}),
|
||||||
|
permission: Some(Permission::from_static(Permission::FULL_CONTROL)),
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_get_bucket_acl_output() -> GetBucketAclOutput {
|
||||||
|
GetBucketAclOutput {
|
||||||
|
grants: Some(full_control_grants()),
|
||||||
|
owner: Some(rustfs_owner()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn build_get_object_acl_output() -> GetObjectAclOutput {
|
||||||
|
GetObjectAclOutput {
|
||||||
|
grants: Some(full_control_grants()),
|
||||||
|
owner: Some(rustfs_owner()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::{build_get_bucket_acl_output, build_get_object_acl_output};
|
||||||
|
use crate::storage::s3_api::common::rustfs_owner;
|
||||||
|
use s3s::dto::{Permission, Type};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_get_bucket_acl_output_contains_full_control_grant_and_owner() {
|
||||||
|
let output = build_get_bucket_acl_output();
|
||||||
|
let grants = output.grants.as_ref().expect("grants should be present");
|
||||||
|
let owner = output.owner.as_ref().expect("owner should be present");
|
||||||
|
|
||||||
|
assert_eq!(grants.len(), 1);
|
||||||
|
assert_eq!(grants[0].permission.as_ref().map(Permission::as_str), Some(Permission::FULL_CONTROL));
|
||||||
|
assert_eq!(
|
||||||
|
grants[0].grantee.as_ref().map(|grantee| grantee.type_.as_str()),
|
||||||
|
Some(Type::CANONICAL_USER)
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected_owner = rustfs_owner();
|
||||||
|
assert_eq!(owner.display_name, expected_owner.display_name);
|
||||||
|
assert_eq!(owner.id, expected_owner.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_build_get_object_acl_output_contains_full_control_grant_and_owner() {
|
||||||
|
let output = build_get_object_acl_output();
|
||||||
|
let grants = output.grants.as_ref().expect("grants should be present");
|
||||||
|
let owner = output.owner.as_ref().expect("owner should be present");
|
||||||
|
|
||||||
|
assert_eq!(grants.len(), 1);
|
||||||
|
assert_eq!(grants[0].permission.as_ref().map(Permission::as_str), Some(Permission::FULL_CONTROL));
|
||||||
|
assert_eq!(
|
||||||
|
grants[0].grantee.as_ref().map(|grantee| grantee.type_.as_str()),
|
||||||
|
Some(Type::CANONICAL_USER)
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected_owner = rustfs_owner();
|
||||||
|
assert_eq!(owner.display_name, expected_owner.display_name);
|
||||||
|
assert_eq!(owner.id, expected_owner.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
//! This file intentionally starts as skeleton-only. Behavior remains in place
|
//! This file intentionally starts as skeleton-only. Behavior remains in place
|
||||||
//! until each helper is moved with dedicated small refactor steps.
|
//! until each helper is moved with dedicated small refactor steps.
|
||||||
|
|
||||||
pub(crate) mod acl {}
|
pub(crate) mod acl;
|
||||||
pub(crate) mod bucket;
|
pub(crate) mod bucket;
|
||||||
pub(crate) mod common;
|
pub(crate) mod common;
|
||||||
pub(crate) mod encryption {}
|
pub(crate) mod encryption {}
|
||||||
|
|||||||
Reference in New Issue
Block a user