refactor: centralize owner server config reads (#3793)

This commit is contained in:
Zhengchao An
2026-06-23 21:27:30 +08:00
committed by GitHub
parent 70a2441407
commit 5c60f0cae9
10 changed files with 259 additions and 78 deletions
+1
View File
@@ -48,6 +48,7 @@ pub mod manager;
pub mod oidc;
pub mod oidc_state;
mod root_credentials;
mod server_config;
pub mod store;
pub mod sys;
pub mod utils;
+2 -2
View File
@@ -26,7 +26,6 @@ use openidconnect::{
};
use reqwest::Client;
use rustfs_config::oidc::*;
use rustfs_config::server_config::get_global_server_config;
use rustfs_config::server_config::{Config as ServerConfig, KVS};
use rustfs_config::{DEFAULT_DELIMITER, ENABLE_KEY, EnableState};
use rustfs_policy::policy::{ClaimLookup, get_claim_case_insensitive};
@@ -410,7 +409,8 @@ impl OidcSys {
/// Parse environment variables and discover all configured OIDC providers.
pub async fn new() -> Result<Self, String> {
let http_client = ReqwestHttpClient::new()?;
let parsed_configs = load_effective_oidc_provider_configs(get_global_server_config().as_ref());
let server_config = crate::server_config::current_server_config();
let parsed_configs = load_effective_oidc_provider_configs(server_config.as_ref());
let mut configs = HashMap::new();
let mut provider_states = HashMap::new();
+19
View File
@@ -0,0 +1,19 @@
// 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 rustfs_config::server_config::{Config as ServerConfig, get_global_server_config};
pub(crate) fn current_server_config() -> Option<ServerConfig> {
get_global_server_config()
}
+5 -1
View File
@@ -12,11 +12,14 @@
// 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;
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,
@@ -31,6 +34,7 @@ pub(crate) use rustfs_ecstore::api::storage::ECStore as ObsStore;
pub mod collectors;
pub mod config;
pub mod report;
mod runtime_sources;
pub mod scheduler;
pub mod schema;
pub mod stats_collector;
+102
View File
@@ -0,0 +1,102 @@
// Copyright 2024 RustFS Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::metrics::{
OBS_GLOBAL_EXPIRY_STATE, OBS_GLOBAL_REPLICATION_STATS, OBS_GLOBAL_TRANSITION_STATE, ObsBucketBandwidthMonitor,
ObsReplicationStats, obs_get_global_bucket_monitor,
};
use rustfs_iam::{get_global_iam_sys, oidc::oidc_plugin_authn_metrics_snapshot};
use std::sync::Arc;
pub(crate) type ObsReplicationStatsHandle = Arc<ObsReplicationStats>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ObsIlmRuntimeSnapshot {
pub(crate) expiry_pending_tasks: u64,
pub(crate) transition_active_tasks: u64,
pub(crate) transition_pending_tasks: u64,
pub(crate) transition_missed_immediate_tasks: u64,
pub(crate) transition_queue_full_tasks: u64,
pub(crate) transition_queue_send_timeout_tasks: u64,
pub(crate) transition_compensation_scheduled_tasks: u64,
pub(crate) transition_compensation_running_tasks: u64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct ObsIamMetricsSnapshot {
pub(crate) last_sync_duration_millis: u64,
pub(crate) plugin_authn_service_failed_requests_minute: u64,
pub(crate) plugin_authn_service_last_fail_seconds: u64,
pub(crate) plugin_authn_service_last_succ_seconds: u64,
pub(crate) plugin_authn_service_succ_avg_rtt_ms_minute: u64,
pub(crate) plugin_authn_service_succ_max_rtt_ms_minute: u64,
pub(crate) plugin_authn_service_total_requests_minute: u64,
pub(crate) since_last_sync_millis: u64,
pub(crate) sync_failures: u64,
pub(crate) sync_successes: u64,
}
fn usize_to_u64_saturating(value: usize) -> u64 {
u64::try_from(value).unwrap_or(u64::MAX)
}
fn i64_to_u64_floor_zero(value: i64) -> u64 {
u64::try_from(value.max(0)).unwrap_or_default()
}
pub(crate) fn bucket_monitor_handle() -> Option<Arc<ObsBucketBandwidthMonitor>> {
obs_get_global_bucket_monitor()
}
pub(crate) fn bucket_monitor_available() -> bool {
bucket_monitor_handle().is_some()
}
pub(crate) fn replication_stats_handle() -> Option<ObsReplicationStatsHandle> {
OBS_GLOBAL_REPLICATION_STATS.get().cloned()
}
pub(crate) async fn ilm_runtime_snapshot() -> ObsIlmRuntimeSnapshot {
ObsIlmRuntimeSnapshot {
expiry_pending_tasks: usize_to_u64_saturating(OBS_GLOBAL_EXPIRY_STATE.read().await.pending_tasks()),
transition_active_tasks: i64_to_u64_floor_zero(OBS_GLOBAL_TRANSITION_STATE.active_tasks()),
transition_pending_tasks: usize_to_u64_saturating(OBS_GLOBAL_TRANSITION_STATE.pending_tasks()),
transition_missed_immediate_tasks: i64_to_u64_floor_zero(OBS_GLOBAL_TRANSITION_STATE.missed_immediate_tasks()),
transition_queue_full_tasks: i64_to_u64_floor_zero(OBS_GLOBAL_TRANSITION_STATE.queue_full_tasks()),
transition_queue_send_timeout_tasks: i64_to_u64_floor_zero(OBS_GLOBAL_TRANSITION_STATE.queue_send_timeout_tasks()),
transition_compensation_scheduled_tasks: i64_to_u64_floor_zero(
OBS_GLOBAL_TRANSITION_STATE.compensation_scheduled_tasks(),
),
transition_compensation_running_tasks: i64_to_u64_floor_zero(OBS_GLOBAL_TRANSITION_STATE.compensation_running_tasks()),
}
}
pub(crate) fn iam_metrics_snapshot() -> Option<ObsIamMetricsSnapshot> {
let iam_sys = get_global_iam_sys()?;
let sync = iam_sys.sync_metrics_snapshot();
let oidc = oidc_plugin_authn_metrics_snapshot();
Some(ObsIamMetricsSnapshot {
last_sync_duration_millis: sync.last_sync_duration_millis,
plugin_authn_service_failed_requests_minute: oidc.failed_requests_minute,
plugin_authn_service_last_fail_seconds: oidc.last_fail_seconds,
plugin_authn_service_last_succ_seconds: oidc.last_succ_seconds,
plugin_authn_service_succ_avg_rtt_ms_minute: oidc.succ_avg_rtt_ms_minute,
plugin_authn_service_succ_max_rtt_ms_minute: oidc.succ_max_rtt_ms_minute,
plugin_authn_service_total_requests_minute: oidc.total_requests_minute,
since_last_sync_millis: sync.since_last_sync_millis,
sync_failures: sync.sync_failures,
sync_successes: sync.sync_successes,
})
}
+2 -2
View File
@@ -70,8 +70,8 @@ use crate::metrics::config::{
ENV_BUCKET_REPLICATION_BANDWIDTH_METRICS_INTERVAL, ENV_CLUSTER_METRICS_INTERVAL, ENV_DEFAULT_METRICS_INTERVAL,
ENV_NODE_METRICS_INTERVAL, ENV_NOTIFICATION_METRICS_INTERVAL, ENV_RESOURCE_METRICS_INTERVAL,
};
use crate::metrics::obs_get_global_bucket_monitor;
use crate::metrics::report::{PrometheusMetric, report_metrics};
use crate::metrics::runtime_sources::bucket_monitor_available;
use crate::metrics::schema::bucket_replication::{
BUCKET_L, BUCKET_REPL_BANDWIDTH_CURRENT_MD, BUCKET_REPL_BANDWIDTH_LIMIT_MD, TARGET_ARN_L,
};
@@ -599,7 +599,7 @@ pub fn init_metrics_runtime(token: CancellationToken) {
loop {
tokio::select! {
_ = interval.tick() => {
let monitor_available = obs_get_global_bucket_monitor().is_some();
let monitor_available = bucket_monitor_available();
let stats = collect_bucket_replication_bandwidth_stats();
let current_live_keys = repl_bw_live_keys(&stats);
+19 -47
View File
@@ -26,15 +26,16 @@ use crate::metrics::collectors::{
DriveDetailedStats, ErasureSetStats, HostNetworkStats, IamStats, IlmStats, MemoryStats, NetworkStats, ProcessStats,
ProcessStatusType, ReplicationStats, ResourceStats, ScannerStats,
};
use crate::metrics::runtime_sources::{
ObsIlmRuntimeSnapshot, bucket_monitor_handle, iam_metrics_snapshot, ilm_runtime_snapshot, replication_stats_handle,
};
use crate::metrics::{
OBS_GLOBAL_EXPIRY_STATE, OBS_GLOBAL_REPLICATION_STATS, OBS_GLOBAL_TRANSITION_STATE, ObsEcstoreResult, ObsStore,
obs_get_global_bucket_monitor, obs_get_quota_config, obs_get_total_usable_capacity, obs_get_total_usable_capacity_free,
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,
};
use chrono::Utc;
use rustfs_common::heal_channel::HealScanMode;
use rustfs_common::metrics::global_metrics;
use rustfs_iam::{get_global_iam_sys, oidc::oidc_plugin_authn_metrics_snapshot};
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};
@@ -74,18 +75,6 @@ struct ObsBucketReplicationBandwidthStats {
current_bandwidth_bytes_per_sec: f64,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct ObsIlmRuntimeSnapshot {
expiry_pending_tasks: u64,
transition_active_tasks: u64,
transition_pending_tasks: u64,
transition_missed_immediate_tasks: u64,
transition_queue_full_tasks: u64,
transition_queue_send_timeout_tasks: u64,
transition_compensation_scheduled_tasks: u64,
transition_compensation_running_tasks: u64,
}
fn usize_to_u64_saturating(value: usize) -> u64 {
u64::try_from(value).unwrap_or(u64::MAX)
}
@@ -148,7 +137,7 @@ async fn obs_bucket_quota_limit_bytes(bucket: &str) -> u64 {
}
fn obs_bucket_replication_bandwidth_stats() -> Option<Vec<ObsBucketReplicationBandwidthStats>> {
let monitor = obs_get_global_bucket_monitor()?;
let monitor = bucket_monitor_handle()?;
Some(
monitor
.get_report(|_| true)
@@ -165,26 +154,11 @@ fn obs_bucket_replication_bandwidth_stats() -> Option<Vec<ObsBucketReplicationBa
}
async fn obs_ilm_runtime_snapshot() -> ObsIlmRuntimeSnapshot {
let expiry_pending_tasks = {
let expiry = OBS_GLOBAL_EXPIRY_STATE.read().await;
usize_to_u64_saturating(expiry.pending_tasks())
};
let transition = &OBS_GLOBAL_TRANSITION_STATE;
ObsIlmRuntimeSnapshot {
expiry_pending_tasks,
transition_active_tasks: i64_to_u64_floor_zero(transition.active_tasks()),
transition_pending_tasks: usize_to_u64_saturating(transition.pending_tasks()),
transition_missed_immediate_tasks: i64_to_u64_floor_zero(transition.missed_immediate_tasks()),
transition_queue_full_tasks: i64_to_u64_floor_zero(transition.queue_full_tasks()),
transition_queue_send_timeout_tasks: i64_to_u64_floor_zero(transition.queue_send_timeout_tasks()),
transition_compensation_scheduled_tasks: i64_to_u64_floor_zero(transition.compensation_scheduled_tasks()),
transition_compensation_running_tasks: i64_to_u64_floor_zero(transition.compensation_running_tasks()),
}
ilm_runtime_snapshot().await
}
async fn obs_bucket_replication_detail_stats() -> Vec<BucketReplicationStats> {
let Some(stats) = OBS_GLOBAL_REPLICATION_STATS.get() else {
let Some(stats) = replication_stats_handle() else {
return Vec::new();
};
@@ -256,7 +230,7 @@ async fn obs_bucket_replication_detail_stats() -> Vec<BucketReplicationStats> {
}
async fn obs_site_replication_stats() -> ReplicationStats {
let Some(stats) = OBS_GLOBAL_REPLICATION_STATS.get() else {
let Some(stats) = replication_stats_handle() else {
return ReplicationStats::default();
};
@@ -904,21 +878,19 @@ pub async fn collect_erasure_set_stats() -> Vec<ErasureSetStats> {
}
pub async fn collect_iam_stats() -> Option<IamStats> {
let iam_sys = get_global_iam_sys()?;
let sync = iam_sys.sync_metrics_snapshot();
let oidc = oidc_plugin_authn_metrics_snapshot();
let snapshot = iam_metrics_snapshot()?;
Some(IamStats {
last_sync_duration_millis: sync.last_sync_duration_millis,
plugin_authn_service_failed_requests_minute: oidc.failed_requests_minute,
plugin_authn_service_last_fail_seconds: oidc.last_fail_seconds,
plugin_authn_service_last_succ_seconds: oidc.last_succ_seconds,
plugin_authn_service_succ_avg_rtt_ms_minute: oidc.succ_avg_rtt_ms_minute,
plugin_authn_service_succ_max_rtt_ms_minute: oidc.succ_max_rtt_ms_minute,
plugin_authn_service_total_requests_minute: oidc.total_requests_minute,
since_last_sync_millis: sync.since_last_sync_millis,
sync_failures: sync.sync_failures,
sync_successes: sync.sync_successes,
last_sync_duration_millis: snapshot.last_sync_duration_millis,
plugin_authn_service_failed_requests_minute: snapshot.plugin_authn_service_failed_requests_minute,
plugin_authn_service_last_fail_seconds: snapshot.plugin_authn_service_last_fail_seconds,
plugin_authn_service_last_succ_seconds: snapshot.plugin_authn_service_last_succ_seconds,
plugin_authn_service_succ_avg_rtt_ms_minute: snapshot.plugin_authn_service_succ_avg_rtt_ms_minute,
plugin_authn_service_succ_max_rtt_ms_minute: snapshot.plugin_authn_service_succ_max_rtt_ms_minute,
plugin_authn_service_total_requests_minute: snapshot.plugin_authn_service_total_requests_minute,
since_last_sync_millis: snapshot.since_last_sync_millis,
sync_failures: snapshot.sync_failures,
sync_successes: snapshot.sync_successes,
})
}
+26 -1
View File
@@ -40,7 +40,9 @@ use std::time::Duration;
use tracing::warn;
const LOG_COMPONENT_SCANNER: &str = "scanner";
const LOG_SUBSYSTEM_RUNTIME: &str = "runtime";
const LOG_SUBSYSTEM_RUNTIME_CONFIG: &str = "runtime_config";
const EVENT_SCANNER_RUNTIME_CONFIG: &str = "scanner_runtime_config";
const EVENT_SCANNER_RUNTIME_CONFIG_PARSE: &str = "scanner_runtime_config_parse";
const ENV_SCANNER_START_DELAY_SECS_DEPRECATED: &str = "RUSTFS_DATA_SCANNER_START_DELAY_SECS";
@@ -671,6 +673,29 @@ fn apply_resolved_runtime_config(config: ScannerRuntimeConfig) {
}
}
fn current_server_config() -> Option<ServerConfig> {
rustfs_config::server_config::get_global_server_config()
}
pub(crate) fn resolve_scanner_runtime_config_from_global() -> ScannerRuntimeConfig {
let config = current_server_config();
match lookup_scanner_runtime_config(config.as_ref()) {
Ok(config) => config,
Err(err) => {
warn!(
target: "rustfs::scanner",
event = EVENT_SCANNER_RUNTIME_CONFIG,
component = LOG_COMPONENT_SCANNER,
subsystem = LOG_SUBSYSTEM_RUNTIME,
state = "resolve_failed",
error = %err,
"Scanner runtime config fallback applied"
);
current_scanner_runtime_config()
}
}
}
pub fn validate_scanner_runtime_config(config: &ServerConfig) -> Result<(), ScannerRuntimeConfigError> {
validate_persisted_scanner_runtime_config(config)
}
@@ -683,7 +708,7 @@ pub fn apply_scanner_runtime_config(config: &ServerConfig) -> Result<(), Scanner
}
pub(crate) fn refresh_scanner_runtime_config_from_global() -> Result<(), ScannerRuntimeConfigError> {
let config = rustfs_config::server_config::get_global_server_config();
let config = current_server_config();
let resolved = lookup_scanner_runtime_config(config.as_ref())?;
apply_resolved_runtime_config(resolved);
Ok(())
+3 -18
View File
@@ -17,8 +17,8 @@ use std::sync::Arc;
use crate::ScannerObjectIO;
use crate::data_usage_define::{BACKGROUND_HEAL_INFO_PATH, DATA_USAGE_BLOOM_NAME_PATH, DATA_USAGE_OBJ_NAME_PATH};
use crate::runtime_config::{
current_scanner_runtime_config, lookup_scanner_runtime_config, refresh_scanner_runtime_config_from_global,
scanner_bitrot_cycle, scanner_cycle_interval, scanner_start_delay, set_scanner_default_cycle_secs,
refresh_scanner_runtime_config_from_global, resolve_scanner_runtime_config_from_global, scanner_bitrot_cycle,
scanner_cycle_interval, scanner_start_delay, set_scanner_default_cycle_secs,
};
use crate::scanner_budget::{ScannerCycleBudget, ScannerCycleBudgetConfig, ScannerCycleBudgetReason};
use crate::scanner_folder::{data_usage_update_dir_cycles, heal_object_select_prob};
@@ -82,22 +82,7 @@ fn scanner_cycle_max_duration() -> Option<Duration> {
}
fn resolve_scanner_runtime_config() -> crate::runtime_config::ScannerRuntimeConfig {
let config = rustfs_config::server_config::get_global_server_config();
match lookup_scanner_runtime_config(config.as_ref()) {
Ok(config) => config,
Err(err) => {
warn!(
target: "rustfs::scanner",
event = EVENT_SCANNER_RUNTIME_CONFIG,
component = LOG_COMPONENT_SCANNER,
subsystem = LOG_SUBSYSTEM_RUNTIME,
state = "resolve_failed",
error = %err,
"Scanner runtime config fallback applied"
);
current_scanner_runtime_config()
}
}
resolve_scanner_runtime_config_from_global()
}
fn scan_cycle_partial_reason(reason: Option<ScannerCycleBudgetReason>) -> ScanCyclePartialReason {
+80 -7
View File
@@ -5,17 +5,18 @@ 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-iam-credential-boundary`
- 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`.
- Based on: API-180 prepared in PR #3791; this branch batches IAM root
credential boundary cleanup on top of that branch.
- Branch: `overtrue/arch-obs-metrics-runtime-sources`
- 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`.
- Based on: API-182 prepared in PR #3793; this branch batches OBS metrics
runtime source boundary cleanup on top of that branch.
- PR type for this branch: `consumer-migration`
- Runtime behavior changes: none.
- Rust code changes: route replication pool, outbound TLS generation, runtime
region, KMS encryption service, runtime support handles, S3 Select DB,
internode RPC metrics, IAM authorization/handler reads, notification
rules/event dispatch, admin OIDC/token-signing reads, and IAM root
credential consumers through AppContext-first or IAM-owned resolver
rules/event dispatch, admin OIDC/token-signing reads, IAM root credential
consumers, IAM OIDC config reads, scanner runtime-config reads, and OBS
metrics runtime source reads through AppContext-first or owner-crate resolver
boundaries.
- CI/script changes: lock completed owner and test/fuzz boundaries against
bare/glob imports, scattered raw ECStore facade subpaths, and startup
@@ -25,7 +26,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 through API-181 owner facade cleanup.
- Docs changes: record the API-136 through API-183 owner facade cleanup.
## Phase 0 Tasks
@@ -4619,6 +4620,36 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
migration guard, layer guard, diff hygiene, residual direct credential scan,
Rust risk scan, branch freshness check, and three-expert review.
- [x] `API-182` Centralize owner server config reads behind crate boundaries.
- Do: route IAM OIDC server-config reads through an IAM-owned helper and
scanner runtime-config global reads through scanner-owned resolver
functions.
- Acceptance: production IAM OIDC and scanner runtime-config consumers no
longer call the server-config global directly outside owner boundary
modules, while parser fallback and effective-provider behavior remain
unchanged.
- Must preserve: OIDC provider parsing, config fallback handling, scanner
runtime config defaults, warning logs, and runtime config refresh behavior.
- Verification: IAM/scanner compile coverage, IAM/scanner focused tests,
formatting, migration guard, layer guard, diff hygiene, residual server
config scan, Rust risk scan, branch freshness check, pre-commit quality
gate, and three-expert review.
- [x] `API-183` Centralize OBS metrics runtime source reads.
- Do: add an OBS metrics runtime-source boundary for IAM metrics, bucket
monitor availability, replication stats, and ILM runtime state, then route
the metrics collector and scheduler through that boundary.
- Acceptance: OBS metrics collector and scheduler code no longer imports
IAM or ECStore global runtime symbols directly outside the OBS runtime
source boundary, while metric field mapping and unavailable-state behavior
remain unchanged.
- Must preserve: IAM sync/plugin metrics, bucket replication bandwidth
availability warnings, ILM pending/transition counters, site/bucket
replication stats, and object-store/data-usage collection.
- Verification: OBS compile coverage, formatting, migration guard, layer
guard, diff hygiene, residual OBS global scan, Rust risk scan, branch
freshness check, pre-commit quality gate, and three-expert review.
## Next PRs
1. `consumer-migration`: continue reducing direct global reads behind AppContext resolver boundaries.
@@ -4718,11 +4749,53 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
| Quality/architecture | pass | API-181 keeps IAM root credential reads centralized in an IAM-owned helper and exposes only a root access-key predicate to protocol code. |
| Migration preservation | pass | Root owner checks, legacy IAM decrypt fallback, token signing, and gateway policy args preserve existing credential semantics. |
| Testing/verification | pass | IAM/protocol compile, IAM unit tests, formatting, migration/layer guards, diff hygiene, residual credential scan, and Rust risk scan passed for API-181. |
| Quality/architecture | pass | API-182 keeps server-config global reads inside IAM and scanner owner boundary helpers without widening public APIs. |
| Migration preservation | pass | OIDC provider parsing and scanner runtime-config fallback semantics keep the same inputs, defaults, and warning behavior. |
| Testing/verification | pass | IAM/scanner compile, focused tests, formatting, migration/layer guards, diff hygiene, residual server-config scan, Rust risk scan, and pre-commit passed for API-182. |
| Quality/architecture | pass | API-183 keeps OBS metrics runtime globals behind a metrics-owned runtime-source module without widening public APIs. |
| Migration preservation | pass | IAM metrics, replication bandwidth availability, ILM counters, and replication stats keep the same source data and fallback behavior. |
| Testing/verification | pass | OBS compile/tests, formatting, residual OBS global scan, targeted guard checks, and pre-commit passed for API-183. |
## Verification Notes
Passed before push:
- Issue #660 API-183 current slice:
- `cargo check -p rustfs-obs --tests`: passed.
- `cargo test -p rustfs-obs --lib`: passed.
- `cargo fmt --all`: passed.
- `cargo fmt --all --check`: passed.
- `git diff --check`: passed.
- `./scripts/check_architecture_migration_rules.sh`: passed.
- `./scripts/check_layer_dependencies.sh`: passed.
- OBS global scan: passed; touched direct IAM and ECStore metrics runtime
globals are isolated to `crates/obs/src/metrics/runtime_sources.rs`.
- Rust risk scan: passed; diff only adds owner-symbol aliases and bounded
integer-conversion fallbacks, with no new `expect`, `panic`, `todo`,
`unimplemented`, or `unsafe`.
- Branch freshness check: based on API-182 PR #3793 head.
- `make pre-commit`: passed.
- Issue #660 API-182 current slice:
- `cargo check -p rustfs-iam -p rustfs-scanner --tests`: passed.
- `cargo test -p rustfs-iam --lib`: passed.
- `cargo test -p rustfs-scanner --lib -- --test-threads=1`: 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.
- IAM/scanner server-config scan: passed; touched production direct
`get_global_server_config` calls are isolated to IAM and scanner boundary
modules, while existing app context, config, and ECStore owner reads remain
unchanged.
- Rust risk scan: no new production unwrap/expect, panic/todo/unsafe, or cast
risk.
- Branch freshness check: rebased on latest `origin/main` after PR #3789 and
API-181 content landed upstream.
- `make pre-commit`: passed.
- Issue #660 API-181 current slice:
- `cargo check -p rustfs-iam -p rustfs-protocols --tests`: passed.
- `cargo test -p rustfs-iam --lib`: passed.