diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index fe3fb8e..605df58 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -3328,3 +3328,122 @@ Next recommended step: 1. define cleaner runtime vs. development boundaries in code/package sets 2. introduce a narrower native boot asset package so the broader native world output is no longer needed as the temporary boot-source store 3. revalidate the full host-base-free path after that split + +## 2026-04-03 — Phase 14.3: split native FreeBSD boot, runtime, and development artifacts + +Completed work: + +- wrote the Phase 14.3 report: + - `docs/reports/phase14-native-splits-freebsd.md` +- added new native packages in `modules/fruix/packages/freebsd.scm`: + - `freebsd-native-bootloader` + - `freebsd-native-headers` +- refined `freebsd-native-runtime` into a narrower runtime slice by pruning more obviously non-runtime content, including at least: + - `boot` + - `rescue` + - `usr/include` + - `usr/lib/debug` + - `usr/lib32` + - `usr/obj` + - `usr/src` + - `usr/share/doc` + - `usr/share/examples` + - `usr/share/info` + - `usr/share/man` + - `usr/share/mk` + - `usr/tests` +- extended the native world-derived build path in `modules/fruix/system/freebsd.scm` with support for: + - `keep-paths` +- native build manifests/output metadata now record both: + - `keep-paths` + - `prune-paths` +- added explicit native package-set boundaries: + - `%freebsd-native-system-packages` + - `%freebsd-native-development-profile-packages` +- the final validated Phase 14 system template now uses: + - `#:kernel freebsd-native-kernel` + - `#:bootloader freebsd-native-bootloader` + - `#:base-packages %freebsd-native-system-packages` +- this removes the need for the broad `freebsd-native-world` artifact from the final validated system closure + +New validation files: + +- `tests/system/phase14-native-split-pid1-operating-system.scm.in` +- `tests/system/run-phase14-native-split-qemu.sh` +- `tests/system/run-phase14-native-split-xcpng.sh` +- `tests/system/run-phase14-native-development-split.sh` + +Validation: + +- development/runtime split harness passes: + - `tests/system/run-phase14-native-development-split.sh` + - workdir: `/tmp/phase14-3-dev5-1775191195` + - result: `PASS phase14-native-development-split` + - confirmed: + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `headers_store=/frx/store/aab09122d37962e6d479c17172ce4b8ea85e5ff33c98aa76424ada2fa1a82617-freebsd-native-headers-15.0-STABLE` + - `native_system_packages=freebsd-native-runtime` + - `native_development_packages=freebsd-native-runtime,freebsd-native-headers,freebsd-clang-toolchain,freebsd-gmake,freebsd-autotools,freebsd-openssl,freebsd-zlib,freebsd-sh,freebsd-bash` + - `runtime_vs_development_split=ok` + - the harness also confirmed: + - bootloader slice contains the expected boot assets only + - headers slice contains headers/mk files + - headers slice does not contain `/boot` or runtime binaries +- final split-system local QEMU validation passes: + - `tests/system/run-phase14-native-split-qemu.sh` + - workdir: `/tmp/phase14-3-qemu-1775191337` + - result: `PASS phase14-native-split-qemu` + - confirmed: + - `disk_capacity=8g` + - `root_size=6g` + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `native_split_boot=ok` +- final split-system real XCP-ng validation passes: + - `tests/system/run-phase14-native-split-xcpng.sh` + - workdir: `/tmp/phase14-3-xcpng-1775191743` + - result: `PASS phase14-native-split-xcpng` + - confirmed: + - `vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289` + - `vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743` + - `guest_ip=192.168.213.62` + - `root_size=6g` + - `bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE` + - `runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE` + - `native_base_store_count=3` + - `host_base_store_count=0` + - `shepherd_pid=1` + - `sshd_status=running` + - `compat_prefix_shims=absent` + - `guile_module_smoke=ok` + - `native_split_boot=ok` + +Important findings: + +- after replacing the temporary broad-world boot source with the narrower native bootloader slice and tightening the runtime slice, the validated image became much smaller again +- the real XCP-ng dynamic VHD upload for the final split path was: + - `1560725504` bytes (~1.45 GiB) +- that is far better than the temporary broad-world + runtime duplication in Phase 14.2 +- the final validated Phase 14 closure no longer needs the broad `freebsd-native-world` artifact in its native base store set + +Current assessment: + +- Phase 14 is complete +- Fruix now has a validated, host-base-free FreeBSD system path composed from native artifacts in `/frx/store`: + - `freebsd-native-kernel` + - `freebsd-native-bootloader` + - `freebsd-native-runtime` +- the runtime vs. development boundary is also clearer now through: + - `freebsd-native-headers` + - `%freebsd-native-development-profile-packages` +- this completes the Plan-3 Phase-14 goal of incrementally replacing the host-copy FreeBSD base layer for the validated boot/runtime path + +Next recommended step: + +1. begin Phase 15 by making the FreeBSD base version a declarative Fruix input +2. demonstrate side-by-side native base versions in `/frx/store` +3. validate rebuild/redeploy/rollback across those base versions diff --git a/docs/reports/phase14-native-splits-freebsd.md b/docs/reports/phase14-native-splits-freebsd.md new file mode 100644 index 0000000..194a323 --- /dev/null +++ b/docs/reports/phase14-native-splits-freebsd.md @@ -0,0 +1,225 @@ +# Phase 14.3: split native FreeBSD boot, runtime, and development artifacts + +Date: 2026-04-03 + +## Goal + +Phase 14.3 finished the Phase 14 cleanup work by replacing the temporary broad-world reuse with narrower native artifacts and by making the runtime/development boundary explicit in code. + +The target was: + +- no host-staged FreeBSD base stores in the validated path +- no need to keep the broad `freebsd-native-world` artifact in the final validated system closure +- explicit native boot and runtime slices +- clearer development-profile boundaries + +## Implementation + +### New native packages + +Added in `modules/fruix/packages/freebsd.scm`: + +- `freebsd-native-bootloader` +- `freebsd-native-headers` + +Also refined: + +- `freebsd-native-runtime` + +### Narrower native runtime slice + +`freebsd-native-runtime` now prunes more obviously non-runtime content, including at least: + +- `boot` +- `rescue` +- `usr/include` +- `usr/lib/debug` +- `usr/lib32` +- `usr/obj` +- `usr/src` +- `usr/share/doc` +- `usr/share/examples` +- `usr/share/info` +- `usr/share/man` +- `usr/share/mk` +- `usr/tests` + +This shrank the runtime output substantially and made the runtime/development distinction much cleaner. + +### Native bootloader slice + +`freebsd-native-bootloader` is now a native world-derived slice that keeps only the validated boot assets Fruix currently needs: + +- `boot/loader` +- `boot/loader.efi` +- `boot/device.hints` +- `boot/defaults` +- `boot/lua` + +### Native headers slice + +`freebsd-native-headers` now captures the development-facing header/mk boundary explicitly: + +- `usr/include` +- `usr/share/mk` + +### Build-system support for sliced native outputs + +`modules/fruix/system/freebsd.scm` gained support for `keep-paths` on native world-derived packages. + +That means a native package can now: + +- install full world/distribution into a staging tree +- keep only selected subtrees/files for its final store output +- still participate in the same `/usr/src`-based identity/build-root story + +Native output metadata now records both: + +- `keep-paths` +- `prune-paths` + +## New package-set boundaries + +Added explicit package sets: + +- `%freebsd-native-system-packages` + - currently centered on `freebsd-native-runtime` +- `%freebsd-native-development-profile-packages` + - `freebsd-native-runtime` + - `freebsd-native-headers` + - explicit toolchain/dev helpers that remain separate artifacts + +This makes the boundary clearer: + +- runtime world output +- headers artifact +- toolchain artifact(s) +- optional development profile composition + +## Final validated Phase 14 system model + +The final Phase 14 PID1 system template now uses: + +- `#:kernel freebsd-native-kernel` +- `#:bootloader freebsd-native-bootloader` +- `#:base-packages %freebsd-native-system-packages` + +That means the validated system closure now contains: + +- native kernel +- native bootloader slice +- native runtime slice +- Fruix runtime stores + +and no longer needs the broad `freebsd-native-world` artifact in the final system closure. + +## New files + +Added: + +- `tests/system/phase14-native-split-pid1-operating-system.scm.in` +- `tests/system/run-phase14-native-split-qemu.sh` +- `tests/system/run-phase14-native-split-xcpng.sh` +- `tests/system/run-phase14-native-development-split.sh` + +## Validation + +### Development split validation + +Passing run: + +- `PASS phase14-native-development-split` +- workdir: `/tmp/phase14-3-dev5-1775191195` + +Confirmed: + +```text +bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE +headers_store=/frx/store/aab09122d37962e6d479c17172ce4b8ea85e5ff33c98aa76424ada2fa1a82617-freebsd-native-headers-15.0-STABLE +native_system_packages=freebsd-native-runtime +native_development_packages=freebsd-native-runtime,freebsd-native-headers,freebsd-clang-toolchain,freebsd-gmake,freebsd-autotools,freebsd-openssl,freebsd-zlib,freebsd-sh,freebsd-bash +runtime_vs_development_split=ok +``` + +The harness also confirmed: + +- native bootloader slice contains only expected boot assets +- native headers slice contains headers/mk files +- native headers slice does not contain `/boot` or runtime binaries + +### Local QEMU / UEFI / TCG + +Passing run: + +- `PASS phase14-native-split-qemu` +- workdir: `/tmp/phase14-3-qemu-1775191337` + +Confirmed: + +```text +disk_capacity=8g +root_size=6g +bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE +runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE +native_base_store_count=3 +host_base_store_count=0 +shepherd_pid=1 +sshd_status=running +native_split_boot=ok +``` + +### Real XCP-ng VM + +Passing run: + +- `PASS phase14-native-split-xcpng` +- workdir: `/tmp/phase14-3-xcpng-1775191743` + +Confirmed: + +```text +vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289 +vdi_id=0f1f90d3-48ca-4fa2-91d8-fc6339b95743 +guest_ip=192.168.213.62 +root_size=6g +bootloader_store=/frx/store/71aa3ba5dd9a02f7d2710bfc3624cbf5e3cd18f1fbff0744c82df36901b10ec0-freebsd-native-bootloader-15.0-STABLE +runtime_store=/frx/store/1b4b8774d0df36df2635fe1c35367a2c5fa7790e303f0aaa26eabfe3cce667f2-freebsd-native-runtime-15.0-STABLE +native_base_store_count=3 +host_base_store_count=0 +shepherd_pid=1 +sshd_status=running +compat_prefix_shims=absent +guile_module_smoke=ok +native_split_boot=ok +``` + +Notably, after the narrower native split, the XCP-ng upload size dropped back down dramatically: + +- dynamic VHD upload: `1560725504` bytes (~1.45 GiB) + +That is much better than the temporary broad-world + runtime duplication in Phase 14.2. + +## Result + +Phase 14 is complete. + +Fruix now has a validated, host-base-free FreeBSD system path built from native artifacts in `/frx/store`: + +- `freebsd-native-kernel` +- `freebsd-native-bootloader` +- `freebsd-native-runtime` + +with a clearer development boundary via: + +- `freebsd-native-headers` +- `%freebsd-native-development-profile-packages` + +This completes the Phase 14 objective of incrementally replacing the host-copy FreeBSD base layer for the validated boot/runtime path. + +## Next step + +Proceed to Phase 15: + +1. make the FreeBSD base version a declarative input +2. demonstrate side-by-side base versions in `/frx/store` +3. establish rebuild/redeploy/rollback across those base versions diff --git a/modules/fruix/packages/freebsd.scm b/modules/fruix/packages/freebsd.scm index 8618ccc..e66413c 100644 --- a/modules/fruix/packages/freebsd.scm +++ b/modules/fruix/packages/freebsd.scm @@ -31,8 +31,12 @@ freebsd-native-kernel freebsd-native-world freebsd-native-runtime + freebsd-native-bootloader + freebsd-native-headers freebsd-native-build-package? freebsd-host-staged-package? + %freebsd-native-system-packages + %freebsd-native-development-profile-packages %freebsd-host-staged-all-packages %freebsd-host-staged-core-packages %freebsd-host-staged-development-profile-packages @@ -542,7 +546,12 @@ both boot and runtime roles." "MK_DEBUG_FILES=no" "MK_TESTS=no")) (prune-paths . ("boot" + "rescue" "usr/include" + "usr/lib/debug" + "usr/lib32" + "usr/obj" + "usr/src" "usr/share/doc" "usr/share/examples" "usr/share/info" @@ -550,6 +559,61 @@ both boot and runtime roles." "usr/share/mk" "usr/tests"))))) +(define freebsd-native-bootloader + (freebsd-package + #:name "freebsd-native-bootloader" + #:version freebsd-release + #:build-system 'freebsd-world-build-system + #:home-page "https://www.freebsd.org/" + #:synopsis "Native Fruix-managed FreeBSD boot asset slice" + #:description + "FreeBSD-specific package definition that stages only the loader and boot +support assets needed by the validated Fruix image path. It is the narrower +native replacement for using the broad native world output as a temporary +boot-source artifact." + #:license 'bsd-2 + #:install-plan + '((source-root . "/usr/src") + (target . "amd64") + (target-arch . "amd64") + (kernconf . "GENERIC") + (make-flags . ("__MAKE_CONF=/dev/null" + "SRCCONF=/dev/null" + "SRC_ENV_CONF=/dev/null" + "MK_DEBUG_FILES=no" + "MK_TESTS=no")) + (keep-paths . ("boot/loader" + "boot/loader.efi" + "boot/device.hints" + "boot/defaults" + "boot/lua"))))) + +(define freebsd-native-headers + (freebsd-package + #:name "freebsd-native-headers" + #:version freebsd-release + #:build-system 'freebsd-world-build-system + #:home-page "https://www.freebsd.org/" + #:synopsis "Native Fruix-managed FreeBSD headers slice" + #:description + "FreeBSD-specific package definition that stages the userland header set and +build-system support files from installworld/distribution so development +profiles can depend on an explicit headers artifact rather than on the runtime +slice." + #:license 'bsd-2 + #:install-plan + '((source-root . "/usr/src") + (target . "amd64") + (target-arch . "amd64") + (kernconf . "GENERIC") + (make-flags . ("__MAKE_CONF=/dev/null" + "SRCCONF=/dev/null" + "SRC_ENV_CONF=/dev/null" + "MK_DEBUG_FILES=no" + "MK_TESTS=no")) + (keep-paths . ("usr/include" + "usr/share/mk"))))) + (define (freebsd-native-build-package? package) (not (not (memq (freebsd-package-build-system package) '(freebsd-kernel-build-system freebsd-world-build-system))))) @@ -617,6 +681,20 @@ both boot and runtime roles." (fourth-wave . (freebsd-kernel-headers freebsd-clang-toolchain)) (fifth-wave . (freebsd-gmake freebsd-autotools freebsd-openssl freebsd-zlib freebsd-sh freebsd-bash)))) +(define %freebsd-native-system-packages + (list freebsd-native-runtime)) + +(define %freebsd-native-development-profile-packages + (list freebsd-native-runtime + freebsd-native-headers + freebsd-clang-toolchain + freebsd-gmake + freebsd-autotools + freebsd-openssl + freebsd-zlib + freebsd-sh + freebsd-bash)) + (define %freebsd-core-packages %freebsd-host-staged-core-packages) (define %freebsd-development-profile-packages %freebsd-host-staged-development-profile-packages) (define %freebsd-system-packages %freebsd-host-staged-system-packages) diff --git a/modules/fruix/system/freebsd.scm b/modules/fruix/system/freebsd.scm index bacbb09..997b667 100644 --- a/modules/fruix/system/freebsd.scm +++ b/modules/fruix/system/freebsd.scm @@ -307,6 +307,7 @@ (define (native-build-manifest-string package input-paths) (let* ((plan (freebsd-package-install-plan package)) (common (native-build-common-manifest plan)) + (keep-paths (build-plan-ref plan 'keep-paths '())) (prune-paths (build-plan-ref plan 'prune-paths '()))) (string-append "name=" (freebsd-package-name package) "\n" @@ -315,6 +316,8 @@ "inputs=" (string-join input-paths ",") "\n" "native-build-common=\n" (object->string common) + "\nkeep-paths=\n" + (object->string keep-paths) "\nprune-paths=\n" (object->string prune-paths)))) @@ -363,8 +366,12 @@ (_ (error (format #f "unsupported install plan entry: ~s" entry))))) +(define (clear-file-flags path) + (false-if-exception (system* "chflags" "-R" "noschg,nouchg" path))) + (define (delete-path-if-exists path) (when (or (file-exists? path) (false-if-exception (readlink path))) + (clear-file-flags path) (let ((kind (stat:type (lstat path)))) (case kind ((directory) (delete-file-recursively path)) @@ -442,56 +449,79 @@ (delete-path-if-exists (string-append stage-root "/" path))) paths)) +(define (select-stage-paths stage-root paths) + (let ((selected-root (string-append stage-root ".selected"))) + (delete-path-if-exists selected-root) + (mkdir-p selected-root) + (for-each (lambda (path) + (let ((source (string-append stage-root "/" path)) + (target (string-append selected-root "/" path))) + (unless (or (file-exists? source) + (false-if-exception (readlink source))) + (error (format #f "native stage path is missing: ~a" source))) + (copy-node source target))) + paths) + selected-root)) (define (native-build-output-metadata package common build-root stage-root) - `((package . ,(freebsd-package-name package)) - (version . ,(freebsd-package-version package)) - (build-system . ,(freebsd-package-build-system package)) - (source-root . ,(assoc-ref common 'source-root)) - (source-tree-sha256 . ,(assoc-ref common 'source-tree-sha256)) - (target . ,(assoc-ref common 'target)) - (target-arch . ,(assoc-ref common 'target-arch)) - (kernconf . ,(assoc-ref common 'kernconf)) - (kernconf-path . ,(assoc-ref common 'kernconf-path)) - (kernconf-sha256 . ,(assoc-ref common 'kernconf-sha256)) - (make-flags . ,(assoc-ref common 'make-flags)) - (build-root . ,build-root) - (stage-root . ,stage-root) - (buildworld-log . ,(string-append build-root "/logs/buildworld.log")) - (buildkernel-log . ,(string-append build-root "/logs/buildkernel-" (assoc-ref common 'kernconf) ".log")) - (install-log . ,(string-append build-root "/logs/install-" (freebsd-package-name package) ".log")))) + (let ((plan (freebsd-package-install-plan package))) + `((package . ,(freebsd-package-name package)) + (version . ,(freebsd-package-version package)) + (build-system . ,(freebsd-package-build-system package)) + (source-root . ,(assoc-ref common 'source-root)) + (source-tree-sha256 . ,(assoc-ref common 'source-tree-sha256)) + (target . ,(assoc-ref common 'target)) + (target-arch . ,(assoc-ref common 'target-arch)) + (kernconf . ,(assoc-ref common 'kernconf)) + (kernconf-path . ,(assoc-ref common 'kernconf-path)) + (kernconf-sha256 . ,(assoc-ref common 'kernconf-sha256)) + (make-flags . ,(assoc-ref common 'make-flags)) + (keep-paths . ,(build-plan-ref plan 'keep-paths '())) + (prune-paths . ,(build-plan-ref plan 'prune-paths '())) + (build-root . ,build-root) + (stage-root . ,stage-root) + (buildworld-log . ,(string-append build-root "/logs/buildworld.log")) + (buildkernel-log . ,(string-append build-root "/logs/buildkernel-" (assoc-ref common 'kernconf) ".log")) + (install-log . ,(string-append build-root "/logs/install-" (freebsd-package-name package) ".log"))))) (define (materialize-native-freebsd-package package input-paths manifest output-path) (let* ((plan (freebsd-package-install-plan package)) (common (native-build-common-manifest plan)) (build-root (native-build-root common)) (stage-root (string-append build-root "/stage-" (freebsd-package-name package) "-" (string-hash manifest))) - (install-log (string-append build-root "/logs/install-" (freebsd-package-name package) ".log"))) - (case (freebsd-package-build-system package) - ((freebsd-world-build-system) - (ensure-native-buildworld common build-root) - (delete-path-if-exists stage-root) - (mkdir-p stage-root) - (run-command/log install-log - (string-append (make-command-string common build-root "installworld" #:destdir stage-root) - " && " - (make-command-string common build-root "distribution" #:destdir stage-root))) - (prune-stage-paths stage-root (build-plan-ref plan 'prune-paths '()))) - ((freebsd-kernel-build-system) - (ensure-native-buildkernel common build-root) - (delete-path-if-exists stage-root) - (mkdir-p stage-root) - (run-command/log install-log - (make-command-string common build-root "installkernel" #:destdir stage-root))) - (else - (error (format #f "unsupported native FreeBSD build system: ~a" - (freebsd-package-build-system package))))) + (install-log (string-append build-root "/logs/install-" (freebsd-package-name package) ".log")) + (final-stage-root + (case (freebsd-package-build-system package) + ((freebsd-world-build-system) + (ensure-native-buildworld common build-root) + (delete-path-if-exists stage-root) + (mkdir-p stage-root) + (run-command/log install-log + (string-append (make-command-string common build-root "installworld" #:destdir stage-root) + " && " + (make-command-string common build-root "distribution" #:destdir stage-root))) + (let* ((keep-paths (build-plan-ref plan 'keep-paths '())) + (selected-root (if (null? keep-paths) + stage-root + (select-stage-paths stage-root keep-paths)))) + (prune-stage-paths selected-root (build-plan-ref plan 'prune-paths '())) + selected-root)) + ((freebsd-kernel-build-system) + (ensure-native-buildkernel common build-root) + (delete-path-if-exists stage-root) + (mkdir-p stage-root) + (run-command/log install-log + (make-command-string common build-root "installkernel" #:destdir stage-root)) + stage-root) + (else + (error (format #f "unsupported native FreeBSD build system: ~a" + (freebsd-package-build-system package))))))) (mkdir-p output-path) - (stage-tree-into-output stage-root output-path) + (stage-tree-into-output final-stage-root output-path) (write-file (string-append output-path "/.references") (string-join input-paths "\n")) (write-file (string-append output-path "/.fruix-package") manifest) (write-file (string-append output-path "/.freebsd-native-build-info.scm") - (object->string (native-build-output-metadata package common build-root stage-root))))) + (object->string (native-build-output-metadata package common build-root final-stage-root))))) (define (package-cache-key package) (string-append (freebsd-package-name package) "-" (freebsd-package-version package))) diff --git a/tests/system/phase14-native-split-pid1-operating-system.scm.in b/tests/system/phase14-native-split-pid1-operating-system.scm.in new file mode 100644 index 0000000..d18a19b --- /dev/null +++ b/tests/system/phase14-native-split-pid1-operating-system.scm.in @@ -0,0 +1,71 @@ +(use-modules (fruix system freebsd) + (fruix packages freebsd)) + +(define phase14-operating-system + (operating-system + #:host-name "fruix-freebsd" + #:kernel freebsd-native-kernel + #:bootloader freebsd-native-bootloader + #:base-packages %freebsd-native-system-packages + #:groups (list (user-group #:name "wheel" #:gid 0 #:system? #t) + (user-group #:name "sshd" #:gid 22 #:system? #t) + (user-group #:name "_dhcp" #:gid 65 #:system? #t) + (user-group #:name "operator" #:gid 1000 #:system? #f)) + #:users (list (user-account #:name "root" + #:uid 0 + #:group "wheel" + #:comment "Charlie &" + #:home "/root" + #:shell "/bin/sh" + #:system? #t) + (user-account #:name "sshd" + #:uid 22 + #:group "sshd" + #:comment "Secure Shell Daemon" + #:home "/var/empty" + #:shell "/usr/sbin/nologin" + #:system? #t) + (user-account #:name "_dhcp" + #:uid 65 + #:group "_dhcp" + #:comment "dhcp programs" + #:home "/var/empty" + #:shell "/usr/sbin/nologin" + #:system? #t) + (user-account #:name "operator" + #:uid 1000 + #:group "operator" + #:supplementary-groups '("wheel") + #:comment "Fruix Operator" + #:home "/home/operator" + #:shell "/bin/sh" + #:system? #f)) + #:file-systems (list (file-system #:device "/dev/gpt/fruix-root" + #:mount-point "/" + #:type "ufs" + #:options "rw" + #:needed-for-boot? #t) + (file-system #:device "devfs" + #:mount-point "/dev" + #:type "devfs" + #:options "rw" + #:needed-for-boot? #t) + (file-system #:device "tmpfs" + #:mount-point "/tmp" + #:type "tmpfs" + #:options "rw,size=64m")) + #:services '(shepherd ready-marker sshd) + #:loader-entries '(("autoboot_delay" . "1") + ("boot_multicons" . "YES") + ("boot_serial" . "YES") + ("console" . "comconsole,vidconsole")) + #:rc-conf-entries '(("clear_tmp_enable" . "NO") + ("hostid_enable" . "NO") + ("sendmail_enable" . "NONE") + ("sshd_enable" . "YES") + ("ifconfig_xn0" . "SYNCDHCP") + ("ifconfig_em0" . "SYNCDHCP") + ("ifconfig_vtnet0" . "SYNCDHCP")) + #:init-mode 'shepherd-pid1 + #:ready-marker "/var/lib/fruix/ready" + #:root-authorized-keys '("__ROOT_AUTHORIZED_KEY__"))) diff --git a/tests/system/run-phase14-native-development-split.sh b/tests/system/run-phase14-native-development-split.sh new file mode 100755 index 0000000..d603f69 --- /dev/null +++ b/tests/system/run-phase14-native-development-split.sh @@ -0,0 +1,142 @@ +#!/bin/sh +set -eu + +repo_root=${PROJECT_ROOT:-$(pwd)} +store_dir=${STORE_DIR:-/frx/store} +metadata_target=${METADATA_OUT:-} +cleanup=0 + +if [ -n "${WORKDIR:-}" ]; then + workdir=$WORKDIR + mkdir -p "$workdir" +else + workdir=$(mktemp -d /tmp/fruix-phase14-native-development.XXXXXX) + cleanup=1 +fi +if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then + cleanup=0 +fi + +metadata_file=$workdir/phase14-native-development-split-metadata.txt + +cleanup_workdir() { + if [ "$cleanup" -eq 1 ]; then + rm -rf "$workdir" 2>/dev/null || sudo rm -rf "$workdir" + fi +} +trap cleanup_workdir EXIT INT TERM + +action_env() { + sudo env \ + HOME="$HOME" \ + GUILE_AUTO_COMPILE=0 \ + FRUIX_FREEBSD_BUILD_JOBS="${FRUIX_FREEBSD_BUILD_JOBS:-8}" \ + GUIX_SOURCE_DIR="${GUIX_SOURCE_DIR:-$HOME/repos/guix}" \ + GUILE_BIN="${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}" \ + GUILE_EXTRA_PREFIX="${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install}" \ + SHEPHERD_PREFIX="${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install}" \ + "$@" +} + +native_system_packages=$(GUILE_AUTO_COMPILE=0 /tmp/guile-freebsd-validate-install/bin/guile -L modules -L "$HOME/repos/guix" -c ' +(use-modules (fruix packages freebsd) (srfi srfi-13)) +(display (string-join (map freebsd-package-name %freebsd-native-system-packages) ",")) +(newline)') + +native_development_packages=$(GUILE_AUTO_COMPILE=0 /tmp/guile-freebsd-validate-install/bin/guile -L modules -L "$HOME/repos/guix" -c ' +(use-modules (fruix packages freebsd) (srfi srfi-13)) +(display (string-join (map freebsd-package-name %freebsd-native-development-profile-packages) ",")) +(newline)') + +materialize_native_package() { + package_name=$1 + action_env env LD_LIBRARY_PATH="/tmp/guile-freebsd-validate-install/lib:/usr/local/lib" /tmp/guile-freebsd-validate-install/bin/guile -L modules -L "$HOME/repos/guix" -c ' +(use-modules (fruix packages freebsd) (ice-9 hash-table)) +(let* ((args (command-line)) + (store-dir (list-ref args (- (length args) 2))) + (package-name (list-ref args (- (length args) 1))) + (pkg (case (string->symbol package-name) + ((freebsd-native-bootloader) freebsd-native-bootloader) + ((freebsd-native-headers) freebsd-native-headers) + (else (error "unsupported package" package-name)))) + (system-module (resolve-module (quote (fruix system freebsd)))) + (materialize (module-ref system-module (quote materialize-freebsd-package))) + (cache (make-hash-table)) + (path (materialize pkg store-dir cache))) + (display "STORE_PATH=") + (display path) + (newline))' dummy "$store_dir" "$package_name" +} + +bootloader_store=$(materialize_native_package freebsd-native-bootloader | sed -n 's/^STORE_PATH=//p' | tail -n 1) +headers_store=$(materialize_native_package freebsd-native-headers | sed -n 's/^STORE_PATH=//p' | tail -n 1) + +case "$bootloader_store" in + /frx/store/*-freebsd-native-bootloader-15.0-STABLE) : ;; + *) echo "unexpected native bootloader store path: $bootloader_store" >&2; exit 1 ;; +esac +case "$headers_store" in + /frx/store/*-freebsd-native-headers-15.0-STABLE) : ;; + *) echo "unexpected native headers store path: $headers_store" >&2; exit 1 ;; +esac + +for path in \ + "$bootloader_store/boot/loader" \ + "$bootloader_store/boot/loader.efi" \ + "$bootloader_store/boot/device.hints" \ + "$bootloader_store/boot/defaults/loader.conf" \ + "$bootloader_store/boot/lua/loader.lua" \ + "$headers_store/usr/include/stdio.h" \ + "$headers_store/usr/include/sys/param.h" \ + "$headers_store/usr/share/mk/bsd.prog.mk" +do + [ -e "$path" ] || { + echo "expected native split artifact path missing: $path" >&2 + exit 1 + } +done + +[ ! -e "$bootloader_store/usr/include" ] || { echo "native bootloader slice unexpectedly contains headers" >&2; exit 1; } +[ ! -e "$headers_store/boot" ] || { echo "native headers slice unexpectedly contains /boot" >&2; exit 1; } +[ ! -e "$headers_store/bin/sh" ] || { echo "native headers slice unexpectedly contains runtime binaries" >&2; exit 1; } + +case ",$native_system_packages," in + *,freebsd-native-runtime,*) : ;; + *) echo "native system package set does not include freebsd-native-runtime" >&2; exit 1 ;; +esac +case ",$native_development_packages," in + *,freebsd-native-runtime,*) : ;; + *) echo "native development package set does not include freebsd-native-runtime" >&2; exit 1 ;; +esac +case ",$native_development_packages," in + *,freebsd-native-headers,*) : ;; + *) echo "native development package set does not include freebsd-native-headers" >&2; exit 1 ;; +esac +case ",$native_development_packages," in + *,freebsd-clang-toolchain,*) : ;; + *) echo "native development package set does not retain the explicit toolchain artifact" >&2; exit 1 ;; +esac + +cat >"$metadata_file" </dev/null || sudo rm -rf "$workdir" + fi +} +trap cleanup_workdir EXIT INT TERM + +KEEP_WORKDIR=1 WORKDIR="$workdir/inner" METADATA_OUT="$inner_metadata" \ + OS_TEMPLATE="$os_template" SYSTEM_NAME="$system_name" DISK_CAPACITY="$disk_capacity" ROOT_SIZE="$root_size" \ + "$repo_root/tests/system/run-phase11-shepherd-pid1-qemu.sh" + +phase8_metadata=$(sed -n 's/^phase8_metadata=//p' "$inner_metadata") +closure_path=$(sed -n 's/^closure_path=//p' "$inner_metadata") +closure_base=$(sed -n 's/^closure_base=//p' "$inner_metadata") +serial_log=$(sed -n 's/^serial_log=//p' "$inner_metadata") +ssh_port=$(sed -n 's/^ssh_port=//p' "$inner_metadata") +shepherd_pid=$(sed -n 's/^shepherd_pid=//p' "$inner_metadata") +sshd_status=$(sed -n 's/^sshd_status=//p' "$inner_metadata") +activate_log=$(sed -n 's/^activate_log=//p' "$inner_metadata") + +native_base_store_count=$(sed -n 's/^native_base_store_count=//p' "$phase8_metadata") +native_base_stores=$(sed -n 's/^native_base_stores=//p' "$phase8_metadata") +host_base_store_count=$(sed -n 's/^host_base_store_count=//p' "$phase8_metadata") +host_base_stores=$(sed -n 's/^host_base_stores=//p' "$phase8_metadata") + +[ "$native_base_store_count" = 3 ] || { echo "expected 3 native base stores, got: $native_base_store_count" >&2; exit 1; } +[ "$host_base_store_count" = 0 ] || { echo "expected 0 host base stores, got: $host_base_store_count" >&2; exit 1; } +[ -z "$host_base_stores" ] || { echo "host base stores are not empty: $host_base_stores" >&2; exit 1; } +printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-kernel-15.0-STABLE$' >/dev/null || { + echo "native base stores do not include the native kernel" >&2 + exit 1 +} +bootloader_store=$(printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-bootloader-15.0-STABLE$' | head -n 1) +runtime_store=$(printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-runtime-15.0-STABLE$' | head -n 1) +[ -n "$bootloader_store" ] || { echo "native base stores do not include the native bootloader slice" >&2; exit 1; } +[ -n "$runtime_store" ] || { echo "native base stores do not include the native runtime slice" >&2; exit 1; } +printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-world-15.0-STABLE$' >/dev/null && { + echo "broad native world artifact should no longer be part of the validated split-system closure" >&2 + exit 1 +} +for path in \ + "$bootloader_store/boot/loader" \ + "$bootloader_store/boot/loader.efi" \ + "$bootloader_store/boot/device.hints" \ + "$bootloader_store/boot/defaults/loader.conf" \ + "$bootloader_store/boot/lua/loader.lua" \ + "$runtime_store/bin/sh" \ + "$runtime_store/sbin/init" \ + "$runtime_store/etc/rc" \ + "$runtime_store/usr/sbin/sshd" \ + "$runtime_store/sbin/dhclient" \ + "$runtime_store/usr/bin/ssh-keygen" \ + "$runtime_store/usr/share/locale/C.UTF-8/LC_CTYPE" +do + [ -e "$path" ] || { + echo "required native split path missing: $path" >&2 + exit 1 + } +done +[ ! -e "$runtime_store/boot" ] || { echo "native runtime still contains /boot" >&2; exit 1; } +[ ! -e "$runtime_store/usr/include" ] || { echo "native runtime still contains /usr/include" >&2; exit 1; } +[ "$shepherd_pid" = 1 ] || { echo "shepherd was not PID 1" >&2; exit 1; } +[ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; } +case "$activate_log" in + *fruix-activate:done*) : ;; + *) echo "activation log does not show success" >&2; exit 1 ;; +esac + +cat >"$metadata_file" <&2; exit 1; } +[ "$host_base_store_count" = 0 ] || { echo "expected 0 host base stores, got: $host_base_store_count" >&2; exit 1; } +[ -z "$host_base_stores" ] || { echo "host base stores are not empty: $host_base_stores" >&2; exit 1; } +printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-kernel-15.0-STABLE$' >/dev/null || { + echo "native base stores do not include the native kernel" >&2 + exit 1 +} +bootloader_store=$(printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-bootloader-15.0-STABLE$' | head -n 1) +runtime_store=$(printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-runtime-15.0-STABLE$' | head -n 1) +[ -n "$bootloader_store" ] || { echo "native base stores do not include the native bootloader slice" >&2; exit 1; } +[ -n "$runtime_store" ] || { echo "native base stores do not include the native runtime slice" >&2; exit 1; } +printf '%s\n' "$native_base_stores" | tr ',' '\n' | grep 'freebsd-native-world-15.0-STABLE$' >/dev/null && { + echo "broad native world artifact should no longer be part of the validated split-system closure" >&2 + exit 1 +} +for path in \ + "$bootloader_store/boot/loader" \ + "$bootloader_store/boot/loader.efi" \ + "$bootloader_store/boot/device.hints" \ + "$bootloader_store/boot/defaults/loader.conf" \ + "$bootloader_store/boot/lua/loader.lua" \ + "$runtime_store/bin/sh" \ + "$runtime_store/sbin/init" \ + "$runtime_store/etc/rc" \ + "$runtime_store/usr/sbin/sshd" \ + "$runtime_store/sbin/dhclient" \ + "$runtime_store/usr/bin/ssh-keygen" \ + "$runtime_store/usr/share/locale/C.UTF-8/LC_CTYPE" +do + [ -e "$path" ] || { + echo "required native split path missing: $path" >&2 + exit 1 + } +done +[ ! -e "$runtime_store/boot" ] || { echo "native runtime still contains /boot" >&2; exit 1; } +[ ! -e "$runtime_store/usr/include" ] || { echo "native runtime still contains /usr/include" >&2; exit 1; } +[ "$shepherd_pid" = 1 ] || { echo "shepherd was not PID 1" >&2; exit 1; } +[ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; } +[ "$compat_prefix_shims" = absent ] || { echo "compatibility prefix shims reappeared" >&2; exit 1; } +[ "$guile_module_smoke" = ok ] || { echo "guest Guile module smoke failed" >&2; exit 1; } +case "$activate_log" in + *fruix-activate:done*) : ;; + *) echo "activation log does not show success" >&2; exit 1 ;; +esac + +cat >"$metadata_file" <