From 2fe059811a308db64a32895623516ff49631a513 Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Tue, 23 Jun 2026 11:22:20 +0800 Subject: [PATCH] refactor: route admin topology reads through app context (#3774) * refactor: route admin topology reads through app context * chore: accept app context layer baseline entries --- docs/architecture/migration-progress.md | 51 ++++++++++++-- rustfs/src/admin/handlers/replication.rs | 5 +- rustfs/src/admin/handlers/site_replication.rs | 20 +++--- rustfs/src/admin/mod.rs | 16 +---- rustfs/src/admin/router.rs | 6 +- rustfs/src/app/context.rs | 68 ++++++++++++++++++- rustfs/src/app/context/global.rs | 26 +++++-- rustfs/src/app/context/handles.rs | 39 +++++++++-- rustfs/src/app/context/interfaces.rs | 10 +++ rustfs/src/app/mod.rs | 8 +++ rustfs/src/storage/mod.rs | 8 +++ scripts/layer-dependency-baseline.txt | 7 ++ 12 files changed, 215 insertions(+), 49 deletions(-) diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index 75368b0ce..4037b8d42 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,21 +5,22 @@ 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-runtime-context-resolvers` -- 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`. -- Based on: API-159 branch while PR #3772 is pending. +- Branch: `overtrue/arch-admin-topology-context-resolvers` +- 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`. +- Based on: API-160 branch while PR #3773 is pending. - PR type for this branch: `consumer-migration` - Runtime behavior changes: none. -- Rust code changes: route admin/server action credentials, region, and server - config consumers through AppContext resolvers with legacy global fallback. +- Rust code changes: route admin topology endpoint, deployment-id, and runtime + port consumers through AppContext resolvers with legacy global fallback. - 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 regressions, plus external runtime, test, fuzz, and storage-owner module ECStore compatibility bypasses, plus runtime crate, owner crate, test/fuzz, and storage owner thin bridge regressions, plus app context and notify - event-bridge thin module regressions. -- 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 owner facade cleanup. + 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 owner facade cleanup. ## Phase 0 Tasks @@ -4312,6 +4313,20 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block migration guard, formatting, diff hygiene, Rust risk scan, branch freshness check, pre-commit, and three-expert review. +- [x] `API-161` Route admin topology reads through AppContext resolvers. + - Do: add deployment-id and runtime-port AppContext interfaces, reuse the + endpoints resolver, default legacy adapters, and route admin topology + consumers through resolvers. + - Acceptance: admin site replication, replication handlers, and router code + no longer directly read endpoints, deployment id, or runtime port globals + outside AppContext default adapters. + - Must preserve: site replication endpoint inference, console-port fallback, + replication same-target validation, stale same-deployment target detection, + and legacy global fallback when AppContext is absent. + - Verification: RustFS compile coverage, targeted context resolver tests, + migration guard, formatting, diff hygiene, Rust risk scan, branch freshness + check, pre-commit, and three-expert review. + ## Next PRs 1. `consumer-migration`: continue reducing direct global reads behind AppContext resolver boundaries. @@ -4347,11 +4362,33 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block | Quality/architecture | pass | API-160 keeps admin runtime action credentials, region, and server config reads behind AppContext resolver boundaries. | | Migration preservation | pass | Admin authorization, object-ZIP token encryption, object-lambda signing, OIDC restart detection, and site replication metadata keep legacy fallback behavior. | | Testing/verification | pass | RustFS focused compile, targeted context tests, formatting, migration guard, diff hygiene, Rust risk scan, and pre-commit passed for API-160. | +| Quality/architecture | pass | API-161 keeps admin topology endpoint, deployment id, and runtime port reads behind AppContext resolver boundaries. | +| Migration preservation | pass | Site replication endpoint inference, same-target checks, same-deployment stale target detection, and runtime-port fallback keep legacy behavior. | +| Testing/verification | pass | RustFS focused compile, targeted context tests, formatting, migration guard, diff hygiene, Rust risk scan, and pre-commit passed for API-161. | +| Testing/verification | pass | CI follow-up: layer dependency baseline accepts the reviewed AppContext resolver reverse dependencies, and the layer guard passes. | ## Verification Notes Passed before push: +- Issue #660 API-161 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 after CI baseline + follow-up. + - `make pre-commit`: passed. + - AppContext admin topology resolver scan: passed; direct admin deployment + id, endpoint, and runtime port global reads are isolated to AppContext + default adapters. + - Rust risk scan: no new production panic/todo/unsafe/cast risks added; new + unwrap/expect hits are resolver fallback plumbing or test assertions. + - Issue #660 API-160 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/replication.rs b/rustfs/src/admin/handlers/replication.rs index 36a922d82..140ee3a0b 100644 --- a/rustfs/src/admin/handlers/replication.rs +++ b/rustfs/src/admin/handlers/replication.rs @@ -14,7 +14,6 @@ use super::super::StorageError; use super::super::bucket_target_sys::{BucketTargetError, BucketTargetSys}; -use super::super::global_rustfs_port; use super::super::metadata::BUCKET_TARGETS_FILE; use super::super::metadata_sys; use super::super::metadata_sys::get_replication_config; @@ -25,7 +24,7 @@ use crate::admin::auth::validate_admin_request; use crate::admin::handlers::site_replication::site_replication_peer_deployment_id_for_endpoint; use crate::admin::router::{AdminOperation, Operation, S3Router}; use crate::admin::utils::read_compatible_admin_body; -use crate::app::context::resolve_object_store_handle; +use crate::app::context::{resolve_object_store_handle, resolve_runtime_port}; use crate::auth::{check_key_valid, get_session_token}; use crate::error::ApiError; use crate::server::{ADMIN_PREFIX, RemoteAddr}; @@ -223,7 +222,7 @@ impl Operation for SetRemoteTargetHandler { let same_target = rustfs_utils::net::is_local_host( target_url.host().unwrap_or(Host::Domain("localhost")), target_url.port().unwrap_or(80), - global_rustfs_port(), + resolve_runtime_port(), ) .unwrap_or_default(); diff --git a/rustfs/src/admin/handlers/site_replication.rs b/rustfs/src/admin/handlers/site_replication.rs index 2e93c303e..e3a6973ca 100644 --- a/rustfs/src/admin/handlers/site_replication.rs +++ b/rustfs/src/admin/handlers/site_replication.rs @@ -25,7 +25,6 @@ use super::super::replication::{ResyncOpts, get_global_replication_pool}; use super::super::target::{ARN, BucketTarget, BucketTargetType, BucketTargets, Credentials}; use super::super::{AdminReplicationConfigExt as _, AdminVersioningConfigExt as _}; use super::super::{delete_admin_config, read_admin_config, save_admin_config}; -use super::super::{get_global_deployment_id, get_global_endpoints_opt, global_rustfs_port}; use crate::admin::auth::validate_admin_request; use crate::admin::router::{AdminOperation, Operation, S3Router}; use crate::admin::site_replication_identity::{ @@ -33,7 +32,10 @@ use crate::admin::site_replication_identity::{ site_identity_key, }; use crate::admin::utils::{encode_compatible_admin_payload, read_compatible_admin_body}; -use crate::app::context::{resolve_object_store_handle, resolve_region, resolve_server_config}; +use crate::app::context::{ + resolve_deployment_id, resolve_endpoints_handle, resolve_object_store_handle, resolve_region, resolve_runtime_port, + resolve_server_config, +}; use crate::auth::{check_key_valid, get_session_token}; use crate::config::get_config_snapshot; use crate::error::ApiError; @@ -671,7 +673,7 @@ fn runtime_tls_enabled_with(endpoints: Option<&super::super::EndpointServerPools } fn runtime_tls_enabled() -> bool { - let endpoints = get_global_endpoints_opt(); + let endpoints = resolve_endpoints_handle(); runtime_tls_enabled_with(endpoints.as_ref()) } @@ -822,7 +824,7 @@ fn request_endpoint(uri: &Uri, headers: &HeaderMap) -> String { .map(str::to_string) .or_else(|| uri.authority().map(|value| value.as_str().to_string())) .or_else(|| { - get_global_endpoints_opt().and_then(|endpoints| { + resolve_endpoints_handle().and_then(|endpoints| { endpoints .as_ref() .iter() @@ -831,7 +833,7 @@ fn request_endpoint(uri: &Uri, headers: &HeaderMap) -> String { .map(|endpoint| endpoint.host_port()) }) }) - .unwrap_or_else(|| format!("127.0.0.1:{}", global_rustfs_port())); + .unwrap_or_else(|| format!("127.0.0.1:{}", resolve_runtime_port())); format!("{scheme}://{host}") } @@ -859,7 +861,7 @@ fn site_replication_local_endpoint(uri: &Uri, headers: &HeaderMap) -> String { if !matches!(parsed.scheme(), "http" | "https") || parsed.host_str().is_none() { return request_endpoint(&Uri::from_static("/"), &HeaderMap::new()); } - if parsed.port_or_known_default() == runtime_console_port() && parsed.set_port(Some(global_rustfs_port())).is_ok() { + if parsed.port_or_known_default() == runtime_console_port() && parsed.set_port(Some(resolve_runtime_port())).is_ok() { parsed.to_string().trim_end_matches('/').to_string() } else { endpoint @@ -899,7 +901,7 @@ fn non_negative_u64(value: i64) -> u64 { fn current_local_peer(req: &S3Request, state: &SiteReplicationState) -> PeerInfo { let endpoint = site_replication_local_endpoint(&req.uri, &req.headers); - let deployment_id = get_global_deployment_id().unwrap_or_else(|| deployment_id_for_endpoint(&endpoint)); + let deployment_id = resolve_deployment_id().unwrap_or_else(|| deployment_id_for_endpoint(&endpoint)); let stored_peer = state.peers.get(&deployment_id); PeerInfo { @@ -923,7 +925,7 @@ fn current_local_peer(req: &S3Request, state: &SiteReplicationState) -> Pe fn current_local_runtime_peer(state: &SiteReplicationState) -> PeerInfo { let endpoint = current_local_runtime_endpoint(); - let deployment_id = get_global_deployment_id().unwrap_or_else(|| deployment_id_for_endpoint(&endpoint)); + let deployment_id = resolve_deployment_id().unwrap_or_else(|| deployment_id_for_endpoint(&endpoint)); let stored_peer = state.peers.get(&deployment_id); PeerInfo { @@ -4287,7 +4289,7 @@ impl Operation for SiteReplicationEditHandler { }; for target in current_state.peers.values() { - let local_target = get_global_deployment_id() + let local_target = resolve_deployment_id() .as_ref() .is_some_and(|deployment_id| deployment_id == &target.deployment_id); if local_target { diff --git a/rustfs/src/admin/mod.rs b/rustfs/src/admin/mod.rs index 4f6ef598c..711e3c9a9 100644 --- a/rustfs/src/admin/mod.rs +++ b/rustfs/src/admin/mod.rs @@ -136,9 +136,7 @@ mod ecstore_error { } mod ecstore_global { - pub(crate) use crate::storage::ecstore_global::{ - GLOBAL_BOOT_TIME, get_global_bucket_monitor, get_global_deployment_id, get_global_endpoints_opt, global_rustfs_port, - }; + pub(crate) use crate::storage::ecstore_global::{GLOBAL_BOOT_TIME, get_global_bucket_monitor}; } #[allow(unused_imports)] @@ -516,18 +514,6 @@ pub(crate) fn get_global_bucket_monitor() -> Option Option { - ecstore_global::get_global_deployment_id() -} - -pub(crate) fn get_global_endpoints_opt() -> Option { - ecstore_global::get_global_endpoints_opt() -} - -pub(crate) fn global_rustfs_port() -> u16 { - ecstore_global::global_rustfs_port() -} - pub(crate) async fn collect_local_metrics( types: MetricType, opts: &CollectMetricsOpts, diff --git a/rustfs/src/admin/router.rs b/rustfs/src/admin/router.rs index 8a5f73778..02442841a 100644 --- a/rustfs/src/admin/router.rs +++ b/rustfs/src/admin/router.rs @@ -16,6 +16,7 @@ use super::GLOBAL_BOOT_TIME; use super::PeerRestClient; use super::bandwidth::monitor::BandwidthDetails; use super::bucket_target_sys::{BucketTargetSys, PutObjectOptions, RemoveObjectOptions, S3ClientError, TargetClient}; +use super::get_global_bucket_monitor; use super::get_global_notification_sys; use super::metadata::BUCKET_TARGETS_FILE; use super::metadata_sys; @@ -26,10 +27,9 @@ use super::replication::{ use super::target::{BucketTarget, BucketTargetType, BucketTargets}; use super::versioning_sys::BucketVersioningSys; use super::{AdminReplicationConfigExt as _, AdminVersioningConfigExt as _}; -use super::{get_global_bucket_monitor, get_global_deployment_id}; use crate::admin::console::{is_console_path, make_console_server}; use crate::admin::handlers::oidc::is_oidc_path; -use crate::app::context::{resolve_object_store_handle, resolve_region, resolve_server_config}; +use crate::app::context::{resolve_deployment_id, resolve_object_store_handle, resolve_region, resolve_server_config}; use crate::app::object_usecase::DefaultObjectUsecase; use crate::auth::{check_key_valid, get_session_token}; use crate::error::ApiError; @@ -1829,7 +1829,7 @@ async fn check_replication_target(bucket: &str, target: &BucketTarget) -> Replic if target.target_bucket == bucket && !target.deployment_id.is_empty() - && get_global_deployment_id().as_deref() == Some(target.deployment_id.as_str()) + && resolve_deployment_id().as_deref() == Some(target.deployment_id.as_str()) { result.status = "FAILED".to_string(); result.error = Some("target bucket must not match source bucket on the same deployment".to_string()); diff --git a/rustfs/src/app/context.rs b/rustfs/src/app/context.rs index 0501f3c3b..2f1b1eae8 100644 --- a/rustfs/src/app/context.rs +++ b/rustfs/src/app/context.rs @@ -84,6 +84,16 @@ pub fn resolve_endpoints_handle() -> Option { resolve_endpoints_handle_with(get_global_app_context(), || default_endpoints_interface().handle()) } +/// Resolve deployment identity using AppContext-first precedence. +pub fn resolve_deployment_id() -> Option { + resolve_deployment_id_with(get_global_app_context(), || default_deployment_id_interface().get()) +} + +/// Resolve runtime port using AppContext-first precedence. +pub fn resolve_runtime_port() -> u16 { + resolve_runtime_port_with(get_global_app_context(), || default_runtime_port_interface().get()) +} + /// Resolve lock client using AppContext-first precedence. pub fn resolve_lock_client() -> Option> { resolve_lock_client_with(get_global_app_context(), || default_lock_client_interface().handle()) @@ -163,6 +173,14 @@ fn resolve_endpoints_handle_with( context.and_then(|context| context.endpoints().handle()).or_else(fallback) } +fn resolve_deployment_id_with(context: Option>, fallback: impl FnOnce() -> Option) -> Option { + context.and_then(|context| context.deployment_id().get()).or_else(fallback) +} + +fn resolve_runtime_port_with(context: Option>, fallback: impl FnOnce() -> u16) -> u16 { + context.map_or_else(fallback, |context| context.runtime_port().get()) +} + fn resolve_lock_client_with( context: Option>, fallback: impl FnOnce() -> Option>, @@ -226,9 +244,9 @@ mod tests { use crate::app::context::global::AppContextTestInterfaces; use crate::app::context::handles::default_notify_interface; use crate::app::context::interfaces::{ - ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, EndpointsInterface, IamInterface, - KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, RegionInterface, ServerConfigInterface, - TierConfigInterface, + ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, + IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, RegionInterface, + RuntimePortInterface, ServerConfigInterface, TierConfigInterface, }; use crate::config::{RustFSBufferConfig, WorkloadProfile}; use async_trait::async_trait; @@ -292,6 +310,26 @@ mod tests { } } + struct TestDeploymentIdInterface { + id: Option, + } + + impl DeploymentIdInterface for TestDeploymentIdInterface { + fn get(&self) -> Option { + self.id.clone() + } + } + + struct TestRuntimePortInterface { + port: u16, + } + + impl RuntimePortInterface for TestRuntimePortInterface { + fn get(&self) -> u16 { + self.port + } + } + struct TestLockClientInterface { client: Option>, } @@ -426,6 +464,10 @@ mod tests { let fallback_lock_client: Arc = Arc::new(LocalClient::new()); let context_node_name = "context-node".to_string(); let fallback_node_name = "fallback-node".to_string(); + let context_deployment_id = "context-deployment".to_string(); + let fallback_deployment_id = "fallback-deployment".to_string(); + let context_runtime_port = 19000; + let fallback_runtime_port = 29000; let context_credentials = Credentials { access_key: "context-access-key".to_string(), ..Default::default() @@ -454,6 +496,12 @@ mod tests { endpoints: Arc::new(TestEndpointsInterface { endpoints: Some(endpoints.clone()), }), + deployment_id: Arc::new(TestDeploymentIdInterface { + id: Some(context_deployment_id.clone()), + }), + runtime_port: Arc::new(TestRuntimePortInterface { + port: context_runtime_port, + }), lock_client: Arc::new(TestLockClientInterface { client: Some(context_lock_client.clone()), }), @@ -497,6 +545,15 @@ mod tests { .drives_per_set, endpoints.as_ref()[0].drives_per_set ); + assert_eq!( + resolve_deployment_id_with(Some(context.clone()), || Some(fallback_deployment_id.clone())) + .expect("context deployment id"), + context_deployment_id + ); + assert_eq!( + resolve_runtime_port_with(Some(context.clone()), || fallback_runtime_port), + context_runtime_port + ); assert!(Arc::ptr_eq( &resolve_lock_client_with(Some(context.clone()), || None).expect("context lock client"), &context_lock_client @@ -549,6 +606,11 @@ mod tests { .drives_per_set, endpoints.as_ref()[0].drives_per_set ); + assert_eq!( + resolve_deployment_id_with(None, || Some(fallback_deployment_id.clone())).expect("fallback deployment id"), + fallback_deployment_id + ); + assert_eq!(resolve_runtime_port_with(None, || fallback_runtime_port), fallback_runtime_port); assert!(Arc::ptr_eq( &resolve_lock_client_with(None, || Some(fallback_lock_client.clone())).expect("fallback lock client"), &fallback_lock_client diff --git a/rustfs/src/app/context/global.rs b/rustfs/src/app/context/global.rs index 84fadc5d8..e42f54bd2 100644 --- a/rustfs/src/app/context/global.rs +++ b/rustfs/src/app/context/global.rs @@ -15,14 +15,14 @@ use super::super::{ECStore, set_object_store_resolver}; use super::handles::{ IamHandle, KmsHandle, default_action_credential_interface, default_bucket_metadata_interface, - default_buffer_config_interface, default_endpoints_interface, default_kms_runtime_interface, + default_buffer_config_interface, default_deployment_id_interface, default_endpoints_interface, default_kms_runtime_interface, default_local_node_name_interface, default_lock_client_interface, default_notify_interface, default_region_interface, - default_server_config_interface, default_tier_config_interface, + default_runtime_port_interface, default_server_config_interface, default_tier_config_interface, }; use super::interfaces::{ - ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, EndpointsInterface, IamInterface, KmsInterface, - KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotifyInterface, RegionInterface, ServerConfigInterface, - TierConfigInterface, + ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, + IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotifyInterface, + RegionInterface, RuntimePortInterface, ServerConfigInterface, TierConfigInterface, }; use rustfs_iam::{store::object::ObjectStore, sys::IamSys}; use rustfs_kms::KmsServiceManager; @@ -39,6 +39,8 @@ pub struct AppContext { notify: Arc, bucket_metadata: Arc, endpoints: Arc, + deployment_id: Arc, + runtime_port: Arc, lock_client: Arc, local_node_name: Arc, action_credentials: Arc, @@ -58,6 +60,8 @@ impl AppContext { notify: default_notify_interface(), bucket_metadata: default_bucket_metadata_interface(), endpoints: default_endpoints_interface(), + deployment_id: default_deployment_id_interface(), + runtime_port: default_runtime_port_interface(), lock_client: default_lock_client_interface(), local_node_name: default_local_node_name_interface(), action_credentials: default_action_credential_interface(), @@ -105,6 +109,14 @@ impl AppContext { self.endpoints.clone() } + pub fn deployment_id(&self) -> Arc { + self.deployment_id.clone() + } + + pub fn runtime_port(&self) -> Arc { + self.runtime_port.clone() + } + pub fn lock_client(&self) -> Arc { self.lock_client.clone() } @@ -142,6 +154,8 @@ pub(super) struct AppContextTestInterfaces { pub(super) notify: Arc, pub(super) bucket_metadata: Arc, pub(super) endpoints: Arc, + pub(super) deployment_id: Arc, + pub(super) runtime_port: Arc, pub(super) lock_client: Arc, pub(super) local_node_name: Arc, pub(super) action_credentials: Arc, @@ -162,6 +176,8 @@ impl AppContext { notify: interfaces.notify, bucket_metadata: interfaces.bucket_metadata, endpoints: interfaces.endpoints, + deployment_id: interfaces.deployment_id, + runtime_port: interfaces.runtime_port, lock_client: interfaces.lock_client, local_node_name: interfaces.local_node_name, action_credentials: interfaces.action_credentials, diff --git a/rustfs/src/app/context/handles.rs b/rustfs/src/app/context/handles.rs index 3e5ec204d..df7025430 100644 --- a/rustfs/src/app/context/handles.rs +++ b/rustfs/src/app/context/handles.rs @@ -15,11 +15,14 @@ use super::super::EndpointServerPools; use super::super::TierConfigMgr; use super::super::metadata_sys::{BucketMetadataSys, get_global_bucket_metadata_sys}; -use super::super::{get_global_endpoints_opt, get_global_lock_client, get_global_region, get_global_tier_config_mgr}; +use super::super::{ + get_global_deployment_id, get_global_endpoints_opt, get_global_lock_client, get_global_region, get_global_tier_config_mgr, + global_rustfs_port, +}; use super::interfaces::{ - ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, EndpointsInterface, IamInterface, KmsInterface, - KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotifyInterface, RegionInterface, ServerConfigInterface, - TierConfigInterface, + ActionCredentialInterface, BucketMetadataInterface, BufferConfigInterface, DeploymentIdInterface, EndpointsInterface, + IamInterface, KmsInterface, KmsRuntimeInterface, LocalNodeNameInterface, LockClientInterface, NotifyInterface, + RegionInterface, RuntimePortInterface, ServerConfigInterface, TierConfigInterface, }; use crate::config::{RustFSBufferConfig, get_global_buffer_config}; use async_trait::async_trait; @@ -129,6 +132,26 @@ impl EndpointsInterface for EndpointsHandle { } } +/// Default deployment identity interface adapter. +#[derive(Default)] +pub struct DeploymentIdHandle; + +impl DeploymentIdInterface for DeploymentIdHandle { + fn get(&self) -> Option { + get_global_deployment_id() + } +} + +/// Default runtime port interface adapter. +#[derive(Default)] +pub struct RuntimePortHandle; + +impl RuntimePortInterface for RuntimePortHandle { + fn get(&self) -> u16 { + global_rustfs_port() + } +} + /// Default lock client interface adapter. #[derive(Default)] pub struct LockClientHandle; @@ -216,6 +239,14 @@ pub fn default_endpoints_interface() -> Arc { Arc::new(EndpointsHandle) } +pub fn default_deployment_id_interface() -> Arc { + Arc::new(DeploymentIdHandle) +} + +pub fn default_runtime_port_interface() -> Arc { + Arc::new(RuntimePortHandle) +} + pub fn default_lock_client_interface() -> Arc { Arc::new(LockClientHandle) } diff --git a/rustfs/src/app/context/interfaces.rs b/rustfs/src/app/context/interfaces.rs index 89bbfca98..12bcf2d9a 100644 --- a/rustfs/src/app/context/interfaces.rs +++ b/rustfs/src/app/context/interfaces.rs @@ -70,6 +70,16 @@ pub trait EndpointsInterface: Send + Sync { fn handle(&self) -> Option; } +/// Deployment identity interface for admin topology integration. +pub trait DeploymentIdInterface: Send + Sync { + fn get(&self) -> Option; +} + +/// Runtime port interface for admin topology integration. +pub trait RuntimePortInterface: Send + Sync { + fn get(&self) -> u16; +} + /// Lock client interface for application-layer use-cases. pub trait LockClientInterface: Send + Sync { fn handle(&self) -> Option>; diff --git a/rustfs/src/app/mod.rs b/rustfs/src/app/mod.rs index 11b70c154..5b3740ad6 100644 --- a/rustfs/src/app/mod.rs +++ b/rustfs/src/app/mod.rs @@ -630,6 +630,10 @@ pub(crate) fn get_global_endpoints_opt() -> Option { crate::storage::get_global_endpoints_opt() } +pub(crate) fn get_global_deployment_id() -> Option { + crate::storage::get_global_deployment_id() +} + pub(crate) fn get_global_lock_client() -> Option> { crate::storage::get_global_lock_client() } @@ -638,6 +642,10 @@ pub(crate) fn get_global_region() -> Option { crate::storage::get_global_region() } +pub(crate) fn global_rustfs_port() -> u16 { + crate::storage::global_rustfs_port() +} + pub(crate) fn get_global_tier_config_mgr() -> Arc> { crate::storage::get_global_tier_config_mgr() } diff --git a/rustfs/src/storage/mod.rs b/rustfs/src/storage/mod.rs index 2b3dc618c..35f265bdc 100644 --- a/rustfs/src/storage/mod.rs +++ b/rustfs/src/storage/mod.rs @@ -813,10 +813,18 @@ pub(crate) fn get_global_endpoints_opt() -> Option { ecstore_global::get_global_endpoints_opt() } +pub(crate) fn get_global_deployment_id() -> Option { + ecstore_global::get_global_deployment_id() +} + pub(crate) fn get_global_region() -> Option { ecstore_global::get_global_region() } +pub(crate) fn global_rustfs_port() -> u16 { + ecstore_global::global_rustfs_port() +} + pub(crate) fn get_global_tier_config_mgr() -> Arc> { ecstore_global::get_global_tier_config_mgr() } diff --git a/scripts/layer-dependency-baseline.txt b/scripts/layer-dependency-baseline.txt index 785f644bb..2f82a2e28 100644 --- a/scripts/layer-dependency-baseline.txt +++ b/scripts/layer-dependency-baseline.txt @@ -41,15 +41,22 @@ accepted|rustfs/src/protocols/client.rs|infra->interface|crate::storage::ecfs::F accepted|rustfs/src/server/audit.rs|infra->app|crate::app::context::resolve_server_config|config resolution uses global AppContext accepted|rustfs/src/server/event.rs|infra->app|crate::app::context::resolve_server_config|config resolution uses global AppContext accepted|rustfs/src/server/http.rs|infra->interface|crate::admin|HTTP server routes to admin handlers +accepted|rustfs/src/server/layer.rs|infra->app|crate::app::context::resolve_kms_runtime_service_manager|HTTP layer reads KMS runtime through AppContext resolver accepted|rustfs/src/server/layer.rs|infra->interface|crate::admin::console::is_console_path|pure path predicate for routing accepted|rustfs/src/server/layer.rs|infra->interface|crate::admin::handlers::health::HealthProbe|HTTP layer builds health responses accepted|rustfs/src/server/layer.rs|infra->interface|crate::admin::handlers::health::build_health_response_parts|HTTP layer builds health responses +accepted|rustfs/src/server/readiness.rs|infra->app|crate::app::context::resolve_endpoints_handle|readiness checks endpoint availability through AppContext resolver +accepted|rustfs/src/server/readiness.rs|infra->app|crate::app::context::resolve_iam_ready|readiness checks IAM availability through AppContext resolver accepted|rustfs/src/startup_iam.rs|infra->app|crate::app::context::AppContext|startup wires IAM bootstrap through AppContext +accepted|rustfs/src/storage/ecfs_extend.rs|infra->app|crate::app::context::resolve_buffer_config|storage buffer sizing reads runtime config through AppContext resolver accepted|rustfs/src/storage/ecfs_extend.rs|infra->interface|crate::storage::ecfs::ListObjectUnorderedQuery|storage extension uses current ECFS interface query type accepted|rustfs/src/storage/ecfs_test.rs|infra->interface|crate::storage::ecfs::FS|storage tests exercise current ECFS interface path accepted|rustfs/src/storage/ecfs_test.rs|infra->interface|crate::storage::ecfs::validate_object_lock_configuration_input|storage tests exercise current ECFS object-lock validator accepted|rustfs/src/storage/ecfs_test.rs|infra->interface|crate::storage::s3_api::common::rustfs_initiator|storage tests use current S3 API initiator helper accepted|rustfs/src/storage/ecfs_test.rs|infra->interface|crate::storage::s3_api::common::rustfs_owner|storage tests use current S3 API owner helper +accepted|rustfs/src/storage/rpc/health.rs|infra->app|crate::app::context::resolve_local_node_name|RPC health labels node identity through AppContext resolver +accepted|rustfs/src/storage/rpc/node_service.rs|infra->app|crate::app::context::resolve_iam_handle|node RPC IAM operations use AppContext resolver fallback +accepted|rustfs/src/storage/rpc/node_service.rs|infra->app|crate::app::context::resolve_lock_client|node RPC locking uses AppContext resolver fallback accepted|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::service::config::reload_dynamic_config_runtime_state|node RPC reloads admin runtime state accepted|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::service::config::reload_runtime_config_snapshot|node RPC reloads admin runtime state accepted|rustfs/src/storage/rpc/node_service.rs|infra->interface|crate::admin::service::site_replication::reload_site_replication_runtime_state|node RPC reloads admin runtime state