Add Fruix bootable installer environment

This commit is contained in:
2026-04-04 03:09:25 +02:00
parent 2517710282
commit 1d0090752d
7 changed files with 1313 additions and 24 deletions

View File

@@ -0,0 +1,191 @@
# Phase 18.2: minimal Fruix-managed installer environment on FreeBSD
Date: 2026-04-04
## Goal
Phase 18.2 builds on the Phase 18.1 host-driven install primitive.
The goal here is not a polished live installer. The goal is a small Fruix-managed environment that can:
- boot as its own Fruix system,
- carry a selected target Fruix system closure and rootfs payload,
- install that target system onto a second disk from inside the booted environment,
- and leave the installed target bootable.
## Implementation
### New installer-environment API
Added in `modules/fruix/system/freebsd.scm`:
- `installer-operating-system`
- `operating-system-installer-image-spec`
- `materialize-installer-image`
The installer environment is derived from the selected target operating system, but with installer-specific behavior:
- host name defaults to:
- `<target-host-name>-installer`
- init mode is kept on the currently most stable installer path:
- `freebsd-init+rc.d-shepherd`
- the installer image root label is distinct:
- `fruix-installer-root`
- `sshd` is enabled for operator/debug access
- installer accounts needed for SSH/DHCP are ensured if absent:
- `sshd`
- `_dhcp`
### Bootable installer image contents
`materialize-installer-image` now produces a bootable image that contains:
- the installer system closure and its runtime store closure
- the selected target system closure
- the selected target system's referenced store items
- a prebuilt target rootfs tree staged under:
- `/var/lib/fruix/installer/target-rootfs`
- installer plan/state files under:
- `/var/lib/fruix/installer`
- installer helper scripts:
- `/usr/local/libexec/fruix-installer-run`
- `/usr/local/etc/rc.d/fruix-installer`
The booted installer environment runs a background rc.d job that:
- partitions the selected target disk
- creates EFI + UFS filesystems
- copies the staged target rootfs onto the target
- copies only the target system's required store items into the target `/frx/store`
- installs the target's `loader.efi`
- writes `/var/lib/fruix/install.scm` on the target
- records installer state in:
- `/var/lib/fruix/installer/state`
- logs to:
- `/var/log/fruix-installer.log`
### New CLI action
Added in `scripts/fruix.scm`:
- `fruix system installer`
Added option:
- `--install-target-device DEVICE`
This action materializes a bootable installer image in `/frx/store` and emits metadata for:
- installer image paths
- installer closure path
- target closure path
- target install device
- installer state/log paths
- declared/materialized FreeBSD source metadata
- target/native/runtime store metadata
### FreeBSD virtio target-device detail
A practical detail surfaced during validation:
- the correct FreeBSD virtio block device node for the second QEMU disk is:
- `/dev/vtbd1`
The earlier Linux-flavored guess:
- `/dev/vtblk1`
was wrong for the actual FreeBSD device node namespace in this environment.
The installer defaults were updated accordingly.
### Small image-builder correctness fix
While doing this work I also fixed `materialize-bhyve-image` so its generated UFS filesystem label respects the requested:
- `root-partition-label`
instead of always hardcoding:
- `fruix-root`
This matters for the installer image because it needs a distinct root label while the target disk still uses the normal target label.
## Validation
Added validation artifacts:
- `tests/system/phase18-installer-target-operating-system.scm.in`
- `tests/system/run-phase18-installer-environment.sh`
Passing validations:
- `PASS phase18-installer-environment`
- regression re-check:
- `PASS phase18-system-install`
- regression re-check:
- `PASS phase17-source-revisions-qemu`
Validated installer-environment result:
```text
installer_image_store_path=/frx/store/fb038dbf5dac2ad1bb767a264d3a268915f489b936dc5dd32425645102d3da48-fruix-installer-image-fruix-freebsd-installer
installer_disk_image=/frx/store/fb038dbf5dac2ad1bb767a264d3a268915f489b936dc5dd32425645102d3da48-fruix-installer-image-fruix-freebsd-installer/disk.img
installer_disk_capacity=16g
installer_root_size=14g
target_disk_capacity=12g
install_target_device=/dev/vtbd1
installer_closure_path=/frx/store/ea821f20b579684877fdc86a2a1e80485cf2b12d9d32f74f42e368d738c2ad4d-fruix-system-fruix-freebsd-installer
target_closure_path=/frx/store/7ee225db532b6973e385f8507d2d61aec3cd3aeb0864f983c2ae4b6e149ef3b0-fruix-system-fruix-freebsd
freebsd_source_kind=git
freebsd_source_ref=stable/15
freebsd_source_commit=332708a606f6bf0841c1d4a74c0d067f5640fe89
materialized_source_store=/frx/store/7563df2714ae7fa9bd40b83c74512ffe2cb2ad91b297915591b55c76edbb2fcb-freebsd-source-stable15-installer-target-source
installer_state=done
installer_sshd_status=running
target_esp_fstype=msdosfs
target_root_fstype=ufs
target_shepherd_status=running
target_sshd_status=running
installer_environment_boot=ok
installer_environment_install=ok
installed_target_boot=ok
```
The harness verified all of the following:
1. `fruix system installer` produces a bootable installer image in `/frx/store`
2. validation boots a workdir copy of that installer disk image so the store artifact itself is not mutated during the boot/install run
3. the installer environment boots successfully under QEMU/UEFI/TCG
4. the installer environment becomes reachable over SSH
5. `/run/current-system` inside the installer environment points at the installer closure
6. the installer rc.d job reaches:
- `state=done`
7. the installer log records:
- `fruix-installer:done`
8. the target raw disk is transformed into a valid GPT-installed Fruix target with:
- EFI filesystem: `msdosfs`
- root filesystem: `ufs`
- `EFI/BOOT/BOOTX64.EFI` present
- `/var/lib/fruix/install.scm` present
9. the installed target then boots successfully as its own Fruix system under QEMU/UEFI/TCG
10. after target boot:
- `/run/current-system` points at the target closure
- `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running
- `sshd` is running
- activation completed successfully
## Result
Phase 18.2 is complete.
Fruix now has a real installer substrate on FreeBSD:
- a bootable Fruix-managed installer image
- a target closure bundled inside that installer environment
- in-guest non-interactive installation onto a second disk
- validated boot of the installed result
The next step is Phase 18.3:
- produce a bootable installer ISO for UEFI systems, rather than only a disk-image-style installer environment.