240 lines
11 KiB
Bash
Executable File
240 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
set -eu
|
|
|
|
repo_root=${PROJECT_ROOT:-$(pwd)}
|
|
os_template=${OS_TEMPLATE:-$repo_root/tests/system/phase20-development-operating-system.scm.in}
|
|
system_name=${SYSTEM_NAME:-phase20-operating-system}
|
|
root_size=${ROOT_SIZE:-20g}
|
|
store_dir=${STORE_DIR:-/frx/store}
|
|
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}
|
|
cleanup=0
|
|
|
|
if [ -n "${WORKDIR:-}" ]; then
|
|
workdir=$WORKDIR
|
|
mkdir -p "$workdir"
|
|
else
|
|
workdir=$(mktemp -d /tmp/fruix-phase20-host-initiated-native-build-store-promotion-xcpng.XXXXXX)
|
|
cleanup=1
|
|
fi
|
|
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
|
cleanup=0
|
|
fi
|
|
|
|
inner_metadata=$workdir/phase20-host-initiated-native-build-store-promotion-inner-metadata.txt
|
|
promotion_out=$workdir/native-build-promote.txt
|
|
metadata_file=$workdir/phase20-host-initiated-native-build-store-promotion-xcpng-metadata.txt
|
|
import_root=$workdir/import
|
|
|
|
action_cleanup() {
|
|
if [ "$cleanup" -eq 1 ]; then
|
|
rm -rf "$workdir"
|
|
fi
|
|
}
|
|
trap action_cleanup EXIT INT TERM
|
|
|
|
KEEP_WORKDIR=1 WORKDIR="$workdir/inner" METADATA_OUT="$inner_metadata" \
|
|
ROOT_AUTHORIZED_KEY_FILE="$root_authorized_key_file" \
|
|
ROOT_SSH_PRIVATE_KEY_FILE="$root_ssh_private_key_file" \
|
|
OS_TEMPLATE="$os_template" SYSTEM_NAME="$system_name" ROOT_SIZE="$root_size" \
|
|
"$repo_root/tests/system/run-phase20-host-initiated-native-build-xcpng.sh"
|
|
|
|
guest_ip=$(sed -n 's/^guest_ip=//p' "$inner_metadata")
|
|
vm_id=$(sed -n 's/^vm_id=//p' "$inner_metadata")
|
|
vdi_id=$(sed -n 's/^vdi_id=//p' "$inner_metadata")
|
|
closure_path=$(sed -n 's/^closure_path=//p' "$inner_metadata")
|
|
closure_base=$(sed -n 's/^closure_base=//p' "$inner_metadata")
|
|
run_id=$(sed -n 's/^run_id=//p' "$inner_metadata")
|
|
source_store=$(sed -n 's/^source_store=//p' "$inner_metadata")
|
|
result_root=$(sed -n 's/^result_root=//p' "$inner_metadata")
|
|
promotion_file=$(sed -n 's/^promotion_file=//p' "$inner_metadata")
|
|
world_artifact=$(sed -n 's/^world_artifact=//p' "$inner_metadata")
|
|
kernel_artifact=$(sed -n 's/^kernel_artifact=//p' "$inner_metadata")
|
|
headers_artifact=$(sed -n 's/^headers_artifact=//p' "$inner_metadata")
|
|
bootloader_artifact=$(sed -n 's/^bootloader_artifact=//p' "$inner_metadata")
|
|
sha_kernel=$(sed -n 's/^sha_kernel=//p' "$inner_metadata")
|
|
sha_loader=$(sed -n 's/^sha_loader=//p' "$inner_metadata")
|
|
sha_param=$(sed -n 's/^sha_param=//p' "$inner_metadata")
|
|
|
|
ssh_guest() {
|
|
ssh -i "$root_ssh_private_key_file" \
|
|
-o BatchMode=yes \
|
|
-o StrictHostKeyChecking=no \
|
|
-o UserKnownHostsFile=/dev/null \
|
|
-o ConnectTimeout=5 \
|
|
root@"$guest_ip" "$@"
|
|
}
|
|
|
|
mkdir -p "$import_root"
|
|
result_base=$(basename "$result_root")
|
|
ssh -i "$root_ssh_private_key_file" \
|
|
-o BatchMode=yes \
|
|
-o StrictHostKeyChecking=no \
|
|
-o UserKnownHostsFile=/dev/null \
|
|
-o ConnectTimeout=5 \
|
|
root@"$guest_ip" "tar -C '$(dirname "$result_root")' -cf - '$result_base'" | tar -C "$import_root" -xf -
|
|
local_result_root=$import_root/$result_base
|
|
[ -d "$local_result_root" ] || { echo "failed to import native build result root" >&2; exit 1; }
|
|
[ -f "$local_result_root/promotion.scm" ] || { echo "imported result is missing promotion.scm" >&2; exit 1; }
|
|
[ -f "$local_result_root/artifacts/world/bin/sh" ] || { echo "imported result is missing world artifact" >&2; exit 1; }
|
|
[ -f "$local_result_root/artifacts/kernel/boot/kernel/kernel" ] || { echo "imported result is missing kernel artifact" >&2; exit 1; }
|
|
[ -f "$local_result_root/artifacts/headers/usr/include/sys/param.h" ] || { echo "imported result is missing headers artifact" >&2; exit 1; }
|
|
[ -f "$local_result_root/artifacts/bootloader/boot/loader.efi" ] || { echo "imported result is missing bootloader artifact" >&2; exit 1; }
|
|
|
|
action_env() {
|
|
sudo env \
|
|
HOME="$HOME" \
|
|
GUILE_AUTO_COMPILE=0 \
|
|
GUIX_SOURCE_DIR="${GUIX_SOURCE_DIR:-$HOME/repos/guix}" \
|
|
GUILE_BIN="${GUILE_BIN:-/tmp/guile-freebsd-validate-install/bin/guile}" \
|
|
GUILE_EXTRA_PREFIX="${GUILE_EXTRA_PREFIX:-/tmp/guile-gnutls-freebsd-validate-install}" \
|
|
SHEPHERD_PREFIX="${SHEPHERD_PREFIX:-/tmp/shepherd-freebsd-validate-install}" \
|
|
"$@"
|
|
}
|
|
|
|
action_env "$repo_root/bin/fruix" native-build promote "$local_result_root" --store "$store_dir" >"$promotion_out"
|
|
|
|
field() {
|
|
sed -n "s/^$1=//p" "$promotion_out" | tail -n 1
|
|
}
|
|
|
|
executor_kind=$(field executor_kind)
|
|
executor_name=$(field executor_name)
|
|
executor_version=$(field executor_version)
|
|
result_store=$(field result_store)
|
|
result_metadata_file=$(field result_metadata_file)
|
|
artifact_store_count=$(field artifact_store_count)
|
|
artifact_stores=$(field artifact_stores)
|
|
world_store=$(field world_store)
|
|
kernel_store=$(field kernel_store)
|
|
headers_store=$(field headers_store)
|
|
bootloader_store=$(field bootloader_store)
|
|
|
|
[ "$executor_kind" = ssh-guest ] || { echo "unexpected executor kind: $executor_kind" >&2; exit 1; }
|
|
[ "$executor_name" = ssh-guest ] || { echo "unexpected executor name: $executor_name" >&2; exit 1; }
|
|
[ "$executor_version" = 1 ] || { echo "unexpected executor version: $executor_version" >&2; exit 1; }
|
|
[ "$artifact_store_count" = 4 ] || { echo "unexpected artifact store count: $artifact_store_count" >&2; exit 1; }
|
|
case "$result_store" in
|
|
/frx/store/*-fruix-native-build-result-*-ssh-guest) : ;;
|
|
*) echo "unexpected result store path: $result_store" >&2; exit 1 ;;
|
|
esac
|
|
case "$world_store" in
|
|
/frx/store/*-fruix-native-world-*-ssh-guest) : ;;
|
|
*) echo "unexpected world store path: $world_store" >&2; exit 1 ;;
|
|
esac
|
|
case "$kernel_store" in
|
|
/frx/store/*-fruix-native-kernel-*-ssh-guest) : ;;
|
|
*) echo "unexpected kernel store path: $kernel_store" >&2; exit 1 ;;
|
|
esac
|
|
case "$headers_store" in
|
|
/frx/store/*-fruix-native-headers-*-ssh-guest) : ;;
|
|
*) echo "unexpected headers store path: $headers_store" >&2; exit 1 ;;
|
|
esac
|
|
case "$bootloader_store" in
|
|
/frx/store/*-fruix-native-bootloader-*-ssh-guest) : ;;
|
|
*) echo "unexpected bootloader store path: $bootloader_store" >&2; exit 1 ;;
|
|
esac
|
|
|
|
[ -f "$result_metadata_file" ] || { echo "missing result metadata file: $result_metadata_file" >&2; exit 1; }
|
|
[ -f "$world_store/.fruix-native-build-object.scm" ] || { echo "missing world store metadata" >&2; exit 1; }
|
|
[ -f "$kernel_store/.fruix-native-build-object.scm" ] || { echo "missing kernel store metadata" >&2; exit 1; }
|
|
[ -f "$headers_store/.fruix-native-build-object.scm" ] || { echo "missing headers store metadata" >&2; exit 1; }
|
|
[ -f "$bootloader_store/.fruix-native-build-object.scm" ] || { echo "missing bootloader store metadata" >&2; exit 1; }
|
|
[ -L "$result_store/artifacts/world" ] || { echo "missing promoted world artifact link" >&2; exit 1; }
|
|
[ -L "$result_store/artifacts/kernel" ] || { echo "missing promoted kernel artifact link" >&2; exit 1; }
|
|
[ -L "$result_store/artifacts/headers" ] || { echo "missing promoted headers artifact link" >&2; exit 1; }
|
|
[ -L "$result_store/artifacts/bootloader" ] || { echo "missing promoted bootloader artifact link" >&2; exit 1; }
|
|
[ "$(readlink "$result_store/artifacts/world")" = "$world_store" ] || { echo "world artifact link mismatch" >&2; exit 1; }
|
|
[ "$(readlink "$result_store/artifacts/kernel")" = "$kernel_store" ] || { echo "kernel artifact link mismatch" >&2; exit 1; }
|
|
[ "$(readlink "$result_store/artifacts/headers")" = "$headers_store" ] || { echo "headers artifact link mismatch" >&2; exit 1; }
|
|
[ "$(readlink "$result_store/artifacts/bootloader")" = "$bootloader_store" ] || { echo "bootloader artifact link mismatch" >&2; exit 1; }
|
|
[ -f "$world_store/bin/sh" ] || { echo "promoted world store missing /bin/sh" >&2; exit 1; }
|
|
[ -f "$kernel_store/boot/kernel/kernel" ] || { echo "promoted kernel store missing kernel" >&2; exit 1; }
|
|
[ -f "$headers_store/usr/include/sys/param.h" ] || { echo "promoted headers store missing param.h" >&2; exit 1; }
|
|
[ -f "$bootloader_store/boot/loader.efi" ] || { echo "promoted bootloader store missing loader.efi" >&2; exit 1; }
|
|
|
|
promoted_kernel_sha=$(sha256 -q "$kernel_store/boot/kernel/kernel")
|
|
promoted_loader_sha=$(sha256 -q "$bootloader_store/boot/loader.efi")
|
|
promoted_param_sha=$(sha256 -q "$headers_store/usr/include/sys/param.h")
|
|
[ "$promoted_kernel_sha" = "$sha_kernel" ] || { echo "kernel sha mismatch after promotion" >&2; exit 1; }
|
|
[ "$promoted_loader_sha" = "$sha_loader" ] || { echo "loader sha mismatch after promotion" >&2; exit 1; }
|
|
[ "$promoted_param_sha" = "$sha_param" ] || { echo "param.h sha mismatch after promotion" >&2; exit 1; }
|
|
|
|
grep -F '(executor-kind . ssh-guest)' "$result_metadata_file" >/dev/null || {
|
|
echo "result metadata file is missing ssh-guest executor kind" >&2
|
|
exit 1
|
|
}
|
|
grep -F '(executor-name . "ssh-guest")' "$result_metadata_file" >/dev/null || {
|
|
echo "result metadata file is missing ssh-guest executor name" >&2
|
|
exit 1
|
|
}
|
|
grep -F "$source_store" "$result_metadata_file" >/dev/null || {
|
|
echo "result metadata file is missing source store provenance" >&2
|
|
exit 1
|
|
}
|
|
grep -F '(artifact-kind . kernel)' "$kernel_store/.fruix-native-build-object.scm" >/dev/null || {
|
|
echo "kernel store metadata is missing artifact kind" >&2
|
|
exit 1
|
|
}
|
|
grep -F '(artifact-kind . world)' "$world_store/.fruix-native-build-object.scm" >/dev/null || {
|
|
echo "world store metadata is missing artifact kind" >&2
|
|
exit 1
|
|
}
|
|
|
|
cat >"$metadata_file" <<EOF
|
|
workdir=$workdir
|
|
inner_metadata=$inner_metadata
|
|
promotion_out=$promotion_out
|
|
closure_path=$closure_path
|
|
closure_base=$closure_base
|
|
vm_id=$vm_id
|
|
vdi_id=$vdi_id
|
|
guest_ip=$guest_ip
|
|
root_size=$root_size
|
|
run_id=$run_id
|
|
source_store=$source_store
|
|
guest_result_root=$result_root
|
|
guest_promotion_file=$promotion_file
|
|
guest_world_artifact=$world_artifact
|
|
guest_kernel_artifact=$kernel_artifact
|
|
guest_headers_artifact=$headers_artifact
|
|
guest_bootloader_artifact=$bootloader_artifact
|
|
local_result_root=$local_result_root
|
|
store_dir=$store_dir
|
|
executor_kind=$executor_kind
|
|
executor_name=$executor_name
|
|
executor_version=$executor_version
|
|
result_store=$result_store
|
|
result_metadata_file=$result_metadata_file
|
|
artifact_store_count=$artifact_store_count
|
|
artifact_stores=$artifact_stores
|
|
world_store=$world_store
|
|
kernel_store=$kernel_store
|
|
headers_store=$headers_store
|
|
bootloader_store=$bootloader_store
|
|
sha_kernel=$sha_kernel
|
|
sha_loader=$sha_loader
|
|
sha_param=$sha_param
|
|
promoted_kernel_sha=$promoted_kernel_sha
|
|
promoted_loader_sha=$promoted_loader_sha
|
|
promoted_param_sha=$promoted_param_sha
|
|
boot_backend=xcp-ng-xo-cli
|
|
init_mode=shepherd-pid1
|
|
host_initiated_native_build_store_promotion=ok
|
|
EOF
|
|
|
|
if [ -n "$metadata_target" ]; then
|
|
mkdir -p "$(dirname "$metadata_target")"
|
|
cp "$metadata_file" "$metadata_target"
|
|
fi
|
|
|
|
printf 'PASS phase20-host-initiated-native-build-store-promotion-xcpng\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"
|