Add Fruix bootable installer environment
This commit is contained in:
@@ -1,5 +1,97 @@
|
||||
# Progress
|
||||
|
||||
## 2026-04-04 — Phase 18.2 completed: Fruix now boots a minimal installer environment and installs a target system from inside it
|
||||
|
||||
Completed work:
|
||||
|
||||
- added in `modules/fruix/system/freebsd.scm`:
|
||||
- `installer-operating-system`
|
||||
- `operating-system-installer-image-spec`
|
||||
- `materialize-installer-image`
|
||||
- the installer environment is now derived from the selected target operating system, while forcing the currently most stable installer boot path:
|
||||
- `freebsd-init+rc.d-shepherd`
|
||||
- the installer image now carries:
|
||||
- its own installer-system closure
|
||||
- the selected target-system closure
|
||||
- the selected target-system store closure
|
||||
- a staged target rootfs 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 now performs the install from inside the guest by:
|
||||
- partitioning the selected target disk
|
||||
- creating EFI + UFS filesystems
|
||||
- copying the staged target rootfs
|
||||
- copying only the selected target system's required store items into the target `/frx/store`
|
||||
- installing the target `loader.efi`
|
||||
- writing target install metadata to:
|
||||
- `/var/lib/fruix/install.scm`
|
||||
- recording installer state in:
|
||||
- `/var/lib/fruix/installer/state`
|
||||
- logging to:
|
||||
- `/var/log/fruix-installer.log`
|
||||
- added user-facing CLI support in `scripts/fruix.scm`:
|
||||
- `fruix system installer`
|
||||
- new option:
|
||||
- `--install-target-device DEVICE`
|
||||
- corrected the default FreeBSD virtio install target device for QEMU validation to:
|
||||
- `/dev/vtbd1`
|
||||
rather than the earlier incorrect Linux-flavored guess:
|
||||
- `/dev/vtblk1`
|
||||
- fixed `materialize-bhyve-image` so the generated UFS filesystem label now respects:
|
||||
- `root-partition-label`
|
||||
rather than always hardcoding:
|
||||
- `fruix-root`
|
||||
- added validation artifacts:
|
||||
- `tests/system/phase18-installer-target-operating-system.scm.in`
|
||||
- `tests/system/run-phase18-installer-environment.sh`
|
||||
- wrote:
|
||||
- `docs/reports/phase18-installer-environment-freebsd.md`
|
||||
|
||||
Validation:
|
||||
|
||||
- `PASS phase18-installer-environment`
|
||||
- regression re-checks:
|
||||
- `PASS phase18-system-install`
|
||||
- `PASS phase17-source-revisions-qemu`
|
||||
- validated a full two-disk workflow:
|
||||
- booted Fruix installer image under QEMU/UEFI/TCG
|
||||
- installer environment became reachable over SSH
|
||||
- installer environment completed in-guest install with:
|
||||
- `installer_state=done`
|
||||
- installer log recorded:
|
||||
- `fruix-installer:done`
|
||||
- installed target disk contained:
|
||||
- GPT partition table
|
||||
- ESP filesystem:
|
||||
- `msdosfs`
|
||||
- root filesystem:
|
||||
- `ufs`
|
||||
- `EFI/BOOT/BOOTX64.EFI`
|
||||
- `/var/lib/fruix/install.scm`
|
||||
- validated source-driven provenance through the installer environment from:
|
||||
- Git ref:
|
||||
- `stable/15`
|
||||
- pinned commit:
|
||||
- `332708a606f6bf0841c1d4a74c0d067f5640fe89`
|
||||
- materialized source store:
|
||||
- `/frx/store/7563df2714ae7fa9bd40b83c74512ffe2cb2ad91b297915591b55c76edbb2fcb-freebsd-source-stable15-installer-target-source`
|
||||
- validated boot of the installed target after in-guest installation:
|
||||
- `/run/current-system` points at the installed target closure
|
||||
- `/usr/local/etc/rc.d/fruix-shepherd onestatus` reports running
|
||||
- `sshd` running
|
||||
- activation completed successfully
|
||||
|
||||
Current assessment:
|
||||
|
||||
- Phase 18.2 is complete
|
||||
- Fruix now has a minimal Fruix-managed installer environment, not just a host-driven installation primitive
|
||||
- the next step is Phase 18.3:
|
||||
- produce a bootable installer ISO for UEFI systems
|
||||
|
||||
## 2026-04-03 — Phase 18.1 completed: Fruix now has a minimal non-interactive installation flow
|
||||
|
||||
Completed work:
|
||||
|
||||
@@ -32,6 +32,7 @@ Completed milestones include:
|
||||
- **Source-driven boot validation**: Fruix can now also boot systems built from distinct declared FreeBSD source revisions while preserving those source identities in image/build metadata.
|
||||
- **Explicit source policy**: the repo now records how FreeBSD source objects are fetched, cached, identified, invalidated, and consumed by native base builds in `docs/freebsd-source-policy.md`.
|
||||
- **Minimal installation workflow**: Fruix now has a non-interactive `fruix system install` path that can partition, format, populate, and boot a target image or disk from a declarative system closure.
|
||||
- **Minimal installer environment**: Fruix can now also build and boot a dedicated installer image that carries a selected target closure, installs it onto a second disk from inside the guest, and leaves the installed target bootable.
|
||||
- **Base upgrade story**: Fruix can now keep distinct declared base versions side by side in `/frx/store` and roll forward / back between them through the normal system deployment flow.
|
||||
|
||||
## Major pain points now behind us
|
||||
@@ -46,7 +47,7 @@ Completed milestones include:
|
||||
## Major pain points still ahead
|
||||
|
||||
- **True store-native runtime artifacts**: some historical build/install prefixes are still embedded in binaries and metadata. They are no longer required at runtime, but the local Guile/guile-extra/Shepherd build/install flow should still be moved to a genuinely store-native prefix from the start.
|
||||
- **Installer environment**: Fruix now has a host-driven non-interactive install path, but it still lacks a dedicated Fruix-managed installer environment that can boot into an install context and run that workflow from within the target environment.
|
||||
- **Installer media beyond disk images**: Fruix now has both a host-driven install path and a bootable installer environment, but it still lacks a UEFI installer ISO and a more polished operator-facing installation medium.
|
||||
- **Boot-path simplification**: Fruix now supports both the legacy `freebsd-init+rc.d-shepherd` path and the more Guix-like `shepherd-pid1` path. We still need to decide whether Shepherd PID 1 becomes the preferred/default architecture.
|
||||
- **Reduce transitional FreeBSD glue**: more of the current bootstrap/activation/runtime setup should become cleaner and less prototype-specific over time.
|
||||
- **Tooling and platform constraints**: local bhyve remains blocked by missing nested virtualization under Xen, and XO permissions still prevent creating/importing new VDIs; current validation must keep reusing the approved VM/VDI path.
|
||||
@@ -54,4 +55,4 @@ Completed milestones include:
|
||||
|
||||
## Bottom line
|
||||
|
||||
Fruix has crossed the most important threshold: it is no longer just a collection of isolated FreeBSD experiments. It can now build declarative FreeBSD system artifacts, boot them on the real target VM, reach the network, serve SSH, run Shepherd as PID 1, operate from `/frx` without depending on temporary runtime-prefix shims, build native FreeBSD base artifacts into `/frx/store`, roll forward / back between declared base versions, materialize declared FreeBSD source inputs into `/frx/store`, drive native base builds from those materialized source snapshots, boot systems from distinct source revisions, explain the source provenance/invalidation rules explicitly, and install a declarative system onto a target image through a repeatable Fruix workflow. The biggest remaining work is no longer “can this build/install at all?” but “how does this become a fuller installer/deployment/generation story?”
|
||||
Fruix has crossed the most important threshold: it is no longer just a collection of isolated FreeBSD experiments. It can now build declarative FreeBSD system artifacts, boot them on the real target VM, reach the network, serve SSH, run Shepherd as PID 1, operate from `/frx` without depending on temporary runtime-prefix shims, build native FreeBSD base artifacts into `/frx/store`, roll forward / back between declared base versions, materialize declared FreeBSD source inputs into `/frx/store`, drive native base builds from those materialized source snapshots, boot systems from distinct source revisions, explain the source provenance/invalidation rules explicitly, install a declarative system onto a target image through a repeatable Fruix workflow, and boot a dedicated Fruix-managed installer environment that performs that installation from inside the guest. The biggest remaining work is no longer “can this build/install at all?” but “how does this become a fuller installer/deployment/generation/installer-media story?”
|
||||
|
||||
191
docs/reports/phase18-installer-environment-freebsd.md
Normal file
191
docs/reports/phase18-installer-environment-freebsd.md
Normal 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.
|
||||
Reference in New Issue
Block a user