Enable Fruix FreeBSD guest SSH boot on XCP-ng
This commit is contained in:
@@ -2154,3 +2154,66 @@ Next recommended step:
|
|||||||
- Fruix at the product boundary
|
- Fruix at the product boundary
|
||||||
- `/frx` as the canonical store root
|
- `/frx` as the canonical store root
|
||||||
- stable upstream-derived internal names unless there is strong architectural value in renaming them
|
- stable upstream-derived internal names unless there is strong architectural value in renaming them
|
||||||
|
|
||||||
|
## 2026-04-02 — Phase 9 checkpoint: XCP-ng guest reached DHCP and SSH
|
||||||
|
|
||||||
|
Completed work:
|
||||||
|
|
||||||
|
- added a dedicated Phase 9 XCP-ng operating-system template:
|
||||||
|
- `tests/system/phase9-minimal-operating-system.scm.in`
|
||||||
|
- added an XCP-ng boot/import/validation harness:
|
||||||
|
- `tests/system/run-phase9-xcpng-boot.sh`
|
||||||
|
- extended the staged FreeBSD runtime and system-generation layers so the guest can complete enough of real boot for network access:
|
||||||
|
- `modules/fruix/packages/freebsd.scm`
|
||||||
|
- `modules/fruix/system/freebsd.scm`
|
||||||
|
- updated the integrated image-generation path for Phase 9 use cases:
|
||||||
|
- `tests/system/materialize-phase8-system-image.scm`
|
||||||
|
- `tests/system/run-phase8-system-image.sh`
|
||||||
|
- wrote the checkpoint report:
|
||||||
|
- `docs/reports/phase9-xcpng-ssh-boot-freebsd.md`
|
||||||
|
|
||||||
|
Important findings:
|
||||||
|
|
||||||
|
- a decisive local QEMU/TCG serial-boot pass exposed the first real early-boot blocker:
|
||||||
|
- the generated `fstab` was wrong for pseudo-filesystems, so `rc` tried to fsck `devfs` and aborted boot
|
||||||
|
- after fixing `fstab`, later serial logs exposed additional FreeBSD base runtime gaps that only appear during real boot, including missing commands, runtime directories, and base config files used by `rc`, DHCP, logging, and service startup
|
||||||
|
- the staged image now includes the minimum currently known set of FreeBSD runtime pieces needed to:
|
||||||
|
- run `rc`
|
||||||
|
- obtain DHCP
|
||||||
|
- generate SSH host keys
|
||||||
|
- start `sshd`
|
||||||
|
- public-key SSH login initially still failed because the minimal guest did not stage a complete PAM runtime/config path; for the current Phase 9 prototype track, the generated `sshd_config` now uses:
|
||||||
|
- `UsePAM no`
|
||||||
|
- the current XCP-ng validation path succeeded against the operator-approved VM and existing VDI only:
|
||||||
|
- VM `90490f2e-e8fc-4b7a-388e-5c26f0157289`
|
||||||
|
- VDI `0f1f90d3-48ca-4fa2-91d8-fc6339b95743`
|
||||||
|
- the successful XCP-ng boot obtained:
|
||||||
|
- guest IP `192.168.213.62`
|
||||||
|
- successful SSH validation on the real guest confirmed:
|
||||||
|
- `hostname=fruix-freebsd`
|
||||||
|
- `sshd` is reachable with the injected root key
|
||||||
|
- networking is configured on the Xen NIC
|
||||||
|
|
||||||
|
Current assessment:
|
||||||
|
|
||||||
|
- this checkpoint establishes the first real network-reachable Fruix boot on the active FreeBSD/XCP-ng track
|
||||||
|
- the generated image now boots far enough for DHCP and SSH, which closes the earlier uncertainty about whether the Phase 8 image could become a remotely usable guest at all
|
||||||
|
- Phase 9 is still not complete because the Fruix-specific readiness path remains blocked:
|
||||||
|
- `fruix-shepherd` does not start
|
||||||
|
- `/var/lib/fruix/ready` is still missing
|
||||||
|
- Guile still crashes in the guest with `signal 11`
|
||||||
|
- therefore the current state is:
|
||||||
|
- kernel boot: yes
|
||||||
|
- root mount: yes
|
||||||
|
- DHCP: yes
|
||||||
|
- SSH: yes
|
||||||
|
- Shepherd/ready marker: not yet
|
||||||
|
|
||||||
|
Next recommended step:
|
||||||
|
|
||||||
|
1. continue the in-guest Guile crash investigation so `fruix-shepherd` can start on the booted guest
|
||||||
|
2. once Shepherd is stable, rerun `tests/system/run-phase9-xcpng-boot.sh` to validate the full ready-marker path end-to-end
|
||||||
|
3. then close Phase 9 with updated report/progress entries for:
|
||||||
|
- deterministic boot readiness
|
||||||
|
- in-guest Shepherd validation
|
||||||
|
- minimal operator usability
|
||||||
|
|||||||
213
docs/reports/phase9-xcpng-ssh-boot-freebsd.md
Normal file
213
docs/reports/phase9-xcpng-ssh-boot-freebsd.md
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
# Phase 9 checkpoint: XCP-ng boot reached DHCP and SSH on FreeBSD
|
||||||
|
|
||||||
|
Date: 2026-04-02
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Advance Phase 9 from a static image-generation milestone to a real booted Fruix guest on the active FreeBSD/XCP-ng track, using the operator-approved VM:
|
||||||
|
|
||||||
|
- VM: `90490f2e-e8fc-4b7a-388e-5c26f0157289`
|
||||||
|
- existing target VDI: `0f1f90d3-48ca-4fa2-91d8-fc6339b95743`
|
||||||
|
|
||||||
|
The immediate objective for this checkpoint was narrower than full Phase 9 completion:
|
||||||
|
|
||||||
|
- boot the generated image under XCP-ng,
|
||||||
|
- obtain DHCP,
|
||||||
|
- and reach SSH access with the injected root key.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
This checkpoint succeeded.
|
||||||
|
|
||||||
|
The current Fruix FreeBSD image now:
|
||||||
|
|
||||||
|
- boots on the target XCP-ng VM,
|
||||||
|
- mounts the generated root filesystem,
|
||||||
|
- completes enough of FreeBSD `rc` startup to configure networking,
|
||||||
|
- obtains a DHCP lease on the Xen NIC,
|
||||||
|
- starts `sshd`,
|
||||||
|
- and accepts root public-key authentication over the network.
|
||||||
|
|
||||||
|
Validated guest details from the successful XCP-ng boot:
|
||||||
|
|
||||||
|
- guest IP: `192.168.213.62`
|
||||||
|
- hostname: `fruix-freebsd`
|
||||||
|
- kernel string:
|
||||||
|
- `FreeBSD 15.0-STABLE stable/15-n282801-29dce45d8c50 GENERIC amd64`
|
||||||
|
|
||||||
|
Representative successful SSH validation output:
|
||||||
|
|
||||||
|
```text
|
||||||
|
FreeBSD fruix-freebsd 15.0-STABLE FreeBSD 15.0-STABLE stable/15-n282801-29dce45d8c50 GENERIC amd64
|
||||||
|
fruix-freebsd
|
||||||
|
192.168.213.62
|
||||||
|
```
|
||||||
|
|
||||||
|
Successful XCP-ng work directory:
|
||||||
|
|
||||||
|
- `/tmp/phase9-xcpng-ssh-1775097470`
|
||||||
|
|
||||||
|
## Important boot/debugging findings
|
||||||
|
|
||||||
|
The first decisive breakthrough came from running the generated image locally under QEMU/TCG with serial capture. That made the previously opaque early-boot failure visible.
|
||||||
|
|
||||||
|
### 1. The original early boot abort was not an XCP-ng image-format problem anymore
|
||||||
|
|
||||||
|
After the earlier switch from raw uploads to dynamic VHD uploads, the remaining boot failure was inside the guest boot process, not in the XO import path.
|
||||||
|
|
||||||
|
### 2. FreeBSD `fstab` handling for pseudo-filesystems was wrong
|
||||||
|
|
||||||
|
The serial log showed that boot aborted during filesystem checks because the generated `fstab` gave non-zero fsck fields to non-UFS mounts such as `devfs`.
|
||||||
|
|
||||||
|
Representative failure:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Starting file system checks:
|
||||||
|
/dev/gpt/fruix-root: FILE SYSTEM CLEAN; SKIPPING CHECKS
|
||||||
|
/dev/gpt/fruix-root: clean, ...
|
||||||
|
fsck: exec fsck_devfs for devfs in /sbin:/usr/sbin: No such file or directory
|
||||||
|
Unknown error 1; help!
|
||||||
|
ERROR: ABORTING BOOT (sending SIGTERM to parent)!
|
||||||
|
```
|
||||||
|
|
||||||
|
The fix was to generate fsck pass fields only for UFS entries and emit `0 0` for pseudo-filesystems.
|
||||||
|
|
||||||
|
### 3. The minimal image was still missing many base files and commands expected by `rc`
|
||||||
|
|
||||||
|
Once `rc` ran further, QEMU serial logs exposed a long tail of missing runtime pieces that had not been visible from the earlier static validations alone.
|
||||||
|
|
||||||
|
Examples included:
|
||||||
|
|
||||||
|
- missing base commands:
|
||||||
|
- `dd`
|
||||||
|
- `expr`
|
||||||
|
- `rmdir`
|
||||||
|
- `sort`
|
||||||
|
- `mktemp`
|
||||||
|
- `egrep`
|
||||||
|
- `fsync`
|
||||||
|
- `kldload`
|
||||||
|
- `kldstat`
|
||||||
|
- `devfs`
|
||||||
|
- `devctl`
|
||||||
|
- `newsyslog`
|
||||||
|
- `ip6addrctl`
|
||||||
|
- missing base config files:
|
||||||
|
- `/etc/network.subr`
|
||||||
|
- `/etc/devd.conf`
|
||||||
|
- `/etc/newsyslog.conf`
|
||||||
|
- `/etc/syslog.conf`
|
||||||
|
- missing runtime directories:
|
||||||
|
- `/var/db`
|
||||||
|
- `/var/cron`
|
||||||
|
- missing libraries needed by later boot helpers:
|
||||||
|
- `libgeom.so.5`
|
||||||
|
- `libdevctl.so.5`
|
||||||
|
- `libcap_net.so.1`
|
||||||
|
- C++ runtime pieces used by `devd`
|
||||||
|
|
||||||
|
These were staged into the current FreeBSD package layer and linked into the generated rootfs.
|
||||||
|
|
||||||
|
### 4. SSH auth initially failed because the image relied on PAM without a complete PAM runtime/configuration
|
||||||
|
|
||||||
|
`sshd` would start, but root public-key authentication still failed. A direct in-guest debug run showed:
|
||||||
|
|
||||||
|
```text
|
||||||
|
PAM: initialisation failed
|
||||||
|
```
|
||||||
|
|
||||||
|
For the minimal Phase 9 guest, the practical fix was to make the generated `sshd_config` use:
|
||||||
|
|
||||||
|
- `UsePAM no`
|
||||||
|
|
||||||
|
while still keeping key-only login enabled.
|
||||||
|
|
||||||
|
That was sufficient to unlock real SSH access on both the local QEMU debug guest and the XCP-ng guest.
|
||||||
|
|
||||||
|
## Current code-level outcomes
|
||||||
|
|
||||||
|
The current checkpoint work materially expanded the minimal FreeBSD runtime staged into Fruix images.
|
||||||
|
|
||||||
|
Highlights:
|
||||||
|
|
||||||
|
- `modules/fruix/packages/freebsd.scm`
|
||||||
|
- added dedicated runtime packages for:
|
||||||
|
- `freebsd-networking`
|
||||||
|
- `freebsd-openssh`
|
||||||
|
- expanded staged base runtime coverage substantially for `rc`, networking, and SSH
|
||||||
|
- added required config files and shared libraries used during real boot
|
||||||
|
- `modules/fruix/system/freebsd.scm`
|
||||||
|
- added root authorized-key support to the operating-system model
|
||||||
|
- generated static account databases and supporting files:
|
||||||
|
- `/etc/passwd`
|
||||||
|
- `/etc/master.passwd`
|
||||||
|
- `/etc/group`
|
||||||
|
- `/etc/login.conf`
|
||||||
|
- `/etc/ttys`
|
||||||
|
- activation now runs:
|
||||||
|
- `cap_mkdb`
|
||||||
|
- `pwd_mkdb`
|
||||||
|
- activation creates required directories and SSH host keys
|
||||||
|
- generated `sshd_config` now disables PAM for the current minimal key-only Phase 9 path
|
||||||
|
- `fstab` generation now avoids fsck pass numbers for pseudo-filesystems
|
||||||
|
- rootfs generation now links the additional `/etc` files needed by real boot
|
||||||
|
- `tests/system/phase9-minimal-operating-system.scm.in`
|
||||||
|
- enables DHCP on the relevant NIC names for the current tracks:
|
||||||
|
- `xn0`
|
||||||
|
- `em0`
|
||||||
|
- `vtnet0`
|
||||||
|
- injects the root authorized key
|
||||||
|
- includes the SSH/network runtime packages and required system users/groups
|
||||||
|
- `tests/system/run-phase8-system-image.sh`
|
||||||
|
- now accepts `OS_FILE`
|
||||||
|
- now accepts/passes `DISK_CAPACITY`
|
||||||
|
- serial-console validation was relaxed from an exact loader string to a `comconsole` presence check
|
||||||
|
|
||||||
|
## Verified current state
|
||||||
|
|
||||||
|
The current validated Phase 9 state is:
|
||||||
|
|
||||||
|
- XCP-ng VHD upload path works against the existing VDI
|
||||||
|
- the guest boots far enough for normal `rc` networking and `sshd`
|
||||||
|
- DHCP works on the Xen NIC
|
||||||
|
- SSH key injection works
|
||||||
|
- root login over SSH works
|
||||||
|
|
||||||
|
This means the project has crossed an important Phase 9 boundary:
|
||||||
|
|
||||||
|
- the first boot validation no longer depends on local bhyve serial automation,
|
||||||
|
- and the real XCP-ng target can now be exercised over the network.
|
||||||
|
|
||||||
|
## Remaining blocker
|
||||||
|
|
||||||
|
Phase 9 is not complete yet because the Fruix-specific readiness path still fails.
|
||||||
|
|
||||||
|
Current remaining blocker:
|
||||||
|
|
||||||
|
- Guile still crashes in the guest
|
||||||
|
- therefore `fruix-shepherd` does not start
|
||||||
|
- therefore `/var/lib/fruix/ready` is still absent
|
||||||
|
|
||||||
|
Representative guest evidence:
|
||||||
|
|
||||||
|
```text
|
||||||
|
pid 262 (guile), jid 0, uid 0: exited on signal 11 (core dumped)
|
||||||
|
```
|
||||||
|
|
||||||
|
Over SSH on the real XCP-ng guest:
|
||||||
|
|
||||||
|
- `sshd` is running
|
||||||
|
- DHCP is active
|
||||||
|
- `fruix-shepherd` is stopped
|
||||||
|
- `/var/lib/fruix/ready` is missing
|
||||||
|
|
||||||
|
A retrieved core dump and local `lldb` analysis show the Guile crash occurs extremely early during initialization, in the locale/string conversion path while building Guile load/build info. This remains the next debugging target.
|
||||||
|
|
||||||
|
## Assessment
|
||||||
|
|
||||||
|
This checkpoint satisfies a meaningful Phase 9 intermediate milestone on the active FreeBSD/XCP-ng track:
|
||||||
|
|
||||||
|
- the generated Fruix image now boots as a network-reachable FreeBSD guest,
|
||||||
|
- and minimal operator access via SSH is working.
|
||||||
|
|
||||||
|
However, the full Fruix boot milestone is still blocked by in-guest Guile/Shepherd failure, so the overall Phase 9 milestone remains open.
|
||||||
@@ -18,6 +18,8 @@
|
|||||||
freebsd-bootloader
|
freebsd-bootloader
|
||||||
freebsd-rc-scripts
|
freebsd-rc-scripts
|
||||||
freebsd-runtime
|
freebsd-runtime
|
||||||
|
freebsd-networking
|
||||||
|
freebsd-openssh
|
||||||
freebsd-userland
|
freebsd-userland
|
||||||
freebsd-clang-toolchain
|
freebsd-clang-toolchain
|
||||||
freebsd-gmake
|
freebsd-gmake
|
||||||
@@ -95,9 +97,16 @@ and the userland C headers needed for development profiles."
|
|||||||
#:install-plan
|
#:install-plan
|
||||||
'((file "/lib/libc.so.7" "lib/libc.so.7")
|
'((file "/lib/libc.so.7" "lib/libc.so.7")
|
||||||
(file "/lib/libsys.so.7" "lib/libsys.so.7")
|
(file "/lib/libsys.so.7" "lib/libsys.so.7")
|
||||||
|
(file "/lib/libthr.so.3" "lib/libthr.so.3")
|
||||||
(file "/lib/libutil.so.10" "lib/libutil.so.10")
|
(file "/lib/libutil.so.10" "lib/libutil.so.10")
|
||||||
(file "/lib/libxo.so.0" "lib/libxo.so.0")
|
(file "/lib/libxo.so.0" "lib/libxo.so.0")
|
||||||
|
(file "/lib/libgeom.so.5" "lib/libgeom.so.5")
|
||||||
|
(file "/lib/libc++.so.1" "lib/libc++.so.1")
|
||||||
|
(file "/lib/libcxxrt.so.1" "lib/libcxxrt.so.1")
|
||||||
|
(file "/lib/libgcc_s.so.1" "lib/libgcc_s.so.1")
|
||||||
(file "/lib/libm.so.5" "lib/libm.so.5")
|
(file "/lib/libm.so.5" "lib/libm.so.5")
|
||||||
|
(file "/lib/libelf.so.2" "lib/libelf.so.2")
|
||||||
|
(file "/lib/libkvm.so.7" "lib/libkvm.so.7")
|
||||||
(file "/lib/lib80211.so.1" "lib/lib80211.so.1")
|
(file "/lib/lib80211.so.1" "lib/lib80211.so.1")
|
||||||
(file "/lib/libjail.so.1" "lib/libjail.so.1")
|
(file "/lib/libjail.so.1" "lib/libjail.so.1")
|
||||||
(file "/lib/libnv.so.1" "lib/libnv.so.1")
|
(file "/lib/libnv.so.1" "lib/libnv.so.1")
|
||||||
@@ -105,6 +114,31 @@ and the userland C headers needed for development profiles."
|
|||||||
(file "/lib/libbsdxml.so.4" "lib/libbsdxml.so.4")
|
(file "/lib/libbsdxml.so.4" "lib/libbsdxml.so.4")
|
||||||
(file "/lib/libcrypt.so.5" "lib/libcrypt.so.5")
|
(file "/lib/libcrypt.so.5" "lib/libcrypt.so.5")
|
||||||
(file "/lib/libmd.so.7" "lib/libmd.so.7")
|
(file "/lib/libmd.so.7" "lib/libmd.so.7")
|
||||||
|
(file "/lib/libedit.so.8" "lib/libedit.so.8")
|
||||||
|
(file "/lib/libtinfow.so.9" "lib/libtinfow.so.9")
|
||||||
|
(file "/lib/libcasper.so.1" "lib/libcasper.so.1")
|
||||||
|
(file "/lib/libcap_syslog.so.1" "lib/libcap_syslog.so.1")
|
||||||
|
(file "/lib/libcap_fileargs.so.1" "lib/libcap_fileargs.so.1")
|
||||||
|
(file "/lib/libcap_net.so.1" "lib/libcap_net.so.1")
|
||||||
|
(file "/lib/libufs.so.8" "lib/libufs.so.8")
|
||||||
|
(file "/usr/lib/libdevinfo.so.7" "usr/lib/libdevinfo.so.7")
|
||||||
|
(file "/usr/lib/libdevctl.so.5" "usr/lib/libdevctl.so.5")
|
||||||
|
(file "/lib/libz.so.6" "lib/libz.so.6")
|
||||||
|
(file "/lib/libcrypto.so.35" "lib/libcrypto.so.35")
|
||||||
|
(file "/usr/lib/libssl.so.35" "usr/lib/libssl.so.35")
|
||||||
|
(file "/usr/lib/libdl.so.1" "usr/lib/libdl.so.1")
|
||||||
|
(file "/usr/lib/libpam.so.6" "usr/lib/libpam.so.6")
|
||||||
|
(file "/usr/lib/libbsm.so.3" "usr/lib/libbsm.so.3")
|
||||||
|
(file "/usr/lib/libblocklist.so.0" "usr/lib/libblocklist.so.0")
|
||||||
|
(file "/usr/lib/libregex.so.1" "usr/lib/libregex.so.1")
|
||||||
|
(file "/usr/lib/libprivatessh.so.5" "usr/lib/libprivatessh.so.5")
|
||||||
|
(file "/usr/lib/libprivateldns.so.5" "usr/lib/libprivateldns.so.5")
|
||||||
|
(file "/usr/lib/libwrap.so.6" "usr/lib/libwrap.so.6")
|
||||||
|
(file "/usr/lib/libgssapi_krb5.so.122" "usr/lib/libgssapi_krb5.so.122")
|
||||||
|
(file "/usr/lib/libkrb5.so.122" "usr/lib/libkrb5.so.122")
|
||||||
|
(file "/usr/lib/libk5crypto.so.122" "usr/lib/libk5crypto.so.122")
|
||||||
|
(file "/usr/lib/libcom_err.so.122" "usr/lib/libcom_err.so.122")
|
||||||
|
(file "/usr/lib/libkrb5support.so.122" "usr/lib/libkrb5support.so.122")
|
||||||
(file "/libexec/ld-elf.so.1" "libexec/ld-elf.so.1"))))
|
(file "/libexec/ld-elf.so.1" "libexec/ld-elf.so.1"))))
|
||||||
|
|
||||||
(define freebsd-bootloader
|
(define freebsd-bootloader
|
||||||
@@ -155,16 +189,45 @@ userland commands needed for development and build experiments."
|
|||||||
#:license 'bsd-2
|
#:license 'bsd-2
|
||||||
#:install-plan
|
#:install-plan
|
||||||
'((file "/bin/cat" "bin/cat")
|
'((file "/bin/cat" "bin/cat")
|
||||||
|
(file "/bin/chflags" "bin/chflags")
|
||||||
|
(file "/bin/chmod" "bin/chmod")
|
||||||
(file "/bin/cp" "bin/cp")
|
(file "/bin/cp" "bin/cp")
|
||||||
|
(file "/bin/date" "bin/date")
|
||||||
|
(file "/bin/dd" "bin/dd")
|
||||||
(file "/bin/echo" "bin/echo")
|
(file "/bin/echo" "bin/echo")
|
||||||
|
(file "/bin/expr" "bin/expr")
|
||||||
(file "/bin/ln" "bin/ln")
|
(file "/bin/ln" "bin/ln")
|
||||||
(file "/bin/ls" "bin/ls")
|
(file "/bin/ls" "bin/ls")
|
||||||
(file "/bin/mkdir" "bin/mkdir")
|
(file "/bin/mkdir" "bin/mkdir")
|
||||||
(file "/bin/mv" "bin/mv")
|
(file "/bin/mv" "bin/mv")
|
||||||
|
(file "/bin/ps" "bin/ps")
|
||||||
(file "/bin/pwd" "bin/pwd")
|
(file "/bin/pwd" "bin/pwd")
|
||||||
|
(file "/bin/rmdir" "bin/rmdir")
|
||||||
(file "/bin/rm" "bin/rm")
|
(file "/bin/rm" "bin/rm")
|
||||||
|
(file "/bin/sleep" "bin/sleep")
|
||||||
|
(file "/bin/stty" "bin/stty")
|
||||||
|
(file "/bin/sync" "bin/sync")
|
||||||
|
(file "/usr/bin/awk" "usr/bin/awk")
|
||||||
|
(file "/usr/bin/basename" "usr/bin/basename")
|
||||||
|
(file "/usr/bin/cap_mkdb" "usr/bin/cap_mkdb")
|
||||||
|
(file "/usr/bin/cut" "usr/bin/cut")
|
||||||
|
(file "/usr/bin/dirname" "usr/bin/dirname")
|
||||||
|
(file "/usr/bin/egrep" "usr/bin/egrep")
|
||||||
|
(file "/usr/bin/env" "usr/bin/env")
|
||||||
(file "/usr/bin/find" "bin/find")
|
(file "/usr/bin/find" "bin/find")
|
||||||
|
(file "/usr/bin/fsync" "usr/bin/fsync")
|
||||||
|
(file "/usr/bin/grep" "usr/bin/grep")
|
||||||
|
(file "/usr/bin/mktemp" "usr/bin/mktemp")
|
||||||
|
(file "/usr/bin/head" "usr/bin/head")
|
||||||
|
(file "/usr/bin/install" "usr/bin/install")
|
||||||
|
(file "/usr/bin/limits" "usr/bin/limits")
|
||||||
|
(file "/usr/bin/logger" "usr/bin/logger")
|
||||||
|
(file "/usr/bin/readlink" "usr/bin/readlink")
|
||||||
|
(file "/usr/bin/sed" "usr/bin/sed")
|
||||||
|
(file "/usr/bin/sort" "usr/bin/sort")
|
||||||
(file "/usr/bin/tar" "bin/tar")
|
(file "/usr/bin/tar" "bin/tar")
|
||||||
|
(file "/usr/bin/tr" "usr/bin/tr")
|
||||||
|
(file "/usr/bin/uname" "usr/bin/uname")
|
||||||
(file "/usr/bin/xargs" "bin/xargs"))))
|
(file "/usr/bin/xargs" "bin/xargs"))))
|
||||||
|
|
||||||
(define freebsd-rc-scripts
|
(define freebsd-rc-scripts
|
||||||
@@ -183,6 +246,10 @@ files needed by the first Fruix system-closure experiments."
|
|||||||
'((file "/etc/rc" "etc/rc")
|
'((file "/etc/rc" "etc/rc")
|
||||||
(file "/etc/rc.subr" "etc/rc.subr")
|
(file "/etc/rc.subr" "etc/rc.subr")
|
||||||
(file "/etc/rc.shutdown" "etc/rc.shutdown")
|
(file "/etc/rc.shutdown" "etc/rc.shutdown")
|
||||||
|
(file "/etc/devd.conf" "etc/devd.conf")
|
||||||
|
(file "/etc/network.subr" "etc/network.subr")
|
||||||
|
(file "/etc/newsyslog.conf" "etc/newsyslog.conf")
|
||||||
|
(file "/etc/syslog.conf" "etc/syslog.conf")
|
||||||
(directory "/etc/rc.d" "etc/rc.d")
|
(directory "/etc/rc.d" "etc/rc.d")
|
||||||
(directory "/etc/defaults" "etc/defaults"))))
|
(directory "/etc/defaults" "etc/defaults"))))
|
||||||
|
|
||||||
@@ -200,17 +267,81 @@ commands needed by the first declarative Fruix system and activation payload
|
|||||||
experiments."
|
experiments."
|
||||||
#:license 'bsd-2
|
#:license 'bsd-2
|
||||||
#:install-plan
|
#:install-plan
|
||||||
'((file "/sbin/init" "sbin/init")
|
'((file "/sbin/adjkerntz" "sbin/adjkerntz")
|
||||||
(file "/sbin/mount" "sbin/mount")
|
(file "/sbin/devd" "sbin/devd")
|
||||||
|
(file "/sbin/devmatch" "sbin/devmatch")
|
||||||
|
(file "/sbin/dmesg" "sbin/dmesg")
|
||||||
|
(file "/sbin/fsck" "sbin/fsck")
|
||||||
|
(file "/sbin/fsck_ufs" "sbin/fsck_ufs")
|
||||||
|
(file "/sbin/gpart" "sbin/gpart")
|
||||||
|
(file "/sbin/init" "sbin/init")
|
||||||
(file "/sbin/ifconfig" "sbin/ifconfig")
|
(file "/sbin/ifconfig" "sbin/ifconfig")
|
||||||
|
(file "/sbin/md5" "sbin/md5")
|
||||||
|
(file "/sbin/mount" "sbin/mount")
|
||||||
|
(file "/sbin/rcorder" "sbin/rcorder")
|
||||||
(file "/sbin/reboot" "sbin/reboot")
|
(file "/sbin/reboot" "sbin/reboot")
|
||||||
|
(file "/sbin/sha256" "sbin/sha256")
|
||||||
(file "/sbin/shutdown" "sbin/shutdown")
|
(file "/sbin/shutdown" "sbin/shutdown")
|
||||||
|
(file "/sbin/swapon" "sbin/swapon")
|
||||||
|
(file "/sbin/sysctl" "sbin/sysctl")
|
||||||
|
(file "/usr/sbin/chown" "usr/sbin/chown")
|
||||||
|
(file "/usr/sbin/cron" "usr/sbin/cron")
|
||||||
|
(file "/usr/sbin/devctl" "usr/sbin/devctl")
|
||||||
|
(file "/usr/sbin/nologin" "usr/sbin/nologin")
|
||||||
|
(file "/usr/sbin/pwd_mkdb" "usr/sbin/pwd_mkdb")
|
||||||
(file "/usr/sbin/service" "usr/sbin/service")
|
(file "/usr/sbin/service" "usr/sbin/service")
|
||||||
(file "/usr/sbin/pw" "usr/sbin/pw")
|
(file "/usr/sbin/ip6addrctl" "usr/sbin/ip6addrctl")
|
||||||
|
(file "/usr/sbin/newsyslog" "usr/sbin/newsyslog")
|
||||||
|
(file "/usr/sbin/syslogd" "usr/sbin/syslogd")
|
||||||
|
(file "/usr/sbin/utx" "usr/sbin/utx")
|
||||||
(file "/usr/bin/id" "usr/bin/id")
|
(file "/usr/bin/id" "usr/bin/id")
|
||||||
|
(file "/sbin/kldload" "sbin/kldload")
|
||||||
|
(file "/sbin/kldstat" "sbin/kldstat")
|
||||||
|
(file "/sbin/devfs" "sbin/devfs")
|
||||||
|
(file "/bin/freebsd-version" "bin/freebsd-version")
|
||||||
(file "/bin/hostname" "bin/hostname")
|
(file "/bin/hostname" "bin/hostname")
|
||||||
(file "/bin/kenv" "bin/kenv"))))
|
(file "/bin/kenv" "bin/kenv"))))
|
||||||
|
|
||||||
|
(define freebsd-networking
|
||||||
|
(freebsd-package
|
||||||
|
#:name "freebsd-networking"
|
||||||
|
#:version freebsd-release
|
||||||
|
#:build-system 'copy-build-system
|
||||||
|
#:inputs (list freebsd-libc freebsd-runtime freebsd-sh)
|
||||||
|
#:home-page "https://www.freebsd.org/"
|
||||||
|
#:synopsis "Prototype package for FreeBSD network runtime tools"
|
||||||
|
#:description
|
||||||
|
"Prototype package definition that stages the minimal FreeBSD networking
|
||||||
|
runtime needed for DHCP-based boot validation in virtual machines."
|
||||||
|
#:license 'bsd-2
|
||||||
|
#:install-plan
|
||||||
|
'((file "/sbin/dhclient" "sbin/dhclient")
|
||||||
|
(file "/sbin/dhclient-script" "sbin/dhclient-script")
|
||||||
|
(file "/sbin/route" "sbin/route")
|
||||||
|
(file "/usr/bin/netstat" "usr/bin/netstat")
|
||||||
|
(file "/usr/sbin/arp" "usr/sbin/arp"))))
|
||||||
|
|
||||||
|
(define freebsd-openssh
|
||||||
|
(freebsd-package
|
||||||
|
#:name "freebsd-openssh"
|
||||||
|
#:version freebsd-release
|
||||||
|
#:build-system 'copy-build-system
|
||||||
|
#:inputs (list freebsd-libc freebsd-runtime freebsd-sh)
|
||||||
|
#:home-page "https://www.freebsd.org/"
|
||||||
|
#:synopsis "Prototype package for the FreeBSD OpenSSH runtime"
|
||||||
|
#:description
|
||||||
|
"Prototype package definition that stages the FreeBSD OpenSSH server and
|
||||||
|
client tools needed for first-boot operator access on the Fruix prototype
|
||||||
|
track."
|
||||||
|
#:license 'bsd-2
|
||||||
|
#:install-plan
|
||||||
|
'((file "/usr/sbin/sshd" "usr/sbin/sshd")
|
||||||
|
(file "/usr/bin/ssh" "usr/bin/ssh")
|
||||||
|
(file "/usr/bin/ssh-keygen" "usr/bin/ssh-keygen")
|
||||||
|
(file "/usr/libexec/sshd-auth" "usr/libexec/sshd-auth")
|
||||||
|
(file "/usr/libexec/sshd-session" "usr/libexec/sshd-session")
|
||||||
|
(file "/etc/ssh/moduli" "etc/ssh/moduli"))))
|
||||||
|
|
||||||
(define freebsd-clang-toolchain
|
(define freebsd-clang-toolchain
|
||||||
(freebsd-package
|
(freebsd-package
|
||||||
#:name "freebsd-clang-toolchain"
|
#:name "freebsd-clang-toolchain"
|
||||||
@@ -354,6 +485,8 @@ library for profile experiments."
|
|||||||
freebsd-libc
|
freebsd-libc
|
||||||
freebsd-rc-scripts
|
freebsd-rc-scripts
|
||||||
freebsd-runtime
|
freebsd-runtime
|
||||||
|
freebsd-networking
|
||||||
|
freebsd-openssh
|
||||||
freebsd-userland
|
freebsd-userland
|
||||||
freebsd-sh
|
freebsd-sh
|
||||||
freebsd-bash))
|
freebsd-bash))
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
operating-system-loader-entries
|
operating-system-loader-entries
|
||||||
operating-system-rc-conf-entries
|
operating-system-rc-conf-entries
|
||||||
operating-system-ready-marker
|
operating-system-ready-marker
|
||||||
|
operating-system-root-authorized-keys
|
||||||
validate-operating-system
|
validate-operating-system
|
||||||
operating-system-closure-spec
|
operating-system-closure-spec
|
||||||
operating-system-image-spec
|
operating-system-image-spec
|
||||||
@@ -96,7 +97,7 @@
|
|||||||
(define-record-type <operating-system>
|
(define-record-type <operating-system>
|
||||||
(make-operating-system host-name kernel bootloader base-packages users groups
|
(make-operating-system host-name kernel bootloader base-packages users groups
|
||||||
file-systems services loader-entries rc-conf-entries
|
file-systems services loader-entries rc-conf-entries
|
||||||
ready-marker)
|
ready-marker root-authorized-keys)
|
||||||
operating-system?
|
operating-system?
|
||||||
(host-name operating-system-host-name)
|
(host-name operating-system-host-name)
|
||||||
(kernel operating-system-kernel)
|
(kernel operating-system-kernel)
|
||||||
@@ -108,7 +109,8 @@
|
|||||||
(services operating-system-services)
|
(services operating-system-services)
|
||||||
(loader-entries operating-system-loader-entries)
|
(loader-entries operating-system-loader-entries)
|
||||||
(rc-conf-entries operating-system-rc-conf-entries)
|
(rc-conf-entries operating-system-rc-conf-entries)
|
||||||
(ready-marker operating-system-ready-marker))
|
(ready-marker operating-system-ready-marker)
|
||||||
|
(root-authorized-keys operating-system-root-authorized-keys))
|
||||||
|
|
||||||
(define* (operating-system #:key
|
(define* (operating-system #:key
|
||||||
(host-name "fruix-freebsd")
|
(host-name "fruix-freebsd")
|
||||||
@@ -153,10 +155,11 @@
|
|||||||
(rc-conf-entries '(("clear_tmp_enable" . "YES")
|
(rc-conf-entries '(("clear_tmp_enable" . "YES")
|
||||||
("sendmail_enable" . "NONE")
|
("sendmail_enable" . "NONE")
|
||||||
("sshd_enable" . "NO")))
|
("sshd_enable" . "NO")))
|
||||||
(ready-marker "/var/lib/fruix/ready"))
|
(ready-marker "/var/lib/fruix/ready")
|
||||||
|
(root-authorized-keys '()))
|
||||||
(make-operating-system host-name kernel bootloader base-packages users groups
|
(make-operating-system host-name kernel bootloader base-packages users groups
|
||||||
file-systems services loader-entries rc-conf-entries
|
file-systems services loader-entries rc-conf-entries
|
||||||
ready-marker))
|
ready-marker root-authorized-keys))
|
||||||
|
|
||||||
(define default-minimal-operating-system (operating-system))
|
(define default-minimal-operating-system (operating-system))
|
||||||
|
|
||||||
@@ -292,11 +295,41 @@
|
|||||||
(hash-set! cache (package-cache-key package) output-path)
|
(hash-set! cache (package-cache-key package) output-path)
|
||||||
output-path))))
|
output-path))))
|
||||||
|
|
||||||
(define (prefix-manifest-string source-path)
|
(define prefix-materializer-version "2")
|
||||||
(string-append "prefix-source=" source-path "\n" (path-signature source-path)))
|
|
||||||
|
|
||||||
(define (materialize-prefix source-path name version store-dir)
|
(define (prefix-manifest-string source-path extra-files)
|
||||||
(let* ((manifest (prefix-manifest-string source-path))
|
(string-append
|
||||||
|
"prefix-materializer-version=" prefix-materializer-version "\n"
|
||||||
|
"prefix-source=" source-path "\n"
|
||||||
|
(path-signature source-path)
|
||||||
|
(if (null? extra-files)
|
||||||
|
""
|
||||||
|
(string-append
|
||||||
|
"\nextra-files=\n"
|
||||||
|
(string-join
|
||||||
|
(map (lambda (entry)
|
||||||
|
(string-append (cdr entry) "\n" (path-signature (car entry))))
|
||||||
|
extra-files)
|
||||||
|
"\n")))))
|
||||||
|
|
||||||
|
(define (copy-extra-node source destination)
|
||||||
|
(let ((kind (stat:type (lstat source))))
|
||||||
|
(mkdir-p (dirname destination))
|
||||||
|
(case kind
|
||||||
|
((symlink)
|
||||||
|
(unless (or (file-exists? destination)
|
||||||
|
(false-if-exception (readlink destination)))
|
||||||
|
(let ((target (readlink source)))
|
||||||
|
(symlink target destination)
|
||||||
|
(unless (string-prefix? "/" target)
|
||||||
|
(copy-extra-node (string-append (dirname source) "/" target)
|
||||||
|
(string-append (dirname destination) "/" target))))))
|
||||||
|
(else
|
||||||
|
(unless (file-exists? destination)
|
||||||
|
(copy-node source destination))))))
|
||||||
|
|
||||||
|
(define* (materialize-prefix source-path name version store-dir #:key (extra-files '()))
|
||||||
|
(let* ((manifest (prefix-manifest-string source-path extra-files))
|
||||||
(hash (string-hash manifest))
|
(hash (string-hash manifest))
|
||||||
(output-path (string-append store-dir "/" hash "-" name "-" version)))
|
(output-path (string-append store-dir "/" hash "-" name "-" version)))
|
||||||
(unless (file-exists? output-path)
|
(unless (file-exists? output-path)
|
||||||
@@ -305,6 +338,10 @@
|
|||||||
(copy-node (string-append source-path "/" entry)
|
(copy-node (string-append source-path "/" entry)
|
||||||
(string-append output-path "/" entry)))
|
(string-append output-path "/" entry)))
|
||||||
(directory-entries source-path))
|
(directory-entries source-path))
|
||||||
|
(for-each (lambda (entry)
|
||||||
|
(copy-extra-node (car entry)
|
||||||
|
(string-append output-path "/" (cdr entry))))
|
||||||
|
extra-files)
|
||||||
(write-file (string-append output-path "/.fruix-package") manifest))
|
(write-file (string-append output-path "/.fruix-package") manifest))
|
||||||
output-path))
|
output-path))
|
||||||
|
|
||||||
@@ -352,8 +389,18 @@
|
|||||||
"\n")
|
"\n")
|
||||||
"\n"))
|
"\n"))
|
||||||
|
|
||||||
|
(define (rc-conf-entry-value os key)
|
||||||
|
(let ((entry (assoc key (operating-system-rc-conf-entries os))))
|
||||||
|
(and entry (cdr entry))))
|
||||||
|
|
||||||
|
(define (sshd-enabled? os)
|
||||||
|
(let ((value (rc-conf-entry-value os "sshd_enable")))
|
||||||
|
(and value
|
||||||
|
(member (string-upcase value) '("YES" "TRUE" "1")))))
|
||||||
|
|
||||||
(define (render-rc.conf os)
|
(define (render-rc.conf os)
|
||||||
(let* ((entries (append `(("hostname" . ,(operating-system-host-name os))
|
(let* ((entries (append `(("hostname" . ,(operating-system-host-name os))
|
||||||
|
("fruix_activate_enable" . "YES")
|
||||||
("fruix_shepherd_enable" . "YES"))
|
("fruix_shepherd_enable" . "YES"))
|
||||||
(operating-system-rc-conf-entries os))))
|
(operating-system-rc-conf-entries os))))
|
||||||
(string-append
|
(string-append
|
||||||
@@ -386,6 +433,23 @@
|
|||||||
"\n")
|
"\n")
|
||||||
"\n")))
|
"\n")))
|
||||||
|
|
||||||
|
(define (render-master-passwd os)
|
||||||
|
(let ((groups (operating-system-groups os)))
|
||||||
|
(string-append
|
||||||
|
(string-join
|
||||||
|
(map (lambda (account)
|
||||||
|
(format #f "~a:*:~a:~a::0:0:~a:~a:~a"
|
||||||
|
(user-account-name account)
|
||||||
|
(user-account-uid account)
|
||||||
|
(or (group-name->gid groups (user-account-group account))
|
||||||
|
(error "unknown primary group" (user-account-group account)))
|
||||||
|
(user-account-comment account)
|
||||||
|
(user-account-home account)
|
||||||
|
(user-account-shell account)))
|
||||||
|
(operating-system-users os))
|
||||||
|
"\n")
|
||||||
|
"\n")))
|
||||||
|
|
||||||
(define (render-group os)
|
(define (render-group os)
|
||||||
(let ((users (operating-system-users os)))
|
(let ((users (operating-system-users os)))
|
||||||
(string-append
|
(string-append
|
||||||
@@ -404,17 +468,25 @@
|
|||||||
"\n")
|
"\n")
|
||||||
"\n")))
|
"\n")))
|
||||||
|
|
||||||
|
(define (fstab-fsck-fields fs)
|
||||||
|
(if (string=? (file-system-type fs) "ufs")
|
||||||
|
(if (string=? (file-system-mount-point fs) "/")
|
||||||
|
'(1 1)
|
||||||
|
'(2 2))
|
||||||
|
'(0 0)))
|
||||||
|
|
||||||
(define (render-fstab os)
|
(define (render-fstab os)
|
||||||
(string-append
|
(string-append
|
||||||
(string-join
|
(string-join
|
||||||
(map (lambda (fs)
|
(map (lambda (fs)
|
||||||
(format #f "~a\t~a\t~a\t~a\t~a\t~a"
|
(let ((checks (fstab-fsck-fields fs)))
|
||||||
(file-system-device fs)
|
(format #f "~a\t~a\t~a\t~a\t~a\t~a"
|
||||||
(file-system-mount-point fs)
|
(file-system-device fs)
|
||||||
(file-system-type fs)
|
(file-system-mount-point fs)
|
||||||
(file-system-options fs)
|
(file-system-type fs)
|
||||||
(if (string=? (file-system-mount-point fs) "/") 1 0)
|
(file-system-options fs)
|
||||||
(if (file-system-needed-for-boot? fs) 1 2)))
|
(first checks)
|
||||||
|
(second checks))))
|
||||||
(operating-system-file-systems os))
|
(operating-system-file-systems os))
|
||||||
"\n")
|
"\n")
|
||||||
"\n"))
|
"\n"))
|
||||||
@@ -431,43 +503,85 @@
|
|||||||
(define (render-motd os)
|
(define (render-motd os)
|
||||||
(string-append "Welcome to Fruix on FreeBSD (" (operating-system-host-name os) ")\n"))
|
(string-append "Welcome to Fruix on FreeBSD (" (operating-system-host-name os) ")\n"))
|
||||||
|
|
||||||
|
(define (render-login-conf)
|
||||||
|
(string-append
|
||||||
|
"default:\\\n"
|
||||||
|
"\t:path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin:\\\n"
|
||||||
|
"\t:umask=022:\\\n"
|
||||||
|
"\t:charset=UTF-8:\\\n"
|
||||||
|
"\t:lang=C.UTF-8:\n"
|
||||||
|
"daemon:\\\n"
|
||||||
|
"\t:path=/sbin /bin /usr/sbin /usr/bin /usr/local/sbin /usr/local/bin:\\\n"
|
||||||
|
"\t:tc=default:\n"
|
||||||
|
"root:\\\n"
|
||||||
|
"\t:ignorenologin:\\\n"
|
||||||
|
"\t:tc=default:\n"))
|
||||||
|
|
||||||
|
(define (render-ttys)
|
||||||
|
(string-append
|
||||||
|
"console\tnone\tunknown\toff secure\n"
|
||||||
|
"ttyu0\tnone\tvt100\toff secure\n"
|
||||||
|
"xc0\tnone\txterm\toff secure\n"))
|
||||||
|
|
||||||
|
(define (render-root-authorized-keys os)
|
||||||
|
(if (null? (operating-system-root-authorized-keys os))
|
||||||
|
""
|
||||||
|
(string-append
|
||||||
|
(string-join (operating-system-root-authorized-keys os) "\n")
|
||||||
|
"\n")))
|
||||||
|
|
||||||
|
(define (render-sshd-config os)
|
||||||
|
(string-append
|
||||||
|
"Port 22\n"
|
||||||
|
"PermitRootLogin yes\n"
|
||||||
|
"PasswordAuthentication no\n"
|
||||||
|
"KbdInteractiveAuthentication no\n"
|
||||||
|
"ChallengeResponseAuthentication no\n"
|
||||||
|
"UsePAM no\n"
|
||||||
|
"PubkeyAuthentication yes\n"
|
||||||
|
"AuthorizedKeysFile .ssh/authorized_keys\n"
|
||||||
|
"PidFile /var/run/sshd.pid\n"
|
||||||
|
"UseDNS no\n"))
|
||||||
|
|
||||||
(define (render-activation-script os)
|
(define (render-activation-script os)
|
||||||
(let* ((users (operating-system-users os))
|
(let* ((users (operating-system-users os))
|
||||||
(groups (operating-system-groups os))
|
(groups (operating-system-groups os))
|
||||||
(non-root-groups (filter (lambda (group)
|
(home-setup
|
||||||
(> (user-group-gid group) 0))
|
(string-join
|
||||||
groups))
|
(map (lambda (account)
|
||||||
(non-root-users (filter (lambda (account)
|
(let ((name (user-account-name account))
|
||||||
(> (user-account-uid account) 0))
|
(uid (user-account-uid account))
|
||||||
users)))
|
(gid (or (group-name->gid groups (user-account-group account))
|
||||||
|
(error "unknown primary group" (user-account-group account))))
|
||||||
|
(home (user-account-home account))
|
||||||
|
(system? (user-account-system? account)))
|
||||||
|
(string-append
|
||||||
|
"mkdir -p " home "\n"
|
||||||
|
(if (or (string=? name "root") system?)
|
||||||
|
""
|
||||||
|
(format #f "if [ -x /usr/sbin/chown ]; then /usr/sbin/chown ~a:~a ~a 2>/dev/null || true; fi\n"
|
||||||
|
uid gid home)))))
|
||||||
|
users)
|
||||||
|
""))
|
||||||
|
(ssh-section
|
||||||
|
(string-append
|
||||||
|
"mkdir -p /var/empty /etc/ssh /root/.ssh\n"
|
||||||
|
"chmod 700 /root/.ssh\n"
|
||||||
|
(if (null? (operating-system-root-authorized-keys os))
|
||||||
|
""
|
||||||
|
"if [ -f /run/current-system/root/.ssh/authorized_keys ]; then cp /run/current-system/root/.ssh/authorized_keys /root/.ssh/authorized_keys; chmod 600 /root/.ssh/authorized_keys; fi\n")
|
||||||
|
(if (sshd-enabled? os)
|
||||||
|
"if [ -x /usr/bin/ssh-keygen ]; then /usr/bin/ssh-keygen -A; fi\n"
|
||||||
|
""))))
|
||||||
(string-append
|
(string-append
|
||||||
"#!/bin/sh\n"
|
"#!/bin/sh\n"
|
||||||
"set -eu\n"
|
"set -eu\n"
|
||||||
"mkdir -p /var/lib/fruix /var/log /var/run /root /home /tmp\n"
|
"mkdir -p /var/cron /var/db /var/lib/fruix /var/log /var/run /root /home /tmp\n"
|
||||||
"chmod 1777 /tmp\n"
|
"chmod 1777 /tmp\n"
|
||||||
(string-join
|
"if [ -x /usr/bin/cap_mkdb ] && [ -f /etc/login.conf ]; then /usr/bin/cap_mkdb /etc/login.conf; fi\n"
|
||||||
(append
|
"if [ -x /usr/sbin/pwd_mkdb ] && [ -f /etc/master.passwd ]; then /usr/sbin/pwd_mkdb -p /etc/master.passwd; fi\n"
|
||||||
(map (lambda (group)
|
home-setup
|
||||||
(format #f "pw groupadd ~a -g ~a 2>/dev/null || true"
|
ssh-section)))
|
||||||
(user-group-name group)
|
|
||||||
(user-group-gid group)))
|
|
||||||
non-root-groups)
|
|
||||||
(map (lambda (account)
|
|
||||||
(let ((group (user-account-group account))
|
|
||||||
(supplementary (user-account-supplementary-groups account)))
|
|
||||||
(format #f "pw useradd ~a -u ~a -g ~a~a -d ~a -m -s ~a -c '~a' 2>/dev/null || true"
|
|
||||||
(user-account-name account)
|
|
||||||
(user-account-uid account)
|
|
||||||
group
|
|
||||||
(if (null? supplementary)
|
|
||||||
""
|
|
||||||
(string-append " -G " (string-join supplementary ",")))
|
|
||||||
(user-account-home account)
|
|
||||||
(user-account-shell account)
|
|
||||||
(user-account-comment account))))
|
|
||||||
non-root-users))
|
|
||||||
"\n")
|
|
||||||
"\n")))
|
|
||||||
|
|
||||||
(define (render-shepherd-config os)
|
(define (render-shepherd-config os)
|
||||||
(let ((ready-marker (operating-system-ready-marker os)))
|
(let ((ready-marker (operating-system-ready-marker os)))
|
||||||
@@ -502,6 +616,26 @@
|
|||||||
" #:respawn? #f)))\n\n"
|
" #:respawn? #f)))\n\n"
|
||||||
"(start-service (lookup-service 'fruix-ready))\n")))
|
"(start-service (lookup-service 'fruix-ready))\n")))
|
||||||
|
|
||||||
|
(define (render-activation-rc-script)
|
||||||
|
(string-append
|
||||||
|
"#!/bin/sh\n"
|
||||||
|
"# PROVIDE: fruix_activate\n"
|
||||||
|
"# REQUIRE: FILESYSTEMS\n"
|
||||||
|
"# BEFORE: LOGIN sshd fruix_shepherd\n"
|
||||||
|
"# KEYWORD: shutdown\n\n"
|
||||||
|
". /etc/rc.subr\n\n"
|
||||||
|
"name=fruix_activate\n"
|
||||||
|
"rcvar=fruix_activate_enable\n"
|
||||||
|
": ${fruix_activate_enable:=YES}\n"
|
||||||
|
"start_cmd=fruix_activate_start\n"
|
||||||
|
"stop_cmd=:\n\n"
|
||||||
|
"fruix_activate_start()\n"
|
||||||
|
"{\n"
|
||||||
|
" /run/current-system/activate\n"
|
||||||
|
"}\n\n"
|
||||||
|
"load_rc_config $name\n"
|
||||||
|
"run_rc_command \"$1\"\n"))
|
||||||
|
|
||||||
(define (render-rc-script shepherd-store guile-store guile-extra-store)
|
(define (render-rc-script shepherd-store guile-store guile-extra-store)
|
||||||
(let ((ld-library-path (string-append guile-extra-store "/lib:"
|
(let ((ld-library-path (string-append guile-extra-store "/lib:"
|
||||||
guile-store "/lib:/usr/local/lib"))
|
guile-store "/lib:/usr/local/lib"))
|
||||||
@@ -514,7 +648,7 @@
|
|||||||
(string-append
|
(string-append
|
||||||
"#!/bin/sh\n"
|
"#!/bin/sh\n"
|
||||||
"# PROVIDE: fruix_shepherd\n"
|
"# PROVIDE: fruix_shepherd\n"
|
||||||
"# REQUIRE: FILESYSTEMS\n"
|
"# REQUIRE: FILESYSTEMS fruix_activate\n"
|
||||||
"# BEFORE: LOGIN\n"
|
"# BEFORE: LOGIN\n"
|
||||||
"# KEYWORD: shutdown\n\n"
|
"# KEYWORD: shutdown\n\n"
|
||||||
". /etc/rc.subr\n\n"
|
". /etc/rc.subr\n\n"
|
||||||
@@ -535,7 +669,7 @@
|
|||||||
" GUILE_LOAD_PATH='" guile-load-path "' \\\n"
|
" GUILE_LOAD_PATH='" guile-load-path "' \\\n"
|
||||||
" GUILE_LOAD_COMPILED_PATH='" guile-load-compiled-path "' \\\n"
|
" GUILE_LOAD_COMPILED_PATH='" guile-load-compiled-path "' \\\n"
|
||||||
" GUILE_EXTENSIONS_PATH='" guile-extensions-path "' \\\n"
|
" GUILE_EXTENSIONS_PATH='" guile-extensions-path "' \\\n"
|
||||||
" " shepherd-store "/bin/shepherd -I -s \"$socket\" -c \"$config\" --pid=\"$pidfile\" -l \"$logfile\" >/var/log/shepherd-bootstrap.out 2>&1 &\n"
|
" " guile-store "/bin/guile --no-auto-compile " shepherd-store "/bin/shepherd -I -s \"$socket\" -c \"$config\" --pid=\"$pidfile\" -l \"$logfile\" >/var/log/shepherd-bootstrap.out 2>&1 &\n"
|
||||||
" for _try in 1 2 3 4 5 6 7 8 9 10; do\n"
|
" for _try in 1 2 3 4 5 6 7 8 9 10; do\n"
|
||||||
" [ -f \"$pidfile\" ] && [ -S \"$socket\" ] && return 0\n"
|
" [ -f \"$pidfile\" ] && [ -S \"$socket\" ] && return 0\n"
|
||||||
" sleep 1\n"
|
" sleep 1\n"
|
||||||
@@ -548,7 +682,7 @@
|
|||||||
" GUILE_LOAD_PATH='" guile-load-path "' \\\n"
|
" GUILE_LOAD_PATH='" guile-load-path "' \\\n"
|
||||||
" GUILE_LOAD_COMPILED_PATH='" guile-load-compiled-path "' \\\n"
|
" GUILE_LOAD_COMPILED_PATH='" guile-load-compiled-path "' \\\n"
|
||||||
" GUILE_EXTENSIONS_PATH='" guile-extensions-path "' \\\n"
|
" GUILE_EXTENSIONS_PATH='" guile-extensions-path "' \\\n"
|
||||||
" " shepherd-store "/bin/herd -s \"$socket\" stop root >/dev/null 2>&1 || true\n"
|
" " guile-store "/bin/guile --no-auto-compile " shepherd-store "/bin/herd -s \"$socket\" stop root >/dev/null 2>&1 || true\n"
|
||||||
" for _try in 1 2 3 4 5 6 7 8 9 10; do\n"
|
" for _try in 1 2 3 4 5 6 7 8 9 10; do\n"
|
||||||
" [ ! -f \"$pidfile\" ] && return 0\n"
|
" [ ! -f \"$pidfile\" ] && return 0\n"
|
||||||
" sleep 1\n"
|
" sleep 1\n"
|
||||||
@@ -565,16 +699,26 @@
|
|||||||
"run_rc_command \"$1\"\n")))
|
"run_rc_command \"$1\"\n")))
|
||||||
|
|
||||||
(define (operating-system-generated-files os)
|
(define (operating-system-generated-files os)
|
||||||
`(("boot/loader.conf" . ,(render-loader-conf (operating-system-loader-entries os)))
|
(append
|
||||||
("etc/rc.conf" . ,(render-rc.conf os))
|
`(("boot/loader.conf" . ,(render-loader-conf (operating-system-loader-entries os)))
|
||||||
("etc/fstab" . ,(render-fstab os))
|
("etc/rc.conf" . ,(render-rc.conf os))
|
||||||
("etc/hosts" . ,(render-hosts os))
|
("etc/fstab" . ,(render-fstab os))
|
||||||
("etc/passwd" . ,(render-passwd os))
|
("etc/hosts" . ,(render-hosts os))
|
||||||
("etc/group" . ,(render-group os))
|
("etc/passwd" . ,(render-passwd os))
|
||||||
("etc/shells" . ,(render-shells os))
|
("etc/master.passwd" . ,(render-master-passwd os))
|
||||||
("etc/motd" . ,(render-motd os))
|
("etc/group" . ,(render-group os))
|
||||||
("activate" . ,(render-activation-script os))
|
("etc/login.conf" . ,(render-login-conf))
|
||||||
("shepherd/init.scm" . ,(render-shepherd-config os))))
|
("etc/shells" . ,(render-shells os))
|
||||||
|
("etc/motd" . ,(render-motd os))
|
||||||
|
("etc/ttys" . ,(render-ttys))
|
||||||
|
("activate" . ,(render-activation-script os))
|
||||||
|
("shepherd/init.scm" . ,(render-shepherd-config os)))
|
||||||
|
(if (sshd-enabled? os)
|
||||||
|
`(("etc/ssh/sshd_config" . ,(render-sshd-config os)))
|
||||||
|
'())
|
||||||
|
(if (null? (operating-system-root-authorized-keys os))
|
||||||
|
'()
|
||||||
|
`(("root/.ssh/authorized_keys" . ,(render-root-authorized-keys os))))))
|
||||||
|
|
||||||
(define (operating-system-closure-spec os)
|
(define (operating-system-closure-spec os)
|
||||||
(validate-operating-system os)
|
(validate-operating-system os)
|
||||||
@@ -649,11 +793,31 @@
|
|||||||
(base-package-stores (map (lambda (package)
|
(base-package-stores (map (lambda (package)
|
||||||
(materialize-freebsd-package package store-dir cache))
|
(materialize-freebsd-package package store-dir cache))
|
||||||
(operating-system-base-packages os)))
|
(operating-system-base-packages os)))
|
||||||
(guile-store (materialize-prefix guile-prefix "fruix-guile-runtime" "3.0" store-dir))
|
(guile-runtime-extra-files
|
||||||
(guile-extra-store (materialize-prefix guile-extra-prefix "fruix-guile-extra" "3.0" store-dir))
|
'(("/usr/local/lib/libgc-threaded.so.1" . "lib/libgc-threaded.so.1")
|
||||||
|
("/usr/local/lib/libffi.so.8" . "lib/libffi.so.8")
|
||||||
|
("/usr/local/lib/libintl.so.8" . "lib/libintl.so.8")
|
||||||
|
("/usr/local/lib/libunistring.so.5" . "lib/libunistring.so.5")
|
||||||
|
("/usr/local/lib/libiconv.so.2" . "lib/libiconv.so.2")
|
||||||
|
("/usr/local/lib/libgmp.so.10" . "lib/libgmp.so.10")))
|
||||||
|
(guile-extra-runtime-files
|
||||||
|
'(("/usr/local/lib/libevent-2.1.so.7" . "lib/libevent-2.1.so.7")
|
||||||
|
("/usr/local/lib/libgnutls.so.30" . "lib/libgnutls.so.30")
|
||||||
|
("/usr/local/lib/libp11-kit.so.0" . "lib/libp11-kit.so.0")
|
||||||
|
("/usr/local/lib/libidn2.so.0" . "lib/libidn2.so.0")
|
||||||
|
("/usr/local/lib/libtasn1.so.6" . "lib/libtasn1.so.6")
|
||||||
|
("/usr/local/lib/libhogweed.so.6" . "lib/libhogweed.so.6")
|
||||||
|
("/usr/local/lib/libnettle.so.8" . "lib/libnettle.so.8")))
|
||||||
|
(guile-store (materialize-prefix guile-prefix "fruix-guile-runtime" "3.0" store-dir
|
||||||
|
#:extra-files guile-runtime-extra-files))
|
||||||
|
(guile-extra-store (materialize-prefix guile-extra-prefix "fruix-guile-extra" "3.0" store-dir
|
||||||
|
#:extra-files (append guile-runtime-extra-files
|
||||||
|
guile-extra-runtime-files)))
|
||||||
(shepherd-store (materialize-prefix shepherd-prefix "fruix-shepherd-runtime" "1.0.9" store-dir))
|
(shepherd-store (materialize-prefix shepherd-prefix "fruix-shepherd-runtime" "1.0.9" store-dir))
|
||||||
(generated-files (append (operating-system-generated-files os)
|
(generated-files (append (operating-system-generated-files os)
|
||||||
`(("usr/local/etc/rc.d/fruix-shepherd"
|
`(("usr/local/etc/rc.d/fruix-activate"
|
||||||
|
. ,(render-activation-rc-script))
|
||||||
|
("usr/local/etc/rc.d/fruix-shepherd"
|
||||||
. ,(render-rc-script shepherd-store guile-store guile-extra-store)))))
|
. ,(render-rc-script shepherd-store guile-store guile-extra-store)))))
|
||||||
(references (append (list kernel-store bootloader-store guile-store guile-extra-store shepherd-store)
|
(references (append (list kernel-store bootloader-store guile-store guile-extra-store shepherd-store)
|
||||||
base-package-stores))
|
base-package-stores))
|
||||||
@@ -692,6 +856,7 @@
|
|||||||
(write-file (string-append closure-path "/" (car entry)) (cdr entry)))
|
(write-file (string-append closure-path "/" (car entry)) (cdr entry)))
|
||||||
generated-files)
|
generated-files)
|
||||||
(chmod (string-append closure-path "/activate") #o555)
|
(chmod (string-append closure-path "/activate") #o555)
|
||||||
|
(chmod (string-append closure-path "/usr/local/etc/rc.d/fruix-activate") #o555)
|
||||||
(chmod (string-append closure-path "/usr/local/etc/rc.d/fruix-shepherd") #o555)
|
(chmod (string-append closure-path "/usr/local/etc/rc.d/fruix-shepherd") #o555)
|
||||||
(write-file (string-append closure-path "/parameters.scm")
|
(write-file (string-append closure-path "/parameters.scm")
|
||||||
(object->string (operating-system-closure-spec os)))
|
(object->string (operating-system-closure-spec os)))
|
||||||
@@ -731,8 +896,8 @@
|
|||||||
(mkdir-p rootfs)
|
(mkdir-p rootfs)
|
||||||
(for-each (lambda (dir)
|
(for-each (lambda (dir)
|
||||||
(mkdir-p (string-append rootfs dir)))
|
(mkdir-p (string-append rootfs dir)))
|
||||||
'("/run" "/boot" "/etc" "/usr" "/usr/local" "/usr/local/etc"
|
'("/run" "/boot" "/etc" "/etc/ssh" "/usr" "/usr/local" "/usr/local/etc"
|
||||||
"/usr/local/etc/rc.d" "/var" "/var/lib" "/var/lib/fruix"
|
"/usr/local/etc/rc.d" "/var" "/var/cron" "/var/db" "/var/lib" "/var/lib/fruix"
|
||||||
"/var/log" "/var/run" "/tmp" "/dev" "/root" "/home"))
|
"/var/log" "/var/run" "/tmp" "/dev" "/root" "/home"))
|
||||||
(chmod (string-append rootfs "/tmp") #o1777)
|
(chmod (string-append rootfs "/tmp") #o1777)
|
||||||
(symlink-force closure-path (string-append rootfs "/run/current-system"))
|
(symlink-force closure-path (string-append rootfs "/run/current-system"))
|
||||||
@@ -744,19 +909,26 @@
|
|||||||
(for-each (lambda (dir)
|
(for-each (lambda (dir)
|
||||||
(symlink-force (string-append "/run/current-system/profile/usr/" dir)
|
(symlink-force (string-append "/run/current-system/profile/usr/" dir)
|
||||||
(string-append rootfs "/usr/" dir)))
|
(string-append rootfs "/usr/" dir)))
|
||||||
'("bin" "sbin" "libexec"))
|
'("bin" "lib" "sbin" "libexec"))
|
||||||
(for-each (lambda (path)
|
(for-each (lambda (path)
|
||||||
(symlink-force (string-append "/run/current-system/profile/etc/" path)
|
(symlink-force (string-append "/run/current-system/profile/etc/" path)
|
||||||
(string-append rootfs "/etc/" path)))
|
(string-append rootfs "/etc/" path)))
|
||||||
'("rc" "rc.subr" "rc.shutdown" "rc.d" "defaults"))
|
'("rc" "rc.subr" "rc.shutdown" "rc.d" "defaults"
|
||||||
|
"devd.conf" "network.subr" "newsyslog.conf" "syslog.conf"))
|
||||||
(for-each (lambda (path)
|
(for-each (lambda (path)
|
||||||
(symlink-force (string-append "/run/current-system/etc/" path)
|
(symlink-force (string-append "/run/current-system/etc/" path)
|
||||||
(string-append rootfs "/etc/" path)))
|
(string-append rootfs "/etc/" path)))
|
||||||
'("rc.conf" "fstab" "hosts" "passwd" "group" "shells" "motd"))
|
'("rc.conf" "fstab" "hosts" "passwd" "master.passwd" "group"
|
||||||
|
"login.conf" "shells" "motd" "ttys"))
|
||||||
|
(when (file-exists? (string-append closure-path "/etc/ssh/sshd_config"))
|
||||||
|
(symlink-force "/run/current-system/etc/ssh/sshd_config"
|
||||||
|
(string-append rootfs "/etc/ssh/sshd_config")))
|
||||||
(for-each (lambda (path)
|
(for-each (lambda (path)
|
||||||
(symlink-force (string-append "/run/current-system/boot/" path)
|
(symlink-force (string-append "/run/current-system/boot/" path)
|
||||||
(string-append rootfs "/boot/" path)))
|
(string-append rootfs "/boot/" path)))
|
||||||
'("kernel" "loader" "loader.efi" "device.hints" "defaults" "lua" "loader.conf"))
|
'("kernel" "loader" "loader.efi" "device.hints" "defaults" "lua" "loader.conf"))
|
||||||
|
(symlink-force "/run/current-system/usr/local/etc/rc.d/fruix-activate"
|
||||||
|
(string-append rootfs "/usr/local/etc/rc.d/fruix-activate"))
|
||||||
(symlink-force "/run/current-system/usr/local/etc/rc.d/fruix-shepherd"
|
(symlink-force "/run/current-system/usr/local/etc/rc.d/fruix-shepherd"
|
||||||
(string-append rootfs "/usr/local/etc/rc.d/fruix-shepherd"))
|
(string-append rootfs "/usr/local/etc/rc.d/fruix-shepherd"))
|
||||||
`((rootfs . ,rootfs)
|
`((rootfs . ,rootfs)
|
||||||
@@ -771,6 +943,7 @@
|
|||||||
(partition-scheme 'gpt)
|
(partition-scheme 'gpt)
|
||||||
(efi-size "64m")
|
(efi-size "64m")
|
||||||
(root-size "256m")
|
(root-size "256m")
|
||||||
|
(disk-capacity #f)
|
||||||
(efi-partition-label "efiboot")
|
(efi-partition-label "efiboot")
|
||||||
(root-partition-label "fruix-root")
|
(root-partition-label "fruix-root")
|
||||||
(serial-console "comconsole"))
|
(serial-console "comconsole"))
|
||||||
@@ -780,6 +953,7 @@
|
|||||||
(partition-scheme . ,partition-scheme)
|
(partition-scheme . ,partition-scheme)
|
||||||
(efi-size . ,efi-size)
|
(efi-size . ,efi-size)
|
||||||
(root-size . ,root-size)
|
(root-size . ,root-size)
|
||||||
|
(disk-capacity . ,disk-capacity)
|
||||||
(efi-partition-label . ,efi-partition-label)
|
(efi-partition-label . ,efi-partition-label)
|
||||||
(root-partition-label . ,root-partition-label)
|
(root-partition-label . ,root-partition-label)
|
||||||
(serial-console . ,serial-console)
|
(serial-console . ,serial-console)
|
||||||
@@ -830,6 +1004,19 @@
|
|||||||
(define (mktemp-directory pattern)
|
(define (mktemp-directory pattern)
|
||||||
(command-output "mktemp" "-d" pattern))
|
(command-output "mktemp" "-d" pattern))
|
||||||
|
|
||||||
|
(define image-builder-version "2")
|
||||||
|
|
||||||
|
(define (resize-gpt-image image disk-capacity)
|
||||||
|
(when disk-capacity
|
||||||
|
(run-command "truncate" "-s" disk-capacity image)
|
||||||
|
(let ((md (command-output "mdconfig" "-a" "-t" "vnode" "-f" image)))
|
||||||
|
(dynamic-wind
|
||||||
|
(lambda () #t)
|
||||||
|
(lambda ()
|
||||||
|
(run-command "gpart" "recover" (string-append "/dev/" md)))
|
||||||
|
(lambda ()
|
||||||
|
(run-command "mdconfig" "-d" "-u" (string-drop md 2)))))))
|
||||||
|
|
||||||
(define* (materialize-bhyve-image os
|
(define* (materialize-bhyve-image os
|
||||||
#:key
|
#:key
|
||||||
(store-dir "/frx/store")
|
(store-dir "/frx/store")
|
||||||
@@ -838,6 +1025,7 @@
|
|||||||
(shepherd-prefix "/tmp/shepherd-freebsd-validate-install")
|
(shepherd-prefix "/tmp/shepherd-freebsd-validate-install")
|
||||||
(efi-size "64m")
|
(efi-size "64m")
|
||||||
(root-size "256m")
|
(root-size "256m")
|
||||||
|
(disk-capacity #f)
|
||||||
(efi-partition-label "efiboot")
|
(efi-partition-label "efiboot")
|
||||||
(root-partition-label "fruix-root")
|
(root-partition-label "fruix-root")
|
||||||
(serial-console "comconsole"))
|
(serial-console "comconsole"))
|
||||||
@@ -850,12 +1038,15 @@
|
|||||||
(image-spec (operating-system-image-spec os
|
(image-spec (operating-system-image-spec os
|
||||||
#:efi-size efi-size
|
#:efi-size efi-size
|
||||||
#:root-size root-size
|
#:root-size root-size
|
||||||
|
#:disk-capacity disk-capacity
|
||||||
#:efi-partition-label efi-partition-label
|
#:efi-partition-label efi-partition-label
|
||||||
#:root-partition-label root-partition-label
|
#:root-partition-label root-partition-label
|
||||||
#:serial-console serial-console))
|
#:serial-console serial-console))
|
||||||
(store-items (store-reference-closure (list closure-path)))
|
(store-items (store-reference-closure (list closure-path)))
|
||||||
(manifest (string-append
|
(manifest (string-append
|
||||||
"image-spec=\n"
|
"image-builder-version=\n"
|
||||||
|
image-builder-version
|
||||||
|
"\nimage-spec=\n"
|
||||||
(object->string image-spec)
|
(object->string image-spec)
|
||||||
"closure-path=\n"
|
"closure-path=\n"
|
||||||
closure-path
|
closure-path
|
||||||
@@ -905,6 +1096,7 @@
|
|||||||
"-p" (string-append "efi/" efi-partition-label ":=" temp-esp)
|
"-p" (string-append "efi/" efi-partition-label ":=" temp-esp)
|
||||||
"-p" (string-append "freebsd-ufs/" root-partition-label ":=" temp-root)
|
"-p" (string-append "freebsd-ufs/" root-partition-label ":=" temp-root)
|
||||||
"-o" temp-disk)
|
"-o" temp-disk)
|
||||||
|
(resize-gpt-image temp-disk disk-capacity)
|
||||||
(mkdir-p temp-output)
|
(mkdir-p temp-output)
|
||||||
(copy-regular-file temp-disk (string-append temp-output "/disk.img"))
|
(copy-regular-file temp-disk (string-append temp-output "/disk.img"))
|
||||||
(copy-regular-file temp-esp (string-append temp-output "/esp.img"))
|
(copy-regular-file temp-esp (string-append temp-output "/esp.img"))
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
"/tmp/shepherd-freebsd-validate-install"))
|
"/tmp/shepherd-freebsd-validate-install"))
|
||||||
(define metadata-file
|
(define metadata-file
|
||||||
(string-append workdir "/phase8-system-image-metadata.txt"))
|
(string-append workdir "/phase8-system-image-metadata.txt"))
|
||||||
|
(define disk-capacity
|
||||||
|
(let ((value (getenv "DISK_CAPACITY")))
|
||||||
|
(and value (not (string-null? value)) value)))
|
||||||
|
|
||||||
(define (trim-trailing-newlines str)
|
(define (trim-trailing-newlines str)
|
||||||
(let loop ((len (string-length str)))
|
(let loop ((len (string-length str)))
|
||||||
@@ -48,16 +51,30 @@
|
|||||||
(primitive-load os-file)
|
(primitive-load os-file)
|
||||||
(validate-operating-system phase7-operating-system)
|
(validate-operating-system phase7-operating-system)
|
||||||
|
|
||||||
(let* ((image-a (materialize-bhyve-image phase7-operating-system
|
(let* ((image-a (if disk-capacity
|
||||||
#:store-dir store-dir
|
(materialize-bhyve-image phase7-operating-system
|
||||||
#:guile-prefix guile-prefix
|
#:store-dir store-dir
|
||||||
#:guile-extra-prefix guile-extra-prefix
|
#:guile-prefix guile-prefix
|
||||||
#:shepherd-prefix shepherd-prefix))
|
#:guile-extra-prefix guile-extra-prefix
|
||||||
(image-b (materialize-bhyve-image phase7-operating-system
|
#:shepherd-prefix shepherd-prefix
|
||||||
#:store-dir store-dir
|
#:disk-capacity disk-capacity)
|
||||||
#:guile-prefix guile-prefix
|
(materialize-bhyve-image phase7-operating-system
|
||||||
#:guile-extra-prefix guile-extra-prefix
|
#:store-dir store-dir
|
||||||
#:shepherd-prefix shepherd-prefix))
|
#:guile-prefix guile-prefix
|
||||||
|
#:guile-extra-prefix guile-extra-prefix
|
||||||
|
#:shepherd-prefix shepherd-prefix)))
|
||||||
|
(image-b (if disk-capacity
|
||||||
|
(materialize-bhyve-image phase7-operating-system
|
||||||
|
#:store-dir store-dir
|
||||||
|
#:guile-prefix guile-prefix
|
||||||
|
#:guile-extra-prefix guile-extra-prefix
|
||||||
|
#:shepherd-prefix shepherd-prefix
|
||||||
|
#:disk-capacity disk-capacity)
|
||||||
|
(materialize-bhyve-image phase7-operating-system
|
||||||
|
#:store-dir store-dir
|
||||||
|
#:guile-prefix guile-prefix
|
||||||
|
#:guile-extra-prefix guile-extra-prefix
|
||||||
|
#:shepherd-prefix shepherd-prefix)))
|
||||||
(image-store-path (assoc-ref image-a 'image-store-path))
|
(image-store-path (assoc-ref image-a 'image-store-path))
|
||||||
(image-store-path-rebuild (assoc-ref image-b 'image-store-path))
|
(image-store-path-rebuild (assoc-ref image-b 'image-store-path))
|
||||||
(disk-image (assoc-ref image-a 'disk-image))
|
(disk-image (assoc-ref image-a 'disk-image))
|
||||||
@@ -85,6 +102,7 @@
|
|||||||
(format port "esp_image=~a~%" esp-image)
|
(format port "esp_image=~a~%" esp-image)
|
||||||
(format port "root_image=~a~%" root-image)
|
(format port "root_image=~a~%" root-image)
|
||||||
(format port "closure_path=~a~%" closure-path)
|
(format port "closure_path=~a~%" closure-path)
|
||||||
|
(format port "disk_capacity=~a~%" (or disk-capacity "<default>"))
|
||||||
(format port "store_item_count=~a~%" (length store-items))
|
(format port "store_item_count=~a~%" (length store-items))
|
||||||
(format port "raw_sha256=~a~%" raw-sha256)
|
(format port "raw_sha256=~a~%" raw-sha256)
|
||||||
(format port "image_size_bytes=~a~%" image-size-bytes)
|
(format port "image_size_bytes=~a~%" image-size-bytes)
|
||||||
|
|||||||
@@ -46,7 +46,8 @@
|
|||||||
#:services '(shepherd ready-marker)
|
#:services '(shepherd ready-marker)
|
||||||
#:loader-entries '(("autoboot_delay" . "1")
|
#:loader-entries '(("autoboot_delay" . "1")
|
||||||
("console" . "comconsole"))
|
("console" . "comconsole"))
|
||||||
#:rc-conf-entries '(("clear_tmp_enable" . "YES")
|
#:rc-conf-entries '(("clear_tmp_enable" . "NO")
|
||||||
|
("hostid_enable" . "NO")
|
||||||
("sendmail_enable" . "NONE")
|
("sendmail_enable" . "NONE")
|
||||||
("sshd_enable" . "NO"))
|
("sshd_enable" . "NO"))
|
||||||
#:ready-marker "/var/lib/fruix/ready"))
|
#:ready-marker "/var/lib/fruix/ready"))
|
||||||
|
|||||||
77
tests/system/phase9-minimal-operating-system.scm.in
Normal file
77
tests/system/phase9-minimal-operating-system.scm.in
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
(use-modules (fruix system freebsd)
|
||||||
|
(fruix packages freebsd))
|
||||||
|
|
||||||
|
(define phase7-operating-system
|
||||||
|
(operating-system
|
||||||
|
#:host-name "fruix-freebsd"
|
||||||
|
#:kernel freebsd-kernel
|
||||||
|
#:bootloader freebsd-bootloader
|
||||||
|
#:base-packages (list freebsd-runtime
|
||||||
|
freebsd-networking
|
||||||
|
freebsd-openssh
|
||||||
|
freebsd-userland
|
||||||
|
freebsd-libc
|
||||||
|
freebsd-rc-scripts
|
||||||
|
freebsd-sh
|
||||||
|
freebsd-bash)
|
||||||
|
#: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"))
|
||||||
|
#:ready-marker "/var/lib/fruix/ready"
|
||||||
|
#:root-authorized-keys '("__ROOT_AUTHORIZED_KEY__")))
|
||||||
@@ -5,11 +5,12 @@ project_root=${PROJECT_ROOT:-$(pwd)}
|
|||||||
guix_source_dir=${GUIX_SOURCE_DIR:-"$HOME/repos/guix"}
|
guix_source_dir=${GUIX_SOURCE_DIR:-"$HOME/repos/guix"}
|
||||||
script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
|
script_dir=$(CDPATH= cd -- "$(dirname "$0")" && pwd)
|
||||||
runner_scm=$script_dir/materialize-phase8-system-image.scm
|
runner_scm=$script_dir/materialize-phase8-system-image.scm
|
||||||
os_file=$script_dir/phase7-minimal-operating-system.scm
|
os_file=${OS_FILE:-$script_dir/phase7-minimal-operating-system.scm}
|
||||||
guile_bin=${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}
|
guile_bin=${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}
|
||||||
guile_extra_prefix=${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install}
|
guile_extra_prefix=${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install}
|
||||||
shepherd_prefix=${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install}
|
shepherd_prefix=${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install}
|
||||||
store_dir=${STORE_DIR:-/frx/store}
|
store_dir=${STORE_DIR:-/frx/store}
|
||||||
|
disk_capacity=${DISK_CAPACITY:-}
|
||||||
metadata_target=${METADATA_OUT:-}
|
metadata_target=${METADATA_OUT:-}
|
||||||
|
|
||||||
if [ ! -x "$guile_bin" ]; then
|
if [ ! -x "$guile_bin" ]; then
|
||||||
@@ -84,6 +85,7 @@ sudo env \
|
|||||||
WORKDIR="$workdir" \
|
WORKDIR="$workdir" \
|
||||||
OS_FILE="$os_file" \
|
OS_FILE="$os_file" \
|
||||||
STORE_DIR="$store_dir" \
|
STORE_DIR="$store_dir" \
|
||||||
|
DISK_CAPACITY="$disk_capacity" \
|
||||||
GUILE_PREFIX="$guile_prefix" \
|
GUILE_PREFIX="$guile_prefix" \
|
||||||
GUILE_EXTRA_PREFIX="$guile_extra_prefix" \
|
GUILE_EXTRA_PREFIX="$guile_extra_prefix" \
|
||||||
SHEPHERD_PREFIX="$shepherd_prefix" \
|
SHEPHERD_PREFIX="$shepherd_prefix" \
|
||||||
@@ -95,6 +97,7 @@ disk_image=$(sed -n 's/^disk_image=//p' "$build_metadata")
|
|||||||
closure_path=$(sed -n 's/^closure_path=//p' "$build_metadata")
|
closure_path=$(sed -n 's/^closure_path=//p' "$build_metadata")
|
||||||
raw_sha256=$(sed -n 's/^raw_sha256=//p' "$build_metadata")
|
raw_sha256=$(sed -n 's/^raw_sha256=//p' "$build_metadata")
|
||||||
image_size_bytes=$(sed -n 's/^image_size_bytes=//p' "$build_metadata")
|
image_size_bytes=$(sed -n 's/^image_size_bytes=//p' "$build_metadata")
|
||||||
|
disk_capacity_reported=$(sed -n 's/^disk_capacity=//p' "$build_metadata")
|
||||||
store_item_count=$(sed -n 's/^store_item_count=//p' "$build_metadata")
|
store_item_count=$(sed -n 's/^store_item_count=//p' "$build_metadata")
|
||||||
closure_base=$(basename "$closure_path")
|
closure_base=$(basename "$closure_path")
|
||||||
|
|
||||||
@@ -131,7 +134,7 @@ rc_script_target=$(readlink "$mnt_root/usr/local/etc/rc.d/fruix-shepherd")
|
|||||||
[ "$rc_script_target" = /run/current-system/usr/local/etc/rc.d/fruix-shepherd ] || { echo "unexpected fruix_shepherd rc target: $rc_script_target" >&2; exit 1; }
|
[ "$rc_script_target" = /run/current-system/usr/local/etc/rc.d/fruix-shepherd ] || { echo "unexpected fruix_shepherd rc target: $rc_script_target" >&2; exit 1; }
|
||||||
loader_conf_image=$mnt_root/frx/store/$closure_base/boot/loader.conf
|
loader_conf_image=$mnt_root/frx/store/$closure_base/boot/loader.conf
|
||||||
rc_conf_image=$mnt_root/frx/store/$closure_base/etc/rc.conf
|
rc_conf_image=$mnt_root/frx/store/$closure_base/etc/rc.conf
|
||||||
grep -F 'console="comconsole"' "$loader_conf_image" >/dev/null || { echo "loader.conf is missing serial console config" >&2; exit 1; }
|
grep -F 'comconsole' "$loader_conf_image" >/dev/null || { echo "loader.conf is missing serial console config" >&2; exit 1; }
|
||||||
grep -F 'hostname="fruix-freebsd"' "$rc_conf_image" >/dev/null || { echo "rc.conf is missing hostname" >&2; exit 1; }
|
grep -F 'hostname="fruix-freebsd"' "$rc_conf_image" >/dev/null || { echo "rc.conf is missing hostname" >&2; exit 1; }
|
||||||
|
|
||||||
cat >"$metadata_file" <<EOF
|
cat >"$metadata_file" <<EOF
|
||||||
@@ -144,6 +147,7 @@ closure_path=$closure_path
|
|||||||
closure_base=$closure_base
|
closure_base=$closure_base
|
||||||
raw_sha256=$raw_sha256
|
raw_sha256=$raw_sha256
|
||||||
image_size_bytes=$image_size_bytes
|
image_size_bytes=$image_size_bytes
|
||||||
|
disk_capacity=$disk_capacity_reported
|
||||||
store_item_count=$store_item_count
|
store_item_count=$store_item_count
|
||||||
gpart_log=$gpart_log
|
gpart_log=$gpart_log
|
||||||
esp_fstype=$esp_fstype
|
esp_fstype=$esp_fstype
|
||||||
|
|||||||
204
tests/system/run-phase9-xcpng-boot.sh
Executable file
204
tests/system/run-phase9-xcpng-boot.sh
Executable file
@@ -0,0 +1,204 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
repo_root=$(CDPATH= cd -- "$(dirname "$0")/../.." && pwd)
|
||||||
|
vm_id=90490f2e-e8fc-4b7a-388e-5c26f0157289
|
||||||
|
metadata_target=${METADATA_OUT:-}
|
||||||
|
root_authorized_key_file=${ROOT_AUTHORIZED_KEY_FILE:-$HOME/.ssh/id_ed25519.pub}
|
||||||
|
requested_disk_capacity=${DISK_CAPACITY:-}
|
||||||
|
|
||||||
|
cleanup=0
|
||||||
|
if [ -n "${WORKDIR:-}" ]; then
|
||||||
|
workdir=$WORKDIR
|
||||||
|
mkdir -p "$workdir"
|
||||||
|
else
|
||||||
|
workdir=$(mktemp -d /tmp/fruix-phase9-xcpng.XXXXXX)
|
||||||
|
cleanup=1
|
||||||
|
fi
|
||||||
|
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
||||||
|
cleanup=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
phase9_os_template=$repo_root/tests/system/phase9-minimal-operating-system.scm.in
|
||||||
|
phase9_os_file=$workdir/phase9-minimal-operating-system.scm
|
||||||
|
phase8_log=$workdir/phase8-system-image.log
|
||||||
|
phase8_metadata=$workdir/phase8-system-image-metadata.txt
|
||||||
|
arp_scan_log=$workdir/arp-scan.log
|
||||||
|
ssh_stdout=$workdir/ssh.out
|
||||||
|
ssh_stderr=$workdir/ssh.err
|
||||||
|
metadata_file=$workdir/phase9-xcpng-boot-metadata.txt
|
||||||
|
vdi_info_json=$workdir/vdi-info.json
|
||||||
|
vm_info_json=$workdir/vm-info.json
|
||||||
|
upload_image=$workdir/disk.vhd
|
||||||
|
|
||||||
|
cleanup_workdir() {
|
||||||
|
if [ "$cleanup" -eq 1 ]; then
|
||||||
|
rm -rf "$workdir"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup_workdir EXIT INT TERM
|
||||||
|
|
||||||
|
[ -f "$root_authorized_key_file" ] || {
|
||||||
|
echo "missing root authorized key file: $root_authorized_key_file" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
root_authorized_key=$(tr -d '\n' < "$root_authorized_key_file")
|
||||||
|
|
||||||
|
# Discover the existing target VDI attached as disk 0 for the operator-provided VM.
|
||||||
|
xo-cli list-objects id=$vm_id >"$vm_info_json"
|
||||||
|
vdi_id=$(xo-cli list-objects type=VBD | jq -r '.[] | select(.VM=="'$vm_id'" and .is_cd_drive==false and .position=="0") | .VDI' | head -n 1)
|
||||||
|
[ -n "$vdi_id" ] || { echo "failed to discover target VDI for VM $vm_id" >&2; exit 1; }
|
||||||
|
xo-cli list-objects type=VDI | jq '[.[] | select(.id=="'$vdi_id'")]' >"$vdi_info_json"
|
||||||
|
vdi_size=$(jq -r '.[0].size' "$vdi_info_json")
|
||||||
|
[ -n "$vdi_size" ] || { echo "failed to discover VDI size for $vdi_id" >&2; exit 1; }
|
||||||
|
|
||||||
|
if [ -n "$requested_disk_capacity" ] && [ "$requested_disk_capacity" != "$vdi_size" ]; then
|
||||||
|
echo "existing XCP-ng import path requires an image that matches the target VDI size; use DISK_CAPACITY=$vdi_size or leave it unset" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
disk_capacity=$vdi_size
|
||||||
|
requested_disk_bytes=$vdi_size
|
||||||
|
|
||||||
|
sed "s|__ROOT_AUTHORIZED_KEY__|$root_authorized_key|g" "$phase9_os_template" > "$phase9_os_file"
|
||||||
|
|
||||||
|
KEEP_WORKDIR=1 WORKDIR=$workdir/phase8-build OS_FILE=$phase9_os_file DISK_CAPACITY=$disk_capacity \
|
||||||
|
METADATA_OUT=$phase8_metadata "$repo_root/tests/system/run-phase8-system-image.sh" \
|
||||||
|
>"$phase8_log" 2>&1
|
||||||
|
|
||||||
|
disk_image=$(sed -n 's/^disk_image=//p' "$phase8_metadata")
|
||||||
|
closure_path=$(sed -n 's/^closure_path=//p' "$phase8_metadata")
|
||||||
|
closure_base=$(basename "$closure_path")
|
||||||
|
raw_sha256=$(sed -n 's/^raw_sha256=//p' "$phase8_metadata")
|
||||||
|
image_store_path=$(sed -n 's/^image_store_path=//p' "$phase8_metadata")
|
||||||
|
|
||||||
|
command -v qemu-img >/dev/null 2>&1 || {
|
||||||
|
echo "qemu-img is required to convert the raw Fruix image to XCP-ng-compatible VHD" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
qemu-img convert -f raw -O vpc -o subformat=dynamic,force_size=on "$disk_image" "$upload_image"
|
||||||
|
upload_sha256=$(sha256 -q "$upload_image")
|
||||||
|
upload_size_bytes=$(stat -f '%z' "$upload_image")
|
||||||
|
|
||||||
|
xo-cli vm.stop id=$vm_id force=true >/dev/null 2>&1 || true
|
||||||
|
xo-cli disk.importContent id=$vdi_id @=$upload_image >"$workdir/disk-import.out"
|
||||||
|
xo-cli vm.setBootOrder vm=$vm_id order=dcn >"$workdir/set-boot-order.out"
|
||||||
|
xo-cli vm.start id=$vm_id >"$workdir/vm-start.out"
|
||||||
|
|
||||||
|
# Wait for the VM to obtain an address and accept SSH using the injected key.
|
||||||
|
vm_mac=$(jq -r '.[0].VIFs[0]' "$vm_info_json")
|
||||||
|
if [ -n "$vm_mac" ] && [ "$vm_mac" != null ]; then
|
||||||
|
vm_mac=$(xo-cli list-objects type=VIF | jq -r '.[] | select(.id=="'$vm_mac'") | .MAC' | tr 'A-Z' 'a-z')
|
||||||
|
else
|
||||||
|
vm_mac=
|
||||||
|
fi
|
||||||
|
host_interface=$(route -n get default | awk '/interface:/{print $2; exit}')
|
||||||
|
host_ip=$(ifconfig "$host_interface" | awk '/inet /{print $2; exit}')
|
||||||
|
subnet_prefix=${host_ip%.*}
|
||||||
|
|
||||||
|
ssh_guest() {
|
||||||
|
ssh -i "$root_authorized_key_file" \
|
||||||
|
-o BatchMode=yes \
|
||||||
|
-o StrictHostKeyChecking=no \
|
||||||
|
-o UserKnownHostsFile=/dev/null \
|
||||||
|
-o ConnectTimeout=5 \
|
||||||
|
root@"$guest_ip" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
guest_ip=
|
||||||
|
for attempt in $(jot 90 1 90); do
|
||||||
|
: >"$arp_scan_log"
|
||||||
|
for host in $(jot 254 1 254); do
|
||||||
|
ip=$subnet_prefix.$host
|
||||||
|
(
|
||||||
|
ping -c 1 -W 1000 "$ip" >/dev/null 2>&1 && echo "$ip" >>"$arp_scan_log"
|
||||||
|
) &
|
||||||
|
done
|
||||||
|
wait
|
||||||
|
if [ -n "$vm_mac" ]; then
|
||||||
|
guest_ip=$(arp -an | awk -v mac="$vm_mac" 'tolower($4)==mac {gsub(/[()]/,"",$2); print $2; exit}')
|
||||||
|
fi
|
||||||
|
if [ -n "$guest_ip" ]; then
|
||||||
|
if ssh -i "$root_authorized_key_file" \
|
||||||
|
-o BatchMode=yes \
|
||||||
|
-o StrictHostKeyChecking=no \
|
||||||
|
-o UserKnownHostsFile=/dev/null \
|
||||||
|
-o ConnectTimeout=3 \
|
||||||
|
root@"$guest_ip" 'test -f /var/lib/fruix/ready' >"$ssh_stdout" 2>"$ssh_stderr"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
done
|
||||||
|
|
||||||
|
[ -n "$guest_ip" ] || {
|
||||||
|
echo "guest IP was not discovered; manual console inspection is likely required" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
ready_marker=$(ssh_guest 'cat /var/lib/fruix/ready')
|
||||||
|
run_current_system_target=$(ssh_guest 'readlink /run/current-system')
|
||||||
|
rc_conf_hostname=$(ssh_guest 'grep "^hostname=" /etc/rc.conf | cut -d"\"" -f2')
|
||||||
|
shepherd_status=$(ssh_guest '/usr/local/etc/rc.d/fruix-shepherd onestatus >/dev/null 2>&1 && echo running || echo stopped')
|
||||||
|
logger_log=$(ssh_guest 'cat /var/log/fruix-shepherd.log' | tr '\n' ' ')
|
||||||
|
sshd_status=$(ssh_guest 'service sshd onestatus >/dev/null 2>&1 && echo running || echo stopped')
|
||||||
|
uname_output=$(ssh_guest 'uname -sr')
|
||||||
|
operator_home_listing=$(ssh_guest 'ls -d /home/operator')
|
||||||
|
activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n' ' ')
|
||||||
|
|
||||||
|
[ "$ready_marker" = ready ] || { echo "unexpected ready marker contents: $ready_marker" >&2; exit 1; }
|
||||||
|
[ "$shepherd_status" = running ] || { echo "fruix_shepherd is not running" >&2; exit 1; }
|
||||||
|
[ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; }
|
||||||
|
[ "$run_current_system_target" = "/frx/store/$closure_base" ] || {
|
||||||
|
echo "unexpected /run/current-system target in guest: $run_current_system_target" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
[ "$rc_conf_hostname" = fruix-freebsd ] || { echo "unexpected guest hostname config: $rc_conf_hostname" >&2; exit 1; }
|
||||||
|
[ "$operator_home_listing" = /home/operator ] || { echo "operator home missing" >&2; exit 1; }
|
||||||
|
|
||||||
|
cat >"$metadata_file" <<EOF
|
||||||
|
workdir=$workdir
|
||||||
|
vm_id=$vm_id
|
||||||
|
vdi_id=$vdi_id
|
||||||
|
vdi_size=$vdi_size
|
||||||
|
disk_capacity=$disk_capacity
|
||||||
|
requested_disk_capacity=${requested_disk_capacity:-<auto>}
|
||||||
|
requested_disk_bytes=$requested_disk_bytes
|
||||||
|
phase9_os_file=$phase9_os_file
|
||||||
|
phase8_log=$phase8_log
|
||||||
|
phase8_metadata=$phase8_metadata
|
||||||
|
image_store_path=$image_store_path
|
||||||
|
disk_image=$disk_image
|
||||||
|
upload_image=$upload_image
|
||||||
|
upload_format=vhd-dynamic
|
||||||
|
upload_sha256=$upload_sha256
|
||||||
|
upload_size_bytes=$upload_size_bytes
|
||||||
|
closure_path=$closure_path
|
||||||
|
closure_base=$closure_base
|
||||||
|
raw_sha256=$raw_sha256
|
||||||
|
guest_ip=$guest_ip
|
||||||
|
vm_mac=$vm_mac
|
||||||
|
ready_marker=$ready_marker
|
||||||
|
run_current_system_target=$run_current_system_target
|
||||||
|
shepherd_status=$shepherd_status
|
||||||
|
sshd_status=$sshd_status
|
||||||
|
logger_log=$logger_log
|
||||||
|
uname_output=$uname_output
|
||||||
|
operator_home_listing=$operator_home_listing
|
||||||
|
activate_preview=$activate_preview
|
||||||
|
boot_backend=xcp-ng-xo-cli
|
||||||
|
operator_access=ssh-root-key
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ -n "$metadata_target" ]; then
|
||||||
|
mkdir -p "$(dirname "$metadata_target")"
|
||||||
|
cp "$metadata_file" "$metadata_target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf 'PASS phase9-xcpng-boot\n'
|
||||||
|
printf 'Work directory: %s\n' "$workdir"
|
||||||
|
printf 'Metadata file: %s\n' "$metadata_file"
|
||||||
|
if [ -n "$metadata_target" ]; then
|
||||||
|
printf 'Copied metadata to: %s\n' "$metadata_target"
|
||||||
|
fi
|
||||||
|
printf '%s\n' '--- metadata ---'
|
||||||
|
cat "$metadata_file"
|
||||||
Reference in New Issue
Block a user