2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-10-21 07:08:12 +00:00

Merge pull request #7922 from VersatusHPC/fix/xcattest-vmothersetting-restore

fix(xcat-test): the installation cases corrupt a versioned machine type in vmothersetting
This commit is contained in:
Daniel Hilst
2026-10-14 11:04:30 -03:00
committed by GitHub
4 changed files with 413 additions and 105 deletions
+145
View File
@@ -0,0 +1,145 @@
#!/bin/bash
# vm_machine_type.sh - set and clear the KVM machine type in vmothersetting of a node.
#
# Usage:
# vm_machine_type.sh invalid <node> save vmothersetting, then add machine:invalid
# vm_machine_type.sh apply <node> <arch> write the saved value with a valid machine type
# vm_machine_type.sh restore <node> [<arch>] write the saved value back and delete it
#
# The saved value is in $VM_MACHINE_TYPE_STATE_DIR, one file per node. The
# default directory is /tmp/xcattest-vmothersetting.<uid>.
vm_machine_type_dir()
{
printf '%s\n' "${VM_MACHINE_TYPE_STATE_DIR:-/tmp/xcattest-vmothersetting.$(id -u)}"
}
vm_machine_type_state()
{
printf '%s/xcattest-%s-vmothersetting\n' "$(vm_machine_type_dir)" "$1"
}
# private_dir -- create the state directory, or accept it only when it is a
# directory that the current user owns and nobody else can open.
vm_machine_type_private_dir()
{
local dir
dir="$(vm_machine_type_dir)"
[ -e "$dir" ] || [ -L "$dir" ] || mkdir -m 0700 "$dir" 2>/dev/null
if [ -L "$dir" ] || [ ! -d "$dir" ] || [ ! -O "$dir" ] ||
[ -n "$(find "$dir" -maxdepth 0 -perm /077)" ]; then
echo "vm_machine_type.sh: $dir is not a private directory of $(id -un)" >&2
return 1
fi
}
vm_machine_type_for_arch()
{
case "$1" in
ppc64*) echo 'machine:pseries-rhel7.6.0' ;;
x86_64) echo 'machine:pc' ;;
riscv64) echo 'machine:virt' ;;
aarch64) echo 'machine:virt' ;;
*) return 1 ;;
esac
}
vm_machine_type_get()
{
local out
if ! out="$(lsdef "$1" -i vmothersetting)"; then
echo "vm_machine_type.sh: cannot read vmothersetting of $1" >&2
return 1
fi
printf '%s\n' "$out" | sed -n 's/^[[:space:]]*vmothersetting=//p'
}
vm_machine_type_saved()
{
local state
vm_machine_type_private_dir || return 1
state="$(vm_machine_type_state "$1")"
if [ ! -e "$state" ] && [ ! -L "$state" ]; then
echo "vm_machine_type.sh: no saved vmothersetting for $1 in $state" >&2
return 1
fi
if [ -L "$state" ] || [ ! -f "$state" ] || [ ! -O "$state" ]; then
echo "vm_machine_type.sh: $state is not a regular file of $(id -un)" >&2
return 1
fi
cat "$state"
}
# join <first> <second> -- join two vmothersetting values with ";".
vm_machine_type_join()
{
if [ -z "$1" ]; then
printf '%s\n' "$2"
else
printf '%s;%s\n' "$1" "$2"
fi
}
vm_machine_type_invalid()
{
local node="$1" state original
vm_machine_type_private_dir || return 1
state="$(vm_machine_type_state "$node")"
# A second invalid would save machine:invalid as the original value.
if [ -e "$state" ] || [ -L "$state" ]; then
echo "vm_machine_type.sh: a saved vmothersetting for $node already exists in $state" >&2
return 1
fi
original="$(vm_machine_type_get "$node")" || return 1
# noclobber makes bash create the file with O_EXCL.
(set -o noclobber && printf '%s' "$original" >"$state") || return 1
# kvm.pm uses the last machine: setting.
if ! chdef "$node" "vmothersetting=$(vm_machine_type_join "$original" 'machine:invalid')"; then
rm -f "$state"
return 1
fi
}
vm_machine_type_apply()
{
local node="$1" arch="$2" original machine
original="$(vm_machine_type_saved "$node")" || return 1
# A machine type the node already names stays in place.
if [[ ";$original" == *";machine:"* ]]; then
chdef "$node" "vmothersetting=$original"
return
fi
if ! machine="$(vm_machine_type_for_arch "$arch")"; then
echo "vm_machine_type.sh: no machine type for arch '$arch'" >&2
return 1
fi
chdef "$node" "vmothersetting=$(vm_machine_type_join "$original" "$machine")"
}
vm_machine_type_restore()
{
local node="$1" original
original="$(vm_machine_type_saved "$node")" || return 1
# An empty value makes chdef delete the attribute.
chdef "$node" "vmothersetting=$original" || return 1
rm -f "$(vm_machine_type_state "$node")"
}
vm_machine_type_main()
{
local action="$1"
shift
case "$action" in
invalid) vm_machine_type_invalid "$@" ;;
apply) vm_machine_type_apply "$@" ;;
restore) vm_machine_type_restore "$@" ;;
*)
echo "usage: vm_machine_type.sh {invalid <node>|apply <node> <arch>|restore <node> [<arch>]}" >&2
return 2
;;
esac
}
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
vm_machine_type_main "$@"
fi
@@ -46,7 +46,7 @@ cmd:rm -rf /tmp/mountoutput
cmd:packimage __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-netboot-compute
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str1=`lsdef $$CN | grep vmothersetting | cut -d '=' -f 2`;str2=";"; str3="machine:invalid"; if [ -z $str1 ]; then str4=$str3; else str4=$str1$str2$str3;fi; chdef $$CN vmothersetting=$str4; fi
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then /opt/xcat/share/xcat/tools/autotest/testcase/commoncmd/vm_machine_type.sh invalid $$CN; fi
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str=`lsdef $$CN | grep vmothersetting`; if [[ $str =~ "invalid" ]]; then exit 0; else exit 1; fi; fi
check:rc==0
@@ -57,7 +57,7 @@ check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str=`/opt/xcat/share/xcat/tools/autotest/testcase/commoncmd/retry_install.sh $$CN __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-netboot-compute 1`; if [[ $str =~ "failed" ]]; then exit 0; else exit 1; fi; fi
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str1=`lsdef $$CN | grep vmothersetting | cut -d '=' -f 2`;str2="machine:invalid"; if [[ "__GETNODEATTR($$CN,arch)__" =~ "ppc64" ]]; then str3="machine:pseries-rhel7.6.0"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "x86_64" ]]; then str3="machine:pc"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "riscv64" ]]; then str3="machine:virt"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "aarch64" ]]; then str3="machine:virt";fi; if [ "$str1" == "$str2" ]; then str5=$str3; else str4=`echo $str1 | sed -e "s/$str2//"`;str5=$str4$str3;fi; chdef $$CN vmothersetting=$str5; fi
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then /opt/xcat/share/xcat/tools/autotest/testcase/commoncmd/vm_machine_type.sh apply $$CN __GETNODEATTR($$CN,arch)__; fi
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str=`lsdef $$CN | grep vmothersetting`; if [[ $str =~ "machine" ]]; then exit 0; else exit 1; fi; fi
check:rc==0
@@ -68,7 +68,7 @@ check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str=`/opt/xcat/share/xcat/tools/autotest/testcase/commoncmd/retry_install.sh $$CN __GETNODEATTR($$CN,os)__-__GETNODEATTR($$CN,arch)__-netboot-compute`; echo $str; if [[ $str =~ "The provision succeeded" ]]; then exit 0; else exit 1; fi; fi
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then str1=`lsdef $$CN | grep vmothersetting | cut -d '=' -f 2`;str2=";"; if [[ "__GETNODEATTR($$CN,arch)__" =~ "ppc64" ]]; then str3="machine:pseries-rhel7.6.0"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "x86_64" ]]; then str3="machine:pc"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "riscv64" ]]; then str3="machine:virt"; elif [[ "__GETNODEATTR($$CN,arch)__" =~ "aarch64" ]]; then str3="machine:virt";fi; if [ "$str1" == "$str3" ]; then chdef $$CN vmothersetting=; else str4=`echo $str1 | sed -e "s/$str2$str3//"`; chdef $$CN vmothersetting=$str4;fi; fi
cmd:if [ "__GETNODEATTR($$CN,mgt)__" == "kvm" ]; then /opt/xcat/share/xcat/tools/autotest/testcase/commoncmd/vm_machine_type.sh restore $$CN __GETNODEATTR($$CN,arch)__; fi
check:rc==0
cmd:if [ "__GETNODEATTR($$CN,arch)__" != "ppc64" -a "__GETNODEATTR($$CN,mgt)__" != "ipmi" -a "__GETNODEATTR($$CN,mgt)__" != "openbmc" ];then echo "CN node $$CN is a VM, mgt is __GETNODEATTR($$CN,mgt)__, starting to recreate the vm"; echo "rpower $$CN off"; rpower $$CN off; sleep 3; echo "rpower $$CN stat"; rpower $$CN stat; var=`expr substr "__GETNODEATTR($$CN,vmstorage)__" 1 3`; echo "The disk type of $$CN is $var"; if [ "$var" = "phy" ]; then echo "mkvm $$CN"; mkvm $$CN; echo "rmvm $$CN -f -p"; rmvm $$CN -f -p; echo "mkvm $$CN"; mkvm $$CN; exit $?; elif [ "$var" = "dir" ]; then echo "mkvm $$CN -s 30G -f"; mkvm $$CN -s 30G -f; echo "rmvm $$CN -f -p"; rmvm $$CN -f -p; echo "mkvm $$CN -s 30G -f"; mkvm $$CN -s 30G -f; exit $?; elif ["$var" = "nfs" -o "$var" = "lvm" ];then echo "Need to fix disk type $var"; exit 2; else echo "Unsupported disk type $var"; exit 3;fi;else echo "CN node $$CN is not a VM; do not need to recreate it";fi
check:rc==0
@@ -1,102 +0,0 @@
#!/usr/bin/env bats
#
# reg_linux_diskless_installation_flat corrupts the KVM machine type of the compute node, checks
# that the node fails to boot, and then restores it. The restore reads a machine type from a
# ladder that names ppc64 and x86_64 only, so on any other architecture it writes an empty
# vmothersetting and the check after it fails.
#
# The two commands are lifted out of the case file and RUN, with lsdef and chdef shadowed, so
# the assertions read the value the case would write. The extraction fails the test when it
# stops matching, so a rewrite fails loudly instead of covering nothing.
load 'helpers/shell_source'
setup()
{
CASE="$(repo_path 'xCAT-test/autotest/testcase/installation/reg_linux_diskless_installation_flat')"
[ -r "$CASE" ] || skip "$CASE is required"
export CASE
}
# The command that restores the machine type, and the one that removes it again afterwards.
restore_command()
{
extract_first_matching_line "$CASE" \
'^cmd:.*str2="machine:invalid".*chdef [$][$]CN vmothersetting=[$]str5'
}
remove_command()
{
extract_first_matching_line "$CASE" \
'^cmd:.*str2=";".*~ "ppc64".*chdef [$][$]CN vmothersetting='
}
# Render one command the way xcattest does, then run it with lsdef and chdef shadowed. bash
# resolves a function ahead of PATH, so the case's own backticks read the stub.
#
# Sets OUT to everything the command printed and WRITTEN to the value it gave chdef.
run_case_command()
{
local cmd="$1" arch="$2" lsdef_value="$3"
cmd="${cmd#cmd:}"
cmd="${cmd//__GETNODEATTR(\$\$CN,arch)__/$arch}"
cmd="${cmd//__GETNODEATTR(\$\$CN,mgt)__/kvm}"
cmd="${cmd//\$\$CN/cn1}"
OUT="$(bash -c "lsdef() { echo ' vmothersetting=$lsdef_value'; }
chdef() { echo \"CHDEF:[\$*]\"; }
$cmd" 2>&1)" || true
# The brackets keep an empty value apart from no call at all: the cleanup is meant to write
# an empty vmothersetting, and a command that never reaches chdef must not read as that.
CHDEF_CALLS="$(grep -c '^CHDEF:' <<<"$OUT" || true)"
WRITTEN="$(sed -n 's/^CHDEF:\[cn1 vmothersetting=\(.*\)\]$/\1/p' <<<"$OUT")"
}
# The machine type each architecture must end up with. riscv64 guests run the qemu "virt"
# machine; kvm.pm sets it in guest_arch_profile.
#
# The restore writes the machine type; the cleanup after it takes the same machine type away
# again and leaves every other setting. Both read the same ladder, so both are checked against
# the same value.
assert_arch()
{
local arch="$1" machine="$2" restore remove
restore="$(restore_command)"
remove="$(remove_command)"
# The node carries the corrupt value only.
run_case_command "$restore" "$arch" 'machine:invalid'
[ "$CHDEF_CALLS" -eq 1 ]
[ "$WRITTEN" = "machine:$machine" ]
# The node carries a setting of its own beside the corrupt value.
run_case_command "$restore" "$arch" 'cpumode:host-passthrough;machine:invalid'
[ "$CHDEF_CALLS" -eq 1 ]
[ "$WRITTEN" = "cpumode:host-passthrough;machine:$machine" ]
# The cleanup, with nothing but the machine type to remove.
run_case_command "$remove" "$arch" "machine:$machine"
[ "$(grep -c 'unary operator expected' <<<"$OUT")" -eq 0 ]
[ "$CHDEF_CALLS" -eq 1 ]
[ "$WRITTEN" = "" ]
# The cleanup, with a setting of its own that must survive it.
run_case_command "$remove" "$arch" "cpumode:host-passthrough;machine:$machine"
[ "$(grep -c 'unary operator expected' <<<"$OUT")" -eq 0 ]
[ "$CHDEF_CALLS" -eq 1 ]
[ "$WRITTEN" = "cpumode:host-passthrough" ]
}
@test "ppc64le: the restore writes the machine type and the cleanup takes it away" {
assert_arch ppc64le pseries-rhel7.6.0
}
@test "x86_64: the restore writes the machine type and the cleanup takes it away" {
assert_arch x86_64 pc
}
@test "riscv64: the restore writes the machine type and the cleanup takes it away" {
assert_arch riscv64 virt
}
+265
View File
@@ -0,0 +1,265 @@
#!/usr/bin/env bats
# vm_machine_type.sh sets machine:invalid, then a valid machine type, then clears it again.
# lsdef and chdef are shell functions that read and write vmothersetting of node cn1 in a file.
load 'helpers/shell_source'
setup()
{
source "$(require_repo_file 'xCAT-test/autotest/testcase/commoncmd/vm_machine_type.sh')"
VMOTHER="${BATS_TEST_TMPDIR}/vmothersetting"
export VM_MACHINE_TYPE_STATE_DIR="${BATS_TEST_TMPDIR}/state"
mkdir -m 0700 "$VM_MACHINE_TYPE_STATE_DIR"
STATE="${VM_MACHINE_TYPE_STATE_DIR}/xcattest-cn1-vmothersetting"
LSDEF_FAIL=0
CHDEF_FAIL=0
CHDEF_CALLS=0
}
# lsdef prints no line for an attribute without a value.
lsdef()
{
if [ "$LSDEF_FAIL" -ne 0 ]; then
echo "Error: [mn]: Could not find an object named '$1' of type 'node'." >&2
return 1
fi
printf 'Object name: %s\n' "$1"
if [ -s "$VMOTHER" ]; then
printf ' vmothersetting=%s\n' "$(cat "$VMOTHER")"
fi
}
chdef()
{
[ "$1" = cn1 ] || return 1
[ "$CHDEF_FAIL" -eq 0 ] || return 1
case "$2" in
vmothersetting=*) printf '%s' "${2#vmothersetting=}" >"$VMOTHER" ;;
*) return 1 ;;
esac
CHDEF_CALLS=$((CHDEF_CALLS + 1))
}
set_vmother()
{
printf '%s' "$1" >"$VMOTHER"
}
vmother()
{
cat "$VMOTHER"
}
# assert_arch <arch> <machine> <original> -- the value after each step of the case.
assert_arch()
{
local arch="$1" machine="$2" original="$3" sep=''
[ -z "$original" ] || sep=';'
CHDEF_CALLS=0
set_vmother "$original"
vm_machine_type_main invalid cn1
[ "$(vmother)" = "${original}${sep}machine:invalid" ]
vm_machine_type_main apply cn1 "$arch"
[ "$(vmother)" = "${original}${sep}machine:$machine" ]
vm_machine_type_main restore cn1 "$arch"
[ "$(vmother)" = "$original" ]
[ "$CHDEF_CALLS" -eq 3 ]
}
@test "ppc64le: the case sets and clears pseries-rhel7.6.0" {
assert_arch ppc64le pseries-rhel7.6.0 ''
assert_arch ppc64le pseries-rhel7.6.0 'cpumode:host-passthrough'
}
@test "x86_64: the case sets and clears pc" {
assert_arch x86_64 pc ''
assert_arch x86_64 pc 'cpumode:host-passthrough'
}
@test "riscv64: the case sets and clears virt" {
assert_arch riscv64 virt ''
assert_arch riscv64 virt 'cpumode:host-passthrough'
}
@test "aarch64: the case sets and clears virt" {
assert_arch aarch64 virt ''
assert_arch aarch64 virt 'cpumode:host-passthrough'
}
# assert_round_trip <arch> <original> -- the case ends with the exact value it started with.
assert_round_trip()
{
local arch="$1" original="$2" machine
set_vmother "$original"
vm_machine_type_main invalid cn1
# kvm.pm uses the last machine: field of vmothersetting.
machine="$(vmother | tr ';' '\n' | grep '^machine:' | tail -n 1)"
[ "$machine" = "machine:invalid" ]
vm_machine_type_main apply cn1 "$arch"
vm_machine_type_main restore cn1 "$arch"
[ "$(vmother)" = "$original" ]
[ -z "$(ls -A "$VM_MACHINE_TYPE_STATE_DIR")" ]
}
@test "round trip: no vmothersetting" {
assert_round_trip x86_64 ''
}
@test "round trip: machine:invalid" {
assert_round_trip x86_64 'machine:invalid'
}
@test "round trip: cpumode:host-passthrough" {
assert_round_trip x86_64 'cpumode:host-passthrough'
}
@test "round trip: x86_64 with a versioned machine type" {
assert_round_trip x86_64 'cpumode:host-passthrough;machine:pc-q35-9.2'
}
@test "round trip: riscv64 with a versioned machine type" {
assert_round_trip riscv64 'machine:virt-9.2'
}
@test "round trip: riscv64 with a versioned machine type after another setting" {
assert_round_trip riscv64 'cpumode:host-passthrough;machine:virt-9.2'
}
@test "round trip: several settings" {
assert_round_trip ppc64le 'vcpupin:0-3;membind:0;devpassthrough:pci_0000_01_00_0,pci_0000_02_00_0;cpumode:host-model'
}
@test "apply keeps a machine type the node already names" {
set_vmother 'cpumode:host-passthrough;machine:pc-q35-9.2'
vm_machine_type_main invalid cn1
vm_machine_type_main apply cn1 x86_64
[ "$(vmother)" = 'cpumode:host-passthrough;machine:pc-q35-9.2' ]
}
@test "restore without a saved value fails and leaves vmothersetting alone" {
set_vmother 'cpumode:host-passthrough;machine:pc'
run vm_machine_type_main restore cn1 x86_64
[ "$status" -ne 0 ]
[[ "$output" == *"no saved vmothersetting for cn1"* ]]
[ "$(vmother)" = 'cpumode:host-passthrough;machine:pc' ]
}
@test "apply fails for an architecture without a machine type" {
set_vmother ''
vm_machine_type_main invalid cn1
run vm_machine_type_main apply cn1 s390x
[ "$status" -ne 0 ]
[[ "$output" == *"no machine type for arch 's390x'"* ]]
[ "$(vmother)" = 'machine:invalid' ]
}
@test "invalid saves an empty vmothersetting that lsdef read" {
set_vmother ''
vm_machine_type_main invalid cn1
[ -f "$STATE" ]
[ ! -s "$STATE" ]
[ "$(vmother)" = 'machine:invalid' ]
}
@test "invalid creates a private state directory" {
rmdir "$VM_MACHINE_TYPE_STATE_DIR"
vm_machine_type_main invalid cn1
[ -d "$VM_MACHINE_TYPE_STATE_DIR" ]
[ -z "$(find "$VM_MACHINE_TYPE_STATE_DIR" -maxdepth 0 -perm /077)" ]
}
@test "invalid fails without a snapshot or chdef when lsdef fails" {
set_vmother 'cpumode:host-passthrough'
LSDEF_FAIL=1
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[[ "$output" == *"cannot read vmothersetting of cn1"* ]]
[ ! -e "$STATE" ]
[ "$CHDEF_CALLS" -eq 0 ]
[ "$(vmother)" = 'cpumode:host-passthrough' ]
}
@test "a second invalid is refused and keeps the first snapshot" {
set_vmother 'cpumode:host-passthrough'
vm_machine_type_main invalid cn1
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[[ "$output" == *"saved vmothersetting for cn1 already exists"* ]]
[ "$(cat "$STATE")" = 'cpumode:host-passthrough' ]
[ "$(vmother)" = 'cpumode:host-passthrough;machine:invalid' ]
[ "$CHDEF_CALLS" -eq 1 ]
vm_machine_type_main apply cn1 x86_64
vm_machine_type_main restore cn1 x86_64
[ "$(vmother)" = 'cpumode:host-passthrough' ]
}
@test "invalid refuses a snapshot left by an earlier run" {
set_vmother 'cpumode:host-passthrough'
printf '%s' 'machine:stale' >"$STATE"
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[[ "$output" == *"saved vmothersetting for cn1 already exists"* ]]
[ "$(cat "$STATE")" = 'machine:stale' ]
[ "$(vmother)" = 'cpumode:host-passthrough' ]
[ "$CHDEF_CALLS" -eq 0 ]
}
@test "invalid refuses a symbolic link as the state file" {
set_vmother 'cpumode:host-passthrough'
ln -s "${BATS_TEST_TMPDIR}/target" "$STATE"
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[ ! -e "${BATS_TEST_TMPDIR}/target" ]
[ "$(vmother)" = 'cpumode:host-passthrough' ]
[ "$CHDEF_CALLS" -eq 0 ]
}
@test "restore refuses a symbolic link as the state file" {
set_vmother 'cpumode:host-passthrough;machine:pc'
printf '%s' 'machine:other' >"${BATS_TEST_TMPDIR}/target"
ln -s "${BATS_TEST_TMPDIR}/target" "$STATE"
run vm_machine_type_main restore cn1 x86_64
[ "$status" -ne 0 ]
[[ "$output" == *"is not a regular file"* ]]
[ "$(vmother)" = 'cpumode:host-passthrough;machine:pc' ]
[ "$CHDEF_CALLS" -eq 0 ]
}
@test "invalid refuses a symbolic link as the state directory" {
set_vmother 'cpumode:host-passthrough'
rmdir "$VM_MACHINE_TYPE_STATE_DIR"
mkdir -m 0700 "${BATS_TEST_TMPDIR}/real"
ln -s "${BATS_TEST_TMPDIR}/real" "$VM_MACHINE_TYPE_STATE_DIR"
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[[ "$output" == *"is not a private directory"* ]]
[ -z "$(ls -A "${BATS_TEST_TMPDIR}/real")" ]
[ "$(vmother)" = 'cpumode:host-passthrough' ]
[ "$CHDEF_CALLS" -eq 0 ]
}
@test "invalid refuses a state directory that other users can write" {
set_vmother 'cpumode:host-passthrough'
chmod 0777 "$VM_MACHINE_TYPE_STATE_DIR"
run vm_machine_type_main invalid cn1
[ "$status" -ne 0 ]
[[ "$output" == *"is not a private directory"* ]]
[ -z "$(ls -A "$VM_MACHINE_TYPE_STATE_DIR")" ]
[ "$CHDEF_CALLS" -eq 0 ]
}
@test "restore keeps the snapshot when chdef fails" {
set_vmother 'cpumode:host-passthrough'
vm_machine_type_main invalid cn1
CHDEF_FAIL=1
run vm_machine_type_main restore cn1 x86_64
[ "$status" -ne 0 ]
[ "$(cat "$STATE")" = 'cpumode:host-passthrough' ]
[ "$(vmother)" = 'cpumode:host-passthrough;machine:invalid' ]
}