mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
refactor: route admin runtime config through app context (#3942)
This commit is contained in:
@@ -44,6 +44,9 @@ update this plan and the guard in the same reviewed migration PR.
|
||||
cover both paths.
|
||||
2. Move one remaining consumer group at a time to explicit context or
|
||||
owner-local runtime-source handles.
|
||||
- Current handoff: admin config, OIDC config, audit runtime config, and
|
||||
dynamic KMS config storage reads/writes resolve through current
|
||||
AppContext-aware boundaries before using the legacy object-store fallback.
|
||||
3. Remove one fallback family per PR only after scans prove no production caller
|
||||
depends on it.
|
||||
4. Keep embedded startup and tests working before deleting any fallback.
|
||||
|
||||
@@ -5,24 +5,24 @@ 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-global-runtime-boundary-batch`
|
||||
- Branch: `overtrue/arch-global-fallback-removal-batch`
|
||||
- Baseline: completed `C-011/C-012/C-013/API-055/API-059/API-079/API-080/API-081/API-082/API-083/API-084/API-085/API-086/API-087/API-088/API-089/API-090/API-091/API-092/API-093/API-094/API-095/API-096/API-097/API-098/API-099/API-100/API-101/API-102/API-103/API-104/API-105/API-106/API-107/API-108/API-109/API-110/API-111/API-112/API-113/API-114/API-115/API-116/API-117/API-118/API-119/API-120/API-121/API-122/API-123/API-124/API-125/API-126/API-127/API-128/API-129/API-130/API-131/API-132/API-133/API-134/API-135/API-136/API-137/API-138/API-139/API-140/API-141/API-142/API-143/API-144/API-145/API-146/API-147/API-148/API-149/API-150/API-151/API-152/API-153/API-154/API-155/API-156/API-157/API-158/API-159/API-160/API-161/API-162/API-163/API-164/API-165/API-166/API-167/API-168/API-169/API-170/API-171/API-172/API-173/API-174/API-175/API-176/API-177/API-178/API-179/API-180/API-181/API-182/API-183/API-184/API-185/API-186/API-187/API-188/API-189/API-190/API-191/API-192/API-193/API-194/API-195/API-196/API-197/API-198/API-199/API-200/API-201/API-202/API-203/API-204/API-205/API-206/API-207/API-208/API-209/API-210/API-211/API-212/API-213/API-214/API-215/API-216/API-217/API-218/API-219/API-220/API-221/API-222/API-223/API-224/API-225/API-226/API-227/API-228/API-229/API-230/API-231/API-232/API-233/API-234/API-235/API-236/API-237/API-238/API-239/API-240/API-241/API-242/API-243/API-244/API-245/API-246/API-247/API-248/API-249/API-250/API-251/API-252/API-253/API-254/CTX-002`.
|
||||
- Current baseline also includes API-255 from PR #3923, API-256 from PR
|
||||
#3925, CFG-009 from PR #3927, C-007/C-009 from PR #3935, C-008/C-010
|
||||
from PR #3936, and DOC-001/DOC-002/DOC-003/DOC-004/DOC-005/
|
||||
TEST-DOC-001 from PR #3938, plus GLOB-001/GLOB-002/GLOB-003/GLOB-004/
|
||||
GLOB-005/GLOB-006/CRATE-001/CRATE-002 from PR #3939.
|
||||
- Current phase PR: GLOB-006 ECStore runtime facade boundary batch.
|
||||
- Based on: `origin/main` after PR #3939 merged.
|
||||
TEST-DOC-001 from PR #3938, GLOB-001/GLOB-002/GLOB-003/GLOB-004/
|
||||
GLOB-005/CRATE-001/CRATE-002 from PR #3939, and GLOB-006 from PR #3941.
|
||||
- Current phase PR: GLOB-007 admin runtime context handoff batch.
|
||||
- Based on: `origin/main` after PR #3941 merged.
|
||||
- PR type for this branch: `ci-gate`.
|
||||
- Runtime behavior changes: none intended.
|
||||
- Rust code changes: add the selected `rustfs_ecstore::api::runtime` facade and
|
||||
route external crate-local `storage_api` boundaries away from direct
|
||||
`rustfs_ecstore::api::global` imports.
|
||||
- CI/script changes: shrink the direct ECStore global facade allowlist to the
|
||||
root storage owner boundary.
|
||||
- Rust code changes: add context-aware notification-system and server-config
|
||||
resolution, then route admin config, OIDC config, audit runtime config, and
|
||||
dynamic KMS config storage access through current AppContext-aware resolver
|
||||
boundaries before falling back to legacy globals.
|
||||
- CI/script changes: none intended.
|
||||
- Docs changes: update the global-state plan and this progress ledger for the
|
||||
runtime facade batch.
|
||||
admin runtime context handoff batch.
|
||||
|
||||
## Phase 0 Tasks
|
||||
|
||||
@@ -2764,20 +2764,27 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
|
||||
[`global-state-crate-split-plan.md`](global-state-crate-split-plan.md) to
|
||||
record the remaining owner boundaries and fallback removal sequence.
|
||||
- Verification: architecture migration guard and diff hygiene.
|
||||
- [~] `GLOB-006` Shrink `ecstore::global`.
|
||||
- Current slice: expose selected ECStore runtime-source reads through
|
||||
- [x] `GLOB-006` Shrink `ecstore::global`.
|
||||
- Completed slice: expose selected ECStore runtime-source reads through
|
||||
`rustfs_ecstore::api::runtime`, migrate heal, IAM, notify, observability,
|
||||
Swift, S3 Select, and scanner storage API boundaries away from direct
|
||||
`rustfs_ecstore::api::global` imports, and keep the direct global facade
|
||||
confined to the root storage owner boundary.
|
||||
- Remaining work: move additional ECStore bootstrap/runtime globals behind
|
||||
explicit owner handles where safe; do not remove bootstrap state in this
|
||||
runtime facade PR.
|
||||
explicit owner handles where safe; do not remove bootstrap state until all
|
||||
dependent runtime owners have explicit handles.
|
||||
- Verification: focused compile coverage, architecture migration guard, diff
|
||||
hygiene, Rust risk scan, and full PR gate.
|
||||
- [ ] `GLOB-007` Remove fallbacks.
|
||||
- [~] `GLOB-007` Remove fallbacks.
|
||||
- Current slice: move admin config, OIDC config, audit runtime config, and
|
||||
dynamic KMS config storage access paths to current AppContext-aware
|
||||
resolver boundaries, and expose notification-system/server-config
|
||||
resolution for explicit AppContext handoff.
|
||||
- Remaining work: remove one fallback family per PR only after scans prove no
|
||||
production caller depends on it.
|
||||
production caller depends on it; this slice keeps the fallback behavior
|
||||
because broader admin/server consumers still use the root resolvers.
|
||||
- Verification: focused RustFS compile, resolver residual scan, formatting,
|
||||
diff hygiene, architecture guard, Rust risk scan, and full PR gate.
|
||||
- [~] `CRATE-001/CRATE-002` Evaluate future crate splits.
|
||||
- Current slice: record evidence required before `ecstore-erasure` or
|
||||
`storage-cluster` split proposals.
|
||||
@@ -6041,6 +6048,9 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
|
||||
|
||||
| Expert | Status | Notes |
|
||||
|---|---|---|
|
||||
| Quality/architecture | pass | GLOB-007 adds AppContext-aware notification-system and server-config resolver boundaries, then routes admin config, OIDC config, audit runtime config, and dynamic KMS config storage access through current AppContext-aware owners before legacy fallbacks. |
|
||||
| Migration preservation | pass | Existing admin config reload, OIDC restart detection, audit config writes, and dynamic KMS config load/save behavior stay unchanged because context lookup falls back to the same root object-store, notification, and server-config owners. |
|
||||
| Testing/verification | pass | Focused RustFS compile/tests, resolver residual scan, formatting, architecture guard, diff hygiene, Rust risk scan, and full `make pre-pr` passed before PR. |
|
||||
| Quality/architecture | pass | GLOB-006 exposes selected ECStore runtime-source reads through `rustfs_ecstore::api::runtime` and removes external crate direct global facade imports while leaving ECStore owner state intact. |
|
||||
| Migration preservation | pass | Object-store, bucket-monitor, tier-config, erasure flags, IAM first-node, and local-disk-map reads delegate to the same ECStore runtime/global owners; startup, readiness, IAM/KMS, lock quorum, scanner, heal, Swift, S3 Select, and notification behavior stay unchanged. |
|
||||
| Testing/verification | pass | Focused compile, formatting, shell syntax, architecture guard, global facade scan, diff hygiene, Rust risk scan, full `make pre-pr`, and post-rebase focused checks passed before PR. |
|
||||
@@ -6398,6 +6408,22 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
|
||||
|
||||
Passed before push:
|
||||
|
||||
- Issue #660 GLOB-007 current slice:
|
||||
- Branch freshness check: rebased onto `origin/main` after PR #3941 merged.
|
||||
- `cargo fmt --all --check`: passed.
|
||||
- `git diff --check`: passed.
|
||||
- Resolver residual scan over migrated admin files: passed.
|
||||
- Diff-added Rust risk scan: passed; no new production unwrap/expect,
|
||||
unchecked narrow casts, stringly errors, or ad-hoc stdout/stderr.
|
||||
- `cargo check -p rustfs --lib`: passed.
|
||||
- `./scripts/check_architecture_migration_rules.sh`: passed.
|
||||
- `cargo test -p rustfs --lib app::context::tests::resolver_helpers_are_context_first_and_fallback_when_context_is_absent`:
|
||||
passed.
|
||||
- `cargo test -p rustfs --lib admin::service::config`: passed.
|
||||
- Three-expert review: passed.
|
||||
- `make pre-pr`: passed, including 6911 nextest tests passed, 112 skipped,
|
||||
and doctests.
|
||||
|
||||
- Issue #660 GLOB-001/GLOB-002/GLOB-003/GLOB-004/GLOB-005/GLOB-006/
|
||||
CRATE-001/CRATE-002 current slice:
|
||||
- Branch freshness check: rebased onto `origin/main` after PR #3938 merged.
|
||||
|
||||
@@ -13,15 +13,15 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::admin::handlers::target_descriptor::AdminTargetSpec;
|
||||
use crate::admin::runtime_sources::resolve_object_store_handle;
|
||||
use crate::admin::runtime_sources::{AppContext, current_app_context, resolve_object_store_handle_for_context};
|
||||
use crate::admin::storage_api::config::{read_admin_config_without_migrate, save_admin_server_config};
|
||||
use rustfs_audit::{audit_system, start_audit_system as start_global_audit_system, system::AuditSystemState};
|
||||
use rustfs_config::DEFAULT_DELIMITER;
|
||||
use rustfs_config::server_config::Config;
|
||||
use s3s::{S3Result, s3_error};
|
||||
|
||||
pub(crate) async fn load_server_config_from_store() -> S3Result<Config> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
pub(crate) async fn load_server_config_from_store_for_context(context: Option<&AppContext>) -> S3Result<Config> {
|
||||
let Some(store) = resolve_object_store_handle_for_context(context) else {
|
||||
return Ok(Config::new());
|
||||
};
|
||||
|
||||
@@ -30,6 +30,11 @@ pub(crate) async fn load_server_config_from_store() -> S3Result<Config> {
|
||||
.map_err(|e| s3_error!(InternalError, "failed to read server config: {}", e))
|
||||
}
|
||||
|
||||
pub(crate) async fn load_server_config_from_store() -> S3Result<Config> {
|
||||
let context = current_app_context();
|
||||
load_server_config_from_store_for_context(context.as_deref()).await
|
||||
}
|
||||
|
||||
fn has_any_audit_targets(specs: &[AdminTargetSpec], config: &Config) -> bool {
|
||||
specs.iter().any(|spec| {
|
||||
config
|
||||
@@ -75,11 +80,15 @@ pub(crate) async fn apply_audit_runtime_config(specs: &[AdminTargetSpec], config
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn update_audit_config_and_reload<F>(specs: &[AdminTargetSpec], mut modifier: F) -> S3Result<()>
|
||||
async fn update_audit_config_and_reload_for_context<F>(
|
||||
context: Option<&AppContext>,
|
||||
specs: &[AdminTargetSpec],
|
||||
mut modifier: F,
|
||||
) -> S3Result<()>
|
||||
where
|
||||
F: FnMut(&mut Config) -> bool,
|
||||
{
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
let Some(store) = resolve_object_store_handle_for_context(context) else {
|
||||
return Err(s3_error!(InternalError, "server storage not initialized"));
|
||||
};
|
||||
|
||||
@@ -98,6 +107,14 @@ where
|
||||
apply_audit_runtime_config(specs, config).await
|
||||
}
|
||||
|
||||
pub(crate) async fn update_audit_config_and_reload<F>(specs: &[AdminTargetSpec], modifier: F) -> S3Result<()>
|
||||
where
|
||||
F: FnMut(&mut Config) -> bool,
|
||||
{
|
||||
let context = current_app_context();
|
||||
update_audit_config_and_reload_for_context(context.as_deref(), specs, modifier).await
|
||||
}
|
||||
|
||||
pub(crate) async fn set_audit_target_config(
|
||||
specs: &[AdminTargetSpec],
|
||||
subsystem: &str,
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
use crate::admin::auth::validate_admin_request;
|
||||
use crate::admin::router::{AdminOperation, Operation, S3Router};
|
||||
use crate::admin::runtime_sources::{publish_server_config, resolve_object_store_handle, resolve_server_config};
|
||||
use crate::admin::runtime_sources::{
|
||||
current_app_context, publish_server_config, resolve_object_store_handle_for_context, resolve_server_config_for_context,
|
||||
};
|
||||
use crate::admin::service::config::{
|
||||
apply_dynamic_config_for_subsystem, is_dynamic_config_subsystem, signal_config_snapshot_reload, signal_dynamic_config_reload,
|
||||
validate_server_config,
|
||||
@@ -709,7 +711,9 @@ fn success_response(config_applied: bool) -> S3Result<S3Response<(StatusCode, Bo
|
||||
}
|
||||
|
||||
fn object_store() -> S3Result<std::sync::Arc<crate::admin::storage_api::runtime::ECStore>> {
|
||||
resolve_object_store_handle().ok_or_else(|| s3_error!(InternalError, "server storage not initialized"))
|
||||
let context = current_app_context();
|
||||
resolve_object_store_handle_for_context(context.as_deref())
|
||||
.ok_or_else(|| s3_error!(InternalError, "server storage not initialized"))
|
||||
}
|
||||
|
||||
async fn load_server_config_from_store() -> S3Result<ServerConfig> {
|
||||
@@ -725,7 +729,9 @@ async fn load_active_server_config() -> S3Result<ServerConfig> {
|
||||
return Ok(config);
|
||||
}
|
||||
|
||||
resolve_server_config().ok_or_else(|| s3_error!(InternalError, "server config is not initialized"))
|
||||
let context = current_app_context();
|
||||
resolve_server_config_for_context(context.as_deref())
|
||||
.ok_or_else(|| s3_error!(InternalError, "server config is not initialized"))
|
||||
}
|
||||
|
||||
async fn save_server_config_to_store(config: &ServerConfig) -> S3Result<()> {
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
use crate::admin::auth::validate_admin_request;
|
||||
use crate::admin::router::{AdminOperation, Operation, S3Router};
|
||||
use crate::admin::runtime_sources::{
|
||||
resolve_kms_runtime_service_manager, resolve_object_store_handle, resolve_or_init_kms_runtime_service_manager,
|
||||
current_app_context, resolve_kms_runtime_service_manager, resolve_object_store_handle_for_context,
|
||||
resolve_or_init_kms_runtime_service_manager,
|
||||
};
|
||||
use crate::admin::storage_api::config::{read_admin_config, save_admin_config};
|
||||
use crate::auth::{check_key_valid, get_session_token};
|
||||
@@ -105,7 +106,8 @@ fn normalize_configure_request_auth(
|
||||
/// Save KMS configuration to cluster storage
|
||||
#[instrument(skip(config))]
|
||||
async fn save_kms_config(config: &KmsConfig) -> Result<(), String> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
let context = current_app_context();
|
||||
let Some(store) = resolve_object_store_handle_for_context(context.as_deref()) else {
|
||||
return Err("Storage layer not initialized".to_string());
|
||||
};
|
||||
|
||||
@@ -129,7 +131,8 @@ async fn save_kms_config(config: &KmsConfig) -> Result<(), String> {
|
||||
/// Load KMS configuration from cluster storage
|
||||
#[instrument]
|
||||
pub async fn load_kms_config() -> Option<KmsConfig> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
let context = current_app_context();
|
||||
let Some(store) = resolve_object_store_handle_for_context(context.as_deref()) else {
|
||||
warn!(
|
||||
component = LOG_COMPONENT_ADMIN,
|
||||
subsystem = LOG_SUBSYSTEM_KMS,
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
use super::sts::create_oidc_sts_credentials;
|
||||
use crate::admin::auth::validate_admin_request;
|
||||
use crate::admin::router::{AdminOperation, Operation, S3Router};
|
||||
use crate::admin::runtime_sources::{resolve_object_store_handle, resolve_oidc_handle, resolve_server_config};
|
||||
use crate::admin::runtime_sources::{
|
||||
current_app_context, resolve_object_store_handle_for_context, resolve_oidc_handle, resolve_server_config_for_context,
|
||||
};
|
||||
use crate::admin::storage_api::config::{read_admin_config_without_migrate, save_admin_server_config};
|
||||
use crate::auth::{check_key_valid, get_session_token};
|
||||
use crate::server::{ADMIN_PREFIX, MINIO_ADMIN_PREFIX, RemoteAddr};
|
||||
@@ -792,7 +794,8 @@ fn json_response<T: Serialize>(status: StatusCode, payload: &T) -> S3Result<S3Re
|
||||
}
|
||||
|
||||
async fn load_server_config_from_store() -> S3Result<ServerConfig> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
let context = current_app_context();
|
||||
let Some(store) = resolve_object_store_handle_for_context(context.as_deref()) else {
|
||||
return Err(s3_error!(InternalError, "storage layer not initialized"));
|
||||
};
|
||||
|
||||
@@ -802,7 +805,8 @@ async fn load_server_config_from_store() -> S3Result<ServerConfig> {
|
||||
}
|
||||
|
||||
async fn save_server_config_to_store(config: &ServerConfig) -> S3Result<()> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
let context = current_app_context();
|
||||
let Some(store) = resolve_object_store_handle_for_context(context.as_deref()) else {
|
||||
return Err(s3_error!(InternalError, "storage layer not initialized"));
|
||||
};
|
||||
|
||||
@@ -826,7 +830,8 @@ fn provider_instance_key(provider_id: &str) -> String {
|
||||
}
|
||||
|
||||
fn oidc_restart_required(config: &ServerConfig) -> bool {
|
||||
let active_config = resolve_server_config();
|
||||
let context = current_app_context();
|
||||
let active_config = resolve_server_config_for_context(context.as_deref());
|
||||
oidc_restart_required_from_active_config(config, active_config.as_ref())
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,11 @@ pub(crate) use crate::runtime_sources::{
|
||||
AppContext, publish_server_config, publish_storage_class_config, resolve_action_credentials, resolve_boot_time,
|
||||
resolve_bucket_metadata_handle, resolve_bucket_monitor_handle, resolve_daily_tier_stats, resolve_deployment_id,
|
||||
resolve_endpoints_handle, resolve_iam_handle, resolve_kms_runtime_service_manager, resolve_notification_system,
|
||||
resolve_object_store_handle, resolve_object_store_handle_for_context, resolve_oidc_handle,
|
||||
resolve_or_init_kms_runtime_service_manager, resolve_outbound_tls_generation, resolve_outbound_tls_state,
|
||||
resolve_ready_iam_handle, resolve_region, resolve_replication_pool_handle, resolve_replication_stats_handle,
|
||||
resolve_runtime_port, resolve_scanner_metrics_report, resolve_server_config, resolve_tier_config_handle,
|
||||
resolve_token_signing_key,
|
||||
resolve_notification_system_for_context, resolve_object_store_handle, resolve_object_store_handle_for_context,
|
||||
resolve_oidc_handle, resolve_or_init_kms_runtime_service_manager, resolve_outbound_tls_generation,
|
||||
resolve_outbound_tls_state, resolve_ready_iam_handle, resolve_region, resolve_replication_pool_handle,
|
||||
resolve_replication_stats_handle, resolve_runtime_port, resolve_scanner_metrics_report, resolve_server_config,
|
||||
resolve_server_config_for_context, resolve_tier_config_handle, resolve_token_signing_key,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
use crate::admin::runtime_sources::{
|
||||
AppContext, current_app_context, publish_server_config, publish_storage_class_config, resolve_notification_system,
|
||||
resolve_object_store_handle, resolve_object_store_handle_for_context,
|
||||
AppContext, current_app_context, publish_server_config, publish_storage_class_config,
|
||||
resolve_notification_system_for_context, resolve_object_store_handle_for_context,
|
||||
};
|
||||
use crate::admin::storage_api::config::{STORAGE_CLASS_SUB_SYS, read_admin_config_without_migrate, storageclass};
|
||||
use crate::admin::storage_api::contract::admin::StorageAdminApi;
|
||||
@@ -71,10 +71,8 @@ fn resolve_runtime_config_store_for_context(context: Option<&AppContext>) -> S3R
|
||||
resolve_object_store_handle_for_context(context).ok_or_else(|| internal_error("storage layer not initialized"))
|
||||
}
|
||||
|
||||
async fn apply_storage_class_runtime_config(config: &ServerConfig) -> S3Result<()> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
return Err(internal_error("storage layer not initialized"));
|
||||
};
|
||||
async fn apply_storage_class_runtime_config_for_context(context: Option<&AppContext>, config: &ServerConfig) -> S3Result<()> {
|
||||
let store = resolve_runtime_config_store_for_context(context)?;
|
||||
|
||||
let kvs = config.get_value(STORAGE_CLASS_SUB_SYS, DEFAULT_DELIMITER).unwrap_or_default();
|
||||
let set_drive_count = StorageAdminApi::set_drive_counts(store.as_ref())
|
||||
@@ -96,10 +94,8 @@ fn validate_storage_class_kvs(kvs: &KVS, set_drive_counts: &[usize]) -> S3Result
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn validate_storage_class_config(config: &ServerConfig) -> S3Result<()> {
|
||||
let Some(store) = resolve_object_store_handle() else {
|
||||
return Err(internal_error("storage layer not initialized"));
|
||||
};
|
||||
async fn validate_storage_class_config_for_context(context: Option<&AppContext>, config: &ServerConfig) -> S3Result<()> {
|
||||
let store = resolve_runtime_config_store_for_context(context)?;
|
||||
|
||||
let kvs = config.get_value(STORAGE_CLASS_SUB_SYS, DEFAULT_DELIMITER).unwrap_or_default();
|
||||
let set_drive_counts = StorageAdminApi::set_drive_counts(store.as_ref());
|
||||
@@ -252,9 +248,13 @@ fn validate_identity_openid_config(config: &ServerConfig) -> S3Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn validate_server_config(config: &ServerConfig, sub_system: Option<&str>) -> S3Result<()> {
|
||||
pub async fn validate_server_config_for_context(
|
||||
context: Option<&AppContext>,
|
||||
config: &ServerConfig,
|
||||
sub_system: Option<&str>,
|
||||
) -> S3Result<()> {
|
||||
match sub_system {
|
||||
Some(STORAGE_CLASS_SUB_SYS) => validate_storage_class_config(config).await,
|
||||
Some(STORAGE_CLASS_SUB_SYS) => validate_storage_class_config_for_context(context, config).await,
|
||||
Some(NOTIFY_WEBHOOK_SUB_SYS) => validate_notify_subsystem_config(config, NOTIFY_WEBHOOK_SUB_SYS),
|
||||
Some(NOTIFY_MQTT_SUB_SYS) => validate_notify_subsystem_config(config, NOTIFY_MQTT_SUB_SYS),
|
||||
Some(AUDIT_WEBHOOK_SUB_SYS) => validate_audit_subsystem_config(config, AUDIT_WEBHOOK_SUB_SYS),
|
||||
@@ -264,7 +264,7 @@ pub async fn validate_server_config(config: &ServerConfig, sub_system: Option<&s
|
||||
.map_err(|err| invalid_request(format!("invalid scanner config: {err}"))),
|
||||
Some(_) => Ok(()),
|
||||
None => {
|
||||
validate_storage_class_config(config).await?;
|
||||
validate_storage_class_config_for_context(context, config).await?;
|
||||
validate_notify_subsystem_config(config, NOTIFY_WEBHOOK_SUB_SYS)?;
|
||||
validate_notify_subsystem_config(config, NOTIFY_MQTT_SUB_SYS)?;
|
||||
validate_audit_subsystem_config(config, AUDIT_WEBHOOK_SUB_SYS)?;
|
||||
@@ -277,13 +277,22 @@ pub async fn validate_server_config(config: &ServerConfig, sub_system: Option<&s
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn apply_dynamic_config_for_subsystem(config: &ServerConfig, sub_system: &str) -> S3Result<bool> {
|
||||
pub async fn validate_server_config(config: &ServerConfig, sub_system: Option<&str>) -> S3Result<()> {
|
||||
let context = current_app_context();
|
||||
validate_server_config_for_context(context.as_deref(), config, sub_system).await
|
||||
}
|
||||
|
||||
pub async fn apply_dynamic_config_for_subsystem_for_context(
|
||||
context: Option<&AppContext>,
|
||||
config: &ServerConfig,
|
||||
sub_system: &str,
|
||||
) -> S3Result<bool> {
|
||||
if dynamic_config_reload_plan(sub_system).is_none() {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
match sub_system {
|
||||
STORAGE_CLASS_SUB_SYS => apply_storage_class_runtime_config(config).await?,
|
||||
STORAGE_CLASS_SUB_SYS => apply_storage_class_runtime_config_for_context(context, config).await?,
|
||||
AUDIT_WEBHOOK_SUB_SYS | AUDIT_MQTT_SUB_SYS => reload_audit_config(config.clone())
|
||||
.await
|
||||
.map_err(|err| internal_error(format!("failed to reload audit config: {err}")))?,
|
||||
@@ -297,6 +306,11 @@ pub async fn apply_dynamic_config_for_subsystem(config: &ServerConfig, sub_syste
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub async fn apply_dynamic_config_for_subsystem(config: &ServerConfig, sub_system: &str) -> S3Result<bool> {
|
||||
let context = current_app_context();
|
||||
apply_dynamic_config_for_subsystem_for_context(context.as_deref(), config, sub_system).await
|
||||
}
|
||||
|
||||
pub async fn reload_dynamic_config_runtime_state_for_context(context: Option<&AppContext>, sub_system: &str) -> S3Result<()> {
|
||||
if !is_dynamic_config_subsystem(sub_system) {
|
||||
return Err(internal_error(format!("unsupported dynamic config subsystem: {sub_system}")));
|
||||
@@ -308,10 +322,12 @@ pub async fn reload_dynamic_config_runtime_state_for_context(context: Option<&Ap
|
||||
warn!("peer reload_dynamic_config: failed to load server config for {sub_system}: {err}");
|
||||
internal_error(format!("failed to load server config: {err}"))
|
||||
})?;
|
||||
apply_dynamic_config_for_subsystem(&config, sub_system).await.map_err(|err| {
|
||||
warn!("peer reload_dynamic_config: failed to apply {sub_system}: {err}");
|
||||
err
|
||||
})?;
|
||||
apply_dynamic_config_for_subsystem_for_context(context, &config, sub_system)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("peer reload_dynamic_config: failed to apply {sub_system}: {err}");
|
||||
err
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -337,7 +353,7 @@ pub async fn reload_runtime_config_snapshot_for_context(context: Option<&AppCont
|
||||
SCANNER_SUB_SYS,
|
||||
HEAL_SUB_SYS,
|
||||
] {
|
||||
if let Err(err) = apply_dynamic_config_for_subsystem(&config, sub_system).await {
|
||||
if let Err(err) = apply_dynamic_config_for_subsystem_for_context(context, &config, sub_system).await {
|
||||
warn!("peer reload_runtime_config_snapshot: failed to apply {sub_system}: {err}");
|
||||
}
|
||||
}
|
||||
@@ -351,12 +367,12 @@ pub async fn reload_runtime_config_snapshot() -> S3Result<()> {
|
||||
reload_runtime_config_snapshot_for_context(context.as_deref()).await
|
||||
}
|
||||
|
||||
pub async fn signal_dynamic_config_reload(sub_system: &str) {
|
||||
pub async fn signal_dynamic_config_reload_for_context(context: Option<&AppContext>, sub_system: &str) {
|
||||
if !is_dynamic_config_subsystem(sub_system) {
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(notification_sys) = resolve_notification_system() else {
|
||||
let Some(notification_sys) = resolve_notification_system_for_context(context) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -367,8 +383,13 @@ pub async fn signal_dynamic_config_reload(sub_system: &str) {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn signal_config_snapshot_reload() {
|
||||
let Some(notification_sys) = resolve_notification_system() else {
|
||||
pub async fn signal_dynamic_config_reload(sub_system: &str) {
|
||||
let context = current_app_context();
|
||||
signal_dynamic_config_reload_for_context(context.as_deref(), sub_system).await;
|
||||
}
|
||||
|
||||
pub async fn signal_config_snapshot_reload_for_context(context: Option<&AppContext>) {
|
||||
let Some(notification_sys) = resolve_notification_system_for_context(context) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -379,6 +400,11 @@ pub async fn signal_config_snapshot_reload() {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn signal_config_snapshot_reload() {
|
||||
let context = current_app_context();
|
||||
signal_config_snapshot_reload_for_context(context.as_deref()).await;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -141,6 +141,13 @@ pub fn resolve_notification_system() -> Option<&'static NotificationSys> {
|
||||
resolve_notification_system_with(get_global_app_context(), || default_notification_system_interface().handle())
|
||||
}
|
||||
|
||||
/// Resolve notification system handle using an explicit AppContext, falling back to the legacy global notification system.
|
||||
pub fn resolve_notification_system_for_context(context: Option<&AppContext>) -> Option<&'static NotificationSys> {
|
||||
context
|
||||
.and_then(|context| context.notification_system().handle())
|
||||
.or_else(|| default_notification_system_interface().handle())
|
||||
}
|
||||
|
||||
/// Resolve endpoints using AppContext-first precedence.
|
||||
pub fn resolve_endpoints_handle() -> Option<EndpointServerPools> {
|
||||
resolve_endpoints_handle_with(get_global_app_context(), || default_endpoints_interface().handle())
|
||||
@@ -248,6 +255,11 @@ pub fn resolve_server_config() -> Option<Config> {
|
||||
resolve_server_config_with(get_global_app_context(), || default_server_config_interface().get())
|
||||
}
|
||||
|
||||
/// Resolve server config using an explicit AppContext, falling back to the legacy global server config.
|
||||
pub fn resolve_server_config_for_context(context: Option<&AppContext>) -> Option<Config> {
|
||||
context.map_or_else(|| default_server_config_interface().get(), |context| context.server_config().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));
|
||||
|
||||
@@ -21,11 +21,13 @@ pub(crate) use context::{
|
||||
resolve_buffer_config, resolve_daily_tier_stats, resolve_deployment_id, resolve_encryption_service, resolve_endpoints_handle,
|
||||
resolve_expiry_state_handle, resolve_iam_handle, resolve_iam_ready, resolve_internode_metrics,
|
||||
resolve_kms_runtime_service_manager, resolve_local_node_name, resolve_lock_client, resolve_lock_clients_handle,
|
||||
resolve_notification_system, resolve_notify_interface, resolve_notify_interface_for_context, resolve_object_store_handle,
|
||||
resolve_object_store_handle_for_context, resolve_oidc_handle, resolve_or_init_kms_runtime_service_manager,
|
||||
resolve_outbound_tls_generation, resolve_outbound_tls_state, resolve_performance_metrics, resolve_ready_iam_handle,
|
||||
resolve_region, resolve_replication_pool_handle, resolve_replication_stats_handle, resolve_runtime_port, resolve_s3select_db,
|
||||
resolve_scanner_metrics_report, resolve_server_config, resolve_tier_config_handle, resolve_token_signing_key,
|
||||
resolve_notification_system, resolve_notification_system_for_context, resolve_notify_interface,
|
||||
resolve_notify_interface_for_context, resolve_object_store_handle, resolve_object_store_handle_for_context,
|
||||
resolve_oidc_handle, resolve_or_init_kms_runtime_service_manager, resolve_outbound_tls_generation,
|
||||
resolve_outbound_tls_state, resolve_performance_metrics, resolve_ready_iam_handle, resolve_region,
|
||||
resolve_replication_pool_handle, resolve_replication_stats_handle, resolve_runtime_port, resolve_s3select_db,
|
||||
resolve_scanner_metrics_report, resolve_server_config, resolve_server_config_for_context, resolve_tier_config_handle,
|
||||
resolve_token_signing_key,
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user