#!/bin/sh set -eu repo_root=${PROJECT_ROOT:-$(pwd)} os_template=$repo_root/tests/system/phase11-shepherd-pid1-operating-system.scm.in system_name=${SYSTEM_NAME:-phase11-operating-system} metadata_target=${METADATA_OUT:-} root_authorized_key_file=${ROOT_AUTHORIZED_KEY_FILE:-$HOME/.ssh/id_ed25519.pub} root_ssh_private_key_file=${ROOT_SSH_PRIVATE_KEY_FILE:-$HOME/.ssh/id_ed25519} ssh_port=${QEMU_SSH_PORT:-10022} disk_capacity=${DISK_CAPACITY:-5g} cleanup=0 if [ -n "${WORKDIR:-}" ]; then workdir=$WORKDIR mkdir -p "$workdir" else workdir=$(mktemp -d /tmp/fruix-phase11-pid1-qemu.XXXXXX) cleanup=1 fi if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then cleanup=0 fi phase11_os_file=$workdir/phase11-shepherd-pid1-operating-system.scm phase8_log=$workdir/phase8-system-image.log phase8_metadata=$workdir/phase8-system-image-metadata.txt serial_log=$workdir/serial.log qemu_pidfile=$workdir/qemu.pid metadata_file=$workdir/phase11-shepherd-pid1-qemu-metadata.txt uefi_vars=$workdir/QEMU_UEFI_VARS.fd cleanup_workdir() { if [ -f "$qemu_pidfile" ]; then sudo kill "$(sudo cat "$qemu_pidfile")" >/dev/null 2>&1 || true fi if [ "$cleanup" -eq 1 ]; then rm -rf "$workdir" 2>/dev/null || sudo 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 } [ -f "$root_ssh_private_key_file" ] || { echo "missing root SSH private key file: $root_ssh_private_key_file" >&2 exit 1 } command -v qemu-system-x86_64 >/dev/null 2>&1 || { echo "qemu-system-x86_64 is required" >&2 exit 1 } [ -f /usr/local/share/edk2-qemu/QEMU_UEFI_CODE-x86_64.fd ] || { echo "missing QEMU UEFI firmware" >&2 exit 1 } cp /usr/local/share/edk2-qemu/QEMU_UEFI_VARS-x86_64.fd "$uefi_vars" root_authorized_key=$(tr -d '\n' < "$root_authorized_key_file") sed "s|__ROOT_AUTHORIZED_KEY__|$root_authorized_key|g" "$os_template" > "$phase11_os_file" KEEP_WORKDIR=1 WORKDIR="$workdir/phase8-build" OS_FILE="$phase11_os_file" SYSTEM_NAME="$system_name" 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") sudo qemu-system-x86_64 \ -machine q35,accel=tcg \ -cpu max \ -m 2048 \ -smp 2 \ -display none \ -serial "file:$serial_log" \ -monitor none \ -pidfile "$qemu_pidfile" \ -daemonize \ -drive if=pflash,format=raw,readonly=on,file=/usr/local/share/edk2-qemu/QEMU_UEFI_CODE-x86_64.fd \ -drive if=pflash,format=raw,file="$uefi_vars" \ -drive if=virtio,format=raw,file="$disk_image" \ -netdev user,id=net0,hostfwd=tcp::${ssh_port}-:22 \ -device virtio-net-pci,netdev=net0 ssh_guest() { ssh -p "$ssh_port" -i "$root_ssh_private_key_file" \ -o BatchMode=yes \ -o StrictHostKeyChecking=no \ -o UserKnownHostsFile=/dev/null \ -o ConnectTimeout=5 \ root@127.0.0.1 "$@" } for attempt in $(jot 120 1 120); do if ssh_guest 'test -f /var/lib/fruix/ready' >/dev/null 2>&1; then break fi sleep 2 done ready_marker=$(ssh_guest 'cat /var/lib/fruix/ready') run_current_system_target=$(ssh_guest 'readlink /run/current-system') pid1_command=$(ssh_guest 'ps -p 1 -o command= | sed "s/^ *//"') pid1_binary=$(ssh_guest 'procstat -b 1 2>/dev/null | awk "NR==2 {print \$2}"') shepherd_pid=$(ssh_guest 'cat /var/run/shepherd.pid') shepherd_socket=$(ssh_guest 'test -S /var/run/shepherd.sock && echo present || echo missing') shepherd_status=$(ssh_guest 'test -f /var/run/shepherd.pid && kill -0 "$(cat /var/run/shepherd.pid)" >/dev/null 2>&1 && echo running || echo stopped') sshd_status=$(ssh_guest 'service sshd onestatus >/dev/null 2>&1 && echo running || echo stopped') logger_log=$(ssh_guest 'cat /var/log/fruix-shepherd.log' | tr '\n' ' ') uname_output=$(ssh_guest 'uname -sr') operator_home_listing=$(ssh_guest 'ls -d /home/operator') [ "$ready_marker" = ready ] || { echo "unexpected ready marker contents: $ready_marker" >&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 } [ "$shepherd_pid" = 1 ] || { echo "shepherd is not PID 1: shepherd.pid=$shepherd_pid pid1_command=$pid1_command pid1_binary=$pid1_binary" >&2 exit 1 } [ "$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; } [ "$operator_home_listing" = /home/operator ] || { echo "operator home missing" >&2; exit 1; } cat >"$metadata_file" <