docs: sync with code (topologies, mount scheme, CLI flags, UEFI/BIOS, fstab) and fix relative src links in docs/ to ../src/

This commit is contained in:
2025-09-29 23:24:25 +02:00
parent 7cef73368b
commit b0d8c0bc75
9 changed files with 451 additions and 373 deletions

View File

@@ -24,7 +24,7 @@ Device Discovery
Partitioning Requirements Partitioning Requirements
- Use GPT exclusively. Honor 1MiB alignment boundaries. - Use GPT exclusively. Honor 1MiB alignment boundaries.
- For BIOS compatibility, create a small `bios_boot` partition (exact size TBD—assume 1MiB for now, placed first). - For BIOS compatibility on BIOS systems, create a small `bios_boot` partition (size 1MiB, placed first). When running under UEFI (`/sys/firmware/efi` present), the BIOS boot partition is suppressed.
- Create a 512MiB FAT32 ESP on each disk, label `ZOSBOOT`. Each ESP is independent; synchronization will be handled by another tool (out of scope). Ensure unique partition UUIDs while keeping identical labels. - Create a 512MiB FAT32 ESP on each disk, label `ZOSBOOT`. Each ESP is independent; synchronization will be handled by another tool (out of scope). Ensure unique partition UUIDs while keeping identical labels.
- Remaining disk capacity is provisioned per configuration (see below). - Remaining disk capacity is provisioned per configuration (see below).
- Before making changes, verify the device has no existing partitions or filesystem signatures; abort otherwise. - Before making changes, verify the device has no existing partitions or filesystem signatures; abort otherwise.
@@ -51,11 +51,11 @@ Filesystem Provisioning
Configuration Input Configuration Input
- Accept configuration via: - Accept configuration via:
* Kernel command line parameter (name TBD, e.g., `zosstorage.config=`) pointing to a YAML configuration descriptor. * Kernel command line parameter `zosstorage.config=` pointing to a YAML configuration descriptor.
* Optional CLI flags when run in user space (must mirror kernel cmdline semantics). * Optional CLI flags when run in user space (mirror kernel cmdline semantics).
* On-disk YAML config file (default path TBD, e.g., `/etc/zosstorage/config.yaml`). * On-disk YAML config file (default path `/etc/zosstorage/config.yaml`).
- Establish clear precedence: kernel cmdline overrides CLI arguments, which override config file defaults. No interactive prompts inside initramfs. - Precedence: kernel cmdline overrides CLI arguments, which override config file, which override built-in defaults. No interactive prompts inside initramfs.
- YAML schema must at least describe disk selection rules, desired filesystem layout, boot partition preferences, filesystem options, mount targets, and logging verbosity. Document the schema and provide validation. - YAML schema must describe disk selection rules, desired filesystem layout, boot partition preferences, filesystem options, mount targets, and logging verbosity. See [docs/SCHEMA.md](docs/SCHEMA.md) and [src/types.rs](src/types.rs:1).
State Reporting State Reporting
- After successful provisioning, emit a JSON state report (path TBD, e.g., `/run/zosstorage/state.json`) capturing: - After successful provisioning, emit a JSON state report (path TBD, e.g., `/run/zosstorage/state.json`) capturing:
@@ -70,7 +70,7 @@ Logging
- By default, logs go to stderr; design for optional redirection to a file (path TBD). Avoid using `println!`. - By default, logs go to stderr; design for optional redirection to a file (path TBD). Avoid using `println!`.
System Integration System Integration
- Decide whether to generate `/etc/fstab` entries; if enabled, produce deterministic ordering and documentation. Otherwise, document alternative mount management. - `/etc/fstab` generation: optional via CLI/config. When enabled, write only the four final subvolume/subdir mount entries (system, etc, modules, vm-meta) with `UUID=` sources in deterministic order. Root mounts under `/var/mounts/{UUID}` are runtime-only and excluded from fstab.
- After provisioning, ensure the initramfs can mount the new filesystems (e.g., call `udevadm settle` if necessary). No external services are invoked. - After provisioning, ensure the initramfs can mount the new filesystems (e.g., call `udevadm settle` if necessary). No external services are invoked.
- No responsibility for updating `vmlinuz.efi`; another subsystem handles kernel updates. - No responsibility for updating `vmlinuz.efi`; another subsystem handles kernel updates.
@@ -95,11 +95,17 @@ Documentation & Deliverables
- Include architectural notes describing module boundaries (device discovery, partitioning, filesystem provisioning, config parsing, logging, reporting). - Include architectural notes describing module boundaries (device discovery, partitioning, filesystem provisioning, config parsing, logging, reporting).
Open Items (call out explicitly) Open Items (call out explicitly)
- Exact sizes and ordering for `bios_boot` partition awaiting confirmation; note assumptions in code and documentation. - BIOS vs UEFI: `bios_boot` partition size fixed at 1MiB and created only on BIOS systems; suppressed under UEFI (`/sys/firmware/efi` present).
- Mount point naming scheme under `/var/cache` (per-UUID vs. config-defined) still to be finalized. - Mount scheme finalized:
- Filesystem-specific tuning parameters (compression, RAID values, `bcachefs` options) require explicit defaults from stakeholders. - Root mounts for each data filesystem at `/var/mounts/{UUID}` (runtime only).
- Path/location for YAML config, kernel cmdline key, JSON report path, and optional log file path need final confirmation. - Final subvolume/subdir mounts from the primary data filesystem to `/var/cache/{system,etc,modules,vm-meta}`.
- Decision whether `/etc/fstab` is generated remains pending. - Filesystem-specific tuning parameters (compression, RAID values, `bcachefs` options) remain open for refinement; sensible defaults applied.
- Config paths and keys stabilized:
- Kernel cmdline key: `zosstorage.config=`
- Default config file: `/etc/zosstorage/config.yaml`
- Default report path: `/run/zosstorage/state.json`
- Optional log file: `/run/zosstorage/zosstorage.log`
- `/etc/fstab` generation policy decided: optional flag; writes only the four final subvolume/subdir entries.
Implementation Constraints Implementation Constraints
- Stick to clear module boundaries. Provide unit tests where possible (e.g., config parsing, device filtering). - Stick to clear module boundaries. Provide unit tests where possible (e.g., config parsing, device filtering).

View File

@@ -2,7 +2,7 @@
One-shot disk provisioning utility intended for initramfs. It discovers eligible disks, plans a GPT layout based on a chosen topology, creates filesystems, mounts them under a predictable scheme, and emits a machine-readable report. Safe-by-default with a non-destructive preview mode. One-shot disk provisioning utility intended for initramfs. It discovers eligible disks, plans a GPT layout based on a chosen topology, creates filesystems, mounts them under a predictable scheme, and emits a machine-readable report. Safe-by-default with a non-destructive preview mode.
Status: first-draft preview capable. Partition apply, mkfs, and mounts are gated until the planning is validated in your environment. Status: apply mode implemented. Partition application (sgdisk), filesystem creation (vfat/btrfs/bcachefs), mount scheme with subvolumes, and optional fstab writing are available. Preview mode remains supported.
Key modules Key modules
- CLI and entrypoint: - CLI and entrypoint:
@@ -33,8 +33,9 @@ Requirements
- Linux with /proc and /sys mounted (initramfs friendly) - Linux with /proc and /sys mounted (initramfs friendly)
- External tools discovered at runtime: - External tools discovered at runtime:
- blkid (for probing UUIDs and signatures) - blkid (for probing UUIDs and signatures)
- sgdisk (for GPT application) — planned - sgdisk (for GPT application)
- mkfs.vfat, mkfs.btrfs, bcachefs (for formatting) — invoked by fs/plan when enabled in execution phase - mkfs.vfat, mkfs.btrfs, bcachefs (for formatting)
- udevadm (optional; for settle after partitioning)
- Tracing/logging to stderr by default; optional file at /run/zosstorage/zosstorage.log - Tracing/logging to stderr by default; optional file at /run/zosstorage/zosstorage.log
Install and build Install and build
@@ -57,6 +58,7 @@ CLI usage
- Other: - Other:
-c, --config PATH Merge a YAML config file (overrides defaults) -c, --config PATH Merge a YAML config file (overrides defaults)
-s, --fstab Enable writing /etc/fstab entries (when mounts are applied) -s, --fstab Enable writing /etc/fstab entries (when mounts are applied)
-a, --apply Perform partitioning, filesystem creation, and mounts (destructive)
-f, --force Present but not implemented (returns an error) -f, --force Present but not implemented (returns an error)
Examples Examples
@@ -68,6 +70,8 @@ Examples
sudo ./zosstorage --show -t ssd-hdd-bcachefs --allow-removable -l debug sudo ./zosstorage --show -t ssd-hdd-bcachefs --allow-removable -l debug
- Quiet plan to file: - Quiet plan to file:
sudo ./zosstorage --report /run/zosstorage/plan.json -t dual-independent sudo ./zosstorage --report /run/zosstorage/plan.json -t dual-independent
- Apply single-disk btrfs (DESTRUCTIVE; wipes target disk):
sudo ./zosstorage --apply -t btrfs-single
Preview JSON shape (examples) Preview JSON shape (examples)
1) Already provisioned (idempotency success): 1) Already provisioned (idempotency success):
@@ -107,14 +111,15 @@ Preview JSON shape (examples)
} }
], ],
"filesystems_planned": [ "filesystems_planned": [
{ "kind": "vfat", "from_roles": ["esp"], "label": "ZOSBOOT", "planned_mountpoint": null }, { "kind": "vfat", "from_roles": ["esp"], "label": "ZOSBOOT" },
{ "kind": "btrfs", "from_roles": ["data"], "devices_planned": 2, "label": "ZOSDATA", "planned_mountpoint_template": "/var/cache/{UUID}" } { "kind": "btrfs", "from_roles": ["data"], "devices_planned": 2, "label": "ZOSDATA" }
], ],
"mount": { "mount": {
"scheme": "per_uuid", "scheme": "per_uuid",
"base_dir": "/var/cache", "base_dir": "/var/cache",
"fstab_enabled": false, "fstab_enabled": false,
"target_template": "/var/cache/{UUID}" "root_mount_template": "/var/mounts/{UUID}",
"final_targets": ["/var/cache/system", "/var/cache/etc", "/var/cache/modules", "/var/cache/vm-meta"]
} }
} }

View File

