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