aboutsummaryrefslogtreecommitdiff
path: root/installer
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-12 23:58:01 -0400
committerCraig Jennings <c@cjennings.net>2026-04-12 23:58:01 -0400
commit19f4624749228fcbe385d1edf1d2542c036440ff (patch)
tree961e815d2226178345f5ec7ec7cb82f23da34379 /installer
parent863ceeac8fdb10258a58d35bcee6874097fffc88 (diff)
downloadarchangel-19f4624749228fcbe385d1edf1d2542c036440ff.tar.gz
archangel-19f4624749228fcbe385d1edf1d2542c036440ff.zip
refactor: extract pure RAID logic to lib/raid.sh with bats coverage
Peel the testable pieces of get_raid_level() out of the 1600-line installer monolith into installer/lib/raid.sh: - raid_valid_levels_for_count(count) — replaces the inline option-list builder in get_raid_level() - raid_is_valid(level, count) — useful for unattended-config validation - raid_usable_bytes(level, count, smallest, total) — usable-space math - raid_fault_tolerance(level, count) — max tolerable disk failures archangel now sources lib/raid.sh and uses raid_valid_levels_for_count for the fzf option list. Fzf preview subshell still inlines its own usable-bytes arithmetic (calling exported lib functions across preview subshells is fragile; left for a later pass). 30 bats tests in tests/unit/test_raid.bats cover the full enumeration table, every valid/invalid level-vs-count combo from 2 to 5 disks, mixed-size mirror, and unknown-level error paths. make test: 53/53.
Diffstat (limited to 'installer')
-rwxr-xr-xinstaller/archangel11
-rw-r--r--installer/lib/raid.sh70
2 files changed, 75 insertions, 6 deletions
diff --git a/installer/archangel b/installer/archangel
index 615829d..d1831cf 100755
--- a/installer/archangel
+++ b/installer/archangel
@@ -29,6 +29,7 @@ source "$SCRIPT_DIR/lib/common.sh"
source "$SCRIPT_DIR/lib/config.sh"
source "$SCRIPT_DIR/lib/disk.sh"
source "$SCRIPT_DIR/lib/btrfs.sh"
+source "$SCRIPT_DIR/lib/raid.sh"
#############################
# Configuration
@@ -368,18 +369,16 @@ get_raid_level() {
local total_gb=$((total_bytes / 1073741824))
local smallest_gb=$((smallest_bytes / 1073741824))
- # Build options based on disk count
- local options="mirror\nstripe"
- [[ $disk_count -ge 3 ]] && options+="\nraidz1"
- [[ $disk_count -ge 4 ]] && options+="\nraidz2"
- [[ $disk_count -ge 5 ]] && options+="\nraidz3"
+ # Build options based on disk count (pure logic → lib/raid.sh)
+ local options
+ options=$(raid_valid_levels_for_count "$disk_count")
# Export variables for preview subshell
export RAID_DISK_COUNT=$disk_count
export RAID_TOTAL_GB=$total_gb
export RAID_SMALLEST_GB=$smallest_gb
- RAID_LEVEL=$(echo -e "$options" \
+ RAID_LEVEL=$(echo "$options" \
| fzf --height=20 --layout=reverse --border \
--header="Select RAID Level ($disk_count disks, ${total_gb}GB total)" \
--preview='
diff --git a/installer/lib/raid.sh b/installer/lib/raid.sh
new file mode 100644
index 0000000..3e28177
--- /dev/null
+++ b/installer/lib/raid.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+# raid.sh - Pure RAID-level logic (testable, no I/O).
+# Source after common.sh.
+
+#############################
+# Valid-level enumeration
+#############################
+
+# Print valid RAID levels for a given disk count, one per line.
+# Count <2: nothing printed (single disk = no RAID).
+# Count 2: mirror, stripe
+# Count 3+: + raidz1
+# Count 4+: + raidz2
+# Count 5+: + raidz3
+raid_valid_levels_for_count() {
+ local count=$1
+ [[ $count -lt 2 ]] && return 0
+ echo mirror
+ echo stripe
+ [[ $count -ge 3 ]] && echo raidz1
+ [[ $count -ge 4 ]] && echo raidz2
+ [[ $count -ge 5 ]] && echo raidz3
+ return 0
+}
+
+# Return 0 if level is valid for the given disk count, 1 otherwise.
+# Empty level with count 1 is valid (no RAID).
+raid_is_valid() {
+ local level=$1 count=$2
+ if [[ $count -le 1 ]]; then
+ [[ -z "$level" ]]
+ return
+ fi
+ raid_valid_levels_for_count "$count" | grep -qxF "$level"
+}
+
+#############################
+# Usable-space computation
+#############################
+
+# Print usable bytes for a level given disk count, smallest-disk bytes,
+# and total bytes across all disks. Writes nothing and returns 1 for
+# unknown levels.
+#
+# Usage: raid_usable_bytes LEVEL COUNT SMALLEST_BYTES TOTAL_BYTES
+raid_usable_bytes() {
+ local level=$1 count=$2 smallest=$3 total=$4
+ case "$level" in
+ mirror) echo "$smallest" ;;
+ stripe) echo "$total" ;;
+ raidz1) echo $(( (count - 1) * smallest )) ;;
+ raidz2) echo $(( (count - 2) * smallest )) ;;
+ raidz3) echo $(( (count - 3) * smallest )) ;;
+ *) return 1 ;;
+ esac
+}
+
+# Print fault-tolerance (max number of disks that can fail) for a level
+# at the given disk count. Unknown level → return 1.
+raid_fault_tolerance() {
+ local level=$1 count=$2
+ case "$level" in
+ mirror) echo $(( count - 1 )) ;;
+ stripe) echo 0 ;;
+ raidz1) echo 1 ;;
+ raidz2) echo 2 ;;
+ raidz3) echo 3 ;;
+ *) return 1 ;;
+ esac
+}