@@ -6,34 +6,34 @@ Purpose
- After approval, these will be created in the src tree in Code mode. - After approval, these will be created in the src tree in Code mode.
Index Index
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- [src/errors.rs](src/errors.rs) - [src/errors.rs](../src/errors.rs)
- [src/main.rs](src/main.rs) - [src/main.rs](../src/main.rs)
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- [src/logging/mod.rs](src/logging/mod.rs) - [src/logging/mod.rs](../src/logging/mod.rs)
- [src/types.rs](src/types.rs) - [src/types.rs](../src/types.rs)
- [src/config/loader.rs](src/config/loader.rs) - [src/config/loader.rs](../src/config/loader.rs)
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [src/idempotency/mod.rs](src/idempotency/mod.rs) - [src/idempotency/mod.rs](../src/idempotency/mod.rs)
- [src/util/mod.rs](src/util/mod.rs) - [src/util/mod.rs](../src/util/mod.rs)
Conventions Conventions
- Shared [type Result<T>](src/errors.rs:1) and [enum Error](src/errors.rs:1). - Shared [type Result<T>](../src/errors.rs:1) and [enum Error](../src/errors.rs:1).
- No stdout prints; use tracing only. - No stdout prints; use tracing only.
- External tools invoked via [util](src/util/mod.rs) wrappers. - External tools invoked via [util](../src/util/mod.rs) wrappers.
--- ---
## Crate root ## Crate root
References References
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- [type Result<T> = std::result::Result<T, Error>](src/errors.rs:1) - [type Result<T> = std::result::Result<T, Error>](../src/errors.rs:1)
Skeleton (for later implementation in code mode) Skeleton (for later implementation in code mode)
```rust ```rust
@@ -63,8 +63,8 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
## Errors ## Errors
References References
- [enum Error](src/errors.rs:1) - [enum Error](../src/errors.rs:1)
- [type Result<T>](src/errors.rs:1) - [type Result<T>](../src/errors.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -107,8 +107,8 @@ pub type Result<T> = std::result::Result<T, Error>;
## Entrypoint ## Entrypoint
References References
- [fn main()](src/main.rs:1) - [fn main()](../src/main.rs:1)
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1) - [fn run(ctx: &Context) -> Result<()>](../src/orchestrator/run.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -143,8 +143,8 @@ fn real_main() -> Result<()> {
## CLI ## CLI
References References
- [struct Cli](src/cli/args.rs:1) - [struct Cli](../src/cli/args.rs:1)
- [fn from_args() -> Cli](src/cli/args.rs:1) - [fn from_args() -> Cli](../src/cli/args.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -170,6 +170,18 @@ pub struct Cli {
#[arg(long = "fstab", default_value_t = false)] #[arg(long = "fstab", default_value_t = false)]
pub fstab: bool, pub fstab: bool,
/// Print preview JSON to stdout (non-destructive)
#[arg(long = "show", default_value_t = false)]
pub show: bool,
/// Write preview JSON to a file (non-destructive)
#[arg(long = "report")]
pub report: Option<String>,
/// Perform partitioning, filesystem creation, and mounts (DESTRUCTIVE)
#[arg(long = "apply", default_value_t = false)]
pub apply: bool,
/// Present but non-functional; returns unimplemented error /// Present but non-functional; returns unimplemented error
#[arg(long = "force")] #[arg(long = "force")]
pub force: bool, pub force: bool,
@@ -186,8 +198,8 @@ pub fn from_args() -> Cli {
## Logging ## Logging
References References
- [struct LogOptions](src/logging/mod.rs:1) - [struct LogOptions](../src/logging/mod.rs:1)
- [fn init_logging(opts: &LogOptions) -> Result<()>](src/logging/mod.rs:1) - [fn init_logging(opts: &LogOptions) -> Result<()>](../src/logging/mod.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -218,13 +230,13 @@ pub fn init_logging(opts: &LogOptions) -> Result<()> {
## Configuration types ## Configuration types
References References
- [struct Config](src/types.rs:1) - [struct Config](../src/types.rs:1)
- [enum Topology](src/types.rs:1) - [enum Topology](../src/types.rs:1)
- [struct DeviceSelection](src/types.rs:1) - [struct DeviceSelection](../src/types.rs:1)
- [struct Partitioning](src/types.rs:1) - [struct Partitioning](../src/types.rs:1)
- [struct FsOptions](src/types.rs:1) - [struct FsOptions](../src/types.rs:1)
- [struct MountScheme](src/types.rs:1) - [struct MountScheme](../src/types.rs:1)
- [struct ReportOptions](src/types.rs:1) - [struct ReportOptions](../src/types.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -247,8 +259,10 @@ pub struct DeviceSelection {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum Topology { pub enum Topology {
Single, BtrfsSingle,
BcachefsSingle,
DualIndependent, DualIndependent,
Bcachefs2Copy,
SsdHddBcachefs, SsdHddBcachefs,
BtrfsRaid1, BtrfsRaid1,
} }
@@ -351,8 +365,8 @@ pub struct Config {
## Configuration I/O ## Configuration I/O
References References
- [fn load_and_merge(cli: &Cli) -> Result<Config>](src/config/loader.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) - [fn validate(cfg: &Config) -> Result<()>](../src/config/loader.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -374,10 +388,10 @@ pub fn validate(cfg: &crate::config::types::Config) -> Result<()> {
## Device discovery ## Device discovery
References References
- [struct Disk](src/device/discovery.rs:1) - [struct Disk](../src/device/discovery.rs:1)
- [struct DeviceFilter](src/device/discovery.rs:1) - [struct DeviceFilter](../src/device/discovery.rs:1)
- [trait DeviceProvider](src/device/discovery.rs:1) - [trait DeviceProvider](../src/device/discovery.rs:1)
- [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](src/device/discovery.rs:1) - [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](../src/device/discovery.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -418,12 +432,12 @@ pub fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>> {
## Partitioning ## Partitioning
References References
- [enum PartRole](src/partition/plan.rs:1) - [enum PartRole](../src/partition/plan.rs:1)
- [struct PartitionSpec](src/partition/plan.rs:1) - [struct PartitionSpec](../src/partition/plan.rs:1)
- [struct PartitionPlan](src/partition/plan.rs:1) - [struct PartitionPlan](../src/partition/plan.rs:1)
- [struct PartitionResult](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 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) - [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](../src/partition/plan.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -485,12 +499,12 @@ pub fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>> {
## Filesystems ## Filesystems
References References
- [enum FsKind](src/fs/plan.rs:1) - [enum FsKind](../src/fs/plan.rs:1)
- [struct FsSpec](src/fs/plan.rs:1) - [struct FsSpec](../src/fs/plan.rs:1)
- [struct FsPlan](src/fs/plan.rs:1) - [struct FsPlan](../src/fs/plan.rs:1)
- [struct FsResult](src/fs/plan.rs:1) - [struct FsResult](../src/fs/plan.rs:1)
- [fn plan_filesystems(...)](src/fs/plan.rs:1) - [fn plan_filesystems(...)](../src/fs/plan.rs:1)
- [fn make_filesystems(...)](src/fs/plan.rs:1) - [fn make_filesystems(...)](../src/fs/plan.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -531,8 +545,8 @@ pub fn plan_filesystems(
todo!("map ESP to vfat, data to btrfs or bcachefs according to topology") todo!("map ESP to vfat, data to btrfs or bcachefs according to topology")
} }
/// Create the filesystems and return identity info (UUIDs, labels). //// Create the filesystems and return identity info (UUIDs, labels).
pub fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>> { pub fn make_filesystems(plan: &FsPlan, cfg: &Config) -> Result<Vec<FsResult>> {
todo!("invoke mkfs tools with configured options via util::run_cmd") todo!("invoke mkfs tools with configured options via util::run_cmd")
} }
``` ```
@@ -542,11 +556,11 @@ pub fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>> {
## Mounting ## Mounting
References References
- [struct MountPlan](src/mount/ops.rs:1) - [struct MountPlan](../src/mount/ops.rs:1)
- [struct MountResult](src/mount/ops.rs:1) - [struct MountResult](../src/mount/ops.rs:1)
- [fn plan_mounts(...)](src/mount/ops.rs:1) - [fn plan_mounts(...)](../src/mount/ops.rs:1)
- [fn apply_mounts(...)](src/mount/ops.rs:1) - [fn apply_mounts(...)](../src/mount/ops.rs:1)
- [fn maybe_write_fstab(...)](src/mount/ops.rs:1) - [fn maybe_write_fstab(...)](../src/mount/ops.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -565,9 +579,13 @@ pub struct MountResult {
pub options: String, pub options: String,
} }
/// Build mount plan under /var/cache/<UUID> by default. //// Build mount plan:
//// - Root-mount all data filesystems under `/var/mounts/{UUID}` (runtime only)
//// - Ensure/create subvolumes on the primary data filesystem: system, etc, modules, vm-meta
//// - Plan final mounts to `/var/cache/{system,etc,modules,vm-meta}` using
//// `subvol=` for btrfs and `X-mount.subdir=` for bcachefs.
pub fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan> { pub fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan> {
todo!("create per-UUID directories and mount mapping") todo!("root mounts under /var/mounts/{UUID}; final subvol/subdir mounts to /var/cache/{system,etc,modules,vm-meta}")
} }
/// Apply mounts using syscalls (nix), ensuring directories exist. /// Apply mounts using syscalls (nix), ensuring directories exist.
@@ -575,9 +593,12 @@ pub fn apply_mounts(plan: &MountPlan) -> Result<Vec<MountResult>> {
todo!("perform mount syscalls and return results") todo!("perform mount syscalls and return results")
} }
/// Optionally generate /etc/fstab entries in deterministic order. //// Optionally generate /etc/fstab entries for final subvolume/subdir mounts only.
//// - Write exactly four entries: system, etc, modules, vm-meta
//// - Use UUID= sources; deterministic order by target path
//// - Exclude runtime root mounts under `/var/mounts/{UUID}`
pub fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()> { pub fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()> {
todo!("when enabled, write fstab entries") todo!("when enabled, write only the four final subvolume/subdir entries with UUID= sources")
} }
``` ```
@@ -586,10 +607,10 @@ pub fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()> {
## Reporting ## Reporting
References References
- [const REPORT_VERSION: &str](src/report/state.rs:1) - [const REPORT_VERSION: &str](../src/report/state.rs:1)
- [struct StateReport](src/report/state.rs:1) - [struct StateReport](../src/report/state.rs:1)
- [fn build_report(...)](src/report/state.rs:1) - [fn build_report(...)](../src/report/state.rs:1)
- [fn write_report(...)](src/report/state.rs:1) - [fn write_report(...)](../src/report/state.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -632,8 +653,8 @@ pub fn write_report(report: &StateReport, path: &str) -> Result<()> {
## Orchestrator ## Orchestrator
References References
- [struct Context](src/orchestrator/run.rs:1) - [struct Context](../src/orchestrator/run.rs:1)
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1) - [fn run(ctx: &Context) -> Result<()>](../src/orchestrator/run.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -662,8 +683,8 @@ pub fn run(ctx: &Context) -> Result<()> {
## Idempotency ## Idempotency
References References
- [fn detect_existing_state() -> Result<Option<StateReport>>](src/idempotency/mod.rs:1) - [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) - [fn is_empty_disk(disk: &Disk) -> Result<bool>](../src/idempotency/mod.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -685,11 +706,11 @@ pub fn is_empty_disk(disk: &Disk) -> Result<bool> {
## Utilities ## Utilities
References References
- [struct CmdOutput](src/util/mod.rs:1) - [struct CmdOutput](../src/util/mod.rs:1)
- [fn which_tool(name: &str) -> Result<Option<String>>](src/util/mod.rs:1) - [fn which_tool(name: &str) -> Result<Option<String>>](../src/util/mod.rs:1)
- [fn run_cmd(args: &[&str]) -> Result<()>](src/util/mod.rs:1) - [fn run_cmd(args: &[&str]) -> Result<()>](../src/util/mod.rs:1)
- [fn run_cmd_capture(args: &[&str]) -> Result<CmdOutput>](src/util/mod.rs:1) - [fn run_cmd_capture(args: &[&str]) -> Result<CmdOutput>](../src/util/mod.rs:1)
- [fn udev_settle(timeout_ms: u64) -> Result<()>](src/util/mod.rs:1) - [fn udev_settle(timeout_ms: u64) -> Result<()>](../src/util/mod.rs:1)
Skeleton Skeleton
```rust ```rust
@@ -722,6 +743,11 @@ pub fn run_cmd_capture(args: &[&str]) -> Result<CmdOutput> {
pub fn udev_settle(timeout_ms: u64) -> Result<()> { pub fn udev_settle(timeout_ms: u64) -> Result<()> {
todo!("invoke udevadm settle when present") todo!("invoke udevadm settle when present")
} }
/// Detect UEFI environment by checking /sys/firmware/efi; used to suppress BIOS boot partition on UEFI.
pub fn is_efi_boot() -> bool {
todo!("return Path::new(\"/sys/firmware/efi\").exists()")
}
``` ```
--- ---
@@ -735,24 +761,24 @@ Approval gate
- Add initial tests scaffolding and example configs. - Add initial tests scaffolding and example configs.
References summary References summary
- [fn main()](src/main.rs:1) - [fn main()](../src/main.rs:1)
- [fn from_args()](src/cli/args.rs:1) - [fn from_args()](../src/cli/args.rs:1)
- [fn init_logging(opts: &LogOptions)](src/logging/mod.rs:1) - [fn init_logging(opts: &LogOptions)](../src/logging/mod.rs:1)
- [fn load_and_merge(cli: &Cli)](src/config/loader.rs:1) - [fn load_and_merge(cli: &Cli)](../src/config/loader.rs:1)
- [fn validate(cfg: &Config)](src/config/loader.rs:1) - [fn validate(cfg: &Config)](../src/config/loader.rs:1)
- [fn discover(filter: &DeviceFilter)](src/device/discovery.rs:1) - [fn discover(filter: &DeviceFilter)](../src/device/discovery.rs:1)
- [fn plan_partitions(disks: &[Disk], cfg: &Config)](src/partition/plan.rs:1) - [fn plan_partitions(disks: &[Disk], cfg: &Config)](../src/partition/plan.rs:1)
- [fn apply_partitions(plan: &PartitionPlan)](src/partition/plan.rs:1) - [fn apply_partitions(plan: &PartitionPlan)](../src/partition/plan.rs:1)
- [fn plan_filesystems(parts: &[PartitionResult], cfg: &Config)](src/fs/plan.rs:1) - [fn plan_filesystems(parts: &[PartitionResult], cfg: &Config)](../src/fs/plan.rs:1)
- [fn make_filesystems(plan: &FsPlan)](src/fs/plan.rs:1) - [fn make_filesystems(plan: &FsPlan)](../src/fs/plan.rs:1)
- [fn plan_mounts(fs_results: &[FsResult], cfg: &Config)](src/mount/ops.rs:1) - [fn plan_mounts(fs_results: &[FsResult], cfg: &Config)](../src/mount/ops.rs:1)
- [fn apply_mounts(plan: &MountPlan)](src/mount/ops.rs:1) - [fn apply_mounts(plan: &MountPlan)](../src/mount/ops.rs:1)
- [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config)](src/mount/ops.rs:1) - [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config)](../src/mount/ops.rs:1)
- [fn build_report(...)](src/report/state.rs:1) - [fn build_report(...)](../src/report/state.rs:1)
- [fn write_report(report: &StateReport)](src/report/state.rs:1) - [fn write_report(report: &StateReport)](../src/report/state.rs:1)
- [fn detect_existing_state()](src/idempotency/mod.rs:1) - [fn detect_existing_state()](../src/idempotency/mod.rs:1)
- [fn is_empty_disk(disk: &Disk)](src/idempotency/mod.rs:1) - [fn is_empty_disk(disk: &Disk)](../src/idempotency/mod.rs:1)
- [fn which_tool(name: &str)](src/util/mod.rs:1) - [fn which_tool(name: &str)](../src/util/mod.rs:1)
- [fn run_cmd(args: &[&str])](src/util/mod.rs:1) - [fn run_cmd(args: &[&str])](../src/util/mod.rs:1)
- [fn run_cmd_capture(args: &[&str])](src/util/mod.rs:1) - [fn run_cmd_capture(args: &[&str])](../src/util/mod.rs:1)
- [fn udev_settle(timeout_ms: u64)](src/util/mod.rs:1) - [fn udev_settle(timeout_ms: u64)](../src/util/mod.rs:1)

View File

@@ -8,40 +8,40 @@ Conventions
- External tooling calls are mediated via utility wrappers. - External tooling calls are mediated via utility wrappers.
Module index Module index
- [src/main.rs](src/main.rs) - [src/main.rs](../src/main.rs)
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- [src/errors.rs](src/errors.rs) - [src/errors.rs](../src/errors.rs)
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- [src/logging/mod.rs](src/logging/mod.rs) - [src/logging/mod.rs](../src/logging/mod.rs)
- [src/types.rs](src/types.rs) - [src/types.rs](../src/types.rs)
- [src/config/loader.rs](src/config/loader.rs) - [src/config/loader.rs](../src/config/loader.rs)
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [src/idempotency/mod.rs](src/idempotency/mod.rs) - [src/idempotency/mod.rs](../src/idempotency/mod.rs)
- [src/util/mod.rs](src/util/mod.rs) - [src/util/mod.rs](../src/util/mod.rs)
Common errors and result Common errors and result
- [enum Error](src/errors.rs:1) - [enum Error](../src/errors.rs:1)
- Top-level error type covering parse/validation errors, device discovery errors, partitioning failures, filesystem mkfs errors, mount errors, report write errors, and external tool invocation failures with stderr capture. - Top-level error type covering parse/validation errors, device discovery errors, partitioning failures, filesystem mkfs errors, mount errors, report write errors, and external tool invocation failures with stderr capture.
- [type Result<T> = std::result::Result<T, Error>](src/errors.rs:1) - [type Result<T> = std::result::Result<T, Error>](../src/errors.rs:1)
- Shared result alias across modules. - Shared result alias across modules.
Crate root Crate root
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- Exposes crate version constants, the prelude, and re-exports common types for consumers of the library (tests/integration). No heavy logic. - Exposes crate version constants, the prelude, and re-exports common types for consumers of the library (tests/integration). No heavy logic.
Entrypoint Entrypoint
- [fn main()](src/main.rs:1) - [fn main()](../src/main.rs:1)
- Initializes logging based on CLI defaults, parses CLI flags and kernel cmdline, loads and validates configuration, and invokes the orchestrator run sequence. Avoids stdout; logs via tracing only. - Initializes logging based on CLI defaults, parses CLI flags and kernel cmdline, loads and validates configuration, and invokes the orchestrator run sequence. Avoids stdout; logs via tracing only.
Orchestrator Orchestrator
- [struct Context](src/orchestrator/run.rs:1) - [struct Context](../src/orchestrator/run.rs:1)
- Aggregates resolved configuration, logging options, and environment flags suited for initramfs execution. - Aggregates resolved configuration, logging options, and environment flags suited for initramfs execution.
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1) - [fn run(ctx: &Context) -> Result<()>](../src/orchestrator/run.rs:1)
- High-level one-shot flow: - High-level one-shot flow:
- Idempotency detection - Idempotency detection
- Device discovery - Device discovery
@@ -52,131 +52,141 @@ Orchestrator
- Aborts the entire run on any validation or execution failure. Returns Ok on successful no-op if already provisioned. - Aborts the entire run on any validation or execution failure. Returns Ok on successful no-op if already provisioned.
CLI CLI
- [struct Cli](src/cli/args.rs:1) - [struct Cli](../src/cli/args.rs:1)
- Mirrors kernel cmdline semantics with flags: - Mirrors kernel cmdline semantics with flags:
- --config PATH - --config PATH
- --log-level LEVEL - --log-level LEVEL
- --log-to-file - --log-to-file
- --fstab - --fstab
- --show
- --report PATH
- --apply
- --force (present, returns unimplemented error) - --force (present, returns unimplemented error)
- [fn from_args() -> Cli](src/cli/args.rs:1) - [fn from_args() -> Cli](../src/cli/args.rs:1)
- Parses argv without side effects; suitable for initramfs. - Parses argv without side effects; suitable for initramfs.
Logging Logging
- [struct LogOptions](src/logging/mod.rs:1) - [struct LogOptions](../src/logging/mod.rs:1)
- Holds level and optional file target (/run/zosstorage/zosstorage.log). - Holds level and optional file target (/run/zosstorage/zosstorage.log).
- [fn init_logging(opts: &LogOptions) -> Result<()>](src/logging/mod.rs:1) - [fn init_logging(opts: &LogOptions) -> Result<()>](../src/logging/mod.rs:1)
- Configures tracing-subscriber for stderr by default and optional file layer when enabled. Must be idempotent. - Configures tracing-subscriber for stderr by default and optional file layer when enabled. Must be idempotent.
Configuration types Configuration types
- [struct Config](src/types.rs:1) - [struct Config](../src/types.rs:1)
- The validated configuration used by the orchestrator, containing logging, device selection rules, topology, partitioning, filesystem options, mount scheme, and report path. - The validated configuration used by the orchestrator, containing logging, device selection rules, topology, partitioning, filesystem options, mount scheme, and report path.
- [enum Topology](src/types.rs:1) - [enum Topology](../src/types.rs:1)
- Values: btrfs_single, bcachefs_single, dual_independent, bcachefs_2copy, ssd_hdd_bcachefs, btrfs_raid1 (opt-in). - Values: btrfs_single, bcachefs_single, dual_independent, bcachefs2_copy, ssd_hdd_bcachefs, btrfs_raid1 (opt-in).
- [struct DeviceSelection](src/types.rs:1) - [struct DeviceSelection](../src/types.rs:1)
- Include and exclude regex patterns, minimum size, removable policy. - Include and exclude regex patterns, minimum size, removable policy.
- [struct Partitioning](src/types.rs:1) - [struct Partitioning](../src/types.rs:1)
- Alignment, emptiness requirement, bios_boot, esp, data, cache GPT names and sizes where applicable. - Alignment, emptiness requirement, bios_boot, esp, data, cache GPT names and sizes where applicable.
- [struct BtrfsOptions](src/types.rs:1) - [struct BtrfsOptions](../src/types.rs:1)
- Compression string and raid profile (none or raid1). - Compression string and raid profile (none or raid1).
- [struct BcachefsOptions](src/types.rs:1) - [struct BcachefsOptions](../src/types.rs:1)
- Cache mode (promote or writeback), compression, checksum. - Cache mode (promote or writeback), compression, checksum.
- [struct VfatOptions](src/types.rs:1) - [struct VfatOptions](../src/types.rs:1)
- Reserved for ESP mkfs options; includes label ZOSBOOT. - Reserved for ESP mkfs options; includes label ZOSBOOT.
- [struct FsOptions](src/types.rs:1) - [struct FsOptions](../src/types.rs:1)
- Aggregates BtrfsOptions, BcachefsOptions, VfatOptions and shared defaults such as ZOSDATA label. - Aggregates BtrfsOptions, BcachefsOptions, VfatOptions and shared defaults such as ZOSDATA label.
- [enum MountSchemeKind](src/types.rs:1) - [enum MountSchemeKind](../src/types.rs:1)
- Values: per_uuid, custom (future). - Values: per_uuid, custom (future).
- [struct MountScheme](src/types.rs:1) - [struct MountScheme](../src/types.rs:1)
- Base directory (/var/cache), scheme kind, fstab enabled flag. - Base directory (/var/cache), scheme kind, fstab enabled flag.
- [struct ReportOptions](src/types.rs:1) - [struct ReportOptions](../src/types.rs:1)
- Output path (/run/zosstorage/state.json). - Output path (/run/zosstorage/state.json).
Configuration IO Configuration IO
- [fn load_and_merge(cli: &Cli) -> Result<Config>](src/config/loader.rs:1) - [fn load_and_merge(cli: &Cli) -> Result<Config>](../src/config/loader.rs:1)
- Loads built-in defaults, optionally merges on-disk config, overlays CLI flags, and finally overlays kernel cmdline via zosstorage.config=. Validates the YAML against types and constraints. - Loads built-in defaults, optionally merges on-disk config, overlays CLI flags, and finally overlays kernel cmdline via zosstorage.config=. Validates the YAML against types and constraints.
- [fn validate(cfg: &Config) -> Result<()>](src/config/loader.rs:1) - [fn validate(cfg: &Config) -> Result<()>](../src/config/loader.rs:1)
- Ensures structural and semantic validity (e.g., disk selection rules not empty, sizes non-zero, supported topology combinations). - Ensures structural and semantic validity (e.g., disk selection rules not empty, sizes non-zero, supported topology combinations).
Device discovery Device discovery
- [struct Disk](src/device/discovery.rs:1) - [struct Disk](../src/device/discovery.rs:1)
- Represents an eligible block device with path, size, rotational flag, and identifiers (serial, model if available). - Represents an eligible block device with path, size, rotational flag, and identifiers (serial, model if available).
- [struct DeviceFilter](src/device/discovery.rs:1) - [struct DeviceFilter](../src/device/discovery.rs:1)
- Derived from DeviceSelection; compiled regexes and size thresholds for efficient filtering. - Derived from DeviceSelection; compiled regexes and size thresholds for efficient filtering.
- [trait DeviceProvider](src/device/discovery.rs:1) - [trait DeviceProvider](../src/device/discovery.rs:1)
- Abstraction for listing /dev and probing properties, enabling test doubles. - Abstraction for listing /dev and probing properties, enabling test doubles.
- [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](src/device/discovery.rs:1) - [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](../src/device/discovery.rs:1)
- Returns eligible disks or a well-defined error if none are found. - Returns eligible disks or a well-defined error if none are found.
Partitioning Partitioning
- [enum PartRole](src/partition/plan.rs:1) - [enum PartRole](../src/partition/plan.rs:1)
- Roles: BiosBoot, Esp, Data, Cache. - Roles: BiosBoot, Esp, Data, Cache.
- [struct PartitionSpec](src/partition/plan.rs:1) - [struct PartitionSpec](../src/partition/plan.rs:1)
- Declarative spec for a single partition: role, optional size_mib, gpt_name (zosboot, zosdata, zoscache), and reserved filesystem label when role is Esp (ZOSBOOT). - Declarative spec for a single partition: role, optional size_mib, gpt_name (zosboot, zosdata, zoscache), and reserved filesystem label when role is Esp (ZOSBOOT).
- [struct DiskPlan](src/partition/plan.rs:1) - [struct DiskPlan](../src/partition/plan.rs:1)
- The planned set of PartitionSpec instances for a single Disk in the chosen topology. - The planned set of PartitionSpec instances for a single Disk in the chosen topology.
- [struct PartitionPlan](src/partition/plan.rs:1) - [struct PartitionPlan](../src/partition/plan.rs:1)
- Combined plan across all target disks, including alignment rules and safety checks. - Combined plan across all target disks, including alignment rules and safety checks.
- [struct PartitionResult](src/partition/plan.rs:1) - [struct PartitionResult](../src/partition/plan.rs:1)
- Result of applying a DiskPlan: device path of each created partition, role, partition GUID, and gpt_name. - Result of applying a DiskPlan: device path of each created partition, role, partition GUID, and gpt_name.
- [fn plan_partitions(disks: &[Disk], cfg: &Config) -> Result<PartitionPlan>](src/partition/plan.rs:1) - [fn plan_partitions(disks: &[Disk], cfg: &Config) -> Result<PartitionPlan>](../src/partition/plan.rs:1)
- Produces a GPT-only plan with 1 MiB alignment, bios boot first (1 MiB), ESP 512 MiB, data remainder, and zoscache on SSD for ssd_hdd_bcachefs. - Produces a GPT-only plan with 1 MiB alignment, bios boot first (1 MiB), ESP 512 MiB, data remainder, and zoscache on SSD for ssd_hdd_bcachefs.
- [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](src/partition/plan.rs:1) - [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](../src/partition/plan.rs:1)
- Executes the plan via sgdisk and related utilities. Aborts if target disks are not empty or if signatures are detected. - Executes the plan via sgdisk and related utilities. Aborts if target disks are not empty or if signatures are detected.
Filesystems Filesystems
- [enum FsKind](src/fs/plan.rs:1) - [enum FsKind](../src/fs/plan.rs:1)
- Values: Vfat, Btrfs, Bcachefs. - Values: Vfat, Btrfs, Bcachefs.
- [struct FsSpec](src/fs/plan.rs:1) - [struct FsSpec](../src/fs/plan.rs:1)
- Maps PartitionResult to desired filesystem kind and label (ZOSBOOT for ESP; ZOSDATA for all data filesystems including bcachefs). - Maps PartitionResult to desired filesystem kind and label (ZOSBOOT for ESP; ZOSDATA for all data filesystems including bcachefs).
- [struct FsPlan](src/fs/plan.rs:1) - [struct FsPlan](../src/fs/plan.rs:1)
- Plan of mkfs operations across all partitions and devices given the topology. - Plan of mkfs operations across all partitions and devices given the topology.
- [struct FsResult](src/fs/plan.rs:1) - [struct FsResult](../src/fs/plan.rs:1)
- Output of mkfs: device path(s), fs uuid, label, and kind. - Output of mkfs: device path(s), fs uuid, label, and kind.
- [fn plan_filesystems(disks: &[Disk], parts: &[PartitionResult], cfg: &Config) -> Result<FsPlan>](src/fs/plan.rs:1) - [fn plan_filesystems(disks: &[Disk], parts: &[PartitionResult], cfg: &Config) -> Result<FsPlan>](../src/fs/plan.rs:1)
- Determines which partitions receive vfat, btrfs, or bcachefs, and aggregates tuning options. - Determines which partitions receive vfat, btrfs, or bcachefs, and aggregates tuning options.
- [fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>>](src/fs/plan.rs:1) - [fn make_filesystems(plan: &FsPlan, cfg: &Config) -> Result<Vec<FsResult>>](../src/fs/plan.rs:1)
- Invokes mkfs.vfat, mkfs.btrfs, mkfs.bcachefs accordingly via utility wrappers and returns filesystem identities. - Invokes mkfs.vfat, mkfs.btrfs, mkfs.bcachefs accordingly via utility wrappers and returns filesystem identities.
Mounting Mounting
- [struct MountPlan](src/mount/ops.rs:1) - [struct MountPlan](../src/mount/ops.rs:1)
- Derived from FsResult entries: creates target directories under /var/cache/<UUID> and the mounts required for the current boot. - Derived from FsResult entries. Plans:
- [struct MountResult](src/mount/ops.rs:1) - Root mounts for all data filesystems under `/var/mounts/{UUID}` (runtime only).
- btrfs root options: `rw,noatime,subvolid=5`
- bcachefs root options: `rw,noatime`
- Final subvolume/subdir mounts (from the primary data filesystem) to:
- `/var/cache/system`, `/var/cache/etc`, `/var/cache/modules`, `/var/cache/vm-meta`
- [struct MountResult](../src/mount/ops.rs:1)
- Actual mount operations performed (source, target, fstype, options). - Actual mount operations performed (source, target, fstype, options).
- [fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan>](src/mount/ops.rs:1) - [fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan>](../src/mount/ops.rs:1)
- Translates filesystem identities to mount targets and options. - Translates filesystem identities to mount targets and options, including `subvol=` for btrfs and `X-mount.subdir=` for bcachefs.
- [fn apply_mounts(plan: &MountPlan) -> Result<Vec<MountResult>>](src/mount/ops.rs:1) - [fn apply_mounts(plan: &MountPlan) -> Result<Vec<MountResult>>](../src/mount/ops.rs:1)
- Performs mounts using syscalls (nix crate) with minimal dependencies. Ensures directories exist. - Performs mounts using syscalls (nix crate). Ensures directories exist and creates subvolumes/subdirs if missing.
- [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()>](src/mount/ops.rs:1) - [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()>](../src/mount/ops.rs:1)
- When enabled, generates /etc/fstab entries in deterministic order. Disabled by default. - When enabled, writes only the four subvolume/subdir mount entries to `/etc/fstab` in deterministic order using `UUID=` sources. Root mounts under `/var/mounts` are excluded.
Reporting Reporting
- [const REPORT_VERSION: &str](src/report/state.rs:1) - [const REPORT_VERSION: &str](../src/report/state.rs:1)
- Version string for the JSON payload schema. - Version string for the JSON payload schema.
- [struct StateReport](src/report/state.rs:1) - [struct StateReport](../src/report/state.rs:1)
- Machine-readable state describing discovered disks, created partitions, filesystems, labels, mountpoints, status, and timestamp. - Machine-readable state describing discovered disks, created partitions, filesystems, labels, mountpoints, status, and timestamp.
- [fn build_report(disks: &[Disk], parts: &[PartitionResult], fs: &[FsResult], mounts: &[MountResult], status: &str) -> StateReport](src/report/state.rs:1) - [fn build_report(disks: &[Disk], parts: &[PartitionResult], fs: &[FsResult], mounts: &[MountResult], status: &str) -> StateReport](../src/report/state.rs:1)
- Constructs a StateReport matching REPORT_VERSION. - Constructs a StateReport matching REPORT_VERSION.
- [fn write_report(report: &StateReport) -> Result<()>](src/report/state.rs:1) - [fn write_report(report: &StateReport) -> Result<()>](../src/report/state.rs:1)
- Writes JSON to /run/zosstorage/state.json (configurable). - Writes JSON to /run/zosstorage/state.json (configurable).
Idempotency Idempotency
- [fn detect_existing_state() -> Result<Option<StateReport>>](src/idempotency/mod.rs:1) - [fn detect_existing_state() -> Result<Option<StateReport>>](../src/idempotency/mod.rs:1)
- Probes for expected GPT names (zosboot, zosdata, zoscache where applicable) and filesystem labels (ZOSBOOT, ZOSDATA). If present and consistent, returns a StateReport; orchestrator exits success without changes. - Probes for expected GPT names (zosboot, zosdata, zoscache where applicable) and filesystem labels (ZOSBOOT, ZOSDATA). If present and consistent, returns a StateReport; orchestrator exits success without changes.
- [fn is_empty_disk(disk: &Disk) -> Result<bool>](src/idempotency/mod.rs:1) - [fn is_empty_disk(disk: &Disk) -> Result<bool>](../src/idempotency/mod.rs:1)
- Determines disk emptiness: absence of partitions and known filesystem signatures. - Determines disk emptiness: absence of partitions and known filesystem signatures.
Utilities Utilities
- [struct CmdOutput](src/util/mod.rs:1) - [struct CmdOutput](../src/util/mod.rs:1)
- Captures status, stdout, stderr from external tool invocations. - Captures status, stdout, stderr from external tool invocations.
- [fn which_tool(name: &str) -> Result<Option<String>>](src/util/mod.rs:1) - [fn which_tool(name: &str) -> Result<Option<String>>](../src/util/mod.rs:1)
- Locates a required system utility in PATH, returning its absolute path if available. - Locates a required system utility in PATH, returning its absolute path if available.
- [fn run_cmd(args: &[&str]) -> Result<()>](src/util/mod.rs:1) - [fn run_cmd(args: &[&str]) -> Result<()>](../src/util/mod.rs:1)
- Executes a command (args[0] is binary) and returns Ok when exit status is zero; logs stderr on failure. - Executes a command (args[0] is binary) and returns Ok when exit status is zero; logs stderr on failure.
- [fn run_cmd_capture(args: &[&str]) -> Result<CmdOutput>](src/util/mod.rs:1) - [fn run_cmd_capture(args: &[&str]) -> Result<CmdOutput>](../src/util/mod.rs:1)
- Executes a command and returns captured output for parsing (e.g., blkid). - Executes a command and returns captured output for parsing (e.g., blkid).
- [fn udev_settle(timeout_ms: u64) -> Result<()>](src/util/mod.rs:1) - [fn udev_settle(timeout_ms: u64) -> Result<()>](../src/util/mod.rs:1)
- Calls udevadm settle with a timeout when available; otherwise no-ops with a warning. - Calls udevadm settle with a timeout when available; otherwise no-ops with a warning.
- [fn is_efi_boot() -> bool](../src/util/mod.rs:1)
- Detects UEFI environment by checking `/sys/firmware/efi`; used to suppress BIOS boot partition creation on UEFI systems.
Behavioral notes and contracts Behavioral notes and contracts
- Safety and idempotency: - Safety and idempotency:
@@ -188,10 +198,13 @@ Behavioral notes and contracts
- Data filesystems use label ZOSDATA regardless of backend kind. - Data filesystems use label ZOSDATA regardless of backend kind.
- Cache partitions in bcachefs topology use GPT name zoscache. - Cache partitions in bcachefs topology use GPT name zoscache.
- Topology-specific behavior: - Topology-specific behavior:
- single: one data filesystem (btrfs) on the sole disk. - btrfs_single: one data filesystem (btrfs) on the sole disk.
- dual_independent: two separate btrfs filesystems, one per disk. - bcachefs_single: one data filesystem (bcachefs) on the sole disk.
- dual_independent: independent btrfs filesystems on each eligible disk (one or more).
- bcachefs2_copy: multi-device bcachefs across two or more data partitions with `--replicas=2` (data and metadata).
- ssd_hdd_bcachefs: bcachefs spanning SSD (cache/promote) and HDD (backing), labeled ZOSDATA. - ssd_hdd_bcachefs: bcachefs spanning SSD (cache/promote) and HDD (backing), labeled ZOSDATA.
- btrfs_raid1: only when explicitly requested; otherwise default to independent btrfs. - btrfs_raid1: only when explicitly requested; otherwise default to independent btrfs.
- UEFI vs BIOS: when running under UEFI (`/sys/firmware/efi` present), the BIOS boot partition is suppressed.
Module dependency overview Module dependency overview

View File

@@ -30,116 +30,122 @@ Top level
- [tests/integration_ssd_hdd.rs](tests/integration_ssd_hdd.rs) - [tests/integration_ssd_hdd.rs](tests/integration_ssd_hdd.rs)
Crate sources Crate sources
- [src/main.rs](src/main.rs) - [src/main.rs](../src/main.rs)
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- [src/errors.rs](src/errors.rs) - [src/errors.rs](../src/errors.rs)
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- [src/logging/mod.rs](src/logging/mod.rs) - [src/logging/mod.rs](../src/logging/mod.rs)
- [src/config/loader.rs](src/config/loader.rs) - [src/config/loader.rs](../src/config/loader.rs)
- [src/types.rs](src/types.rs) - [src/types.rs](../src/types.rs)
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [src/idempotency/mod.rs](src/idempotency/mod.rs) - [src/idempotency/mod.rs](../src/idempotency/mod.rs)
- [src/util/mod.rs](src/util/mod.rs) - [src/util/mod.rs](../src/util/mod.rs)
Module responsibilities Module responsibilities
- [src/main.rs](src/main.rs) - [src/main.rs](../src/main.rs)
- Entrypoint. Parse CLI, initialize logging, load and merge configuration per precedence, call orchestrator. No stdout spam. - Entrypoint. Parse CLI, initialize logging, load and merge configuration per precedence, call orchestrator. No stdout spam.
- [src/lib.rs](src/lib.rs) - [src/lib.rs](../src/lib.rs)
- Crate exports, prelude, version constants, Result alias. - Crate exports, prelude, version constants, Result alias.
- [src/errors.rs](src/errors.rs) - [src/errors.rs](../src/errors.rs)
- Common error enum and Result alias via thiserror. - Common error enum and Result alias via thiserror.
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- CLI definition mirroring kernel cmdline semantics; provide non-interactive interface. Stub --force returns unimplemented. - CLI definition mirroring kernel cmdline semantics; provide non-interactive interface. Stub --force returns unimplemented.
- [src/logging/mod.rs](src/logging/mod.rs) - [src/logging/mod.rs](../src/logging/mod.rs)
- Initialize tracing; levels error, warn, info, debug; default to stderr; optional file target. - 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) - [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. - YAML schema types, validation, loading, and merging with CLI and kernel cmdline.
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- Device discovery under /dev with filters and allowlist; probe emptiness safely. - Device discovery under /dev with filters and allowlist; probe emptiness safely.
- [src/partition/plan.rs](src/partition/plan.rs) - [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. - 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) - [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. - 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) - [src/mount/ops.rs](../src/mount/ops.rs)
- Mount per-UUID under /var/cache/<UUID>. Optional fstab writing, disabled by default. - Mount scheme:
- [src/report/state.rs](src/report/state.rs) - Root-mount all data filesystems under `/var/mounts/{UUID}` (runtime only)
- btrfs root: `rw,noatime,subvolid=5`
- bcachefs root: `rw,noatime`
- Create or ensure subvolumes on the primary data filesystem: `system`, `etc`, `modules`, `vm-meta`
- Mount final subvolume/subdir targets at `/var/cache/{system,etc,modules,vm-meta}`
- Optional fstab writing: only the four final targets, deterministic order, `UUID=` sources; disabled by default
- [src/report/state.rs](../src/report/state.rs)
- Build and write JSON state report with version field. - Build and write JSON state report with version field.
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- One-shot flow orchestration with abort-on-any-validation-error policy. - One-shot flow orchestration with abort-on-any-validation-error policy.
- [src/idempotency/mod.rs](src/idempotency/mod.rs) - [src/idempotency/mod.rs](../src/idempotency/mod.rs)
- Detect prior provisioning via GPT names and labels; return success-without-changes. - Detect prior provisioning via GPT names and labels; return success-without-changes.
- [src/util/mod.rs](src/util/mod.rs) - [src/util/mod.rs](../src/util/mod.rs)
- Shell-out, udev settle, and helpers. - Shell-out, udev settle, and helpers.
Public API surface (signatures; implementation to follow after approval) Public API surface (signatures; implementation to follow after approval)
Entrypoint and orchestrator Entrypoint and orchestrator
- [fn main()](src/main.rs:1) - [fn main()](../src/main.rs:1)
- [struct Context](src/orchestrator/run.rs:1) - [struct Context](../src/orchestrator/run.rs:1)
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1) - [fn run(ctx: &Context) -> Result<()>](../src/orchestrator/run.rs:1)
CLI CLI
- [struct Cli](src/cli/args.rs:1) - [struct Cli](../src/cli/args.rs:1)
- [fn from_args() -> Cli](src/cli/args.rs:1) - [fn from_args() -> Cli](../src/cli/args.rs:1)
Logging Logging
- [struct LogOptions](src/logging/mod.rs:1) - [struct LogOptions](../src/logging/mod.rs:1)
- [fn init_logging(opts: &LogOptions) -> Result<()>](src/logging/mod.rs:1) - [fn init_logging(opts: &LogOptions) -> Result<()>](../src/logging/mod.rs:1)
Config Config
- [struct Config](src/types.rs:1) - [struct Config](../src/types.rs:1)
- [enum Topology](src/types.rs:1) - [enum Topology](../src/types.rs:1)
- [struct DeviceSelection](src/types.rs:1) - [struct DeviceSelection](../src/types.rs:1)
- [struct FsOptions](src/types.rs:1) - [struct FsOptions](../src/types.rs:1)
- [struct MountScheme](src/types.rs:1) - [struct MountScheme](../src/types.rs:1)
- [fn load_and_merge(cli: &Cli) -> Result<Config>](src/config/loader.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) - [fn validate(cfg: &Config) -> Result<()>](../src/config/loader.rs:1)
Device discovery Device discovery
- [struct Disk](src/device/discovery.rs:1) - [struct Disk](../src/device/discovery.rs:1)
- [struct DeviceFilter](src/device/discovery.rs:1) - [struct DeviceFilter](../src/device/discovery.rs:1)
- [trait DeviceProvider](src/device/discovery.rs:1) - [trait DeviceProvider](../src/device/discovery.rs:1)
- [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](src/device/discovery.rs:1) - [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](../src/device/discovery.rs:1)
Partitioning Partitioning
- [struct PartitionSpec](src/partition/plan.rs:1) - [struct PartitionSpec](../src/partition/plan.rs:1)
- [struct PartitionPlan](src/partition/plan.rs:1) - [struct PartitionPlan](../src/partition/plan.rs:1)
- [struct PartitionResult](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 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) - [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](../src/partition/plan.rs:1)
Filesystems Filesystems
- [enum FsKind](src/fs/plan.rs:1) - [enum FsKind](../src/fs/plan.rs:1)
- [struct FsSpec](src/fs/plan.rs:1) - [struct FsSpec](../src/fs/plan.rs:1)
- [struct FsPlan](src/fs/plan.rs:1) - [struct FsPlan](../src/fs/plan.rs:1)
- [struct FsResult](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 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) - [fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>>](../src/fs/plan.rs:1)
Mounting Mounting
- [struct MountPlan](src/mount/ops.rs:1) - [struct MountPlan](../src/mount/ops.rs:1)
- [struct MountResult](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 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 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) - [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()>](../src/mount/ops.rs:1)
Reporting Reporting
- [const REPORT_VERSION: &str](src/report/state.rs:1) - [const REPORT_VERSION: &str](../src/report/state.rs:1)
- [struct StateReport](src/report/state.rs:1) - [struct StateReport](../src/report/state.rs:1)
- [fn build_report(...) -> 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) - [fn write_report(report: &StateReport) -> Result<()>](../src/report/state.rs:1)
Idempotency Idempotency
- [fn detect_existing_state() -> Result<Option<StateReport>>](src/idempotency/mod.rs:1) - [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) - [fn is_empty_disk(disk: &Disk) -> Result<bool>](../src/idempotency/mod.rs:1)
Errors and Result Errors and Result
- [enum Error](src/errors.rs:1) - [enum Error](../src/errors.rs:1)
- [type Result<T> = std::result::Result<T, Error>](src/errors.rs:1) - [type Result<T> = std::result::Result<T, Error>](../src/errors.rs:1)
Execution flow Execution flow
@@ -190,8 +196,15 @@ Filesystem provisioning defaults
- Filesystem tuning options configurable with sensible defaults and extension points - Filesystem tuning options configurable with sensible defaults and extension points
Mount scheme and fstab policy Mount scheme and fstab policy
- Mount under /var/cache/<UUID> using filesystem UUID to create stable subdirectories - Runtime root mounts:
- Optional /etc/fstab generation disabled by default; when enabled, produce deterministic order with documentation - Each data filesystem is root-mounted at `/var/mounts/{UUID}` (runtime only)
- btrfs: `rw,noatime,subvolid=5`; bcachefs: `rw,noatime`
- Final targets (from primary data filesystem only):
- `/var/cache/system`, `/var/cache/etc`, `/var/cache/modules`, `/var/cache/vm-meta`
- btrfs subvolume option: `-o subvol={name},noatime`
- bcachefs subdir option: `-o X-mount.subdir={name},noatime`
- /etc/fstab generation:
- Disabled by default. When enabled, write only the four final targets with `UUID=` sources in deterministic order. Root mounts under `/var/mounts` are excluded.
Idempotency detection Idempotency detection
- Consider the system provisioned when expected GPT names and filesystem labels are present and consistent - Consider the system provisioned when expected GPT names and filesystem labels are present and consistent

View File

@@ -8,18 +8,18 @@ Goal
Core Principles Core Principles
1) Contract-first per module 1) Contract-first per module
- API signatures and responsibilities are documented in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) and mirrored by crate modules: - API signatures and responsibilities are documented in [docs/API-SKELETONS.md](docs/API-SKELETONS.md) and mirrored by crate modules:
- [src/types.rs](src/types.rs) - [src/types.rs](../src/types.rs)
- [fn load_and_merge()](src/config/loader.rs:1), [fn validate()](src/config/loader.rs:1) - [fn load_and_merge()](../src/config/loader.rs:1), [fn validate()](../src/config/loader.rs:1)
- [fn from_args()](src/cli/args.rs:1) - [fn from_args()](../src/cli/args.rs:1)
- [struct LogOptions](src/logging/mod.rs:1), [fn init_logging()](src/logging/mod.rs:1) - [struct LogOptions](../src/logging/mod.rs:1), [fn init_logging()](../src/logging/mod.rs:1)
- [fn discover()](src/device/discovery.rs:1) - [fn discover()](../src/device/discovery.rs:1)
- [fn plan_partitions()](src/partition/plan.rs:1), [fn apply_partitions()](src/partition/plan.rs:1) - [fn plan_partitions()](../src/partition/plan.rs:1), [fn apply_partitions()](../src/partition/plan.rs:1)
- [fn plan_filesystems()](src/fs/plan.rs:1), [fn make_filesystems()](src/fs/plan.rs:1) - [fn plan_filesystems()](../src/fs/plan.rs:1), [fn make_filesystems()](../src/fs/plan.rs:1)
- [fn plan_mounts()](src/mount/ops.rs:1), [fn apply_mounts()](src/mount/ops.rs:1), [fn maybe_write_fstab()](src/mount/ops.rs:1) - [fn plan_mounts()](../src/mount/ops.rs:1), [fn apply_mounts()](../src/mount/ops.rs:1), [fn maybe_write_fstab()](../src/mount/ops.rs:1)
- [const REPORT_VERSION](src/report/state.rs:1), [fn build_report()](src/report/state.rs:1), [fn write_report()](src/report/state.rs:1) - [const REPORT_VERSION](../src/report/state.rs:1), [fn build_report()](../src/report/state.rs:1), [fn write_report()](../src/report/state.rs:1)
- [struct Context](src/orchestrator/run.rs:1), [fn run()](src/orchestrator/run.rs:1) - [struct Context](../src/orchestrator/run.rs:1), [fn run()](../src/orchestrator/run.rs:1)
- [fn detect_existing_state()](src/idempotency/mod.rs:1), [fn is_empty_disk()](src/idempotency/mod.rs:1) - [fn detect_existing_state()](../src/idempotency/mod.rs:1), [fn is_empty_disk()](../src/idempotency/mod.rs:1)
- [struct CmdOutput](src/util/mod.rs:1), [fn which_tool()](src/util/mod.rs:1), [fn run_cmd()](src/util/mod.rs:1), [fn run_cmd_capture()](src/util/mod.rs:1), [fn udev_settle()](src/util/mod.rs:1) - [struct CmdOutput](../src/util/mod.rs:1), [fn which_tool()](../src/util/mod.rs:1), [fn run_cmd()](../src/util/mod.rs:1), [fn run_cmd_capture()](../src/util/mod.rs:1), [fn udev_settle()](../src/util/mod.rs:1)
2) Grep-able region markers in code 2) Grep-able region markers in code
- Every module contains the following optional annotated regions: - Every module contains the following optional annotated regions:
@@ -55,22 +55,22 @@ Core Principles
6) Module ownership and boundaries 6) Module ownership and boundaries
- Add a “Module Responsibilities” section in each modules header doc comment summarizing scope and non-goals. - Add a “Module Responsibilities” section in each modules header doc comment summarizing scope and non-goals.
- Example references: - Example references:
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
7) Invariants and safety notes 7) Invariants and safety notes
- For code that must uphold safety or idempotency invariants, annotate with: - For code that must uphold safety or idempotency invariants, annotate with:
// SAFETY: explanation // SAFETY: explanation
// IDEMPOTENCY: explanation // IDEMPOTENCY: explanation
- Example locations: - Example locations:
- [fn apply_partitions()](src/partition/plan.rs:1) must enforce empty-disks rule when configured. - [fn apply_partitions()](../src/partition/plan.rs:1) must enforce empty-disks rule when configured.
- [fn make_filesystems()](src/fs/plan.rs:1) must not run if partitioning failed. - [fn make_filesystems()](../src/fs/plan.rs:1) must not run if partitioning failed.
8) Error mapping consistency 8) Error mapping consistency
- Centralize conversions to [enum Error](src/errors.rs:1). When calling external tools, wrap failures into Error::Tool with stderr captured. - Centralize conversions to [enum Error](../src/errors.rs:1). When calling external tools, wrap failures into Error::Tool with stderr captured.
- Annotate mapping areas with: - Annotate mapping areas with:
// ERROR: mapping external failure to Error::Tool // ERROR: mapping external failure to Error::Tool
@@ -111,7 +111,7 @@ Checklist for adding a new feature
- Add examples if config or output formats change - Add examples if config or output formats change
- Update [config/zosstorage.example.yaml](config/zosstorage.example.yaml) or add a new example file - Update [config/zosstorage.example.yaml](config/zosstorage.example.yaml) or add a new example file
- Keep error mapping and logging consistent: - Keep error mapping and logging consistent:
- Ensure any external tool calls map errors to [enum Error](src/errors.rs:1) - Ensure any external tool calls map errors to [enum Error](../src/errors.rs:1)
- Run cargo build and update any broken references - Run cargo build and update any broken references
Optional automation (future) Optional automation (future)

View File

@@ -43,7 +43,7 @@ device_selection:
allow_removable: false # future option; default false allow_removable: false # future option; default false
min_size_gib: 10 # ignore devices smaller than this (default 10) min_size_gib: 10 # ignore devices smaller than this (default 10)
topology: # desired overall layout; see values below topology: # desired overall layout; see values below
mode: single # single | dual_independent | ssd_hdd_bcachefs | btrfs_raid1 (optional) mode: btrfs_single # btrfs_single | bcachefs_single | dual_independent | bcachefs2_copy | ssd_hdd_bcachefs | btrfs_raid1
partitioning: partitioning:
alignment_mib: 1 # GPT alignment in MiB alignment_mib: 1 # GPT alignment in MiB
require_empty_disks: true # abort if any partition or FS signatures exist require_empty_disks: true # abort if any partition or FS signatures exist
@@ -83,8 +83,8 @@ report:
Topology modes Topology modes
- btrfs_single: One eligible disk. Create BIOS boot (if enabled), ESP 512 MiB, remainder as data. Create a btrfs filesystem labeled ZOSDATA on the data partition. - btrfs_single: One eligible disk. Create BIOS boot (if enabled), ESP 512 MiB, remainder as data. Create a btrfs filesystem labeled ZOSDATA on the data partition.
- bcachefs_single: One eligible disk. Create BIOS boot (if enabled), ESP 512 MiB, remainder as data. Create a bcachefs filesystem labeled ZOSDATA on the data partition. - bcachefs_single: One eligible disk. Create BIOS boot (if enabled), ESP 512 MiB, remainder as data. Create a bcachefs filesystem labeled ZOSDATA on the data partition.
- dual_independent: Two eligible disks. On each disk, create BIOS boot (if enabled) + ESP + data. Create an independent btrfs filesystem labeled ZOSDATA on each data partition. No RAID by default. - dual_independent: One or more eligible disks. On each disk, create BIOS boot (if enabled) + ESP + data. Create an independent btrfs filesystem labeled ZOSDATA on each data partition. No RAID by default.
- bcachefs_2copy: Two eligible disks. Create data partitions on both, then create a single multi-device bcachefs labeled ZOSDATA spanning the data partitions (two-copies semantics to be tuned via mkfs options in a follow-up). - bcachefs2_copy: Two or more eligible disks (minimum 2). Create data partitions and then a single multi-device bcachefs labeled ZOSDATA spanning those data partitions. The mkfs step uses `--replicas=2` (data and metadata).
- ssd_hdd_bcachefs: One SSD/NVMe and one HDD. Create BIOS boot (if enabled) + ESP on both as required. Create cache (on SSD) and data/backing (on HDD) partitions named zoscache and zosdata respectively. Create a bcachefs labeled ZOSDATA across SSD(HDD) per policy (SSD cache/promote; HDD backing). - ssd_hdd_bcachefs: One SSD/NVMe and one HDD. Create BIOS boot (if enabled) + ESP on both as required. Create cache (on SSD) and data/backing (on HDD) partitions named zoscache and zosdata respectively. Create a bcachefs labeled ZOSDATA across SSD(HDD) per policy (SSD cache/promote; HDD backing).
- btrfs_raid1: Optional mode if explicitly requested. Create mirrored btrfs across two disks for the data role with raid1 profile. Not enabled by default. - btrfs_raid1: Optional mode if explicitly requested. Create mirrored btrfs across two disks for the data role with raid1 profile. Not enabled by default.
@@ -119,11 +119,15 @@ Filesystem section
- vfat: label ZOSBOOT used for ESP. - vfat: label ZOSBOOT used for ESP.
Mount section Mount section
- base_dir: default /var/cache. - Runtime root mounts (all data filesystems):
- scheme: - Each data filesystem is root-mounted at `/var/mounts/{UUID}`
- per_uuid: mount data filesystems at /var/cache/<FS-UUID> - btrfs root mount options: `rw,noatime,subvolid=5`
- custom: reserved for future mapping-by-config, not yet implemented. - bcachefs root mount options: `rw,noatime`
- fstab.enabled: default false. When true, zosstorage will generate fstab entries in deterministic order. - Subvolume mounts (from the primary data filesystem only) to final targets:
- Targets: `/var/cache/system`, `/var/cache/etc`, `/var/cache/modules`, `/var/cache/vm-meta`
- btrfs subvol options: `-o rw,noatime,subvol={name}`
- bcachefs subdir options: `-o rw,noatime,X-mount.subdir={name}`
- fstab.enabled: default false. When true, zosstorage writes only the four subvolume mount entries, in deterministic target order, using `UUID=` sources for the filesystem; root mounts under `/var/mounts` are excluded.
Report section Report section
- path: default /run/zosstorage/state.json. - path: default /run/zosstorage/state.json.
@@ -135,7 +139,7 @@ Minimal single-disk btrfs
```yaml ```yaml
version: 1 version: 1
topology: topology:
mode: single mode: btrfs_single
``` ```
Dual independent btrfs (two disks) Dual independent btrfs (two disks)
@@ -186,15 +190,15 @@ Future extensions
- Multiple topology groups on multi-disk systems - Multiple topology groups on multi-disk systems
Reference modules Reference modules
- [src/types.rs](src/types.rs) - [src/types.rs](../src/types.rs)
- [src/config/loader.rs](src/config/loader.rs) - [src/config/loader.rs](../src/config/loader.rs)
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
- [src/idempotency/mod.rs](src/idempotency/mod.rs) - [src/idempotency/mod.rs](../src/idempotency/mod.rs)
Change log Change log
- v1: Initial draft of schema and precedence rules - v1: Initial draft of schema and precedence rules

View File

@@ -3,31 +3,31 @@
This document finalizes core specifications required before code skeleton implementation. It complements [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and [docs/SCHEMA.md](docs/SCHEMA.md), and references the API declarations listed in [docs/API.md](docs/API.md). This document finalizes core specifications required before code skeleton implementation. It complements [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and [docs/SCHEMA.md](docs/SCHEMA.md), and references the API declarations listed in [docs/API.md](docs/API.md).
Linked modules and functions Linked modules and functions
- Logging module: [src/logging/mod.rs](src/logging/mod.rs) - Logging module: [src/logging/mod.rs](../src/logging/mod.rs)
- [fn init_logging(opts: &LogOptions) -> Result<()>](src/logging/mod.rs:1) - [fn init_logging(opts: &LogOptions) -> Result<()>](../src/logging/mod.rs:1)
- Report module: [src/report/state.rs](src/report/state.rs) - Report module: [src/report/state.rs](../src/report/state.rs)
- [const REPORT_VERSION: &str](src/report/state.rs:1) - [const REPORT_VERSION: &str](../src/report/state.rs:1)
- [fn build_report(...) -> 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) - [fn write_report(report: &StateReport) -> Result<()>](../src/report/state.rs:1)
- Device module: [src/device/discovery.rs](src/device/discovery.rs) - Device module: [src/device/discovery.rs](../src/device/discovery.rs)
- [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](src/device/discovery.rs:1) - [fn discover(filter: &DeviceFilter) -> Result<Vec<Disk>>](../src/device/discovery.rs:1)
- Partitioning module: [src/partition/plan.rs](src/partition/plan.rs) - Partitioning module: [src/partition/plan.rs](../src/partition/plan.rs)
- [fn plan_partitions(disks: &[Disk], cfg: &Config) -> Result<PartitionPlan>](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) - [fn apply_partitions(plan: &PartitionPlan) -> Result<Vec<PartitionResult>>](../src/partition/plan.rs:1)
- Filesystems module: [src/fs/plan.rs](src/fs/plan.rs) - Filesystems module: [src/fs/plan.rs](../src/fs/plan.rs)
- [fn plan_filesystems(disks: &[Disk], parts: &[PartitionResult], cfg: &Config) -> Result<FsPlan>](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) - [fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>>](../src/fs/plan.rs:1)
- Mount module: [src/mount/ops.rs](src/mount/ops.rs) - Mount module: [src/mount/ops.rs](../src/mount/ops.rs)
- [fn plan_mounts(fs_results: &[FsResult], cfg: &Config) -> Result<MountPlan>](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 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) - [fn maybe_write_fstab(mounts: &[MountResult], cfg: &Config) -> Result<()>](../src/mount/ops.rs:1)
- Idempotency module: [src/idempotency/mod.rs](src/idempotency/mod.rs) - Idempotency module: [src/idempotency/mod.rs](../src/idempotency/mod.rs)
- [fn detect_existing_state() -> Result<Option<StateReport>>](src/idempotency/mod.rs:1) - [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) - [fn is_empty_disk(disk: &Disk) -> Result<bool>](../src/idempotency/mod.rs:1)
- CLI module: [src/cli/args.rs](src/cli/args.rs) - CLI module: [src/cli/args.rs](../src/cli/args.rs)
- [fn from_args() -> Cli](src/cli/args.rs:1) - [fn from_args() -> Cli](../src/cli/args.rs:1)
- Orchestrator: [src/orchestrator/run.rs](src/orchestrator/run.rs) - Orchestrator: [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [fn run(ctx: &Context) -> Result<()>](src/orchestrator/run.rs:1) - [fn run(ctx: &Context) -> Result<()>](../src/orchestrator/run.rs:1)
--- ---
@@ -39,7 +39,7 @@ Goals
Configuration Configuration
- Levels: error, warn, info, debug (default info). - Levels: error, warn, info, debug (default info).
- Propagation: single global initialization via [fn init_logging](src/logging/mod.rs:1). Subsequent calls must be no-ops. - Propagation: single global initialization via [fn init_logging](../src/logging/mod.rs:1). Subsequent calls must be no-ops.
Implementation notes Implementation notes
- Use tracing and tracing-subscriber. - Use tracing and tracing-subscriber.
@@ -57,7 +57,7 @@ Location
- Default output: /run/zosstorage/state.json - Default output: /run/zosstorage/state.json
Versioning Versioning
- Include a top-level string field version equal to [REPORT_VERSION](src/report/state.rs:1). Start with v1. - Include a top-level string field version equal to [REPORT_VERSION](../src/report/state.rs:1). Start with v1.
Schema example Schema example
@@ -154,17 +154,17 @@ Default exclude patterns
- ^/dev/fd\\d+$ - ^/dev/fd\\d+$
Selection policy Selection policy
- Compile include and exclude regex into [DeviceFilter](src/device/discovery.rs). - Compile include and exclude regex into [DeviceFilter](../src/device/discovery.rs).
- Enumerate device candidates and apply: - Enumerate device candidates and apply:
- Must match at least one include. - Must match at least one include.
- Must not match any exclude. - Must not match any exclude.
- Must be larger than min_size_gib (default 10). - Must be larger than min_size_gib (default 10).
- Probing - Probing
- Gather size, rotational flag, model, serial when available. - Gather size, rotational flag, model, serial when available.
- Expose via [struct Disk](src/device/discovery.rs:1). - Expose via [struct Disk](../src/device/discovery.rs:1).
No eligible disks No eligible disks
- Return a specific error variant in [enum Error](src/errors.rs:1). - Return a specific error variant in [enum Error](../src/errors.rs:1).
--- ---
@@ -181,17 +181,20 @@ Layout defaults
- Cache partitions (only in ssd_hdd_bcachefs): GPT name zoscache on SSD. - Cache partitions (only in ssd_hdd_bcachefs): GPT name zoscache on SSD.
Per-topology specifics Per-topology specifics
- single: All roles on the single disk. - btrfs_single: All roles on the single disk; data formatted as btrfs.
- dual_independent: Each disk gets BIOS boot + ESP + data. - bcachefs_single: All roles on the single disk; data formatted as bcachefs.
- ssd_hdd_bcachefs: SSD gets BIOS boot + ESP + zoscache, HDD gets BIOS boot + ESP + zosdata. - dual_independent: On each eligible disk (one or more), create BIOS boot (if applicable), ESP, and data.
- bcachefs_2copy: Create data partitions on two or more disks; later formatted as one multi-device bcachefs spanning all data partitions.
- ssd_hdd_bcachefs: SSD gets BIOS boot + ESP + zoscache; HDD gets BIOS boot + ESP + zosdata; combined later into one bcachefs.
- btrfs_raid1: Two disks minimum; data partitions mirrored via btrfs RAID1.
Safety checks Safety checks
- Ensure unique partition UUIDs. - Ensure unique partition UUIDs.
- Verify no pre-existing partitions or signatures. Use blkid or similar via [run_cmd_capture](src/util/mod.rs:1). - Verify no pre-existing partitions or signatures. Use blkid or similar via [run_cmd_capture](../src/util/mod.rs:1).
- After partition creation, run udev settle via [udev_settle](src/util/mod.rs:1). - After partition creation, run udev settle via [udev_settle](../src/util/mod.rs:1).
Application Application
- Utilize sgdisk helpers in [apply_partitions](src/partition/plan.rs:1). - Utilize sgdisk helpers in [apply_partitions](../src/partition/plan.rs:1).
--- ---
@@ -199,34 +202,38 @@ Application
Kinds Kinds
- Vfat for ESP, label ZOSBOOT. - Vfat for ESP, label ZOSBOOT.
- Btrfs for data on single and dual_independent. - Btrfs for data in btrfs_single, dual_independent, and btrfs_raid1 (with RAID1 profile).
- Bcachefs for ssd_hdd_bcachefs (SSD cache, HDD backing). - Bcachefs for data in bcachefs_single, ssd_hdd_bcachefs (SSD cache + HDD backing), and bcachefs_2copy (multi-device).
- All data filesystems use label ZOSDATA. - All data filesystems use label ZOSDATA.
Defaults Defaults
- btrfs: compression zstd:3, raid_profile none unless explicitly set to raid1 in btrfs_raid1 mode. - btrfs: compression zstd:3, raid_profile none unless explicitly set; for btrfs_raid1 use -m raid1 -d raid1.
- bcachefs: cache_mode promote, compression zstd, checksum crc32c. - bcachefs: cache_mode promote, compression zstd, checksum crc32c; for bcachefs_2copy use `--replicas=2` (data and metadata).
- vfat: ESP label ZOSBOOT. - vfat: ESP label ZOSBOOT.
Planning and execution Planning and execution
- Decide mapping of [PartitionResult](src/partition/plan.rs:1) to [FsSpec](src/fs/plan.rs:1) in [plan_filesystems](src/fs/plan.rs:1). - Decide mapping of [PartitionResult](../src/partition/plan.rs:1) to [FsSpec](../src/fs/plan.rs:1) in [plan_filesystems](../src/fs/plan.rs:1).
- Create filesystems in [make_filesystems](src/fs/plan.rs:1) through wrapped mkfs tools. - Create filesystems in [make_filesystems](../src/fs/plan.rs:1) through wrapped mkfs tools.
- Capture resulting identifiers (fs uuid, label) in [FsResult](src/fs/plan.rs:1). - Capture resulting identifiers (fs uuid, label) in [FsResult](../src/fs/plan.rs:1).
--- ---
## 6. Mount scheme and fstab policy ## 6. Mount scheme and fstab policy
Scheme Runtime root mounts (all data filesystems)
- per_uuid under /var/cache: directories named as filesystem UUIDs. - Each data filesystem is root-mounted at `/var/mounts/{UUID}` (runtime only).
- btrfs root mount options: `rw,noatime,subvolid=5`
- bcachefs root mount options: `rw,noatime`
Mount options Final subvolume/subdir mounts (from the primary data filesystem)
- btrfs: ssd when non-rotational underlying device, compress from config, defaults otherwise. - Create or ensure subvolumes named: `system`, `etc`, `modules`, `vm-meta`
- vfat: defaults, utf8. - Mount targets: `/var/cache/system`, `/var/cache/etc`, `/var/cache/modules`, `/var/cache/vm-meta`
- btrfs options: `-o rw,noatime,subvol={name}`
- bcachefs options: `-o rw,noatime,X-mount.subdir={name}`
fstab fstab policy
- Disabled by default. - Disabled by default.
- When enabled, [maybe_write_fstab](src/mount/ops.rs:1) writes deterministic entries sorted by target path. - When enabled, [maybe_write_fstab](../src/mount/ops.rs:1) writes only the four final subvolume/subdir entries using `UUID=` sources, in deterministic target order. Root mounts under `/var/mounts` are excluded.
--- ---
@@ -235,20 +242,23 @@ fstab
Signals for already-provisioned system Signals for already-provisioned system
- Expected GPT names found: zosboot, zosdata, and zoscache when applicable. - Expected GPT names found: zosboot, zosdata, and zoscache when applicable.
- Filesystems with labels ZOSBOOT for ESP and ZOSDATA for all data filesystems. - Filesystems with labels ZOSBOOT for ESP and ZOSDATA for all data filesystems.
- When consistent with selected topology, [detect_existing_state](src/idempotency/mod.rs:1) returns a StateReport and orchestrator exits success without changes. - When consistent with selected topology, [detect_existing_state](../src/idempotency/mod.rs:1) returns a StateReport and orchestrator exits success without changes.
Disk emptiness Disk emptiness
- [is_empty_disk](src/idempotency/mod.rs:1) checks for absence of partitions and FS signatures before any modification. - [is_empty_disk](../src/idempotency/mod.rs:1) checks for absence of partitions and FS signatures before any modification.
--- ---
## 8. CLI flags and help text outline ## 8. CLI flags and help text outline
Flags mirrored by [struct Cli](src/cli/args.rs:1) parsed via [from_args](src/cli/args.rs:1) Flags mirrored by [struct Cli](../src/cli/args.rs:1) parsed via [from_args](../src/cli/args.rs:1)
- --config PATH - --config PATH
- --log-level LEVEL error | warn | info | debug - --log-level LEVEL error | warn | info | debug
- --log-to-file - --log-to-file
- --fstab enable fstab generation - --fstab enable fstab generation
- --show print preview JSON to stdout (non-destructive)
- --report PATH write preview JSON to file (non-destructive)
- --apply perform partitioning, filesystem creation, and mounts (DESTRUCTIVE)
- --force present but returns unimplemented error - --force present but returns unimplemented error
Kernel cmdline Kernel cmdline
@@ -257,7 +267,7 @@ Kernel cmdline
Help text sections Help text sections
- NAME, SYNOPSIS, DESCRIPTION - NAME, SYNOPSIS, DESCRIPTION
- CONFIG PRECEDENCE - CONFIG PRECEDENCE
- TOPOLOGIES: single, dual_independent, ssd_hdd_bcachefs, btrfs_raid1 - TOPOLOGIES: btrfs_single, bcachefs_single, dual_independent, bcachefs_2copy, ssd_hdd_bcachefs, btrfs_raid1
- SAFETY AND IDEMPOTENCY - SAFETY AND IDEMPOTENCY
- REPORTS - REPORTS
- EXIT CODES: 0 success or already_provisioned, non-zero on error - EXIT CODES: 0 success or already_provisioned, non-zero on error
@@ -267,9 +277,10 @@ Help text sections
## 9. Integration testing plan (QEMU KVM) ## 9. Integration testing plan (QEMU KVM)
Scenarios to scaffold in [tests/](tests/) Scenarios to scaffold in [tests/](tests/)
- Single disk 40 GiB virtio: validates single topology end-to-end smoke. - Single disk 40 GiB virtio: validates btrfs_single topology end-to-end smoke.
- Dual NVMe 40 GiB each: validates dual_independent topology. - Dual NVMe 40 GiB each: validates dual_independent topology (independent btrfs per disk).
- SSD NVMe + HDD virtio: validates ssd_hdd_bcachefs topology. - SSD NVMe + HDD virtio: validates ssd_hdd_bcachefs topology (bcachefs with SSD cache/promote, HDD backing).
- Three disks: validates bcachefs_2copy across data partitions using `--replicas=2`.
- Negative: no eligible disks, or non-empty disk should abort. - Negative: no eligible disks, or non-empty disk should abort.
Test strategy Test strategy
@@ -281,7 +292,7 @@ Test strategy
Artifacts to validate Artifacts to validate
- Presence of expected partition GPT names. - Presence of expected partition GPT names.
- Filesystems created with correct labels. - Filesystems created with correct labels.
- Mountpoints under /var/cache/<UUID> when running in a VM. - Runtime root mounts under `/var/mounts/{UUID}` and final subvolume targets at `/var/cache/{system,etc,modules,vm-meta}`.
- JSON report validates against v1 schema. - JSON report validates against v1 schema.
--- ---

View File

@@ -47,14 +47,14 @@ Consequences
Implementation Notes Implementation Notes
- Region markers have been added to key modules: - Region markers have been added to key modules:
- [src/config/loader.rs](src/config/loader.rs) - [src/config/loader.rs](../src/config/loader.rs)
- [src/orchestrator/run.rs](src/orchestrator/run.rs) - [src/orchestrator/run.rs](../src/orchestrator/run.rs)
- [src/cli/args.rs](src/cli/args.rs) - [src/cli/args.rs](../src/cli/args.rs)
- [src/device/discovery.rs](src/device/discovery.rs) - [src/device/discovery.rs](../src/device/discovery.rs)
- [src/partition/plan.rs](src/partition/plan.rs) - [src/partition/plan.rs](../src/partition/plan.rs)
- [src/fs/plan.rs](src/fs/plan.rs) - [src/fs/plan.rs](../src/fs/plan.rs)
- [src/mount/ops.rs](src/mount/ops.rs) - [src/mount/ops.rs](../src/mount/ops.rs)
- [src/report/state.rs](src/report/state.rs) - [src/report/state.rs](../src/report/state.rs)
- Remaining modules will follow the same pattern as needed (e.g., util, idempotency, main/lib if helpful). - Remaining modules will follow the same pattern as needed (e.g., util, idempotency, main/lib if helpful).
Related Documents Related Documents