mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-06 13:27:43 +00:00
f63af3df63
The ecstore/global-state migrations are done (backlog#815, #939, #1052 all closed). Review of every migration-era test/gate measure found three things actually retirable or broken — everything else is a live anti-regression guard and stays. Remove: - scripts/check_metrics_migration_refs.sh — guards a migration that finished: rustfs_metrics:: has zero hits, the metrics crate no longer exists, and the script was never wired into CI or make (only reference was one line in config-model-boundary-adr.md, also removed). - crates/obs init_metrics_collectors — the "backward-compatible alias kept during migration" the removed script was guarding. Zero callers; pure delegate to init_metrics_runtime. Archive (docs/superpowers/plans/, continuing the 2026-07 convention, with the standard archived banner): - startup-timeline.md, scheduler-baseline.md, profiling-numa-capability-inventory.md, kms-development-defaults-inventory.md — one-shot snapshots whose only consumer is the already-archived migration-progress ledger (their same-dir links there start resolving again after the move); zero script pins; fed the closed backlog#660/#665 architecture-review ledger. Fixed the one outbound link (startup-timeline -> readiness-matrix) that the move would have broken — check_doc_paths.sh deliberately does not scan plans/, so nothing else would have caught it. Wire (found orphaned by the same review): - scripts/check_extension_schema_boundaries.sh guards a live contract crate but was never invoked anywhere. Add lint-fmt.mak target, include in pre-commit/pre-pr/dev-check, add ci.yml Quick Checks step (job already installs ripgrep), sync the CONTRIBUTING.md enumerated list, and harden the script against a silently-passing rg probe when src/ is missing. Keep (verified live, documented so the next cleanup pass does not repeat this analysis): - scripts/check_architecture_migration_rules.sh — added a header stating it is a permanent boundary guard, not retirable migration scaffolding; 'migration' in the name is historical. - check_migration_gate_count.sh + floor, delete-marker e2e proof, all pinned docs, compat-cleanup-register sync, remaining inventories (referenced by live docs). Verification: all 7 guard scripts pass, actionlint clean, cargo check --workspace (excl e2e) clean, cargo fmt --check clean. Adversarially reviewed by two independent skeptic passes; their 7 findings (alias left behind, broken outbound link, missing banners, wrong backlog attribution, CONTRIBUTING drift, rg exit-2 hole, missing header rationale) are all folded in.
186 lines
6.3 KiB
Markdown
186 lines
6.3 KiB
Markdown
# Config Model Boundary ADR
|
|
|
|
Related issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
|
|
|
|
Task: `CFG-002`
|
|
|
|
## Decision
|
|
|
|
Use the existing `crates/config` package (`rustfs-config`) as the target owner
|
|
for the pure server-config model. Do not create a new config-model crate for
|
|
the first extraction.
|
|
|
|
The next model extraction PR should introduce the model under:
|
|
|
|
```text
|
|
crates/config/src/server_config.rs
|
|
```
|
|
|
|
The exported path should be:
|
|
|
|
```rust
|
|
rustfs_config::server_config::{Config, KV, KVS}
|
|
```
|
|
|
|
The extraction kept the existing path available through a temporary
|
|
compatibility re-export:
|
|
|
|
```rust
|
|
rustfs_ecstore::config::{Config, KV, KVS}
|
|
```
|
|
|
|
That re-export included `RUSTFS_COMPAT_TODO(CFG-004)` and a matching entry in
|
|
[`compat-cleanup-register.md`](compat-cleanup-register.md) until the model
|
|
consumers were migrated. The CFG-004 cleanup removed this old model path after
|
|
code scans showed consumers import the model directly from `rustfs-config`.
|
|
|
|
Follow-up `CFG-008` moved the process-global server-config snapshot accessors
|
|
to `rustfs_config::server_config` after the model path stabilized. Its temporary
|
|
`rustfs_ecstore::config::{get_global_server_config, set_global_server_config}`
|
|
compatibility re-export was removed after in-repo runtime consumers migrated to
|
|
the `rustfs-config` owner.
|
|
|
|
## Why `rustfs-config`
|
|
|
|
`rustfs-config` is already the lowest RustFS crate for configuration constants
|
|
and subsystem identifiers used by ECStore, notify, audit, targets, scanner, IAM,
|
|
and admin code. The current `ecstore::config::{Config, KV, KVS}` model already
|
|
uses `rustfs-config` constants, so moving the pure model upward to
|
|
`rustfs-config` cuts the wrong dependency direction without adding another crate.
|
|
|
|
Creating a new crate now would add a second config namespace before consumers
|
|
are migrated. That would increase re-export and compatibility surface while not
|
|
removing any storage or runtime dependency by itself.
|
|
|
|
## Allowed Dependencies
|
|
|
|
The server-config model module may use only:
|
|
|
|
- `std::collections::HashMap`
|
|
- `std::sync::{LazyLock, OnceLock, RwLock}` for the default `KVS` registration
|
|
surface and process-global server-config snapshot
|
|
- `serde` for `KV` and `KVS` serialization compatibility
|
|
- `serde_json` for `Config::marshal` and `Config::unmarshal`
|
|
- existing `rustfs-config` constants and subsystem modules
|
|
|
|
If `serde` and `serde_json` are added to `rustfs-config`, they should be attached
|
|
only to a model feature such as `server-config-model` unless the implementation
|
|
PR proves that making them non-optional is simpler and harmless for downstream
|
|
builds.
|
|
|
|
## Forbidden Dependencies
|
|
|
|
The model module must not depend on:
|
|
|
|
- `rustfs-ecstore`
|
|
- `rustfs`
|
|
- `StorageAPI` or object persistence helpers
|
|
- notify, audit, targets, IAM, scanner, KMS, or admin handler crates
|
|
- async runtimes, HTTP/router crates, object-store crates, or runtime lifecycle
|
|
state
|
|
- unrelated runtime global state outside the process-global server-config
|
|
snapshot
|
|
- `ConfigSys`, `read_config_without_migrate`, `save_server_config`, or any
|
|
`com.rs` persistence helper
|
|
|
|
## Boundary Split
|
|
|
|
Move in the first extraction:
|
|
|
|
- `KV`
|
|
- `KVS`
|
|
- `Config`
|
|
- `DEFAULT_KVS`
|
|
- `register_default_kvs`
|
|
- `Config::new`
|
|
- `Config::get_value`
|
|
- `Config::set_defaults`
|
|
- `Config::marshal`
|
|
- `Config::unmarshal`
|
|
- `Config::merge`
|
|
|
|
Keep in `ecstore`:
|
|
|
|
- `ConfigSys`
|
|
- `init_global_config_sys`
|
|
- `try_migrate_server_config`
|
|
- `read_config_without_migrate`
|
|
- `save_server_config`
|
|
- generic `com.rs` config-object helpers
|
|
- storage-class runtime global state
|
|
|
|
Keep default registration wiring in `ecstore::config::init` until a later PR
|
|
extracts a dedicated default-registration contract. The values may be registered
|
|
through the moved `rustfs_config::server_config::register_default_kvs`, but the
|
|
startup order and caller remain unchanged.
|
|
|
|
Move in `CFG-008`:
|
|
|
|
- `GLOBAL_SERVER_CONFIG`
|
|
- `get_global_server_config`
|
|
- `set_global_server_config`
|
|
|
|
The temporary ECStore compatibility re-export for these accessors was removed
|
|
after code scans showed in-repo consumers use `rustfs_config::server_config`
|
|
directly.
|
|
|
|
## Required Shape Preservation
|
|
|
|
The extraction PR must preserve:
|
|
|
|
- `KV { key, value, hidden_if_empty }`
|
|
- `#[serde(default, alias = "hiddenIfEmpty")]` on `KV::hidden_if_empty`
|
|
- `KVS(pub Vec<KV>)`
|
|
- `Config(pub HashMap<String, HashMap<String, KVS>>)`
|
|
- `KVS::new`, `get`, `lookup`, `is_empty`, `keys`, `insert`, and `extend`
|
|
- `Config::new`, `get_value`, `set_defaults`, `marshal`, `unmarshal`, and
|
|
`merge`
|
|
- `Config::new()` default application after `ecstore::config::init()`
|
|
- existing persisted server-config JSON shape
|
|
- existing target, notify, audit, scanner, OIDC, and admin interpretation of
|
|
`Config` and `KVS`
|
|
|
|
## Next PR Requirements
|
|
|
|
`CFG-003` should be a pure model extraction or narrow `api-extraction` PR. It
|
|
must not migrate consumers, change persistence helpers, or alter runtime
|
|
behavior.
|
|
|
|
`CFG-004` kept the old `rustfs_ecstore::config::*` path as a temporary
|
|
compatibility shim, registered its removal condition, and removed the shim after
|
|
all in-repo consumers migrated.
|
|
|
|
`CFG-005` should migrate external consumers one group at a time after the model
|
|
and compatibility path are stable.
|
|
|
|
`CFG-008` moves only the global server-config snapshot accessors to
|
|
`rustfs-config` and migrates in-repo direct consumers. It must not move
|
|
`ConfigSys`, storage-class global state, persistence helpers, default
|
|
registration wiring, startup order, or storage behavior.
|
|
|
|
## Verification Gate
|
|
|
|
Before pushing an extraction PR, run:
|
|
|
|
- serde roundtrip tests for old and new paths
|
|
- tests for `hiddenIfEmpty` alias compatibility
|
|
- tests for `KVS` insertion, lookup, extension, and keys behavior
|
|
- tests for `Config::new`, `set_defaults`, `marshal`, `unmarshal`, and `merge`
|
|
- a cleanup scan proving in-repo consumers no longer use the old
|
|
`rustfs_ecstore::config::{Config, KV, KVS}` model path before removing the
|
|
compatibility shim
|
|
- `cargo tree -p rustfs-config --edges normal`
|
|
- `cargo tree -p rustfs-ecstore --edges normal`
|
|
- `./scripts/check_layer_dependencies.sh`
|
|
- `./scripts/check_architecture_migration_rules.sh`
|
|
- `cargo fmt --all --check`
|
|
- `make pre-commit`
|
|
|
|
## Non-Goals
|
|
|
|
- No consumer migration in `CFG-002`.
|
|
- No code movement in `CFG-002`.
|
|
- No new crate in `CFG-002`.
|
|
- No `com.rs` or `StorageAPI` movement in the first model extraction.
|
|
- No global server-config state migration until the model path is stable.
|