native-build: promote results into store objects
This commit is contained in:
231
tests/system/run-phase20-native-build-store-promotion-xcpng.sh
Executable file
231
tests/system/run-phase20-native-build-store-promotion-xcpng.sh
Executable file
@@ -0,0 +1,231 @@
|
||||
#!/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-native-build-store-promotion-xcpng.XXXXXX)
|
||||
cleanup=1
|
||||
fi
|
||||
if [ "${KEEP_WORKDIR:-0}" -eq 1 ]; then
|
||||
cleanup=0
|
||||
fi
|
||||
|
||||
inner_metadata=$workdir/phase20-native-build-store-promotion-inner-metadata.txt
|
||||
existing_inner_metadata=${EXISTING_INNER_METADATA:-}
|
||||
promotion_out=$workdir/native-build-promote.txt
|
||||
metadata_file=$workdir/phase20-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
|
||||
|
||||
if [ -n "$existing_inner_metadata" ]; then
|
||||
cp "$existing_inner_metadata" "$inner_metadata"
|
||||
else
|
||||
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-self-hosted-native-build-xcpng.sh"
|
||||
fi
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
[ "$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-*-guest-self-hosted) : ;;
|
||||
*) echo "unexpected result store path: $result_store" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$world_store" in
|
||||
/frx/store/*-fruix-native-world-*-guest-self-hosted) : ;;
|
||||
*) echo "unexpected world store path: $world_store" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$kernel_store" in
|
||||
/frx/store/*-fruix-native-kernel-*-guest-self-hosted) : ;;
|
||||
*) echo "unexpected kernel store path: $kernel_store" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$headers_store" in
|
||||
/frx/store/*-fruix-native-headers-*-guest-self-hosted) : ;;
|
||||
*) echo "unexpected headers store path: $headers_store" >&2; exit 1 ;;
|
||||
esac
|
||||
case "$bootloader_store" in
|
||||
/frx/store/*-fruix-native-bootloader-*-guest-self-hosted) : ;;
|
||||
*) 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 . "guest-self-hosted")' "$result_metadata_file" >/dev/null || {
|
||||
echo "result metadata file is missing guest-self-hosted executor" >&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
|
||||
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
|
||||
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-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"
|
||||
@@ -88,8 +88,10 @@ result_root=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^result_root=//p
|
||||
logdir=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^logdir=//p')
|
||||
status_file=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^status_file=//p')
|
||||
guest_metadata_file=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^metadata_file=//p')
|
||||
promotion_file=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^promotion_file=//p')
|
||||
world_stage=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^world_stage=//p')
|
||||
kernel_stage=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^kernel_stage=//p')
|
||||
world_artifact=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^world_artifact=//p')
|
||||
kernel_artifact=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^kernel_artifact=//p')
|
||||
headers_artifact=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^headers_artifact=//p')
|
||||
bootloader_artifact=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^bootloader_artifact=//p')
|
||||
@@ -97,6 +99,7 @@ latest_link=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^latest_link=//p
|
||||
root_df=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^root_df=//p')
|
||||
build_root_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^build_root_size=//p')
|
||||
result_root_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^result_root_size=//p')
|
||||
world_artifact_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^world_artifact_size=//p')
|
||||
kernel_artifact_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^kernel_artifact_size=//p')
|
||||
headers_artifact_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^headers_artifact_size=//p')
|
||||
bootloader_artifact_size=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^bootloader_artifact_size=//p')
|
||||
@@ -112,8 +115,10 @@ self_hosted_native_build=$(printf '%s\n' "$self_hosted_metadata" | sed -n 's/^se
|
||||
|
||||
status_value=$(ssh_guest "cat '$status_file'")
|
||||
latest_target=$(ssh_guest "readlink '$latest_link'")
|
||||
ssh_guest "[ -f '$promotion_file' ]"
|
||||
ssh_guest "[ -f '$world_artifact/bin/sh' ]"
|
||||
|
||||
[ "$helper_version" = 2 ] || { echo "unexpected helper version: $helper_version" >&2; exit 1; }
|
||||
[ "$helper_version" = 3 ] || { echo "unexpected helper version: $helper_version" >&2; exit 1; }
|
||||
[ "$build_jobs" = "$guest_build_jobs" ] || { echo "unexpected build job count: $build_jobs" >&2; exit 1; }
|
||||
[ "$status_value" = ok ] || { echo "self-hosted build status is not ok: $status_value" >&2; exit 1; }
|
||||
[ "$latest_target" = "$result_root" ] || { echo "latest link target mismatch: $latest_target" >&2; exit 1; }
|
||||
@@ -202,8 +207,10 @@ result_root=$result_root
|
||||
logdir=$logdir
|
||||
status_file=$status_file
|
||||
guest_metadata_file=$guest_metadata_file
|
||||
promotion_file=$promotion_file
|
||||
world_stage=$world_stage
|
||||
kernel_stage=$kernel_stage
|
||||
world_artifact=$world_artifact
|
||||
kernel_artifact=$kernel_artifact
|
||||
headers_artifact=$headers_artifact
|
||||
bootloader_artifact=$bootloader_artifact
|
||||
@@ -213,6 +220,7 @@ status_value=$status_value
|
||||
root_df=$root_df
|
||||
build_root_size=$build_root_size
|
||||
result_root_size=$result_root_size
|
||||
world_artifact_size=$world_artifact_size
|
||||
kernel_artifact_size=$kernel_artifact_size
|
||||
headers_artifact_size=$headers_artifact_size
|
||||
bootloader_artifact_size=$bootloader_artifact_size
|
||||
|
||||
Reference in New Issue
Block a user