diff --git a/crates/e2e_test/src/lib.rs b/crates/e2e_test/src/lib.rs index 2259b63b7..6afa0c712 100644 --- a/crates/e2e_test/src/lib.rs +++ b/crates/e2e_test/src/lib.rs @@ -13,6 +13,7 @@ // limitations under the License. mod reliant; +mod storage_api; // Common utilities for all E2E tests #[cfg(test)] diff --git a/crates/e2e_test/src/reliant/grpc_lock_client.rs b/crates/e2e_test/src/reliant/grpc_lock_client.rs index 400829ff3..6f632bb7b 100644 --- a/crates/e2e_test/src/reliant/grpc_lock_client.rs +++ b/crates/e2e_test/src/reliant/grpc_lock_client.rs @@ -16,7 +16,6 @@ #![allow(dead_code)] use async_trait::async_trait; -use rustfs_ecstore::api::rpc::{TonicInterceptor, node_service_time_out_client_no_auth}; use rustfs_lock::{ LockClient, LockError, LockId, LockInfo, LockRequest, LockResponse, LockStats, LockStatus, LockType, Result, types::{LockMetadata, LockPriority}, @@ -25,6 +24,8 @@ use rustfs_protos::proto_gen::node_service::{BatchGenerallyLockRequest, Generall use tonic::Request; use tracing::{info, warn}; +use crate::storage_api::{TonicInterceptor, node_service_time_out_client_no_auth}; + /// gRPC lock client without authentication for testing /// Similar to RemoteClient but uses no_auth client #[derive(Debug, Clone)] diff --git a/crates/e2e_test/src/reliant/node_interact_test.rs b/crates/e2e_test/src/reliant/node_interact_test.rs index 04256692b..7be9a983a 100644 --- a/crates/e2e_test/src/reliant/node_interact_test.rs +++ b/crates/e2e_test/src/reliant/node_interact_test.rs @@ -14,10 +14,11 @@ // limitations under the License. use crate::common::workspace_root; +use crate::storage_api::{ + TonicInterceptor, VolumeInfo, WalkDirOptions, gen_tonic_signature_interceptor, node_service_time_out_client, +}; use futures::future::join_all; use rmp_serde::{Deserializer, Serializer}; -use rustfs_ecstore::api::disk::{VolumeInfo, WalkDirOptions}; -use rustfs_ecstore::api::rpc::{TonicInterceptor, gen_tonic_signature_interceptor, node_service_time_out_client}; use rustfs_filemeta::{MetaCacheEntry, MetacacheReader, MetacacheWriter}; use rustfs_protos::proto_gen::node_service::WalkDirRequest; use rustfs_protos::{ diff --git a/crates/e2e_test/src/replication_extension_test.rs b/crates/e2e_test/src/replication_extension_test.rs index e9a4776e7..d03c98a8b 100644 --- a/crates/e2e_test/src/replication_extension_test.rs +++ b/crates/e2e_test/src/replication_extension_test.rs @@ -16,6 +16,7 @@ use crate::common::{ RustFSTestEnvironment, awscurl_available, awscurl_post_sts_form_urlencoded, init_logging, local_http_client, rustfs_binary_path, }; +use crate::storage_api::BucketTargetSys; use aws_sdk_s3::config::{Credentials, Region}; use aws_sdk_s3::error::ProvideErrorMetadata; use aws_sdk_s3::primitives::ByteStream; @@ -28,7 +29,6 @@ use rcgen::{ SanType, generate_simple_self_signed, }; use reqwest::StatusCode; -use rustfs_ecstore::api::bucket::bucket_target_sys::BucketTargetSys; use rustfs_madmin::{ AddServiceAccountReq, ListServiceAccountsResp, PeerInfo, PeerSite, ReplicateAddStatus, ReplicateEditStatus, ReplicateRemoveStatus, SRRemoveReq, SRResyncOpStatus, SRStatusInfo, SiteReplicationInfo, SyncStatus, diff --git a/crates/e2e_test/src/storage_api.rs b/crates/e2e_test/src/storage_api.rs new file mode 100644 index 000000000..eb90610c3 --- /dev/null +++ b/crates/e2e_test/src/storage_api.rs @@ -0,0 +1,21 @@ +// 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. + +#[cfg(test)] +pub(crate) use rustfs_ecstore::api::bucket::bucket_target_sys::BucketTargetSys; +#[cfg(test)] +pub(crate) use rustfs_ecstore::api::disk::{VolumeInfo, WalkDirOptions}; +pub(crate) use rustfs_ecstore::api::rpc::{TonicInterceptor, node_service_time_out_client_no_auth}; +#[cfg(test)] +pub(crate) use rustfs_ecstore::api::rpc::{gen_tonic_signature_interceptor, node_service_time_out_client}; diff --git a/crates/iam/src/lib.rs b/crates/iam/src/lib.rs index 3002c3a59..9aa65613b 100644 --- a/crates/iam/src/lib.rs +++ b/crates/iam/src/lib.rs @@ -15,19 +15,6 @@ use crate::error::{Error, Result}; use manager::IamCache; use oidc::OidcSys; -use rustfs_ecstore::api::config::RUSTFS_CONFIG_PREFIX as ECSTORE_RUSTFS_CONFIG_PREFIX; -use rustfs_ecstore::api::config::com::{ - delete_config as ecstore_delete_config, read_config_no_lock as ecstore_read_config_no_lock, - read_config_with_metadata as ecstore_read_config_with_metadata, save_config as ecstore_save_config, - save_config_with_opts as ecstore_save_config_with_opts, -}; -use rustfs_ecstore::api::error::{ - Error as EcstoreErrorType, Result as EcstoreResultType, StorageError as EcstoreStorageError, - classify_system_path_failure_reason as ecstore_classify_system_path_failure_reason, -}; -use rustfs_ecstore::api::global::is_first_cluster_node_local as ecstore_is_first_cluster_node_local; -use rustfs_ecstore::api::notification::NotificationPeerErr as EcstoreNotificationPeerErr; -use rustfs_ecstore::api::storage::ECStore as EcstoreStore; use std::sync::{Arc, OnceLock}; use store::object::ObjectStore; use sys::IamSys; @@ -48,66 +35,26 @@ pub mod oidc_state; mod root_credentials; mod runtime_sources; mod server_config; +mod storage_api; pub mod store; pub mod sys; pub mod utils; - -pub(crate) const IAM_CONFIG_ROOT_PREFIX: &str = ECSTORE_RUSTFS_CONFIG_PREFIX; - -pub(crate) type IamEcstoreError = EcstoreErrorType; -pub(crate) type IamStorageError = EcstoreStorageError; -pub(crate) type IamStorageResult = EcstoreResultType; -pub(crate) type IamStore = EcstoreStore; -pub(crate) type IamConfigObjectInfo = ::ObjectInfo; -pub(crate) type IamConfigObjectOptions = ::ObjectOptions; +pub(crate) use storage_api::{ + IAM_CONFIG_ROOT_PREFIX, IamEcstoreError, IamStorageError, IamStore, classify_iam_system_path_failure_reason, + delete_iam_config, is_iam_first_cluster_node_local, read_iam_config_no_lock, read_iam_config_with_metadata, save_iam_config, + save_iam_config_with_opts, +}; pub fn is_root_access_key(access_key: &str) -> bool { root_credentials::is_root_access_key(access_key) } -pub(crate) async fn read_iam_config_no_lock(api: Arc, file: &str) -> IamStorageResult> { - ecstore_read_config_no_lock(api, file).await -} - -pub(crate) async fn read_iam_config_with_metadata( - api: Arc, - file: &str, - opts: &IamConfigObjectOptions, -) -> IamStorageResult<(Vec, IamConfigObjectInfo)> { - ecstore_read_config_with_metadata(api, file, opts).await -} - -pub(crate) async fn save_iam_config(api: Arc, file: &str, data: Vec) -> IamStorageResult<()> { - ecstore_save_config(api, file, data).await -} - -pub(crate) async fn save_iam_config_with_opts( - api: Arc, - file: &str, - data: Vec, - opts: &IamConfigObjectOptions, -) -> IamStorageResult<()> { - ecstore_save_config_with_opts(api, file, data, opts).await -} - -pub(crate) async fn delete_iam_config(api: Arc, file: &str) -> IamStorageResult<()> { - ecstore_delete_config(api, file).await -} - -pub(crate) fn classify_iam_system_path_failure_reason(err: &IamEcstoreError) -> &'static str { - ecstore_classify_system_path_failure_reason(err) -} - -pub(crate) async fn is_iam_first_cluster_node_local() -> bool { - ecstore_is_first_cluster_node_local().await -} - pub(crate) struct IamNotificationPeerErr { pub(crate) err: Option, } -impl From for IamNotificationPeerErr { - fn from(value: EcstoreNotificationPeerErr) -> Self { +impl From for IamNotificationPeerErr { + fn from(value: storage_api::IamEcstoreNotificationPeerErr) -> Self { Self { err: value.err } } } diff --git a/crates/iam/src/runtime_sources.rs b/crates/iam/src/runtime_sources.rs index 630a79233..657d11924 100644 --- a/crates/iam/src/runtime_sources.rs +++ b/crates/iam/src/runtime_sources.rs @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::storage_api::{IamNotificationSys, notification_sys as ecstore_notification_sys}; use rustfs_config::server_config::{Config as ServerConfig, get_global_server_config}; use rustfs_credentials::{Credentials, get_global_action_cred}; -use rustfs_ecstore::api::notification::{NotificationSys, get_global_notification_sys}; pub(crate) fn action_credentials() -> Option { get_global_action_cred() @@ -24,6 +24,6 @@ pub(crate) fn current_server_config() -> Option { get_global_server_config() } -pub(crate) fn notification_sys() -> Option<&'static NotificationSys> { - get_global_notification_sys() +pub(crate) fn notification_sys() -> Option<&'static IamNotificationSys> { + ecstore_notification_sys() } diff --git a/crates/iam/src/storage_api.rs b/crates/iam/src/storage_api.rs new file mode 100644 index 000000000..c58d376be --- /dev/null +++ b/crates/iam/src/storage_api.rs @@ -0,0 +1,82 @@ +// 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 std::sync::Arc; + +pub(crate) use rustfs_ecstore::api::config::RUSTFS_CONFIG_PREFIX as IAM_CONFIG_ROOT_PREFIX; +use rustfs_ecstore::api::config::com::{ + delete_config as ecstore_delete_config, read_config_no_lock as ecstore_read_config_no_lock, + read_config_with_metadata as ecstore_read_config_with_metadata, save_config as ecstore_save_config, + save_config_with_opts as ecstore_save_config_with_opts, +}; +use rustfs_ecstore::api::error::{ + Error as EcstoreErrorType, Result as EcstoreResultType, StorageError as EcstoreStorageError, + classify_system_path_failure_reason as ecstore_classify_system_path_failure_reason, +}; +use rustfs_ecstore::api::global::is_first_cluster_node_local as ecstore_is_first_cluster_node_local; +use rustfs_ecstore::api::notification::{ + NotificationPeerErr as EcstoreNotificationPeerErr, NotificationSys as EcstoreNotificationSys, get_global_notification_sys, +}; +use rustfs_ecstore::api::storage::ECStore as EcstoreStore; +pub(crate) use rustfs_storage_api::{HTTPPreconditions, ListOperations, ObjectInfoOrErr, ObjectOperations}; + +pub(crate) type IamEcstoreError = EcstoreErrorType; +pub(crate) type IamStorageError = EcstoreStorageError; +pub(crate) type IamStorageResult = EcstoreResultType; +pub(crate) type IamStore = EcstoreStore; +pub(crate) type IamConfigObjectInfo = ::ObjectInfo; +pub(crate) type IamConfigObjectOptions = ::ObjectOptions; +pub(crate) type IamNotificationSys = EcstoreNotificationSys; +pub(crate) type IamEcstoreNotificationPeerErr = EcstoreNotificationPeerErr; + +pub(crate) async fn read_iam_config_no_lock(api: Arc, file: &str) -> IamStorageResult> { + ecstore_read_config_no_lock(api, file).await +} + +pub(crate) async fn read_iam_config_with_metadata( + api: Arc, + file: &str, + opts: &IamConfigObjectOptions, +) -> IamStorageResult<(Vec, IamConfigObjectInfo)> { + ecstore_read_config_with_metadata(api, file, opts).await +} + +pub(crate) async fn save_iam_config(api: Arc, file: &str, data: Vec) -> IamStorageResult<()> { + ecstore_save_config(api, file, data).await +} + +pub(crate) async fn save_iam_config_with_opts( + api: Arc, + file: &str, + data: Vec, + opts: &IamConfigObjectOptions, +) -> IamStorageResult<()> { + ecstore_save_config_with_opts(api, file, data, opts).await +} + +pub(crate) async fn delete_iam_config(api: Arc, file: &str) -> IamStorageResult<()> { + ecstore_delete_config(api, file).await +} + +pub(crate) fn classify_iam_system_path_failure_reason(err: &IamEcstoreError) -> &'static str { + ecstore_classify_system_path_failure_reason(err) +} + +pub(crate) async fn is_iam_first_cluster_node_local() -> bool { + ecstore_is_first_cluster_node_local().await +} + +pub(crate) fn notification_sys() -> Option<&'static IamNotificationSys> { + get_global_notification_sys() +} diff --git a/crates/iam/src/store/object.rs b/crates/iam/src/store/object.rs index 709ebc5c9..767ab45e4 100644 --- a/crates/iam/src/store/object.rs +++ b/crates/iam/src/store/object.rs @@ -28,7 +28,6 @@ use crate::{ use futures::future::join_all; use rustfs_io_metrics::record_system_path_failure; use rustfs_policy::{auth::UserIdentity, policy::PolicyDoc}; -use rustfs_storage_api::{HTTPPreconditions, ListOperations as _, ObjectInfoOrErr as StorageObjectInfoOrErr, ObjectOperations}; use rustfs_utils::path::{SLASH_SEPARATOR, path_join_buf}; use serde::{Serialize, de::DeserializeOwned}; use std::sync::{LazyLock, Mutex}; @@ -38,6 +37,8 @@ use tokio::sync::mpsc::{self, Sender}; use tokio_util::sync::CancellationToken; use tracing::{debug, error, warn}; +use crate::storage_api::{HTTPPreconditions, ListOperations as _, ObjectInfoOrErr as StorageObjectInfoOrErr, ObjectOperations}; + pub static IAM_CONFIG_PREFIX: LazyLock = LazyLock::new(|| format!("{IAM_CONFIG_ROOT_PREFIX}/iam")); pub static IAM_CONFIG_USERS_PREFIX: LazyLock = LazyLock::new(|| format!("{IAM_CONFIG_ROOT_PREFIX}/iam/users/")); pub static IAM_CONFIG_SERVICE_ACCOUNTS_PREFIX: LazyLock = diff --git a/crates/notify/src/lib.rs b/crates/notify/src/lib.rs index 77d8ac5bb..c76368754 100644 --- a/crates/notify/src/lib.rs +++ b/crates/notify/src/lib.rs @@ -18,15 +18,6 @@ //! It supports sending events to various targets //! (like Webhook and MQTT) and includes features like event persistence and retry on failure. -use std::sync::Arc; - -use rustfs_ecstore::api::config::com::{ - read_config_without_migrate as read_notify_config_without_migrate_from_backend, - save_server_config as save_notify_server_config_to_backend, -}; -use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_notify_object_store_handle_from_backend; -pub(crate) use rustfs_ecstore::api::storage::ECStore as NotifyStore; - mod bucket_config_manager; mod config_manager; mod error; @@ -44,6 +35,7 @@ mod runtime_facade; mod runtime_view; mod services; mod status_view; +mod storage_api; pub use bucket_config_manager::NotifyBucketConfigManager; pub use config_manager::{NotifyConfigManager, runtime_target_id_for_subsystem}; @@ -61,24 +53,6 @@ pub use runtime_facade::NotifyRuntimeFacade; pub use runtime_view::NotifyRuntimeView; pub use services::NotifyServices; pub use status_view::NotifyStatusView; - -pub(crate) fn resolve_notify_object_store_handle() -> Option> { - resolve_notify_object_store_handle_from_backend() -} - -pub(crate) async fn read_notify_server_config_without_migrate( - store: Arc, -) -> Result { - read_notify_config_without_migrate_from_backend(store) - .await - .map_err(|err| err.to_string()) -} - -pub(crate) async fn save_notify_server_config( - store: Arc, - config: &rustfs_config::server_config::Config, -) -> Result<(), String> { - save_notify_server_config_to_backend(store, config) - .await - .map_err(|err| err.to_string()) -} +pub(crate) use storage_api::{ + read_notify_server_config_without_migrate, resolve_notify_object_store_handle, save_notify_server_config, +}; diff --git a/crates/notify/src/storage_api.rs b/crates/notify/src/storage_api.rs new file mode 100644 index 000000000..a6f9df10b --- /dev/null +++ b/crates/notify/src/storage_api.rs @@ -0,0 +1,43 @@ +// 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 std::sync::Arc; + +use rustfs_ecstore::api::config::com::{ + read_config_without_migrate as read_notify_config_without_migrate_from_backend, + save_server_config as save_notify_server_config_to_backend, +}; +use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_notify_object_store_handle_from_backend; +pub(crate) use rustfs_ecstore::api::storage::ECStore as NotifyStore; + +pub(crate) fn resolve_notify_object_store_handle() -> Option> { + resolve_notify_object_store_handle_from_backend() +} + +pub(crate) async fn read_notify_server_config_without_migrate( + store: Arc, +) -> Result { + read_notify_config_without_migrate_from_backend(store) + .await + .map_err(|err| err.to_string()) +} + +pub(crate) async fn save_notify_server_config( + store: Arc, + config: &rustfs_config::server_config::Config, +) -> Result<(), String> { + save_notify_server_config_to_backend(store, config) + .await + .map_err(|err| err.to_string()) +} diff --git a/crates/obs/src/metrics/mod.rs b/crates/obs/src/metrics/mod.rs index 18e80852b..e18963d44 100644 --- a/crates/obs/src/metrics/mod.rs +++ b/crates/obs/src/metrics/mod.rs @@ -12,25 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub(crate) use rustfs_ecstore::api::bucket::bandwidth::monitor::Monitor as ObsBucketBandwidthMonitor; -pub(crate) use rustfs_ecstore::api::bucket::lifecycle::bucket_lifecycle_ops::{ - GLOBAL_ExpiryState as OBS_GLOBAL_EXPIRY_STATE, GLOBAL_TransitionState as OBS_GLOBAL_TRANSITION_STATE, -}; -pub(crate) use rustfs_ecstore::api::bucket::metadata_sys::get_quota_config as obs_get_quota_config; -pub(crate) use rustfs_ecstore::api::bucket::replication::{ - GLOBAL_REPLICATION_STATS as OBS_GLOBAL_REPLICATION_STATS, ReplicationStats as ObsReplicationStats, -}; -pub(crate) use rustfs_ecstore::api::capacity::{ - get_total_usable_capacity as obs_get_total_usable_capacity, - get_total_usable_capacity_free as obs_get_total_usable_capacity_free, -}; -pub(crate) use rustfs_ecstore::api::data_usage::load_data_usage_from_backend as obs_load_data_usage_from_backend; -pub(crate) use rustfs_ecstore::api::error::Result as ObsEcstoreResult; -pub(crate) use rustfs_ecstore::api::global::{ - get_global_bucket_monitor as obs_get_global_bucket_monitor, resolve_object_store_handle as obs_resolve_object_store_handle, -}; -pub(crate) use rustfs_ecstore::api::storage::ECStore as ObsStore; - pub mod collectors; pub mod config; pub mod report; @@ -38,6 +19,7 @@ mod runtime_sources; pub mod scheduler; pub mod schema; pub mod stats_collector; +mod storage_api; pub use collectors::*; pub use config::*; @@ -48,3 +30,9 @@ pub use scheduler::{ MetricsRuntimeShutdownHandle, MetricsRuntimeStatusSnapshot, MetricsRuntimeWorkerMutation, init_metrics_collectors, init_metrics_runtime, metrics_runtime_controller_snapshot, metrics_runtime_status_snapshot, }; +pub(crate) use storage_api::{ + BucketOperations, BucketOptions, OBS_GLOBAL_EXPIRY_STATE, OBS_GLOBAL_REPLICATION_STATS, OBS_GLOBAL_TRANSITION_STATE, + ObsBucketBandwidthMonitor, ObsEcstoreResult, ObsReplicationStats, ObsStore, StorageAdminApi, obs_get_global_bucket_monitor, + obs_get_quota_config, obs_get_total_usable_capacity, obs_get_total_usable_capacity_free, obs_load_data_usage_from_backend, + obs_resolve_object_store_handle, +}; diff --git a/crates/obs/src/metrics/stats_collector.rs b/crates/obs/src/metrics/stats_collector.rs index 05902b0c5..597397c33 100644 --- a/crates/obs/src/metrics/stats_collector.rs +++ b/crates/obs/src/metrics/stats_collector.rs @@ -30,15 +30,15 @@ use crate::metrics::runtime_sources::{ ObsIlmRuntimeSnapshot, bucket_monitor_handle, iam_metrics_snapshot, ilm_runtime_snapshot, replication_stats_handle, }; use crate::metrics::{ - ObsEcstoreResult, ObsStore, obs_get_quota_config, obs_get_total_usable_capacity, obs_get_total_usable_capacity_free, - obs_load_data_usage_from_backend, obs_resolve_object_store_handle, + BucketOperations, BucketOptions, ObsEcstoreResult, ObsStore, StorageAdminApi, obs_get_quota_config, + obs_get_total_usable_capacity, obs_get_total_usable_capacity_free, obs_load_data_usage_from_backend, + obs_resolve_object_store_handle, }; use chrono::Utc; use rustfs_common::heal_channel::HealScanMode; use rustfs_common::metrics::global_metrics; use rustfs_io_metrics::internode_metrics::global_internode_metrics; use rustfs_io_metrics::{ProcessStatusSnapshot, snapshot_process_resource_and_system}; -use rustfs_storage_api::{BucketOperations, BucketOptions, StorageAdminApi}; use std::{collections::HashMap, sync::Arc, time::Duration}; use sysinfo::{Networks, System}; use tracing::{instrument, warn}; diff --git a/crates/obs/src/metrics/storage_api.rs b/crates/obs/src/metrics/storage_api.rs new file mode 100644 index 000000000..c3f221d02 --- /dev/null +++ b/crates/obs/src/metrics/storage_api.rs @@ -0,0 +1,33 @@ +// 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. + +pub(crate) use rustfs_ecstore::api::bucket::bandwidth::monitor::Monitor as ObsBucketBandwidthMonitor; +pub(crate) use rustfs_ecstore::api::bucket::lifecycle::bucket_lifecycle_ops::{ + GLOBAL_ExpiryState as OBS_GLOBAL_EXPIRY_STATE, GLOBAL_TransitionState as OBS_GLOBAL_TRANSITION_STATE, +}; +pub(crate) use rustfs_ecstore::api::bucket::metadata_sys::get_quota_config as obs_get_quota_config; +pub(crate) use rustfs_ecstore::api::bucket::replication::{ + GLOBAL_REPLICATION_STATS as OBS_GLOBAL_REPLICATION_STATS, ReplicationStats as ObsReplicationStats, +}; +pub(crate) use rustfs_ecstore::api::capacity::{ + get_total_usable_capacity as obs_get_total_usable_capacity, + get_total_usable_capacity_free as obs_get_total_usable_capacity_free, +}; +pub(crate) use rustfs_ecstore::api::data_usage::load_data_usage_from_backend as obs_load_data_usage_from_backend; +pub(crate) use rustfs_ecstore::api::error::Result as ObsEcstoreResult; +pub(crate) use rustfs_ecstore::api::global::{ + get_global_bucket_monitor as obs_get_global_bucket_monitor, resolve_object_store_handle as obs_resolve_object_store_handle, +}; +pub(crate) use rustfs_ecstore::api::storage::ECStore as ObsStore; +pub(crate) use rustfs_storage_api::{BucketOperations, BucketOptions, StorageAdminApi}; diff --git a/crates/protocols/src/swift/account.rs b/crates/protocols/src/swift/account.rs index 7110d80ac..7b0d5ca3f 100644 --- a/crates/protocols/src/swift/account.rs +++ b/crates/protocols/src/swift/account.rs @@ -14,10 +14,10 @@ //! Swift account operations and validation +use super::storage_api::{BucketOperations, MakeBucketOptions}; use super::{SwiftError, SwiftResult}; use super::{get_swift_bucket_metadata, resolve_swift_object_store_handle, set_swift_bucket_metadata}; use rustfs_credentials::Credentials; -use rustfs_storage_api::{BucketOperations, MakeBucketOptions}; use s3s::dto::{Tag, Tagging}; use sha2::{Digest, Sha256}; use std::collections::HashMap; diff --git a/crates/protocols/src/swift/container.rs b/crates/protocols/src/swift/container.rs index 727788a8e..00b109a93 100644 --- a/crates/protocols/src/swift/container.rs +++ b/crates/protocols/src/swift/container.rs @@ -17,13 +17,13 @@ //! This module implements Swift container CRUD operations and container-bucket translation. use super::account::validate_account_access; +use super::storage_api::{ + BucketInfo, BucketOperations, BucketOptions, DeleteBucketOptions, ListOperations as _, MakeBucketOptions, +}; use super::types::Container; use super::{SwiftError, SwiftResult}; use super::{get_swift_bucket_metadata, resolve_swift_object_store_handle, set_swift_bucket_metadata}; use rustfs_credentials::Credentials; -use rustfs_storage_api::{ - BucketInfo, BucketOperations, BucketOptions, DeleteBucketOptions, ListOperations as _, MakeBucketOptions, -}; use s3s::dto::{Tag, Tagging}; use sha2::{Digest, Sha256}; use tracing::{debug, error}; diff --git a/crates/protocols/src/swift/dlo.rs b/crates/protocols/src/swift/dlo.rs index 410b16063..c467c917e 100644 --- a/crates/protocols/src/swift/dlo.rs +++ b/crates/protocols/src/swift/dlo.rs @@ -18,6 +18,7 @@ //! Segments are discovered at download time using lexicographic ordering //! based on a container metadata manifest pointer. +use super::storage_api::HTTPRangeSpec; use super::{SwiftError, container, object}; use axum::http::{HeaderMap, Response, StatusCode}; use rustfs_credentials::Credentials; @@ -300,7 +301,7 @@ async fn create_dlo_stream( async move { let range_spec = if byte_start > 0 || byte_end < segment.size as u64 - 1 { - Some(rustfs_storage_api::HTTPRangeSpec { + Some(HTTPRangeSpec { is_suffix_length: false, start: byte_start as i64, end: byte_end as i64, diff --git a/crates/protocols/src/swift/mod.rs b/crates/protocols/src/swift/mod.rs index 8bb340b97..bffb3b100 100644 --- a/crates/protocols/src/swift/mod.rs +++ b/crates/protocols/src/swift/mod.rs @@ -33,16 +33,6 @@ //! and stores credentials in task-local storage, which Swift handlers access //! to enforce tenant isolation. -use std::sync::Arc; - -pub(crate) use rustfs_ecstore::api::bucket::metadata::BucketMetadata as SwiftBucketMetadata; -use rustfs_ecstore::api::bucket::metadata_sys::{ - get as get_swift_bucket_metadata_from_backend, set_bucket_metadata as set_swift_bucket_metadata_in_backend, -}; -pub(crate) use rustfs_ecstore::api::error::Result as SwiftStorageResult; -pub(crate) use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_swift_object_store_handle; -use rustfs_ecstore::api::storage::ECStore as SwiftStore; - pub mod account; pub mod acl; pub mod bulk; @@ -61,6 +51,7 @@ pub mod ratelimit; pub mod router; pub mod slo; pub mod staticweb; +mod storage_api; pub mod symlink; pub mod sync; pub mod tempurl; @@ -70,18 +61,7 @@ pub mod versioning; pub use errors::{SwiftError, SwiftResult}; pub use router::{SwiftRoute, SwiftRouter}; // Note: Container, Object, and SwiftMetadata types used by Swift implementation +pub use storage_api::{SwiftGetObjectReader, SwiftObjectInfo, SwiftObjectOptions, SwiftPutObjReader}; +pub(crate) use storage_api::{get_swift_bucket_metadata, resolve_swift_object_store_handle, set_swift_bucket_metadata}; #[allow(unused_imports)] pub use types::{Container, Object, SwiftMetadata}; - -pub type SwiftGetObjectReader = ::GetObjectReader; -pub type SwiftObjectInfo = ::ObjectInfo; -pub type SwiftObjectOptions = ::ObjectOptions; -pub type SwiftPutObjReader = ::PutObjectReader; - -pub(crate) async fn get_swift_bucket_metadata(bucket: &str) -> SwiftStorageResult> { - get_swift_bucket_metadata_from_backend(bucket).await -} - -pub(crate) async fn set_swift_bucket_metadata(bucket: String, metadata: SwiftBucketMetadata) -> SwiftStorageResult<()> { - set_swift_bucket_metadata_in_backend(bucket, metadata).await -} diff --git a/crates/protocols/src/swift/object.rs b/crates/protocols/src/swift/object.rs index 5133fe635..986bc0368 100644 --- a/crates/protocols/src/swift/object.rs +++ b/crates/protocols/src/swift/object.rs @@ -51,11 +51,11 @@ use super::account::validate_account_access; use super::container::ContainerMapper; +use super::storage_api::{BucketOperations, BucketOptions, HTTPRangeSpec, ObjectIO as _, ObjectOperations as _}; use super::{SwiftError, SwiftResult, resolve_swift_object_store_handle}; use axum::http::HeaderMap; use rustfs_credentials::Credentials; use rustfs_rio::HashReader; -use rustfs_storage_api::{BucketOperations, BucketOptions, ObjectIO as _, ObjectOperations as _}; use std::collections::HashMap; use tracing::debug; use tracing::error; @@ -533,7 +533,7 @@ pub async fn get_object( container: &str, object: &str, credentials: &Credentials, - range: Option, + range: Option, ) -> SwiftResult { // 1. Validate account access and get project_id let project_id = validate_account_access(account, credentials)?; @@ -1028,9 +1028,7 @@ pub fn parse_copy_from_header(copy_from: &str) -> SwiftResult<(String, String)> /// assert_eq!(range.end, 1023); /// ``` #[allow(dead_code)] // Handler integration: Range header -pub fn parse_range_header(range_str: &str) -> SwiftResult { - use rustfs_storage_api::HTTPRangeSpec; - +pub fn parse_range_header(range_str: &str) -> SwiftResult { if !range_str.starts_with("bytes=") { return Err(SwiftError::BadRequest("Range header must start with 'bytes='".to_string())); } diff --git a/crates/protocols/src/swift/slo.rs b/crates/protocols/src/swift/slo.rs index 33c2e4dc4..8ec819c15 100644 --- a/crates/protocols/src/swift/slo.rs +++ b/crates/protocols/src/swift/slo.rs @@ -18,6 +18,7 @@ //! Large files (>5GB) are split into segments, and a manifest defines //! how segments are assembled on download. +use super::storage_api::HTTPRangeSpec; use super::{SwiftError, object}; use axum::http::{HeaderMap, Response, StatusCode}; use rustfs_credentials::Credentials; @@ -420,7 +421,7 @@ async fn create_slo_stream( // Fetch segment with range let range_spec = if byte_start > 0 || byte_end < segment.size_bytes - 1 { - Some(rustfs_storage_api::HTTPRangeSpec { + Some(HTTPRangeSpec { is_suffix_length: false, start: byte_start as i64, end: byte_end as i64, diff --git a/crates/protocols/src/swift/storage_api.rs b/crates/protocols/src/swift/storage_api.rs new file mode 100644 index 000000000..b0f922b85 --- /dev/null +++ b/crates/protocols/src/swift/storage_api.rs @@ -0,0 +1,40 @@ +// 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 std::sync::Arc; + +pub(crate) use rustfs_ecstore::api::bucket::metadata::BucketMetadata as SwiftBucketMetadata; +use rustfs_ecstore::api::bucket::metadata_sys::{ + get as get_swift_bucket_metadata_from_backend, set_bucket_metadata as set_swift_bucket_metadata_in_backend, +}; +pub(crate) use rustfs_ecstore::api::error::Result as SwiftStorageResult; +pub(crate) use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_swift_object_store_handle; +use rustfs_ecstore::api::storage::ECStore as SwiftStore; +pub(crate) use rustfs_storage_api::{ + BucketInfo, BucketOperations, BucketOptions, DeleteBucketOptions, HTTPRangeSpec, ListOperations, MakeBucketOptions, ObjectIO, + ObjectOperations, +}; + +pub type SwiftGetObjectReader = ::GetObjectReader; +pub type SwiftObjectInfo = ::ObjectInfo; +pub type SwiftObjectOptions = ::ObjectOptions; +pub type SwiftPutObjReader = ::PutObjectReader; + +pub(crate) async fn get_swift_bucket_metadata(bucket: &str) -> SwiftStorageResult> { + get_swift_bucket_metadata_from_backend(bucket).await +} + +pub(crate) async fn set_swift_bucket_metadata(bucket: String, metadata: SwiftBucketMetadata) -> SwiftStorageResult<()> { + set_swift_bucket_metadata_in_backend(bucket, metadata).await +} diff --git a/crates/protocols/src/swift/versioning.rs b/crates/protocols/src/swift/versioning.rs index c9d7b13f1..8f4d7c682 100644 --- a/crates/protocols/src/swift/versioning.rs +++ b/crates/protocols/src/swift/versioning.rs @@ -55,9 +55,9 @@ use super::account::validate_account_access; use super::container::ContainerMapper; use super::object::{ObjectKeyMapper, SwiftObjectOptions as ObjectOptions, head_object}; use super::resolve_swift_object_store_handle; +use super::storage_api::{ListOperations as _, ObjectOperations as _}; use super::{SwiftError, SwiftResult}; use rustfs_credentials::Credentials; -use rustfs_storage_api::{ListOperations as _, ObjectOperations as _}; use std::time::{SystemTime, UNIX_EPOCH}; use tracing::{debug, error}; diff --git a/crates/s3select-api/src/lib.rs b/crates/s3select-api/src/lib.rs index 2ed6e97e6..a26ad291e 100644 --- a/crates/s3select-api/src/lib.rs +++ b/crates/s3select-api/src/lib.rs @@ -13,46 +13,23 @@ // limitations under the License. use datafusion::{common::DataFusionError, sql::sqlparser::parser::ParserError}; -pub(crate) use rustfs_ecstore::api::error::StorageError as SelectStorageError; -use rustfs_ecstore::api::error::{ - is_err_bucket_not_found as select_is_err_bucket_not_found_from_backend, - is_err_object_not_found as select_is_err_object_not_found_from_backend, - is_err_version_not_found as select_is_err_version_not_found_from_backend, -}; -use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_select_object_store_handle_from_backend; -pub(crate) use rustfs_ecstore::api::set_disk::DEFAULT_READ_BUFFER_SIZE as SELECT_DEFAULT_READ_BUFFER_SIZE; -pub(crate) use rustfs_ecstore::api::storage::ECStore as SelectStore; use snafu::{Backtrace, Location, Snafu}; -use std::{fmt::Display, sync::Arc}; +use std::fmt::Display; pub mod object_store; pub mod query; pub mod server; +mod storage_api; #[cfg(test)] mod test; pub type QueryResult = Result; - -pub(crate) type SelectGetObjectReader = ::GetObjectReader; -pub(crate) type SelectObjectInfo = ::ObjectInfo; -pub(crate) type SelectObjectOptions = ::ObjectOptions; - -pub(crate) fn resolve_select_object_store_handle() -> Option> { - resolve_select_object_store_handle_from_backend() -} - -pub(crate) fn select_is_err_bucket_not_found(err: &SelectStorageError) -> bool { - select_is_err_bucket_not_found_from_backend(err) -} - -pub(crate) fn select_is_err_object_not_found(err: &SelectStorageError) -> bool { - select_is_err_object_not_found_from_backend(err) -} - -pub(crate) fn select_is_err_version_not_found(err: &SelectStorageError) -> bool { - select_is_err_version_not_found_from_backend(err) -} +pub(crate) use storage_api::{ + SELECT_DEFAULT_READ_BUFFER_SIZE, SelectGetObjectReader, SelectObjectInfo, SelectObjectOptions, SelectStorageError, + SelectStore, resolve_select_object_store_handle, select_is_err_bucket_not_found, select_is_err_object_not_found, + select_is_err_version_not_found, +}; #[derive(Debug, Snafu)] #[snafu(visibility(pub))] diff --git a/crates/s3select-api/src/object_store.rs b/crates/s3select-api/src/object_store.rs index bcbdfb7ad..0b4565c25 100644 --- a/crates/s3select-api/src/object_store.rs +++ b/crates/s3select-api/src/object_store.rs @@ -30,7 +30,6 @@ use futures_core::stream::BoxStream; use http::{HeaderMap, HeaderValue, header::HeaderName}; use pin_project_lite::pin_project; use rustfs_common::DEFAULT_DELIMITER; -use rustfs_storage_api::{HTTPRangeSpec, ObjectIO as _, ObjectOperations as _}; use s3s::S3Result; use s3s::dto::SelectObjectContentInput; use s3s::header::{ @@ -49,6 +48,8 @@ use tokio::io::{AsyncRead, ReadBuf}; use tokio_util::io::ReaderStream; use transform_stream::AsyncTryStream; +use crate::storage_api::{HTTPRangeSpec, ObjectIO as _, ObjectOperations as _}; + fn select_default_read_buffer_size_u64() -> u64 { u64::try_from(SELECT_DEFAULT_READ_BUFFER_SIZE).unwrap_or(u64::MAX) } diff --git a/crates/s3select-api/src/storage_api.rs b/crates/s3select-api/src/storage_api.rs new file mode 100644 index 000000000..edcdee02d --- /dev/null +++ b/crates/s3select-api/src/storage_api.rs @@ -0,0 +1,46 @@ +// 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 std::sync::Arc; + +pub(crate) use rustfs_ecstore::api::error::StorageError as SelectStorageError; +use rustfs_ecstore::api::error::{ + is_err_bucket_not_found as select_is_err_bucket_not_found_from_backend, + is_err_object_not_found as select_is_err_object_not_found_from_backend, + is_err_version_not_found as select_is_err_version_not_found_from_backend, +}; +use rustfs_ecstore::api::global::resolve_object_store_handle as resolve_select_object_store_handle_from_backend; +pub(crate) use rustfs_ecstore::api::set_disk::DEFAULT_READ_BUFFER_SIZE as SELECT_DEFAULT_READ_BUFFER_SIZE; +pub(crate) use rustfs_ecstore::api::storage::ECStore as SelectStore; +pub(crate) use rustfs_storage_api::{HTTPRangeSpec, ObjectIO, ObjectOperations}; + +pub(crate) type SelectGetObjectReader = ::GetObjectReader; +pub(crate) type SelectObjectInfo = ::ObjectInfo; +pub(crate) type SelectObjectOptions = ::ObjectOptions; + +pub(crate) fn resolve_select_object_store_handle() -> Option> { + resolve_select_object_store_handle_from_backend() +} + +pub(crate) fn select_is_err_bucket_not_found(err: &SelectStorageError) -> bool { + select_is_err_bucket_not_found_from_backend(err) +} + +pub(crate) fn select_is_err_object_not_found(err: &SelectStorageError) -> bool { + select_is_err_object_not_found_from_backend(err) +} + +pub(crate) fn select_is_err_version_not_found(err: &SelectStorageError) -> bool { + select_is_err_version_not_found_from_backend(err) +} diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index dd3a2d067..0deeadb27 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,9 +5,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Current Context - Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660) -- Branch: `overtrue/arch-external-crate-storage-boundary-sweep` -- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181/API-182/API-183/API-184/API-185/API-186/API-187/API-188/API-189/API-190/API-191/API-192/API-193/API-194/API-195/API-196/API-197/API-198/API-199/API-200/API-201/API-202/API-203/API-204/API-205/API-206/API-207/API-208/API-209/API-210/API-211/API-212/API-213/API-214/API-215/API-216/API-217/API-218/API-219/API-220/API-221`. -- Based on: API-221 branch; branch routes scanner and heal source plus integration test storage symbols through local `storage_api` boundaries. +- Branch: `overtrue/arch-remaining-external-storage-boundaries` +- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181/API-182/API-183/API-184/API-185/API-186/API-187/API-188/API-189/API-190/API-191/API-192/API-193/API-194/API-195/API-196/API-197/API-198/API-199/API-200/API-201/API-202/API-203/API-204/API-205/API-206/API-207/API-208/API-209/API-210/API-211/API-212/API-213/API-214/API-215/API-216/API-217/API-218/API-219/API-220/API-221/API-222`. +- Based on: API-222 branch; branch routes remaining external runtime, test, and fuzz storage symbols through local `storage_api` boundaries. - PR type for this branch: `consumer-migration` - Runtime behavior changes: none. - Rust code changes: route replication pool, outbound TLS generation, runtime @@ -56,8 +56,10 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block config tests through a root-local storage_api boundary, plus root/server/startup `rustfs_storage_api` contract imports through the same boundary, app/admin `rustfs_storage_api` contract imports through their local boundaries, app - S3 helper forwarding through `app::storage_api`, and scanner/heal source and + S3 helper forwarding through `app::storage_api`, scanner/heal source and test ECStore plus storage contract imports through crate-local `storage_api` + boundaries, and remaining IAM, notify, OBS metrics, Swift, S3 Select, e2e, + and fuzz ECStore/storage contract imports through local `storage_api` boundaries. - CI/script changes: lock completed owner and test/fuzz boundaries against bare/glob imports, scattered raw ECStore facade subpaths, and startup @@ -68,8 +70,8 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block event-bridge thin module regressions, plus IAM runtime-source bypasses; accept the reviewed AppContext resolver reverse dependencies in the layer baseline, and block direct admin AppContext resolver consumers outside the - admin runtime-source boundary, block root, app usecase, and storage direct AppContext resolver consumers outside their runtime-source boundaries, catch grouped AppContext imports, reject app usecase storage wildcard imports, reject app-layer S3 DTO and ECFS wildcard imports, narrow the object-usecase ECFS layer baseline entry to `FS`, reject direct storage S3 API helper imports from app usecase files, reject direct storage helper imports from app select/usecase files, reject completed app/admin storage helper bypasses, reject app usecase bypasses for migrated storage IO/compression/set-disk helpers, reject app usecase/test bypasses for migrated storage error, ETag, and storage-class helpers, reject app root bucket owner facade bypasses from migrated app consumers, reject app/admin runtime/data-usage root facade regressions, reject admin root storage facade regressions from migrated admin consumers, reject root/server/startup direct storage facade regressions from migrated outer consumers, reject root/server/startup direct storage contract imports from migrated outer consumers, reject app/admin direct storage contract imports from migrated owner consumers, keep app S3 helper imports routed through `app::storage_api`, and reject scanner/heal direct ECStore or storage contract imports outside their local `storage_api` boundaries. -- Docs changes: record the API-136 through API-222 owner facade and lifecycle + admin runtime-source boundary, block root, app usecase, and storage direct AppContext resolver consumers outside their runtime-source boundaries, catch grouped AppContext imports, reject app usecase storage wildcard imports, reject app-layer S3 DTO and ECFS wildcard imports, narrow the object-usecase ECFS layer baseline entry to `FS`, reject direct storage S3 API helper imports from app usecase files, reject direct storage helper imports from app select/usecase files, reject completed app/admin storage helper bypasses, reject app usecase bypasses for migrated storage IO/compression/set-disk helpers, reject app usecase/test bypasses for migrated storage error, ETag, and storage-class helpers, reject app root bucket owner facade bypasses from migrated app consumers, reject app/admin runtime/data-usage root facade regressions, reject admin root storage facade regressions from migrated admin consumers, reject root/server/startup direct storage facade regressions from migrated outer consumers, reject root/server/startup direct storage contract imports from migrated outer consumers, reject app/admin direct storage contract imports from migrated owner consumers, keep app S3 helper imports routed through `app::storage_api`, reject scanner/heal direct ECStore or storage contract imports outside their local `storage_api` boundaries, and reject external runtime/test/fuzz ECStore or storage contract imports outside their local `storage_api` boundaries. +- Docs changes: record the API-136 through API-223 owner facade and lifecycle runtime-source cleanup. ## Phase 0 Tasks @@ -5228,14 +5230,32 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block migration and layer guards, diff hygiene, residual scanner/heal boundary scan, Rust risk scan, fast PR gate, and full PR gate before PR. +- [x] `API-223` Route remaining external storage imports through local storage_api boundaries. + - Do: move IAM, notify, OBS metrics, Swift, S3 Select, e2e, and fuzz ECStore + plus `rustfs_storage_api` imports into local boundary modules, then route + callers through those boundaries. + - Acceptance: migrated external runtime/test/fuzz consumers no longer import + ECStore or storage contract symbols directly, and migration rules reject + direct bypasses outside the reviewed boundary modules. + - Must preserve: IAM config/error/notification behavior, notify config + persistence, OBS capacity/data-usage metrics, Swift bucket/object/range + operations, S3 Select object reads, e2e RPC/disk/bucket-target helpers, and + fuzz validation semantics. + - Verification: focused external crate and fuzz compile coverage, formatting, + migration and layer guards, diff hygiene, residual external boundary scan, + Rust risk scan, fast PR gate, and full PR gate before PR. + ## Next PRs -1. `consumer-migration`: continue larger owner/external crate storage-boundary batches after API-222. +1. `consumer-migration`: continue larger owner/external crate storage-boundary batches after API-223. ## Pre-Push Review Log | Expert | Status | Notes | |---|---|---| +| Quality/architecture | pass | API-223 moves the remaining external runtime/test/fuzz ECStore and storage contract imports behind local storage_api boundaries. | +| Migration preservation | pass | IAM, notify, OBS metrics, Swift, S3 Select, e2e, and fuzz callers keep the same ECStore/storage implementations and behavior. | +| Testing/verification | pass | Focused external crate/fuzz compile coverage, formatting, migration/layer guards, residual boundary scan, Rust risk scan, fast PR gate, and full PR gate are planned before PR. | | Quality/architecture | pass | API-222 routes scanner and heal ECStore/storage contract imports through crate-local storage_api boundaries. | | Migration preservation | pass | Scanner lifecycle/tier/replication IO and heal disk/object/bucket test contracts keep the same ECStore and storage-api implementations. | | Testing/verification | pass | Focused scanner/heal compile coverage, formatting, migration/layer guards, residual boundary scan, Rust risk scan, fast PR gate, and full PR gate are planned before PR. | diff --git a/fuzz/fuzz_targets/bucket_validation.rs b/fuzz/fuzz_targets/bucket_validation.rs index 46009b0a0..6504babbc 100644 --- a/fuzz/fuzz_targets/bucket_validation.rs +++ b/fuzz/fuzz_targets/bucket_validation.rs @@ -1,7 +1,8 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use rustfs_ecstore::api::bucket::utils::{ +mod bucket_validation_storage_api; +use bucket_validation_storage_api::{ check_bucket_and_object_names, check_list_objs_args, check_valid_bucket_name_strict, is_meta_bucketname, }; diff --git a/fuzz/fuzz_targets/bucket_validation_storage_api.rs b/fuzz/fuzz_targets/bucket_validation_storage_api.rs new file mode 100644 index 000000000..0bc702d6d --- /dev/null +++ b/fuzz/fuzz_targets/bucket_validation_storage_api.rs @@ -0,0 +1,17 @@ +// 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. + +pub(crate) use rustfs_ecstore::api::bucket::utils::{ + check_bucket_and_object_names, check_list_objs_args, check_valid_bucket_name_strict, is_meta_bucketname, +}; diff --git a/fuzz/fuzz_targets/path_containment.rs b/fuzz/fuzz_targets/path_containment.rs index 2bba67086..4c8947233 100644 --- a/fuzz/fuzz_targets/path_containment.rs +++ b/fuzz/fuzz_targets/path_containment.rs @@ -1,9 +1,8 @@ #![no_main] use libfuzzer_sys::fuzz_target; -use rustfs_ecstore::api::bucket::utils::{ - check_object_name_for_length_and_slash, has_bad_path_component, is_valid_object_prefix, -}; +mod path_containment_storage_api; +use path_containment_storage_api::{check_object_name_for_length_and_slash, has_bad_path_component, is_valid_object_prefix}; use rustfs_utils::path::{clean, path_join}; use std::path::{Path, PathBuf}; diff --git a/fuzz/fuzz_targets/path_containment_storage_api.rs b/fuzz/fuzz_targets/path_containment_storage_api.rs new file mode 100644 index 000000000..f54cdf0e2 --- /dev/null +++ b/fuzz/fuzz_targets/path_containment_storage_api.rs @@ -0,0 +1,17 @@ +// 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. + +pub(crate) use rustfs_ecstore::api::bucket::utils::{ + check_object_name_for_length_and_slash, has_bad_path_component, is_valid_object_prefix, +}; diff --git a/scripts/check_architecture_migration_rules.sh b/scripts/check_architecture_migration_rules.sh index 7d1be626f..89bd669a3 100755 --- a/scripts/check_architecture_migration_rules.sh +++ b/scripts/check_architecture_migration_rules.sh @@ -112,6 +112,7 @@ RUSTFS_APP_BUCKET_OWNER_SOURCE_HITS_FILE="${TMP_DIR}/rustfs_app_bucket_owner_sou RUSTFS_APP_ECSTORE_SOURCE_HITS_FILE="${TMP_DIR}/rustfs_app_ecstore_source_hits.txt" RUSTFS_ADMIN_ECSTORE_SOURCE_HITS_FILE="${TMP_DIR}/rustfs_admin_ecstore_source_hits.txt" EXTERNAL_RUNTIME_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/external_runtime_ecstore_compat_bypass_hits.txt" +EXTERNAL_RUNTIME_STORAGE_API_BYPASS_HITS_FILE="${TMP_DIR}/external_runtime_storage_api_bypass_hits.txt" EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/external_test_ecstore_compat_bypass_hits.txt" FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE="${TMP_DIR}/fuzz_ecstore_compat_bypass_hits.txt" ALL_STORAGE_COMPAT_SELF_FACADE_PATH_HITS_FILE="${TMP_DIR}/all_storage_compat_self_facade_path_hits.txt" @@ -761,7 +762,7 @@ fi --glob '!**/ecstore_test_compat/**' \ --glob '!**/ecstore_fuzz_compat.rs' \ --glob '!target/**' \ - | rg -v '^(rustfs/src/(admin/mod|app/mod|storage/mod)\.rs|crates/e2e_test/src/(replication_extension_test|reliant/(grpc_lock_client|node_interact_test))\.rs|crates/heal/src/heal/storage_api\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/iam/src/(lib|runtime_sources)\.rs|crates/notify/src/lib\.rs|crates/obs/src/metrics/mod\.rs|crates/protocols/src/swift/mod\.rs|crates/s3select-api/src/lib\.rs|crates/scanner/src/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs|fuzz/fuzz_targets/(bucket_validation|path_containment)\.rs):' || true + | rg -v '^(rustfs/src/(admin/mod|app/mod|storage/mod)\.rs|crates/e2e_test/src/storage_api\.rs|crates/heal/src/heal/storage_api\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/iam/src/storage_api\.rs|crates/notify/src/storage_api\.rs|crates/obs/src/metrics/storage_api\.rs|crates/protocols/src/swift/storage_api\.rs|crates/s3select-api/src/storage_api\.rs|crates/scanner/src/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs|fuzz/fuzz_targets/(bucket_validation_storage_api|path_containment_storage_api)\.rs):' || true ) | cat >"$DIRECT_ECSTORE_IMPORT_HITS_FILE" @@ -1110,7 +1111,7 @@ fi --glob '!**/ecstore_compat.rs' \ --glob '!**/ecstore_test_compat.rs' \ --glob '!**/ecstore_test_compat/**' | - rg -v '^(fuzz/fuzz_targets/bucket_validation\.rs|fuzz/fuzz_targets/path_containment\.rs|crates/e2e_test/src/reliant/grpc_lock_client\.rs|crates/e2e_test/src/reliant/node_interact_test\.rs|crates/e2e_test/src/replication_extension_test\.rs|crates/heal/src/heal/storage_api\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/iam/src/(lib|runtime_sources)\.rs|crates/notify/src/lib\.rs|crates/obs/src/metrics/mod\.rs|crates/protocols/src/swift/mod\.rs|crates/s3select-api/src/lib\.rs|crates/scanner/src/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs|rustfs/src/admin/mod\.rs|rustfs/src/app/mod\.rs|rustfs/src/storage/mod\.rs):' || true + rg -v '^(fuzz/fuzz_targets/(bucket_validation_storage_api|path_containment_storage_api)\.rs|crates/e2e_test/src/storage_api\.rs|crates/heal/src/heal/storage_api\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/iam/src/storage_api\.rs|crates/notify/src/storage_api\.rs|crates/obs/src/metrics/storage_api\.rs|crates/protocols/src/swift/storage_api\.rs|crates/s3select-api/src/storage_api\.rs|crates/scanner/src/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs|rustfs/src/admin/mod\.rs|rustfs/src/app/mod\.rs|rustfs/src/storage/mod\.rs):' || true ) >"$ALL_ECSTORE_API_RAW_SUBPATH_HITS_FILE" if [[ -s "$ALL_ECSTORE_API_RAW_SUBPATH_HITS_FILE" ]]; then @@ -1310,11 +1311,28 @@ fi crates/scanner/src \ --glob '*.rs' \ --glob '!**/ecstore_compat.rs' | - rg -v '^(crates/heal/src/heal/storage_api.rs|crates/iam/src/(lib|runtime_sources).rs|crates/notify/src/lib.rs|crates/obs/src/metrics/mod.rs|crates/protocols/src/swift/mod.rs|crates/s3select-api/src/lib.rs|crates/scanner/src/storage_api.rs):' || true + rg -v '^(crates/heal/src/heal/storage_api.rs|crates/iam/src/storage_api.rs|crates/notify/src/storage_api.rs|crates/obs/src/metrics/storage_api.rs|crates/protocols/src/swift/storage_api.rs|crates/s3select-api/src/storage_api.rs|crates/scanner/src/storage_api.rs):' || true ) >"$EXTERNAL_RUNTIME_ECSTORE_COMPAT_BYPASS_HITS_FILE" if [[ -s "$EXTERNAL_RUNTIME_ECSTORE_COMPAT_BYPASS_HITS_FILE" ]]; then - report_failure "external runtime crates must source ECStore API symbols through their owner root or ecstore_compat boundary: $(paste -sd '; ' "$EXTERNAL_RUNTIME_ECSTORE_COMPAT_BYPASS_HITS_FILE")" + report_failure "external runtime crates must source ECStore API symbols through their local storage_api boundary: $(paste -sd '; ' "$EXTERNAL_RUNTIME_ECSTORE_COMPAT_BYPASS_HITS_FILE")" +fi + +( + cd "$ROOT_DIR" + rg -n --with-filename '^use rustfs_storage_api|rustfs_storage_api::' \ + crates/heal/src/heal \ + crates/iam/src \ + crates/obs/src/metrics \ + crates/protocols/src/swift \ + crates/s3select-api/src \ + crates/scanner/src \ + --glob '*.rs' | + rg -v '^(crates/heal/src/heal/storage_api.rs|crates/iam/src/storage_api.rs|crates/obs/src/metrics/storage_api.rs|crates/protocols/src/swift/storage_api.rs|crates/s3select-api/src/storage_api.rs|crates/scanner/src/storage_api.rs):' || true +) >"$EXTERNAL_RUNTIME_STORAGE_API_BYPASS_HITS_FILE" + +if [[ -s "$EXTERNAL_RUNTIME_STORAGE_API_BYPASS_HITS_FILE" ]]; then + report_failure "external runtime crates must source storage-api contracts through their local storage_api boundary: $(paste -sd '; ' "$EXTERNAL_RUNTIME_STORAGE_API_BYPASS_HITS_FILE")" fi ( @@ -1322,11 +1340,11 @@ fi rg -n --with-filename 'get_global_(?:action_cred|server_config|notification_sys)' \ crates/iam/src \ --glob '*.rs' | - rg -v '^crates/iam/src/runtime_sources\.rs:' || true + rg -v '^crates/iam/src/(runtime_sources|storage_api)\.rs:' || true ) >"$IAM_RUNTIME_SOURCE_BYPASS_HITS_FILE" if [[ -s "$IAM_RUNTIME_SOURCE_BYPASS_HITS_FILE" ]]; then - report_failure "IAM runtime-source globals must stay behind crates/iam/src/runtime_sources.rs: $(paste -sd '; ' "$IAM_RUNTIME_SOURCE_BYPASS_HITS_FILE")" + report_failure "IAM runtime-source globals must stay behind IAM runtime or storage boundaries: $(paste -sd '; ' "$IAM_RUNTIME_SOURCE_BYPASS_HITS_FILE")" fi ( @@ -1598,11 +1616,11 @@ fi crates/scanner/tests \ crates/e2e_test/src \ --glob '*.rs' \ - | rg -v '^(crates/e2e_test/src/(replication_extension_test|reliant/(grpc_lock_client|node_interact_test))\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs):' || true + | rg -v '^(crates/e2e_test/src/storage_api\.rs|crates/heal/tests/(endpoint_index_test|heal_bug_fixes_test|heal_integration_test)/storage_api\.rs|crates/scanner/tests/storage_api/mod\.rs):' || true ) >"$EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE" if [[ -s "$EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE" ]]; then - report_failure "external test ECStore API imports must stay in owner test files: $(paste -sd '; ' "$EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE")" + report_failure "external test ECStore API imports must stay in local test storage_api boundaries: $(paste -sd '; ' "$EXTERNAL_TEST_ECSTORE_COMPAT_BYPASS_HITS_FILE")" fi ( @@ -1610,11 +1628,11 @@ fi rg -n --with-filename 'rustfs_ecstore::api::' \ fuzz/fuzz_targets \ --glob '*.rs' | - rg -v '^fuzz/fuzz_targets/(bucket_validation|path_containment)\.rs:' || true + rg -v '^fuzz/fuzz_targets/(bucket_validation_storage_api|path_containment_storage_api)\.rs:' || true ) >"$FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE" if [[ -s "$FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE" ]]; then - report_failure "fuzz ECStore API imports must stay in owner fuzz targets: $(paste -sd '; ' "$FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE")" + report_failure "fuzz ECStore API imports must stay in fuzz storage_api boundary: $(paste -sd '; ' "$FUZZ_ECSTORE_COMPAT_BYPASS_HITS_FILE")" fi (