diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 4da87d5ae..08e5e86a6 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,14 +5,14 @@ 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-admin-kms-manager-context` -- 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`. -- Based on: API-168 local branch stacked on API-167 local branch after API-163 PR #3777 merged. +- Branch: `overtrue/arch-admin-config-writes-context` +- 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`. +- Based on: API-169 local branch after API-168 PR #3781 merged. - PR type for this branch: `consumer-migration` - Runtime behavior changes: none. -- Rust code changes: route admin KMS service-manager initialization fallback - through an AppContext-first resolver with legacy global initialization - preserved when no manager is available. +- Rust code changes: route admin server-config and storage-class runtime + publication through AppContext-first publish helpers, with legacy global + setters preserved as default adapters. - CI/script changes: lock completed owner and test/fuzz boundaries against bare/glob imports, scattered raw ECStore facade subpaths, and startup runtime/root-server/table/S3/app shared/app bucket/app ECStore/admin facade @@ -21,7 +21,7 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block and storage owner thin bridge regressions, plus app context and notify event-bridge thin module regressions; accept the reviewed AppContext resolver reverse dependencies in the layer baseline. -- Docs changes: record the 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 owner facade cleanup. +- Docs changes: record the 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 owner facade cleanup. ## Phase 0 Tasks @@ -4431,6 +4431,21 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block migration guard, layer guard, formatting, diff hygiene, residual admin KMS init scan, Rust risk scan, branch freshness check, and three-expert review. +- [x] `API-169` Route admin config publication through AppContext. + - Do: add AppContext-first publish helpers for server config and storage + class config, then route admin config write/reload publication through + those helpers. + - Acceptance: admin production handlers and services no longer directly call + `set_global_server_config` or the admin storage-class global setter, while + AppContext default adapters preserve the legacy global-setter fallback. + - Must preserve: config validation, config history persistence, runtime + snapshot reload semantics, dynamic subsystem application, storage-class + parsing, and store persistence behavior. + - Verification: RustFS compile coverage, targeted context resolver tests, + migration guard, layer guard, formatting, diff hygiene, residual admin + config publication scan, Rust risk scan, branch freshness check, and + three-expert review. + ## Next PRs 1. `consumer-migration`: continue reducing direct global reads behind AppContext resolver boundaries. @@ -4491,11 +4506,30 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block | Quality/architecture | pass | API-168 keeps admin KMS service-manager initialization behind the AppContext resolver boundary. | | Migration preservation | pass | KMS key, management, and dynamic handlers preserve legacy initialization fallback and existing fallback logs. | | Testing/verification | pass | RustFS focused compile, targeted context tests, formatting, migration/layer guards, diff hygiene, residual KMS init scan, and Rust risk scan passed for API-168. | +| Quality/architecture | pass | API-169 keeps admin config runtime publication behind AppContext publish helpers with default global-setter adapters. | +| Migration preservation | pass | Config writes, runtime reload, dynamic subsystem application, and storage-class parsing preserve existing persistence and runtime side effects. | +| Testing/verification | pass | RustFS focused compile, targeted context tests, formatting, migration/layer guards, diff hygiene, residual config publication scan, and Rust risk scan passed for API-169. | ## Verification Notes Passed before push: +- Issue #660 API-169 current slice: + - `cargo check --tests -p rustfs`: passed. + - `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`: + passed. + - `cargo fmt --all`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - `bash -n scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - AppContext admin config publication scan: passed; direct admin production + `set_global_server_config` and storage-class global setter calls are + removed. + - Rust risk scan: no new production unwrap/expect, panic/todo/unsafe, or cast + risks added. + - Issue #660 API-164 current slice: - `cargo check --tests -p rustfs`: passed. - `cargo test -p rustfs resolver_helpers_are_context_first_and_fallback_when_context_is_absent --lib`: diff --git a/rustfs/src/admin/handlers/config_admin.rs b/rustfs/src/admin/handlers/config_admin.rs index 74ef3d83e..ac1f62ca1 100644 --- a/rustfs/src/admin/handlers/config_admin.rs +++ b/rustfs/src/admin/handlers/config_admin.rs @@ -24,7 +24,7 @@ use crate::admin::service::config::{ validate_server_config, }; use crate::admin::utils::{encode_compatible_admin_payload, is_compat_admin_request, read_compatible_admin_body}; -use crate::app::context::{resolve_object_store_handle, resolve_server_config}; +use crate::app::context::{publish_server_config, resolve_object_store_handle, resolve_server_config}; use crate::auth::{check_key_valid, get_session_token}; use crate::error::ApiError; use crate::server::{ADMIN_PREFIX, RemoteAddr}; @@ -54,7 +54,7 @@ use rustfs_config::oidc::{ OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, OIDC_CONFIG_URL, OIDC_DISPLAY_NAME, OIDC_EMAIL_CLAIM, OIDC_GROUPS_CLAIM, OIDC_REDIRECT_URI, OIDC_REDIRECT_URI_DYNAMIC, OIDC_ROLE_POLICY, OIDC_SCOPES, OIDC_USERNAME_CLAIM, }; -use rustfs_config::server_config::{Config as ServerConfig, DEFAULT_KVS, KV, KVS, set_global_server_config}; +use rustfs_config::server_config::{Config as ServerConfig, DEFAULT_KVS, KV, KVS}; use rustfs_config::{ COMMENT_KEY, DEFAULT_DELIMITER, ENABLE_KEY, ENV_PREFIX, ENV_SCANNER_ALERT_EXCESS_FOLDERS, ENV_SCANNER_ALERT_EXCESS_VERSION_SIZE, ENV_SCANNER_ALERT_EXCESS_VERSIONS, ENV_SCANNER_BITROT_CYCLE_SECS, @@ -1592,7 +1592,7 @@ impl Operation for SetConfigKVHandler { validate_server_config(&config, sub_system).await?; save_server_config_history(&body).await?; save_server_config_to_store(&config).await?; - set_global_server_config(config.clone()); + publish_server_config(config.clone()); let mut config_applied = false; if let Some(sub_system) = sub_system && is_dynamic_config_subsystem(sub_system) @@ -1628,7 +1628,7 @@ impl Operation for DelConfigKVHandler { validate_server_config(&config, sub_system).await?; save_server_config_history(&body).await?; save_server_config_to_store(&config).await?; - set_global_server_config(config.clone()); + publish_server_config(config.clone()); let mut config_applied = false; if let Some(sub_system) = sub_system && is_dynamic_config_subsystem(sub_system) @@ -1726,7 +1726,7 @@ impl Operation for RestoreConfigHistoryKVHandler { apply_set_directives(&mut config, &directives)?; validate_server_config(&config, None).await?; save_server_config_to_store(&config).await?; - set_global_server_config(config.clone()); + publish_server_config(config.clone()); apply_and_signal_dynamic_subsystems(&config).await; signal_config_snapshot_reload().await; @@ -1765,7 +1765,7 @@ impl Operation for SetConfigHandler { validate_server_config(&config, None).await?; save_server_config_history(&body).await?; save_server_config_to_store(&config).await?; - set_global_server_config(config.clone()); + publish_server_config(config.clone()); apply_and_signal_dynamic_subsystems(&config).await; signal_config_snapshot_reload().await; diff --git a/rustfs/src/admin/mod.rs b/rustfs/src/admin/mod.rs index ae7b6a2ab..fb7ccb1a5 100644 --- a/rustfs/src/admin/mod.rs +++ b/rustfs/src/admin/mod.rs @@ -119,7 +119,7 @@ mod ecstore_client { } mod ecstore_config { - pub(crate) use crate::storage::ecstore_config::{com, init, set_global_storage_class, storageclass}; + pub(crate) use crate::storage::ecstore_config::{com, init, storageclass}; } mod ecstore_data_usage { @@ -462,10 +462,6 @@ pub(crate) fn init_admin_config_defaults() { ecstore_config::init(); } -pub(crate) fn set_global_storage_class(cfg: storageclass::Config) { - ecstore_config::set_global_storage_class(cfg); -} - pub(crate) async fn load_data_usage_from_backend( store: Arc, ) -> std::result::Result { diff --git a/rustfs/src/admin/service/config.rs b/rustfs/src/admin/service/config.rs index 62f20a088..592b8edb3 100644 --- a/rustfs/src/admin/service/config.rs +++ b/rustfs/src/admin/service/config.rs @@ -12,15 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use super::super::set_global_storage_class; use super::super::storageclass; use super::super::{STORAGE_CLASS_SUB_SYS, read_admin_config_without_migrate}; -use crate::app::context::{resolve_notification_system, resolve_object_store_handle}; +use crate::app::context::{ + publish_server_config, publish_storage_class_config, resolve_notification_system, resolve_object_store_handle, +}; use rustfs_audit::reload_audit_config; use rustfs_config::audit::{AUDIT_MQTT_SUB_SYS, AUDIT_REDIS_DEFAULT_CHANNEL, AUDIT_WEBHOOK_SUB_SYS}; use rustfs_config::notify::{NOTIFY_MQTT_SUB_SYS, NOTIFY_REDIS_DEFAULT_CHANNEL, NOTIFY_WEBHOOK_SUB_SYS}; use rustfs_config::oidc::IDENTITY_OPENID_SUB_SYS; -use rustfs_config::server_config::{Config as ServerConfig, KVS, set_global_server_config}; +use rustfs_config::server_config::{Config as ServerConfig, KVS}; use rustfs_config::{AUDIT_DEFAULT_DIR, EVENT_DEFAULT_DIR}; use rustfs_config::{DEFAULT_DELIMITER, ENABLE_KEY, EnableState}; use rustfs_config::{HEAL_SUB_SYS, SCANNER_SUB_SYS}; @@ -77,7 +78,7 @@ async fn apply_storage_class_runtime_config(config: &ServerConfig) -> S3Result<( .unwrap_or(1); let parsed = storageclass::lookup_config(&kvs, set_drive_count) .map_err(|err| internal_error(format!("failed to apply storage class config: {err}")))?; - set_global_storage_class(parsed); + publish_storage_class_config(parsed); Ok(()) } @@ -335,7 +336,7 @@ pub async fn reload_runtime_config_snapshot() -> S3Result<()> { } } - set_global_server_config(config); + publish_server_config(config); Ok(()) } diff --git a/rustfs/src/app/context.rs b/rustfs/src/app/context.rs index 5acc3474f..8b1a48cbd 100644 --- a/rustfs/src/app/context.rs +++ b/rustfs/src/app/context.rs @@ -29,6 +29,7 @@ use super::DailyAllTierStats; use super::ECStore; use super::EndpointServerPools; use super::ScannerMetricsReport; +use super::StorageClassConfig; use super::TierConfigMgr; use super::metadata_sys::BucketMetadataSys; use super::new_object_layer_fn; @@ -179,6 +180,18 @@ pub fn resolve_server_config() -> Option { resolve_server_config_with(get_global_app_context(), || default_server_config_interface().get()) } +/// Publish server config using AppContext-first precedence. +pub fn publish_server_config(config: Config) { + publish_server_config_with(get_global_app_context(), config, |config| default_server_config_interface().set(config)); +} + +/// Publish storage class config using AppContext-first precedence. +pub fn publish_storage_class_config(config: StorageClassConfig) { + publish_storage_class_config_with(get_global_app_context(), config, |config| { + default_storage_class_interface().set(config); + }); +} + /// Resolve buffer profile config using AppContext-first precedence. pub fn resolve_buffer_config() -> RustFSBufferConfig { resolve_buffer_config_with(get_global_app_context(), || default_buffer_config_interface().get()) @@ -365,6 +378,26 @@ fn resolve_server_config_with(context: Option>, fallback: impl F context.map_or_else(fallback, |context| context.server_config().get()) } +fn publish_server_config_with(context: Option>, config: Config, fallback: impl FnOnce(Config)) { + if let Some(context) = context { + context.server_config().set(config); + } else { + fallback(config); + } +} + +fn publish_storage_class_config_with( + context: Option>, + config: StorageClassConfig, + fallback: impl FnOnce(StorageClassConfig), +) { + if let Some(context) = context { + context.storage_class().set(config); + } else { + fallback(config); + } +} + fn resolve_buffer_config_with( context: Option>, fallback: impl FnOnce() -> RustFSBufferConfig, @@ -388,13 +421,14 @@ mod tests { ActionCredentialInterface, BootTimeInterface, BucketMetadataInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, OutboundTlsRuntimeInterface, RegionInterface, ReplicationStatsInterface, RuntimePortInterface, ScannerMetricsInterface, - ServerConfigInterface, TierConfigInterface, TierStatsInterface, + ServerConfigInterface, StorageClassInterface, TierConfigInterface, TierStatsInterface, }; use crate::config::{RustFSBufferConfig, WorkloadProfile}; use async_trait::async_trait; use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_lock::{LocalClient, LockClient}; use std::path::PathBuf; + use std::sync::atomic::{AtomicUsize, Ordering}; use std::time::{Duration, SystemTime}; use tempfile::TempDir; use tokio_util::sync::CancellationToken; @@ -582,12 +616,27 @@ mod tests { struct TestServerConfigInterface { config: Option, + published: Arc, } impl ServerConfigInterface for TestServerConfigInterface { fn get(&self) -> Option { self.config.clone() } + + fn set(&self, _config: Config) { + self.published.fetch_add(1, Ordering::SeqCst); + } + } + + struct TestStorageClassInterface { + published: Arc, + } + + impl StorageClassInterface for TestStorageClassInterface { + fn set(&self, _config: StorageClassConfig) { + self.published.fetch_add(1, Ordering::SeqCst); + } } struct TestBufferConfigInterface { @@ -674,6 +723,10 @@ mod tests { }; let tier_config = TierConfigMgr::new(); let server_config = Config::new(); + let context_server_config_published = Arc::new(AtomicUsize::new(0)); + let fallback_server_config_published = Arc::new(AtomicUsize::new(0)); + let context_storage_class_published = Arc::new(AtomicUsize::new(0)); + let fallback_storage_class_published = Arc::new(AtomicUsize::new(0)); let buffer_config = RustFSBufferConfig::new(WorkloadProfile::AiTraining); let context_lock_client: Arc = Arc::new(LocalClient::new()); let fallback_lock_client: Arc = Arc::new(LocalClient::new()); @@ -757,6 +810,10 @@ mod tests { }), server_config: Arc::new(TestServerConfigInterface { config: Some(server_config.clone()), + published: context_server_config_published.clone(), + }), + storage_class: Arc::new(TestStorageClassInterface { + published: context_storage_class_published.clone(), }), buffer_config: Arc::new(TestBufferConfigInterface { config: buffer_config }), }, @@ -847,6 +904,18 @@ mod tests { resolve_server_config_with(Some(context.clone()), || None).expect("context server config"), server_config ); + publish_server_config_with(Some(context.clone()), Config::new(), |config| { + drop(config); + fallback_server_config_published.fetch_add(1, Ordering::SeqCst); + }); + assert_eq!(context_server_config_published.load(Ordering::SeqCst), 1); + assert_eq!(fallback_server_config_published.load(Ordering::SeqCst), 0); + publish_storage_class_config_with(Some(context.clone()), StorageClassConfig::default(), |config| { + drop(config); + fallback_storage_class_published.fetch_add(1, Ordering::SeqCst); + }); + assert_eq!(context_storage_class_published.load(Ordering::SeqCst), 1); + assert_eq!(fallback_storage_class_published.load(Ordering::SeqCst), 0); assert_eq!( resolve_buffer_config_with(Some(context), || RustFSBufferConfig::new(WorkloadProfile::GeneralPurpose)).workload, WorkloadProfile::AiTraining @@ -922,6 +991,16 @@ mod tests { resolve_server_config_with(None, || Some(server_config.clone())).expect("fallback server config"), server_config ); + publish_server_config_with(None, Config::new(), |config| { + drop(config); + fallback_server_config_published.fetch_add(1, Ordering::SeqCst); + }); + assert_eq!(fallback_server_config_published.load(Ordering::SeqCst), 1); + publish_storage_class_config_with(None, StorageClassConfig::default(), |config| { + drop(config); + fallback_storage_class_published.fetch_add(1, Ordering::SeqCst); + }); + assert_eq!(fallback_storage_class_published.load(Ordering::SeqCst), 1); assert_eq!( resolve_buffer_config_with(None, || RustFSBufferConfig::new(WorkloadProfile::DataAnalytics)).workload, WorkloadProfile::DataAnalytics diff --git a/rustfs/src/app/context/global.rs b/rustfs/src/app/context/global.rs index fb54a26ae..f4dc0dc76 100644 --- a/rustfs/src/app/context/global.rs +++ b/rustfs/src/app/context/global.rs @@ -20,14 +20,14 @@ use super::handles::{ default_notification_system_interface, default_notify_interface, default_outbound_tls_runtime_interface, default_region_interface, default_replication_pool_interface, default_replication_stats_interface, default_runtime_port_interface, default_scanner_metrics_interface, default_server_config_interface, - default_tier_config_interface, default_tier_stats_interface, + default_storage_class_interface, default_tier_config_interface, default_tier_stats_interface, }; use super::interfaces::{ ActionCredentialInterface, BootTimeInterface, BucketMetadataInterface, BucketMonitorInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotificationSystemInterface, NotifyInterface, OutboundTlsRuntimeInterface, RegionInterface, ReplicationPoolInterface, ReplicationStatsInterface, RuntimePortInterface, ScannerMetricsInterface, ServerConfigInterface, - TierConfigInterface, TierStatsInterface, + StorageClassInterface, TierConfigInterface, TierStatsInterface, }; use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_kms::KmsServiceManager; @@ -60,6 +60,7 @@ pub struct AppContext { region: Arc, tier_config: Arc, server_config: Arc, + storage_class: Arc, buffer_config: Arc, } @@ -89,6 +90,7 @@ impl AppContext { region: default_region_interface(), tier_config: default_tier_config_interface(), server_config: default_server_config_interface(), + storage_class: default_storage_class_interface(), buffer_config: default_buffer_config_interface(), } } @@ -194,6 +196,10 @@ impl AppContext { self.server_config.clone() } + pub fn storage_class(&self) -> Arc { + self.storage_class.clone() + } + pub fn buffer_config(&self) -> Arc { self.buffer_config.clone() } @@ -223,6 +229,7 @@ pub(super) struct AppContextTestInterfaces { pub(super) region: Arc, pub(super) tier_config: Arc, pub(super) server_config: Arc, + pub(super) storage_class: Arc, pub(super) buffer_config: Arc, } @@ -253,6 +260,7 @@ impl AppContext { region: interfaces.region, tier_config: interfaces.tier_config, server_config: interfaces.server_config, + storage_class: interfaces.storage_class, buffer_config: interfaces.buffer_config, } } diff --git a/rustfs/src/app/context/handles.rs b/rustfs/src/app/context/handles.rs index 7f5d532e2..aa6941809 100644 --- a/rustfs/src/app/context/handles.rs +++ b/rustfs/src/app/context/handles.rs @@ -13,25 +13,27 @@ // limitations under the License. use super::super::EndpointServerPools; +use super::super::StorageClassConfig; use super::super::TierConfigMgr; use super::super::metadata_sys::{BucketMetadataSys, get_global_bucket_metadata_sys}; use super::super::{ collect_scanner_metrics_report, get_daily_all_tier_stats, get_global_boot_time, get_global_bucket_monitor, get_global_deployment_id, get_global_endpoints_opt, get_global_lock_client, get_global_notification_sys, get_global_region, get_global_replication_pool, get_global_replication_stats, get_global_tier_config_mgr, global_rustfs_port, + set_global_storage_class, }; use super::interfaces::{ ActionCredentialInterface, BootTimeInterface, BucketMetadataInterface, BucketMonitorInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotificationSystemInterface, NotifyInterface, OutboundTlsRuntimeInterface, RegionInterface, ReplicationPoolInterface, ReplicationStatsInterface, RuntimePortInterface, ScannerMetricsInterface, ServerConfigInterface, - TierConfigInterface, TierStatsInterface, + StorageClassInterface, TierConfigInterface, TierStatsInterface, }; use crate::config::{RustFSBufferConfig, get_global_buffer_config}; use async_trait::async_trait; use rustfs_common::get_global_local_node_name; use rustfs_config::server_config::Config; -use rustfs_config::server_config::get_global_server_config; +use rustfs_config::server_config::{get_global_server_config, set_global_server_config}; use rustfs_credentials::{Credentials, get_global_action_cred}; use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_kms::{KmsServiceManager, get_global_kms_service_manager}; @@ -303,6 +305,20 @@ impl ServerConfigInterface for ServerConfigHandle { fn get(&self) -> Option { get_global_server_config() } + + fn set(&self, config: Config) { + set_global_server_config(config); + } +} + +/// Default storage class config interface adapter. +#[derive(Default)] +pub struct StorageClassHandle; + +impl StorageClassInterface for StorageClassHandle { + fn set(&self, config: StorageClassConfig) { + set_global_storage_class(config); + } } /// Default buffer profile config interface adapter. @@ -395,6 +411,10 @@ pub fn default_server_config_interface() -> Arc { Arc::new(ServerConfigHandle) } +pub fn default_storage_class_interface() -> Arc { + Arc::new(StorageClassHandle) +} + pub fn default_buffer_config_interface() -> Arc { Arc::new(BufferConfigHandle) } diff --git a/rustfs/src/app/context/interfaces.rs b/rustfs/src/app/context/interfaces.rs index d53eeae9c..6a381e8cf 100644 --- a/rustfs/src/app/context/interfaces.rs +++ b/rustfs/src/app/context/interfaces.rs @@ -15,6 +15,7 @@ use super::super::DailyAllTierStats; use super::super::EndpointServerPools; use super::super::ScannerMetricsReport; +use super::super::StorageClassConfig; use super::super::TierConfigMgr; use super::super::metadata_sys::BucketMetadataSys; use super::super::{BucketBandwidthMonitor, DynReplicationPool, NotificationSys, ReplicationStats}; @@ -156,6 +157,12 @@ pub trait TierConfigInterface: Send + Sync { /// Server config interface for application-layer and server modules. pub trait ServerConfigInterface: Send + Sync { fn get(&self) -> Option; + fn set(&self, config: Config); +} + +/// Storage class config interface for admin runtime config publication. +pub trait StorageClassInterface: Send + Sync { + fn set(&self, config: StorageClassConfig); } /// Buffer profile config interface for application-layer use-cases. diff --git a/rustfs/src/app/mod.rs b/rustfs/src/app/mod.rs index 8040f5d95..a4b612ec4 100644 --- a/rustfs/src/app/mod.rs +++ b/rustfs/src/app/mod.rs @@ -566,6 +566,12 @@ pub(crate) mod storageclass { pub(crate) const STANDARD_IA: &str = super::ecstore_config::storageclass::STANDARD_IA; } +pub(crate) type StorageClassConfig = crate::storage::ecstore_config::storageclass::Config; + +pub(crate) fn set_global_storage_class(cfg: StorageClassConfig) { + crate::storage::ecstore_config::set_global_storage_class(cfg); +} + pub(crate) fn get_total_usable_capacity(disks: &[rustfs_madmin::Disk], info: &rustfs_madmin::StorageInfo) -> usize { ecstore_capacity::get_total_usable_capacity(disks, info) }