Harden FreeBSD guest /etc and activation diagnostics
This commit is contained in:
@@ -2711,3 +2711,102 @@ Next recommended step:
|
||||
1. continue with Phase 12.2 and tighten the guest-side runtime/operator diagnostics
|
||||
2. remove or reduce the most distracting remaining boot/runtime rough edges where the fixes are small and local
|
||||
3. keep the deployment path stable so Phase 13 can start from a sharper baseline
|
||||
|
||||
## 2026-04-02 — Phase 12.2: guest runtime diagnostics tightened and `/etc` handling improved
|
||||
|
||||
Completed work:
|
||||
|
||||
- wrote the Phase 12.2 report:
|
||||
- `docs/reports/phase12-runtime-diagnostics-freebsd.md`
|
||||
- updated `modules/fruix/system/freebsd.scm` so selected database-backed `/etc` files are now materialized as regular files in the guest rootfs instead of symlinks:
|
||||
- `/etc/passwd`
|
||||
- `/etc/master.passwd`
|
||||
- `/etc/group`
|
||||
- `/etc/login.conf`
|
||||
- the generated activation script now refreshes those files from `/run/current-system/etc` before rebuilding FreeBSD databases
|
||||
- activation now writes a guest-visible log:
|
||||
- `/var/log/fruix-activate.log`
|
||||
- with markers including:
|
||||
- `fruix-activate:start`
|
||||
- `fruix-activate:cap_mkdb=ok`
|
||||
- `fruix-activate:pwd_mkdb=ok`
|
||||
- `fruix-activate:done`
|
||||
- exit status marker via shell trap
|
||||
- tightened closure permissions slightly by making:
|
||||
- `etc/master.passwd`
|
||||
mode `0600`
|
||||
- upgraded validation harnesses so they now assert the improved runtime behavior directly:
|
||||
- `tests/system/run-phase8-system-image.sh`
|
||||
- now checks that image `/etc/login.conf` is a regular file
|
||||
- now checks that image `/etc/master.passwd` is a regular file
|
||||
- `tests/system/run-phase9-xcpng-boot.sh`
|
||||
- `tests/system/run-phase11-shepherd-pid1-xcpng.sh`
|
||||
- `tests/system/run-phase11-shepherd-pid1-qemu.sh`
|
||||
- now check for:
|
||||
- `login_conf_kind=regular`
|
||||
- `login_conf_db=present`
|
||||
- `pwd_dbs=present`
|
||||
- activation log completion marker
|
||||
- fixed a small follow-up bug in the activation log path:
|
||||
- initial implementation used `touch`, which is not staged in the minimal guest
|
||||
- switched to shell redirection instead:
|
||||
- `: >> "$logfile"`
|
||||
|
||||
Validation:
|
||||
|
||||
- `tests/system/run-phase8-system-image.sh` passes locally with the new image-layout checks:
|
||||
- workdir: `/tmp/phase12-2-image-1775159011`
|
||||
- confirmed:
|
||||
- `login_conf_kind=regular`
|
||||
- `master_passwd_kind=regular`
|
||||
- `tests/system/run-phase11-shepherd-pid1-qemu.sh` passes locally again with the new activation/runtime checks:
|
||||
- workdir: `/tmp/phase12-2b-qemu-1775161367`
|
||||
- confirmed:
|
||||
- `activate_log=fruix-activate:start ... fruix-activate:done ...`
|
||||
- `login_conf_kind=regular`
|
||||
- `login_conf_db=present`
|
||||
- `pwd_dbs=present`
|
||||
- `shepherd_pid=1`
|
||||
- `sshd_status=running`
|
||||
- `tests/system/run-phase9-xcpng-boot.sh` passes on the real VM with the new checks:
|
||||
- workdir: `/tmp/phase12-2b-phase9-1775161731`
|
||||
- confirmed:
|
||||
- `activate_log=fruix-activate:start ... fruix-activate:done ...`
|
||||
- `login_conf_kind=regular`
|
||||
- `login_conf_db=present`
|
||||
- `pwd_dbs=present`
|
||||
- `compat_prefix_shims=absent`
|
||||
- `guile_module_smoke=ok`
|
||||
- `shepherd_status=running`
|
||||
- `sshd_status=running`
|
||||
- `tests/system/run-phase11-shepherd-pid1-xcpng.sh` passes on the real VM with the new checks:
|
||||
- workdir: `/tmp/phase12-2b-phase11-1775162210`
|
||||
- confirmed:
|
||||
- `activate_log=fruix-activate:start ... fruix-activate:done ...`
|
||||
- `login_conf_kind=regular`
|
||||
- `login_conf_db=present`
|
||||
- `pwd_dbs=present`
|
||||
- `compat_prefix_shims=absent`
|
||||
- `guile_module_smoke=ok`
|
||||
- `shepherd_pid=1`
|
||||
- `sshd_status=running`
|
||||
|
||||
Important findings:
|
||||
|
||||
- the old symlink-based handling for login/password database inputs was a real mismatch with FreeBSD expectations; making those files regular in the guest was a better fit than leaving them store-backed symlinks
|
||||
- adding a direct activation log materially improves post-boot diagnosis and avoids guessing whether activation actually completed
|
||||
- the first attempt exposed a missing-userland dependency (`touch`) quickly; because the new diagnostics were explicit, the follow-up fix was immediate and local
|
||||
- both validated boot paths still hold after this change:
|
||||
- `freebsd-init+rc.d-shepherd`
|
||||
- `shepherd-pid1`
|
||||
|
||||
Current assessment:
|
||||
|
||||
- the current Fruix guest remains intentionally minimal, but its runtime behavior is now less prototype-noisy and easier to inspect as a basic FreeBSD-like system
|
||||
- this is exactly the kind of targeted hardening that makes the existing system a better launch point for native FreeBSD base-build work
|
||||
|
||||
Next recommended step:
|
||||
|
||||
1. complete Phase 12.3 by making the host-staged FreeBSD base boundary explicit in the package/model layer and docs
|
||||
2. document the first intended replacement order for native world/kernel work
|
||||
3. then begin Phase 13 with a clearer transitional boundary
|
||||
|
||||
210
docs/reports/phase12-runtime-diagnostics-freebsd.md
Normal file
210
docs/reports/phase12-runtime-diagnostics-freebsd.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# Phase 12.2: tightened guest runtime diagnostics and reduced early-boot rough edges
|
||||
|
||||
Date: 2026-04-02
|
||||
|
||||
## Goal
|
||||
|
||||
The current Fruix FreeBSD guest already booted, reached the network, and ran Shepherd. The next hardening step was to make the guest easier to diagnose and to remove a few distracting runtime rough edges that were still coming from the prototype-style `/etc` handling.
|
||||
|
||||
The main targets were:
|
||||
|
||||
- reduce early-boot/login-class noise around `/etc/login.conf`
|
||||
- ensure the FreeBSD password/login databases are created in writable guest state, not implicitly in store-backed paths
|
||||
- add a clear activation log inside the guest
|
||||
- teach the validation harnesses to assert the new behavior directly
|
||||
|
||||
## Root cause addressed
|
||||
|
||||
The old rootfs layout symlinked several generated `/etc` files directly to `/run/current-system/etc/...`, including:
|
||||
|
||||
- `/etc/login.conf`
|
||||
- `/etc/master.passwd`
|
||||
- `/etc/passwd`
|
||||
- `/etc/group`
|
||||
|
||||
That worked for static lookup, but it was a poor fit for FreeBSD tools such as:
|
||||
|
||||
- `cap_mkdb`
|
||||
- `pwd_mkdb`
|
||||
- early login-class lookups
|
||||
|
||||
because those tools expect to work with regular files and adjacent generated database files such as:
|
||||
|
||||
- `/etc/login.conf.db`
|
||||
- `/etc/pwd.db`
|
||||
- `/etc/spwd.db`
|
||||
|
||||
With symlink-backed inputs, the system could still limp along, but it produced avoidable warnings and less clear runtime behavior.
|
||||
|
||||
## Implementation
|
||||
|
||||
### 1. Selected `/etc` files now become regular files in the guest rootfs
|
||||
|
||||
`modules/fruix/system/freebsd.scm` now materializes these files as regular files in the rootfs instead of symlinks:
|
||||
|
||||
- `/etc/passwd`
|
||||
- `/etc/master.passwd`
|
||||
- `/etc/group`
|
||||
- `/etc/login.conf`
|
||||
|
||||
Other generated configuration files that do not need this treatment remain symlinked to `/run/current-system/...`.
|
||||
|
||||
This gives FreeBSD's database tools writable, regular inputs in the guest filesystem while keeping the current system closure as the source of truth.
|
||||
|
||||
### 2. Activation now refreshes those files from `/run/current-system/etc`
|
||||
|
||||
The generated activation script now refreshes the regular guest copies from the currently selected system closure before rebuilding databases.
|
||||
|
||||
That means rebuild/redeploy still works coherently even though these specific files are no longer left as symlinks in the booted guest.
|
||||
|
||||
### 3. Activation now records a guest-visible log
|
||||
|
||||
Activation now writes:
|
||||
|
||||
- `/var/log/fruix-activate.log`
|
||||
|
||||
with explicit markers such as:
|
||||
|
||||
- `fruix-activate:start`
|
||||
- `fruix-activate:cap_mkdb=ok`
|
||||
- `fruix-activate:pwd_mkdb=ok`
|
||||
- `fruix-activate:done`
|
||||
- exit status marker from the shell trap
|
||||
|
||||
This gives a direct guest-side indicator of whether activation actually completed.
|
||||
|
||||
### 4. Closure permissions were tightened slightly
|
||||
|
||||
The generated closure now explicitly sets:
|
||||
|
||||
- `etc/master.passwd` => `0600`
|
||||
|
||||
before the rootfs/image path copies it into the guest.
|
||||
|
||||
### 5. Validation harnesses were upgraded
|
||||
|
||||
#### Local image validation
|
||||
|
||||
`tests/system/run-phase8-system-image.sh` now asserts that the mounted image contains:
|
||||
|
||||
- `/etc/login.conf` as a regular file
|
||||
- `/etc/master.passwd` as a regular file
|
||||
|
||||
#### VM validation
|
||||
|
||||
These harnesses now check for the new runtime behavior:
|
||||
|
||||
- `tests/system/run-phase9-xcpng-boot.sh`
|
||||
- `tests/system/run-phase11-shepherd-pid1-xcpng.sh`
|
||||
- `tests/system/run-phase11-shepherd-pid1-qemu.sh`
|
||||
|
||||
New checks include:
|
||||
|
||||
- `login_conf_kind=regular`
|
||||
- `login_conf_db=present`
|
||||
- `pwd_dbs=present`
|
||||
- activation log contains `fruix-activate:done`
|
||||
|
||||
They also capture the activation log into metadata.
|
||||
|
||||
### 6. Small follow-up fix
|
||||
|
||||
The first activation-log implementation briefly used `touch`, which is not staged in the minimal guest userland. This was corrected by switching to shell redirection:
|
||||
|
||||
- `: >> "$logfile"`
|
||||
|
||||
so the activation path no longer depends on an extra utility for log-file creation.
|
||||
|
||||
## Validation
|
||||
|
||||
### Local image structure
|
||||
|
||||
Passing run:
|
||||
|
||||
- `PASS phase8-system-image`
|
||||
- workdir: `/tmp/phase12-2-image-1775159011`
|
||||
|
||||
Key metadata:
|
||||
|
||||
```text
|
||||
login_conf_kind=regular
|
||||
master_passwd_kind=regular
|
||||
```
|
||||
|
||||
### Local QEMU Shepherd PID 1
|
||||
|
||||
Passing run:
|
||||
|
||||
- `PASS phase11-shepherd-pid1-qemu`
|
||||
- workdir: `/tmp/phase12-2b-qemu-1775161367`
|
||||
|
||||
Key metadata:
|
||||
|
||||
```text
|
||||
activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0
|
||||
login_conf_kind=regular
|
||||
login_conf_db=present
|
||||
pwd_dbs=present
|
||||
shepherd_pid=1
|
||||
sshd_status=running
|
||||
```
|
||||
|
||||
### Real VM, `freebsd-init+rc.d-shepherd`
|
||||
|
||||
Passing run:
|
||||
|
||||
- `PASS phase9-xcpng-boot`
|
||||
- workdir: `/tmp/phase12-2b-phase9-1775161731`
|
||||
|
||||
Key metadata:
|
||||
|
||||
```text
|
||||
activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0
|
||||
login_conf_kind=regular
|
||||
login_conf_db=present
|
||||
pwd_dbs=present
|
||||
compat_prefix_shims=absent
|
||||
guile_module_smoke=ok
|
||||
shepherd_status=running
|
||||
sshd_status=running
|
||||
```
|
||||
|
||||
### Real VM, `shepherd-pid1`
|
||||
|
||||
Passing run:
|
||||
|
||||
- `PASS phase11-shepherd-pid1-xcpng`
|
||||
- workdir: `/tmp/phase12-2b-phase11-1775162210`
|
||||
|
||||
Key metadata:
|
||||
|
||||
```text
|
||||
activate_log=fruix-activate:start fruix-activate:cap_mkdb=ok fruix-activate:pwd_mkdb=ok fruix-activate:done fruix-activate:exit status=0
|
||||
login_conf_kind=regular
|
||||
login_conf_db=present
|
||||
pwd_dbs=present
|
||||
shepherd_pid=1
|
||||
compat_prefix_shims=absent
|
||||
guile_module_smoke=ok
|
||||
sshd_status=running
|
||||
```
|
||||
|
||||
## Assessment
|
||||
|
||||
This was a small but high-value hardening step.
|
||||
|
||||
The guest now behaves more like a real FreeBSD system in one of the places where a store-backed prototype can otherwise feel awkward: password/login database management and early `/etc` expectations.
|
||||
|
||||
The important result is not cosmetic; it is operational:
|
||||
|
||||
- activation success is now visible inside the guest
|
||||
- the login/password database inputs live as regular guest files where FreeBSD expects them
|
||||
- both validated boot modes still work locally and on the real XCP-ng VM
|
||||
|
||||
## Next recommended step
|
||||
|
||||
Proceed to Phase 12.3:
|
||||
|
||||
- make the host-staged FreeBSD base boundary explicit in the code/documentation model
|
||||
- group the transitional host-copy base packages more clearly
|
||||
- document the first intended replacement order for native world/kernel artifacts in `/frx/store`
|
||||
@@ -657,7 +657,18 @@
|
||||
uid gid home)))))
|
||||
users)
|
||||
""))
|
||||
(compat-prefixes "")
|
||||
(refresh-db-input-files
|
||||
(string-join
|
||||
(map (lambda (entry)
|
||||
(match entry
|
||||
((name mode)
|
||||
(string-append
|
||||
"if [ -f /run/current-system/etc/" name " ]; then rm -f /etc/" name "; cp /run/current-system/etc/" name " /etc/" name "; chmod " mode " /etc/" name "; fi\n"))))
|
||||
'(("passwd" "0644")
|
||||
("master.passwd" "0600")
|
||||
("group" "0644")
|
||||
("login.conf" "0644")))
|
||||
""))
|
||||
(ssh-section
|
||||
(string-append
|
||||
"mkdir -p /var/empty /etc/ssh /root/.ssh\n"
|
||||
@@ -671,13 +682,22 @@
|
||||
(string-append
|
||||
"#!/bin/sh\n"
|
||||
"set -eu\n"
|
||||
"logfile=/var/log/fruix-activate.log\n"
|
||||
"mkdir -p /var/cron /var/db /var/lib/fruix /var/log /var/run /root /home /tmp\n"
|
||||
": >> \"$logfile\"\n"
|
||||
"trap 'status=$?; echo \"fruix-activate:exit status=$status\" >> \"$logfile\"' EXIT\n"
|
||||
"echo \"fruix-activate:start\" >> \"$logfile\"\n"
|
||||
"chmod 1777 /tmp\n"
|
||||
"if [ -x /usr/bin/cap_mkdb ] && [ -f /etc/login.conf ]; then /usr/bin/cap_mkdb /etc/login.conf || true; fi\n"
|
||||
"if [ -x /usr/sbin/pwd_mkdb ] && [ -f /etc/master.passwd ]; then /usr/sbin/pwd_mkdb -p /etc/master.passwd || true; fi\n"
|
||||
refresh-db-input-files
|
||||
"if [ -x /usr/bin/cap_mkdb ] && [ -f /etc/login.conf ]; then\n"
|
||||
" if /usr/bin/cap_mkdb /etc/login.conf; then echo \"fruix-activate:cap_mkdb=ok\" >> \"$logfile\"; else echo \"fruix-activate:cap_mkdb=failed\" >> \"$logfile\"; fi\n"
|
||||
"fi\n"
|
||||
"if [ -x /usr/sbin/pwd_mkdb ] && [ -f /etc/master.passwd ]; then\n"
|
||||
" if /usr/sbin/pwd_mkdb -p /etc/master.passwd; then echo \"fruix-activate:pwd_mkdb=ok\" >> \"$logfile\"; else echo \"fruix-activate:pwd_mkdb=failed\" >> \"$logfile\"; fi\n"
|
||||
"fi\n"
|
||||
home-setup
|
||||
compat-prefixes
|
||||
ssh-section)))
|
||||
ssh-section
|
||||
"echo \"fruix-activate:done\" >> \"$logfile\"\n")))
|
||||
|
||||
(define (pid1-mount-commands os)
|
||||
(string-join
|
||||
@@ -1131,6 +1151,8 @@
|
||||
(write-file (string-append closure-path "/" (car entry)) (cdr entry)))
|
||||
generated-files)
|
||||
(chmod (string-append closure-path "/activate") #o555)
|
||||
(when (file-exists? (string-append closure-path "/etc/master.passwd"))
|
||||
(chmod (string-append closure-path "/etc/master.passwd") #o600))
|
||||
(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)
|
||||
(when (file-exists? (string-append closure-path "/boot/fruix-pid1"))
|
||||
@@ -1202,8 +1224,11 @@
|
||||
(for-each (lambda (path)
|
||||
(symlink-force (string-append "/run/current-system/etc/" path)
|
||||
(string-append rootfs "/etc/" path)))
|
||||
'("rc.conf" "fstab" "hosts" "passwd" "master.passwd" "group"
|
||||
"login.conf" "shells" "motd" "ttys"))
|
||||
'("rc.conf" "fstab" "hosts" "shells" "motd" "ttys"))
|
||||
(for-each (lambda (path)
|
||||
(copy-regular-file (string-append closure-path "/etc/" path)
|
||||
(string-append rootfs "/etc/" path)))
|
||||
'("passwd" "master.passwd" "group" "login.conf"))
|
||||
(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")))
|
||||
|
||||
@@ -113,6 +113,10 @@ logger_log=$(ssh_guest 'cat /var/log/fruix-shepherd.log' | tr '\n' ' ')
|
||||
shepherd_bootstrap_tail=$(ssh_guest "awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }' /var/log/shepherd-bootstrap.out 2>/dev/null || true" | tr '\n' ' ')
|
||||
shepherd_log_tail=$(ssh_guest "awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }' /var/log/shepherd.log 2>/dev/null || true" | tr '\n' ' ')
|
||||
guest_dmesg_tail=$(ssh_guest "dmesg | awk 'BEGIN { c = 20 } { lines[NR % c] = \$0 } END { start = (NR > c ? NR - c + 1 : 1); for (i = start; i <= NR; i++) print lines[i % c] }'" | tr '\n' ' ')
|
||||
activate_log=$(ssh_guest 'cat /var/log/fruix-activate.log 2>/dev/null || true' | tr '\n' ' ')
|
||||
login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi')
|
||||
login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing')
|
||||
pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi')
|
||||
uname_output=$(ssh_guest 'uname -sr')
|
||||
operator_home_listing=$(ssh_guest 'ls -d /home/operator')
|
||||
|
||||
@@ -128,6 +132,13 @@ operator_home_listing=$(ssh_guest 'ls -d /home/operator')
|
||||
[ "$shepherd_socket" = present ] || { echo "shepherd socket is missing" >&2; exit 1; }
|
||||
[ "$shepherd_status" = running ] || { echo "shepherd is not running" >&2; exit 1; }
|
||||
[ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; }
|
||||
[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; }
|
||||
[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; }
|
||||
[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; }
|
||||
case "$activate_log" in
|
||||
*fruix-activate:done*) : ;;
|
||||
*) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;;
|
||||
esac
|
||||
[ "$operator_home_listing" = /home/operator ] || { echo "operator home missing" >&2; exit 1; }
|
||||
|
||||
cat >"$metadata_file" <<EOF
|
||||
@@ -155,6 +166,10 @@ logger_log=$logger_log
|
||||
shepherd_bootstrap_tail=$shepherd_bootstrap_tail
|
||||
shepherd_log_tail=$shepherd_log_tail
|
||||
guest_dmesg_tail=$guest_dmesg_tail
|
||||
activate_log=$activate_log
|
||||
login_conf_kind=$login_conf_kind
|
||||
login_conf_db=$login_conf_db
|
||||
pwd_dbs=$pwd_dbs
|
||||
uname_output=$uname_output
|
||||
operator_home_listing=$operator_home_listing
|
||||
boot_backend=qemu-uefi-tcg
|
||||
|
||||
@@ -158,6 +158,10 @@ operator_home_listing=$(ssh_guest 'ls -d /home/operator')
|
||||
compat_prefix_shims=$(ssh_guest 'for p in /tmp/guile-freebsd-validate-install /tmp/guile-gnutls-freebsd-validate-install /tmp/shepherd-freebsd-validate-install; do if [ -e "$p" ] || [ -L "$p" ]; then echo present; exit 0; fi; done; echo absent')
|
||||
guile_module_smoke=$(ssh_guest "env LANG='C.UTF-8' LC_ALL='C.UTF-8' LD_LIBRARY_PATH='$guile_extra_store/lib:$guile_store/lib:/usr/local/lib' GUILE_SYSTEM_PATH='$guile_store/share/guile/3.0:$guile_store/share/guile/site/3.0:$guile_store/share/guile/site:$guile_store/share/guile' GUILE_LOAD_PATH='$shepherd_store/share/guile/site/3.0:$guile_extra_store/share/guile/site/3.0' GUILE_SYSTEM_COMPILED_PATH='$guile_store/lib/guile/3.0/ccache:$guile_store/lib/guile/3.0/site-ccache' GUILE_LOAD_COMPILED_PATH='$shepherd_store/lib/guile/3.0/site-ccache:$guile_extra_store/lib/guile/3.0/site-ccache' GUILE_SYSTEM_EXTENSIONS_PATH='$guile_store/lib/guile/3.0/extensions' GUILE_EXTENSIONS_PATH='$guile_extra_store/lib/guile/3.0/extensions' '$guile_store/bin/guile' --no-auto-compile -c '(use-modules (fibers config) (gnutls) (shepherd config)) (display \"ok\") (newline)'")
|
||||
activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n' ' ')
|
||||
activate_log=$(ssh_guest 'cat /var/log/fruix-activate.log 2>/dev/null || true' | tr '\n' ' ')
|
||||
login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi')
|
||||
login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing')
|
||||
pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi')
|
||||
|
||||
[ "$ready_marker" = ready ] || { echo "unexpected ready marker contents: $ready_marker" >&2; exit 1; }
|
||||
[ "$shepherd_pid" = 1 ] || { echo "shepherd is not PID 1: pid=$shepherd_pid command=$pid1_command" >&2; exit 1; }
|
||||
@@ -166,6 +170,13 @@ activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n'
|
||||
[ "$sshd_status" = running ] || { echo "sshd is not running" >&2; exit 1; }
|
||||
[ "$compat_prefix_shims" = absent ] || { echo "compatibility prefix shims are still present in /tmp" >&2; exit 1; }
|
||||
[ "$guile_module_smoke" = ok ] || { echo "guest Guile module smoke failed: $guile_module_smoke" >&2; exit 1; }
|
||||
[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; }
|
||||
[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; }
|
||||
[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; }
|
||||
case "$activate_log" in
|
||||
*fruix-activate:done*) : ;;
|
||||
*) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;;
|
||||
esac
|
||||
[ "$run_current_system_target" = "/frx/store/$closure_base" ] || {
|
||||
echo "unexpected /run/current-system target in guest: $run_current_system_target" >&2
|
||||
exit 1
|
||||
@@ -210,6 +221,10 @@ operator_home_listing=$operator_home_listing
|
||||
compat_prefix_shims=$compat_prefix_shims
|
||||
guile_module_smoke=$guile_module_smoke
|
||||
activate_preview=$activate_preview
|
||||
activate_log=$activate_log
|
||||
login_conf_kind=$login_conf_kind
|
||||
login_conf_db=$login_conf_db
|
||||
pwd_dbs=$pwd_dbs
|
||||
boot_backend=xcp-ng-xo-cli
|
||||
init_mode=shepherd-pid1
|
||||
operator_access=ssh-root-key
|
||||
|
||||
@@ -114,11 +114,15 @@ boot_loader_target=$(readlink "$mnt_root/boot/loader")
|
||||
boot_loader_conf_target=$(readlink "$mnt_root/boot/loader.conf")
|
||||
rc_conf_target=$(readlink "$mnt_root/etc/rc.conf")
|
||||
rc_script_target=$(readlink "$mnt_root/usr/local/etc/rc.d/fruix-shepherd")
|
||||
if [ -L "$mnt_root/etc/login.conf" ]; then login_conf_kind=symlink; elif [ -f "$mnt_root/etc/login.conf" ]; then login_conf_kind=regular; else login_conf_kind=missing; fi
|
||||
if [ -L "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=symlink; elif [ -f "$mnt_root/etc/master.passwd" ]; then master_passwd_kind=regular; else master_passwd_kind=missing; fi
|
||||
[ "$run_current_system_target" = "/frx/store/$closure_base" ] || { echo "unexpected /run/current-system target: $run_current_system_target" >&2; exit 1; }
|
||||
[ "$boot_loader_target" = /run/current-system/boot/loader ] || { echo "unexpected /boot/loader target: $boot_loader_target" >&2; exit 1; }
|
||||
[ "$boot_loader_conf_target" = /run/current-system/boot/loader.conf ] || { echo "unexpected /boot/loader.conf target: $boot_loader_conf_target" >&2; exit 1; }
|
||||
[ "$rc_conf_target" = /run/current-system/etc/rc.conf ] || { echo "unexpected /etc/rc.conf target: $rc_conf_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; }
|
||||
[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in the image" >&2; exit 1; }
|
||||
[ "$master_passwd_kind" = regular ] || { echo "/etc/master.passwd is not a regular file in the image" >&2; exit 1; }
|
||||
loader_conf_image=$mnt_root/frx/store/$closure_base/boot/loader.conf
|
||||
rc_conf_image=$mnt_root/frx/store/$closure_base/etc/rc.conf
|
||||
grep -F 'comconsole' "$loader_conf_image" >/dev/null || { echo "loader.conf is missing serial console config" >&2; exit 1; }
|
||||
@@ -159,6 +163,8 @@ boot_loader_target=$boot_loader_target
|
||||
boot_loader_conf_target=$boot_loader_conf_target
|
||||
rc_conf_target=$rc_conf_target
|
||||
rc_script_target=$rc_script_target
|
||||
login_conf_kind=$login_conf_kind
|
||||
master_passwd_kind=$master_passwd_kind
|
||||
image_generation_mode=declarative-system-layer
|
||||
frontend_invocation=$fruix_cmd system image
|
||||
EOF
|
||||
|
||||
@@ -157,12 +157,23 @@ operator_home_listing=$(ssh_guest 'ls -d /home/operator')
|
||||
compat_prefix_shims=$(ssh_guest 'for p in /tmp/guile-freebsd-validate-install /tmp/guile-gnutls-freebsd-validate-install /tmp/shepherd-freebsd-validate-install; do if [ -e "$p" ] || [ -L "$p" ]; then echo present; exit 0; fi; done; echo absent')
|
||||
guile_module_smoke=$(ssh_guest "env LANG='C.UTF-8' LC_ALL='C.UTF-8' LD_LIBRARY_PATH='$guile_extra_store/lib:$guile_store/lib:/usr/local/lib' GUILE_SYSTEM_PATH='$guile_store/share/guile/3.0:$guile_store/share/guile/site/3.0:$guile_store/share/guile/site:$guile_store/share/guile' GUILE_LOAD_PATH='$shepherd_store/share/guile/site/3.0:$guile_extra_store/share/guile/site/3.0' GUILE_SYSTEM_COMPILED_PATH='$guile_store/lib/guile/3.0/ccache:$guile_store/lib/guile/3.0/site-ccache' GUILE_LOAD_COMPILED_PATH='$shepherd_store/lib/guile/3.0/site-ccache:$guile_extra_store/lib/guile/3.0/site-ccache' GUILE_SYSTEM_EXTENSIONS_PATH='$guile_store/lib/guile/3.0/extensions' GUILE_EXTENSIONS_PATH='$guile_extra_store/lib/guile/3.0/extensions' '$guile_store/bin/guile' --no-auto-compile -c '(use-modules (fibers config) (gnutls) (shepherd config)) (display \"ok\") (newline)'")
|
||||
activate_preview=$(ssh_guest 'head -n 5 /run/current-system/activate' | tr '\n' ' ')
|
||||
activate_log=$(ssh_guest 'cat /var/log/fruix-activate.log 2>/dev/null || true' | tr '\n' ' ')
|
||||
login_conf_kind=$(ssh_guest 'if [ -L /etc/login.conf ]; then echo symlink; elif [ -f /etc/login.conf ]; then echo regular; else echo missing; fi')
|
||||
login_conf_db=$(ssh_guest 'test -f /etc/login.conf.db && echo present || echo missing')
|
||||
pwd_dbs=$(ssh_guest 'if [ -f /etc/pwd.db ] && [ -f /etc/spwd.db ]; then echo present; else echo missing; fi')
|
||||
|
||||
[ "$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; }
|
||||
[ "$compat_prefix_shims" = absent ] || { echo "compatibility prefix shims are still present in /tmp" >&2; exit 1; }
|
||||
[ "$guile_module_smoke" = ok ] || { echo "guest Guile module smoke failed: $guile_module_smoke" >&2; exit 1; }
|
||||
[ "$login_conf_kind" = regular ] || { echo "/etc/login.conf is not a regular file in guest: $login_conf_kind" >&2; exit 1; }
|
||||
[ "$login_conf_db" = present ] || { echo "/etc/login.conf.db is missing in guest" >&2; exit 1; }
|
||||
[ "$pwd_dbs" = present ] || { echo "pwd.db/spwd.db are missing in guest" >&2; exit 1; }
|
||||
case "$activate_log" in
|
||||
*fruix-activate:done*) : ;;
|
||||
*) echo "activation log does not show successful completion: $activate_log" >&2; exit 1 ;;
|
||||
esac
|
||||
[ "$run_current_system_target" = "/frx/store/$closure_base" ] || {
|
||||
echo "unexpected /run/current-system target in guest: $run_current_system_target" >&2
|
||||
exit 1
|
||||
@@ -205,6 +216,10 @@ operator_home_listing=$operator_home_listing
|
||||
compat_prefix_shims=$compat_prefix_shims
|
||||
guile_module_smoke=$guile_module_smoke
|
||||
activate_preview=$activate_preview
|
||||
activate_log=$activate_log
|
||||
login_conf_kind=$login_conf_kind
|
||||
login_conf_db=$login_conf_db
|
||||
pwd_dbs=$pwd_dbs
|
||||
boot_backend=xcp-ng-xo-cli
|
||||
operator_access=ssh-root-key
|
||||
root_authorized_key_file=$root_authorized_key_file
|
||||
|
||||
Reference in New Issue
Block a user