diff --git a/docs/architecture/migration-progress.md b/docs/architecture/migration-progress.md index cbf1a2124..cf958f377 100644 --- a/docs/architecture/migration-progress.md +++ b/docs/architecture/migration-progress.md @@ -5,15 +5,15 @@ 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-embedded-startup-config-identity` -- Baseline: completed `R-048/R-049`. -- Stacked on: embedded startup result shell slice. +- Branch: `overtrue/arch-app-context-bootstrap-result` +- Baseline: completed `R-050/R-051`. +- Stacked on: embedded startup config identity slice. - PR type for this branch: `pure-move` - Runtime behavior changes: none. -- Rust code changes: keep embedded startup identity with prepared startup - config and remove the residual startup-argument clone contract. +- Rust code changes: make IAM AppContext bootstrap outcome explicit and reuse + it in inline and deferred IAM readiness paths. - CI/script changes: none. -- Docs changes: record the embedded startup config identity slices. +- Docs changes: record the AppContext bootstrap result slices. ## Phase 0 Tasks @@ -2435,6 +2435,31 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block risk scan, branch freshness check, pre-commit quality gate, and three-expert review. +- [x] `R-052` Make IAM AppContext bootstrap outcome explicit. + - Do: replace boolean-or-global probing in IAM startup with a crate-private + AppContext bootstrap disposition that reports already-available versus + initialized context. + - Acceptance: successful inline IAM bootstrap still initializes or reuses + AppContext before publishing IAM readiness, while failure still returns an + I/O error. + - Must preserve: IAM initialization order, global AppContext singleton + behavior, KMS/IAM handle construction, degraded-mode fallback, and + readiness stage updates. + - Verification: focused startup IAM checks, RustFS lib check, + migration/layer guards, formatting, diff hygiene, Rust risk scan, branch + freshness check, pre-commit quality gate, and three-expert review. + +- [x] `R-053` Reuse explicit AppContext bootstrap in IAM recovery. + - Do: route degraded IAM recovery finalization through the same AppContext + bootstrap result helper as inline startup. + - Acceptance: recovered IAM still marks `IamReady` and publishes runtime + readiness only after AppContext is available. + - Must preserve: recovery retry/backoff behavior, shutdown-token handling, + readiness publication retry behavior, and log semantics. + - Verification: focused startup IAM checks, RustFS lib check, + migration/layer guards, formatting, diff hygiene, Rust risk scan, branch + freshness check, pre-commit quality gate, and three-expert review. + - [x] `E-001/E-SET-001` Add ECStore layout skeleton and set-layout boundary. - Do: create the ECStore internal layout ownership buckets and pin static set layout versus runtime `Sets`/`SetDisks` orchestration boundaries before any @@ -2677,21 +2702,34 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block ## Next PRs -1. `pure-move`: continue pruning residual embedded handle/startup-only - boundaries after the embedded startup result shell slice lands. +1. `pure-move`: continue the context-first runtime startup path after the + embedded startup ownership slices land. ## Pre-Push Review Log | Expert | Status | Notes | |---|---|---| -| Quality/architecture | passed | R-050 and R-051 keep embedded identity with prepared startup config and remove the residual startup-argument clone contract without widening the public API. | -| Migration preservation | passed | Builder chaining, configured identity, region setup, temporary volume ownership, startup error mapping, and shutdown ownership stay unchanged. | -| Testing/verification | passed | Focused startup-server/startup-embedded/embedded checks, RustFS lib check, architecture/layer/unsafe guards, formatting, diff hygiene, Rust risk scan, and pre-commit gate passed. | +| Quality/architecture | passed | R-052 and R-053 make AppContext bootstrap outcome explicit and share inline/recovery finalization without widening public API. | +| Migration preservation | passed | IAM init order, singleton reuse, KMS/IAM handles, degraded recovery, backoff/shutdown token, readiness stages, and log behavior stay unchanged. | +| Testing/verification | passed | Focused startup IAM checks, RustFS lib check, architecture/layer/unsafe guards, formatting, diff hygiene, Rust risk scan, and pre-commit gate passed. | ## Verification Notes Passed before push: +- Issue #660 R-052/R-053 current slice: + - `cargo test -p rustfs --lib startup_iam -- --nocapture`: passed. + - `cargo check -p rustfs --lib`: passed. + - `cargo fmt --all --check`: passed. + - `git diff --check`: passed. + - `./scripts/check_architecture_migration_rules.sh`: passed. + - `./scripts/check_layer_dependencies.sh`: passed. + - `./scripts/check_unsafe_code_allowances.sh`: passed. + - Rust risk scan on changed Rust files: passed; only a test-only `expect` + call was present. + - `make pre-commit`: passed; nextest ran 6336 tests with 6336 passed and + 111 skipped, and doctests passed. + - Issue #660 R-050/R-051 current slice: - `cargo test -p rustfs --lib startup_server -- --nocapture`: passed. - `cargo test -p rustfs --lib startup_embedded -- --nocapture`: passed. diff --git a/rustfs/src/startup_iam.rs b/rustfs/src/startup_iam.rs index 08b3f8ddb..547db5746 100644 --- a/rustfs/src/startup_iam.rs +++ b/rustfs/src/startup_iam.rs @@ -44,6 +44,12 @@ pub enum IamBootstrapDisposition { Deferred, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum AppContextBootstrapDisposition { + AlreadyAvailable, + Initialized, +} + pub async fn publish_ready_for_iam_bootstrap( disposition: IamBootstrapDisposition, readiness: &GlobalReadiness, @@ -71,17 +77,18 @@ where Ok(false) } -fn init_app_context_if_needed(store: Arc, kms_interface: Arc) -> bool { +fn ensure_app_context_after_iam( + store: Arc, + kms_interface: Arc, +) -> Result { if get_global_app_context().is_some() { - return false; + return Ok(AppContextBootstrapDisposition::AlreadyAvailable); } - let Ok(iam_interface) = rustfs_iam::get() else { - return false; - }; + let iam_interface = rustfs_iam::get().map_err(|_| std::io::Error::other("IAM is initialized but unavailable"))?; init_global_app_context(AppContext::with_default_interfaces(store, iam_interface, kms_interface)); - true + Ok(AppContextBootstrapDisposition::Initialized) } async fn finalize_iam_recovery( @@ -90,9 +97,7 @@ async fn finalize_iam_recovery( readiness: Arc, state_manager: Option>, ) -> Result<()> { - if !init_app_context_if_needed(store, kms_interface) && get_global_app_context().is_none() { - return Err(std::io::Error::other("IAM recovered but app context is still unavailable")); - } + ensure_app_context_after_iam(store, kms_interface)?; readiness.mark_stage(SystemStage::IamReady); publish_ready_when_runtime_ready(readiness.as_ref(), state_manager.as_deref()).await @@ -330,9 +335,7 @@ pub async fn bootstrap_or_defer_iam_init( ) -> Result { match attempt_init_iam_sys(store.clone()).await { Ok(()) => { - if !init_app_context_if_needed(store, kms_interface) && get_global_app_context().is_none() { - return Err(std::io::Error::other("IAM bootstrap succeeded but app context is still unavailable")); - } + ensure_app_context_after_iam(store, kms_interface)?; readiness.mark_stage(SystemStage::IamReady); return Ok(IamBootstrapDisposition::ReadyInline); }