feat: first-draft preview-capable zosstorage

- CLI: add topology selection (-t/--topology), preview flags (--show/--report), and removable policy override (--allow-removable) (src/cli/args.rs)
- Config: built-in sensible defaults; deterministic overlays for logging, fstab, removable, topology (src/config/loader.rs)
- Device: discovery via /proc + /sys with include/exclude regex and removable policy (src/device/discovery.rs)
- Idempotency: detection via blkid; safe emptiness checks (src/idempotency/mod.rs)
- Partition: topology-driven planning (Single, DualIndependent, BtrfsRaid1, SsdHddBcachefs) (src/partition/plan.rs)
- FS: planning + creation (mkfs.vfat, mkfs.btrfs, bcachefs format) and UUID capture via blkid (src/fs/plan.rs)
- Orchestrator: pre-flight with preview JSON (disks, partition_plan, filesystems_planned, mount scheme). Skips emptiness in preview; supports stdout+file (src/orchestrator/run.rs)
- Util/Logging/Types/Errors: process execution, tracing, shared types (src/util/mod.rs, src/logging/mod.rs, src/types.rs, src/errors.rs)
- Docs: add README with exhaustive usage and preview JSON shape (README.md)

Builds and unit tests pass: discovery, util, idempotency helpers, and fs parser tests.
This commit is contained in:
2025-09-29 11:37:07 +02:00
commit 507bc172c2
38 changed files with 6558 additions and 0 deletions

