mirror of
https://github.com/ergosteur/ergo-proxmox-scripts.git
synced 2026-10-28 13:00:37 -04:00
Start passthrough VM and its dependents by device identity, not address
Adding a PCIe card can renumber the buses behind it, so a hostpci entry that names a PCI address can pass through the wrong device. These start the VM only after finding each device by vendor/device/subsystem ID or by its MAC-pinned interface, repoint its resource mapping if it moved, and refuse to start on anything ambiguous. Its dependents then wait for a port on it to answer before starting, so they find their shares up.
This commit is contained in:
Executable
+117
@@ -0,0 +1,117 @@
|
||||
#!/bin/bash
|
||||
# Start the guests that depend on the passthrough VM, once it is serving.
|
||||
#
|
||||
# Usage:
|
||||
# ./start-dependents.sh [--check]
|
||||
#
|
||||
# Run at boot by dependents-start.service, after passthrough-vm-start.service
|
||||
# has started the VM they need (a NAS, typically). The guests to start, in
|
||||
# order, are listed in conf/dependents.conf; give each of them onboot: 0 so that
|
||||
# only this starts them. VM and container IDs both work.
|
||||
#
|
||||
# Before starting anything it waits for WAIT_FOR (host:port) to accept a TCP
|
||||
# connection, for up to WAIT_SECS seconds, because a VM that has started is not
|
||||
# yet one that is serving. If it never answers the guests are started anyway,
|
||||
# with a warning, which is no worse than not waiting at all.
|
||||
#
|
||||
# A guest that fails to start does not stop the others; the script exits
|
||||
# non-zero at the end so the unit shows as failed. Guests already running are
|
||||
# left alone. Nothing is started while prox-maintenance-mode.sh has autostart
|
||||
# disabled.
|
||||
#
|
||||
# Options:
|
||||
# --check Show what would be started and test WAIT_FOR once; start nothing
|
||||
#
|
||||
# The config is looked for relative to this script, so this works both in a
|
||||
# checkout and deployed at /opt/ergosteur. Override with DEPENDENTS_CONFIG.
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
# Print the header comment block: everything from line 2 up to the first blank line.
|
||||
usage() {
|
||||
sed -n '2,/^$/p' "$0" | sed -e 's/^#//' -e 's/^ //'
|
||||
}
|
||||
|
||||
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
|
||||
CONFIG=${DEPENDENTS_CONFIG:-$SCRIPT_DIR/conf/dependents.conf}
|
||||
MAINT_STATE=/var/tmp/proxmox-autostart-backup.txt # written by prox-maintenance-mode.sh --enable
|
||||
CHECK_ONLY=false
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--help) usage; exit 0 ;;
|
||||
--check) CHECK_ONLY=true; shift ;;
|
||||
*) echo "Error: unknown option '$1'." >&2; usage >&2; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -r $CONFIG ]] || { echo "Error: cannot read $CONFIG" >&2; exit 1; }
|
||||
GUESTS=()
|
||||
WAIT_FOR=""
|
||||
WAIT_SECS=300
|
||||
# shellcheck source=conf/dependents.conf.example
|
||||
source "$CONFIG"
|
||||
|
||||
if [[ -e $MAINT_STATE ]]; then
|
||||
echo "maintenance mode is on ($MAINT_STATE exists); not starting anything"
|
||||
exit 0
|
||||
fi
|
||||
if [[ ${#GUESTS[@]} -eq 0 ]]; then
|
||||
echo "no GUESTS listed in $CONFIG; nothing to do"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# True once host:port accepts a TCP connection.
|
||||
answers() {
|
||||
timeout 3 bash -c "exec 3<>/dev/tcp/${1%:*}/${1##*:}" 2>/dev/null
|
||||
}
|
||||
|
||||
if [[ -n $WAIT_FOR ]]; then
|
||||
if $CHECK_ONLY; then
|
||||
if answers "$WAIT_FOR"; then
|
||||
echo "$WAIT_FOR answers"
|
||||
else
|
||||
echo "$WAIT_FOR is not answering right now"
|
||||
fi
|
||||
else
|
||||
echo "waiting up to ${WAIT_SECS}s for $WAIT_FOR"
|
||||
deadline=$((SECONDS + WAIT_SECS))
|
||||
until answers "$WAIT_FOR"; do
|
||||
if (( SECONDS >= deadline )); then
|
||||
echo "WARNING: $WAIT_FOR still not answering after ${WAIT_SECS}s; starting the guests anyway"
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
answers "$WAIT_FOR" && echo "$WAIT_FOR answers"
|
||||
fi
|
||||
fi
|
||||
|
||||
failed=0
|
||||
for id in "${GUESTS[@]}"; do
|
||||
if [[ -e /etc/pve/qemu-server/$id.conf ]]; then
|
||||
tool=qm conf=/etc/pve/qemu-server/$id.conf
|
||||
elif [[ -e /etc/pve/lxc/$id.conf ]]; then
|
||||
tool=pct conf=/etc/pve/lxc/$id.conf
|
||||
else
|
||||
echo "ERROR: no VM or container $id on this node" >&2
|
||||
failed=1
|
||||
continue
|
||||
fi
|
||||
if grep -q '^onboot: 1' "$conf"; then
|
||||
echo "WARNING: $id has onboot: 1, so Proxmox starts it before the VM it needs; set onboot: 0"
|
||||
fi
|
||||
if [[ $($tool status "$id" 2>/dev/null) == "status: running" ]]; then
|
||||
echo "$id is already running"
|
||||
continue
|
||||
fi
|
||||
if $CHECK_ONLY; then
|
||||
echo "would start $id ($tool)"
|
||||
elif $tool start "$id"; then
|
||||
echo "started $id ($tool)"
|
||||
else
|
||||
echo "ERROR: $tool start $id failed" >&2
|
||||
failed=1
|
||||
fi
|
||||
done
|
||||
exit "$failed"
|
||||
Reference in New Issue
Block a user