topology: unify CLI and types::Topology (ValueEnum + aliases); bcachefs-2copy uses --replicas=2; update orchestrator call to make_filesystems(cfg); minor overlay fix; docs previously synced
This commit is contained in:
@@ -72,7 +72,7 @@ Configuration types
|
||||
- [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.
|
||||
- [enum Topology](src/types.rs:1)
|
||||
- Values: single, dual_independent, ssd_hdd_bcachefs, btrfs_raid1 (opt-in).
|
||||
- Values: btrfs_single, bcachefs_single, dual_independent, bcachefs_2copy, ssd_hdd_bcachefs, btrfs_raid1 (opt-in).
|
||||
- [struct DeviceSelection](src/types.rs:1)
|
||||
- Include and exclude regex patterns, minimum size, removable policy.
|
||||
- [struct Partitioning](src/types.rs:1)
|
||||
|
||||
@@ -81,9 +81,11 @@ report:
|
||||
```
|
||||
|
||||
Topology modes
|
||||
- single: One eligible disk. Create BIOS boot (if enabled), ESP 512 MiB, remainder as data. Make a btrfs filesystem labeled ZOSDATA on the data partition.
|
||||
- dual_independent: Two eligible disks. On each disk, create BIOS boot (if enabled) + ESP + data. Create a separate btrfs filesystem labeled ZOSDATA on each data partition. No RAID by default.
|
||||
- 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. Make a bcachefs filesystem across both with label ZOSDATA, using SSD as cache/promote and HDD as backing.
|
||||
- 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.
|
||||
- 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.
|
||||
- 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).
|
||||
- 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.
|
||||
|
||||
Validation rules
|
||||
|
||||
@@ -51,31 +51,8 @@ impl std::fmt::Display for LogLevelArg {
|
||||
}
|
||||
}
|
||||
|
||||
/// Topology argument (maps to config Topology with snake_case semantics).
|
||||
#[derive(Debug, Clone, Copy, ValueEnum)]
|
||||
#[value(rename_all = "kebab_case")]
|
||||
pub enum TopologyArg {
|
||||
BtrfsSingle,
|
||||
BcachefsSingle,
|
||||
DualIndependent,
|
||||
SsdHddBcachefs,
|
||||
Bcachefs2Copy,
|
||||
BtrfsRaid1,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TopologyArg {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
TopologyArg::BtrfsSingle => "btrfs_single",
|
||||
TopologyArg::BcachefsSingle => "bcachefs_single",
|
||||
TopologyArg::DualIndependent => "dual_independent",
|
||||
TopologyArg::SsdHddBcachefs => "ssd_hdd_bcachefs",
|
||||
TopologyArg::Bcachefs2Copy => "bcachefs_2copy",
|
||||
TopologyArg::BtrfsRaid1 => "btrfs_raid1",
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
}
|
||||
//// Using crate::types::Topology (ValueEnum) directly for CLI parsing to avoid duplication.
|
||||
// TopologyArg enum removed; CLI field uses crate::types::Topology
|
||||
|
||||
/// zosstorage - one-shot disk initializer for initramfs.
|
||||
#[derive(Debug, Parser)]
|
||||
@@ -99,7 +76,7 @@ pub struct Cli {
|
||||
|
||||
/// Select topology (overrides config topology)
|
||||
#[arg(short = 't', long = "topology", value_enum)]
|
||||
pub topology: Option<TopologyArg>,
|
||||
pub topology: Option<crate::types::Topology>,
|
||||
|
||||
/// Present but non-functional; returns unimplemented error
|
||||
#[arg(short = 'f', long = "force")]
|
||||
|
||||
@@ -271,8 +271,8 @@ fn cli_overlay_value(cli: &Cli) -> Value {
|
||||
root.insert("device_selection".into(), Value::Object(device_selection));
|
||||
}
|
||||
|
||||
// topology override via --topology
|
||||
if let Some(t) = cli.topology {
|
||||
// topology override via --topology (avoid moving out of borrowed field)
|
||||
if let Some(t) = cli.topology.as_ref() {
|
||||
root.insert("topology".into(), Value::String(t.to_string()));
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// api: fs::FsPlan { specs: Vec<FsSpec> }
|
||||
// api: fs::FsResult { kind: FsKind, devices: Vec<String>, uuid: String, label: String }
|
||||
// api: fs::plan_filesystems(parts: &[crate::partition::PartitionResult], cfg: &crate::config::types::Config) -> crate::Result<FsPlan>
|
||||
// api: fs::make_filesystems(plan: &FsPlan) -> crate::Result<Vec<FsResult>>
|
||||
// api: fs::make_filesystems(plan: &FsPlan, cfg: &crate::types::Config) -> crate::Result<Vec<FsResult>>
|
||||
// REGION: API-END
|
||||
//
|
||||
// REGION: RESPONSIBILITIES
|
||||
@@ -206,7 +206,7 @@ pub fn plan_filesystems(
|
||||
/// - This initial implementation applies labels and creates filesystems with minimal flags.
|
||||
/// - Btrfs RAID profile (e.g., raid1) will be applied in a follow-up by mapping config to mkfs flags.
|
||||
/// - UUID is captured via blkid -o export on the first device of each spec.
|
||||
pub fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>> {
|
||||
pub fn make_filesystems(plan: &FsPlan, cfg: &Config) -> Result<Vec<FsResult>> {
|
||||
// Discover required tools up-front
|
||||
let vfat_tool = which_tool("mkfs.vfat")?;
|
||||
let btrfs_tool = which_tool("mkfs.btrfs")?;
|
||||
@@ -289,9 +289,12 @@ pub fn make_filesystems(plan: &FsPlan) -> Result<Vec<FsResult>> {
|
||||
if spec.devices.is_empty() {
|
||||
return Err(Error::Filesystem("bcachefs requires at least one device".into()));
|
||||
}
|
||||
// bcachefs format --label LABEL dev_cache dev_backing ... (single-device also supported)
|
||||
// TODO(fs): map compression/checksum/cache-mode and data/metadata replica flags in a follow-up.
|
||||
// bcachefs format --label LABEL [--replicas=2] dev1 [dev2 ...]
|
||||
// Apply replicas policy for Bcachefs2Copy topology (data+metadata replicas = 2)
|
||||
let mut args: Vec<String> = vec![mkfs.clone(), "format".into(), "--label".into(), spec.label.clone()];
|
||||
if matches!(cfg.topology, Topology::Bcachefs2Copy) {
|
||||
args.push("--replicas=2".into());
|
||||
}
|
||||
args.extend(spec.devices.iter().cloned());
|
||||
let args_ref: Vec<&str> = args.iter().map(|s| s.as_str()).collect();
|
||||
run_cmd(&args_ref)?;
|
||||
|
||||
@@ -198,7 +198,7 @@ pub fn run(ctx: &Context) -> Result<()> {
|
||||
// Filesystem planning and creation
|
||||
let fs_plan = zfs::plan_filesystems(&part_results, &ctx.cfg)?;
|
||||
info!("orchestrator: filesystem plan contains {} spec(s)", fs_plan.specs.len());
|
||||
let fs_results = zfs::make_filesystems(&fs_plan)?;
|
||||
let fs_results = zfs::make_filesystems(&fs_plan, &ctx.cfg)?;
|
||||
info!("orchestrator: created {} filesystem(s)", fs_results.len());
|
||||
|
||||
// Mount planning and application
|
||||
@@ -345,7 +345,7 @@ fn build_summary_json(disks: &[Disk], plan: &partition::PartitionPlan, cfg: &Con
|
||||
crate::types::Topology::BcachefsSingle => "bcachefs_single",
|
||||
crate::types::Topology::DualIndependent => "dual_independent",
|
||||
crate::types::Topology::SsdHddBcachefs => "ssd_hdd_bcachefs",
|
||||
crate::types::Topology::Bcachefs2Copy => "bcachefs_2copy",
|
||||
crate::types::Topology::Bcachefs2Copy => "bcachefs2_copy",
|
||||
crate::types::Topology::BtrfsRaid1 => "btrfs_raid1",
|
||||
};
|
||||
|
||||
|
||||
40
src/types.rs
40
src/types.rs
@@ -2,8 +2,21 @@
|
||||
//!
|
||||
//! Mirrors docs in [docs/SCHEMA.md](docs/SCHEMA.md) and is loaded/validated by
|
||||
//! [fn load_and_merge()](src/config/loader.rs:1) and [fn validate()](src/config/loader.rs:1).
|
||||
//
|
||||
// REGION: API
|
||||
// api: types::Topology { BtrfsSingle, BcachefsSingle, DualIndependent, Bcachefs2Copy, SsdHddBcachefs, BtrfsRaid1 }
|
||||
// api: types::Config { logging, device_selection, topology, partitioning, filesystem, mount, report }
|
||||
// api: types::Partitioning { alignment_mib, require_empty_disks, bios_boot, esp, data, cache }
|
||||
// api: types::FsOptions { btrfs, bcachefs, vfat }
|
||||
// REGION: API-END
|
||||
//
|
||||
// REGION: RESPONSIBILITIES
|
||||
// - Define serde-serializable configuration types and enums used across modules.
|
||||
// - Keep field names and enums stable; update docs/SCHEMA.md when public surface changes.
|
||||
// REGION: RESPONSIBILITIES-END
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use clap::ValueEnum;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LoggingConfig {
|
||||
@@ -25,23 +38,44 @@ pub struct DeviceSelection {
|
||||
pub min_size_gib: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, ValueEnum)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
#[value(rename_all = "snake_case")]
|
||||
pub enum Topology {
|
||||
/// Single eligible disk; btrfs on remainder.
|
||||
#[value(alias = "btrfs-single")]
|
||||
BtrfsSingle,
|
||||
/// Single eligible disk; bcachefs on remainder.
|
||||
#[value(alias = "bcachefs-single")]
|
||||
BcachefsSingle,
|
||||
/// Two eligible disks; independent btrfs on each data partition.
|
||||
/// Independent btrfs filesystems on each data partition (any number of disks).
|
||||
#[value(alias = "dual-independent")]
|
||||
DualIndependent,
|
||||
/// SSD + HDD; bcachefs with SSD cache/promote and HDD backing.
|
||||
#[value(alias = "ssd-hdd-bcachefs")]
|
||||
SsdHddBcachefs,
|
||||
/// Two-disk bcachefs layout using both data partitions (2 copies semantics).
|
||||
/// Multi-device bcachefs with two replicas (data+metadata).
|
||||
#[value(alias = "bcachefs2-copy", alias = "bcachefs-2copy", alias = "bcachefs-2-copy")]
|
||||
Bcachefs2Copy,
|
||||
/// Optional mirrored btrfs across two disks when explicitly requested.
|
||||
#[value(alias = "btrfs-raid1")]
|
||||
BtrfsRaid1,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Topology {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
Topology::BtrfsSingle => "btrfs_single",
|
||||
Topology::BcachefsSingle => "bcachefs_single",
|
||||
Topology::DualIndependent => "dual_independent",
|
||||
Topology::SsdHddBcachefs => "ssd_hdd_bcachefs",
|
||||
Topology::Bcachefs2Copy => "bcachefs2_copy",
|
||||
Topology::BtrfsRaid1 => "btrfs_raid1",
|
||||
};
|
||||
f.write_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BiosBootSpec {
|
||||
/// Whether to create a tiny BIOS boot partition.
|
||||
|
||||
Reference in New Issue
Block a user