237
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,237 @@
# zosstorage Architecture
This document defines the repository layout, module boundaries, public API surface (signatures only), defaults, and high-level execution flow for the initramfs-only provisioning utility.
Baseline decisions and labels
- External tools inside initramfs are allowed and will be wrapped via helpers: sgdisk, blkid, mkfs.vfat, mkfs.btrfs, mkfs.bcachefs, udevadm.
- Kernel cmdline key: zosstorage.config=
- Default config path: /etc/zosstorage/config.yaml
- JSON state report path: /run/zosstorage/state.json
- Optional log file path: /run/zosstorage/zosstorage.log
- fstab generation: disabled by default
- GPT partition names: zosboot, zosdata, zoscache
- Filesystem labels:
- ESP: ZOSBOOT
- Data filesystems including bcachefs: ZOSDATA
Repository layout
Top level
- [Cargo.toml](Cargo.toml)
- [PROMPT.md](PROMPT.md)
- [README.md](README.md)
- [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
- [docs/SCHEMA.md](docs/SCHEMA.md)
- [examples/config/minimal.yaml](examples/config/minimal.yaml)
- [examples/config/dual-btrfs.yaml](examples/config/dual-btrfs.yaml)
- [examples/config/ssd-hdd-bcachefs.yaml](examples/config/ssd-hdd-bcachefs.yaml)
- [tests/](tests/)
- [tests/integration_single_disk.rs](tests/integration_single_disk.rs)
- [tests/integration_dual_disk.rs](tests/integration_dual_disk.rs)
- [tests/integration_ssd_hdd.rs](tests/integration_ssd_hdd.rs)
Crate sources
- [src/main.rs](src/main.rs)
- [src/lib.rs](src/lib.rs)
- [src/errors.rs](src/errors.rs)
- [src/cli/args.rs](src/cli/args.rs)
- [src/logging/mod.rs](src/logging/mod.rs)
- [src/config/loader.rs](src/config/loader.rs)
- [src/types.rs](src/types.rs)
- [src/device/discovery.rs](src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs)
- [src/idempotency/mod.rs](src/idempotency/mod.rs)
- [src/util/mod.rs](src/util/mod.rs)
Module responsibilities
- [src/main.rs](src/main.rs)
- Entrypoint. Parse CLI, initialize logging, load and merge configuration per precedence, call orchestrator. No stdout spam.
- [src/lib.rs](src/lib.rs)
- Crate exports, prelude, version constants, Result alias.
- [src/errors.rs](src/errors.rs)
- Common error enum and Result alias via thiserror.
- [src/cli/args.rs](src/cli/args.rs)
- CLI definition mirroring kernel cmdline semantics; provide non-interactive interface. Stub --force returns unimplemented.
- [src/logging/mod.rs](src/logging/mod.rs)
- Initialize tracing; levels error, warn, info, debug; default to stderr; optional file target.
- [src/config/loader.rs](src/config/loader.rs) and [src/types.rs](src/types.rs)
- YAML schema types, validation, loading, and merging with CLI and kernel cmdline.
- [src/device/discovery.rs](src/device/discovery.rs)
- Device discovery under /dev with filters and allowlist; probe emptiness safely.
- [src/partition/plan.rs](src/partition/plan.rs)
- GPT-only planning and application; 1 MiB alignment; create bios boot, ESP, data and cache partitions with strict safety checks.
- [src/fs/plan.rs](src/fs/plan.rs)
- Filesystem provisioning: vfat for ESP, btrfs for ZOSDATA, bcachefs for SSD+HDD mode; all data filesystems labeled ZOSDATA.
- [src/mount/ops.rs](src/mount/ops.rs)
- Mount per-UUID under /var/cache/<UUID>. Optional fstab writing, disabled by default.
- [src/report/state.rs](src/report/state.rs)
- Build and write JSON state report with version field.
- [src/orchestrator/run.rs](src/orchestrator/run.rs)
- One-shot flow orchestration with abort-on-any-validation-error policy.
- [src/idempotency/mod.rs](src/idempotency/mod.rs)
- Detect prior provisioning via GPT names and labels; return success-without-changes.
- [src/util/mod.rs](src/util/mod.rs)
- Shell-out, udev settle, and helpers.
Public API surface (signatures; implementation to follow after approval)
Entrypoint and orchestrator
- [fn main()](src/main.rs:1)
- [struct Context](src/orchestrator/run.rs:1)
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1)
CLI
- [struct Cli](src/cli/args.rs:1)
- [fn from_args() -> Cli](src/cli/args.rs:1)
Logging
- [struct LogOptions](src/logging/mod.rs:1)
- [fn init_logging(opts: &LogOptions) -> Result<()>](src/logging/mod.rs:1)
Config
- [struct Config](src/types.rs:1)
- [enum Topology](src/types.rs:1)
- [struct DeviceSelection](src/types.rs:1)
- [struct FsOptions](src/types.rs:1)
- [struct MountScheme](src/types.rs:1)
- [fn load_and_merge(cli: &Cli) -> Result<Config>](src/config/loader.rs:1)
- [fn validate(cfg: &Config) -> Result<()>](src/config/loader.rs:1)
Device discovery
- [struct Disk](src/device/discovery.rs:1)
- [struct DeviceFilter](src/device/discovery.rs:1)
- [trait DeviceProvider](src/device/discovery.rs:1)
- [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](src/device/discovery.rs:1)
Partitioning
- [struct PartitionSpec](src/partition/plan.rs:1)
- [struct PartitionPlan](src/partition/plan.rs:1)
- [struct PartitionResult](src/partition/plan.rs:1)
- [fn plan_partitions(disks: &[Disk], cfg: &Config) -> Result<PartitionPlan>](src/partition/plan.rs:1)
- [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](src/partition/plan.rs:1)
Filesystems
- [enum FsKind](src/fs/plan.rs:1)
- [struct FsSpec](src/fs/plan.rs:1)
- [struct FsPlan](src/fs/plan.rs:1)
- [struct FsResult](src/fs/plan.rs:1)
- [fn plan_filesystems(disks: &[Disk], parts: &[PartitionResult], cfg: &Config) -> Result<FsPlan>](src/fs/plan.rs:1)
- [fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>>](src/fs/plan.rs:1)
Mounting
- [struct MountPlan](src/mount/ops.rs:1)
- [struct MountResult](src/mount/ops.rs:1)
- [fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan>](src/mount/ops.rs:1)
- [fn apply_mounts(plan: &MountPlan) -> Result<Vec<MountResult>>](src/mount/ops.rs:1)
- [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()>](src/mount/ops.rs:1)
Reporting
- [const REPORT_VERSION: &str](src/report/state.rs:1)
- [struct StateReport](src/report/state.rs:1)
- [fn build_report(...) -> StateReport](src/report/state.rs:1)
- [fn write_report(report: &StateReport) -> Result<()>](src/report/state.rs:1)
Idempotency
- [fn detect_existing_state() -> Result<Option<StateReport>>](src/idempotency/mod.rs:1)
- [fn is_empty_disk(disk: &Disk) -> Result<bool>](src/idempotency/mod.rs:1)
Errors and Result
- [enum Error](src/errors.rs:1)
- [type Result<T> = std::result::Result<T, Error>](src/errors.rs:1)
Execution flow
```mermaid
flowchart TD
A[Start] --> B[Initialize logging]
B --> C[Parse CLI and kernel cmdline]
C --> D[Load and validate config]
D --> E[Idempotency detection]
E -->|already provisioned| Z[Exit success]
E -->|not provisioned| F[Discover devices]
F --> G[Plan partitions]
G --> H[Apply partitions]
H --> I[Plan filesystems]
I --> J[Create filesystems]
J --> K[Plan mounts]
K --> L[Apply mounts]
L --> M[Write state report]
M --> N[Finalize]
N --> Z[Exit success]
```
Configuration precedence
- Kernel cmdline key zosstorage.config= overrides CLI and file
- CLI flags override config file
- Config file provides defaults at /etc/zosstorage/config.yaml
- No interactive prompts in initramfs
Device discovery and filtering
- Include device classes by default: /dev/sd*, /dev/nvme*, /dev/vd*
- Exclude pseudodevices: /dev/ram*, /dev/zram*, /dev/fd*, /dev/loop*, etc.
- Allow future allowlists and removable media policies via configuration
- If no eligible disks are found, return a well-defined error
Partitioning plan
- GPT exclusively with 1 MiB alignment
- bios boot partition first, 1 MiB
- ESP 512 MiB FAT32, label ZOSBOOT, GPT name zosboot
- Data partition consumes remainder, GPT name zosdata
- When cache is requested, create GPT name zoscache partitions as needed
- Abort if any pre-existing partitions or filesystem signatures are detected
- Ensure unique partition UUIDs and identical labels where required
Filesystem provisioning defaults
- Single disk: btrfs labeled ZOSDATA
- Two disks: btrfs per disk labeled ZOSDATA, no RAID by default
- SSD plus HDD: bcachefs with SSD as cache or promote and HDD as backing, filesystem label ZOSDATA
- Filesystem tuning options configurable with sensible defaults and extension points
Mount scheme and fstab policy
- Mount under /var/cache/<UUID> using filesystem UUID to create stable subdirectories
- Optional /etc/fstab generation disabled by default; when enabled, produce deterministic order with documentation
Idempotency detection
- Consider the system provisioned when expected GPT names and filesystem labels are present and consistent
- On a provisioned system, exit success without making any changes
Reporting
- Emit machine-readable JSON state report at /run/zosstorage/state.json
- Report includes enumerated disks and roles, created partitions with identifiers, filesystems with labels and mountpoints, overall status and timestamp
- Version the report payload via REPORT_VERSION
Logging
- Use tracing with levels error, warn, info, debug
- Default to stderr; optionally log to file at /run/zosstorage/zosstorage.log
- Avoid println and stdout spam
External tooling policy
- Invoke system utilities via wrappers that check for tool availability, capture stderr, and emit structured logs
- Provide udev settle helper; avoid reliance on long-running services
Planned dependencies to add via cargo add
- clap
- serde, serde_yaml, serde_json
- thiserror
- anyhow or eyre
- tracing, tracing-subscriber
- nix
- regex
- uuid
- which
- time
- tempfile
Open items and assumptions to track
- Exact BIOS boot size and placement pending confirmation; currently 1 MiB first
- Final mount naming scheme under /var/cache may evolve
- Filesystem tuning defaults for btrfs and bcachefs require stakeholder input
- Paths for config, report, and log file may be adjusted later
- fstab generation remains disabled by default pending decision
Next steps after approval
- Formalize configuration schema and validation rules in [docs/SCHEMA.md](docs/SCHEMA.md)
- Define detailed doc comments for all listed types and functions
- Prepare code-mode implementation skeletons with todo placeholders and add dependencies via cargo add