mirror of
https://github.com/unraid/webgui.git
synced 2026-02-05 16:39:01 -06:00
310 lines
8.3 KiB
Bash
Executable File
310 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/bash
|
|
# Init script for libvirtd on Slackware
|
|
# Written by Matteo Bernardini <ponce@slackbuilds.org>
|
|
#
|
|
# Note that a dnsmasq daemon is started by libvirtd itself to serve
|
|
# its virtual network, and possibly can conflict with a dnsmasq
|
|
# already running on the system, see
|
|
# http://wiki.libvirt.org/page/Libvirtd_and_dnsmasq
|
|
# Note also that the tun, vhost_net and kvm related modules are
|
|
# automatically loaded at start and removed at stop: edit the
|
|
# script if this behaviour conflicts with anything else running
|
|
# on your setup
|
|
|
|
# Read unRAID libvirt configuration file (named "domain.cfg" leftover from Xen days)
|
|
|
|
# Modified stop_running_machines by Bergware 2022-03-11
|
|
# Avoid Unraid from hanging when the array is stopped, while VMs are in paused or suspended state
|
|
|
|
if [ -f /boot/config/domain.cfg ]; then
|
|
. /boot/config/domain.cfg
|
|
fi
|
|
|
|
SYSTEM=/sys/class/net
|
|
MODULES=${MODULES:-"vhost_net"}
|
|
TIMEOUT=${TIMEOUT:-60}
|
|
HOSTSHUTDOWN=${HOSTSHUTDOWN:-"shutdown"}
|
|
LIBVIRTD_PIDFILE="/var/run/libvirt/libvirtd.pid"
|
|
LIBVIRTD_OPTS=${LIBVIRT_OPTS:-" -f /etc/libvirt/libvirtd.conf -p $LIBVIRTD_PIDFILE "}
|
|
VIRTLOGD_PIDFILE="/var/run/libvirt/virtlogd.pid"
|
|
VIRTLOGD_OPTS=${VIRTLOGD_OPTS:-" -f /etc/libvirt/virtlogd.conf -p $VIRTLOGD_PIDFILE "}
|
|
VIRTLOCKD_PIDFILE="/var/run/libvirt/virtlockd.pid"
|
|
VIRTLOCKD_OPTS=${VIRTLOCKD_OPTS:-" -f /etc/libvirt/virtlockd.conf -p $VIRTLOCKD_PIDFILE "}
|
|
|
|
vmstate() {
|
|
virsh list --all|awk -F'[[:space:]][[:space:]]+' 'NR>2 && /^.+$/{print $3}'
|
|
}
|
|
|
|
vmlist() {
|
|
local state=
|
|
for arg in ${@: 1}; do
|
|
[[ $arg == all ]] && state="$state --all" || state="$state --state-$arg"
|
|
done
|
|
virsh list --uuid $state|grep -v '^$'
|
|
}
|
|
|
|
waitfor() {
|
|
local c=0
|
|
while [[ $c -lt $TIMEOUT && $(virsh list --state-${1}|awk "NR>2 && /${2:-^.+$}/"|wc -l) -gt 0 ]]; do
|
|
((c++))
|
|
sleep 1
|
|
done
|
|
}
|
|
|
|
stop_running_machines() {
|
|
# create names array
|
|
declare -A NAMES
|
|
while IFS='\n' read -r id; do
|
|
[[ -n $id ]] && NAMES[${id:0:36}]=${id:37}
|
|
done <<< $(virsh list --all --uuid --name)
|
|
|
|
# resume paused VMs
|
|
for uuid in $(vmlist paused); do
|
|
echo "Resuming VM: ${NAMES[$uuid]}"
|
|
virsh resume $uuid 1>/dev/null 2>&1
|
|
done
|
|
# wait until VMs are resumed
|
|
waitfor paused
|
|
|
|
if [[ $HOSTSHUTDOWN == hibernate ]]; then
|
|
for uuid in $(vmlist running); do
|
|
echo "Suspending VM: ${NAMES[$uuid]}"
|
|
virsh dompmsuspend $uuid disk 1>/dev/null 2>&1
|
|
done
|
|
# wait until VMs are suspended
|
|
waitfor running
|
|
fi
|
|
|
|
# graceful shutdown of running VMs
|
|
for uuid in $(vmlist running); do
|
|
echo "Shutting down VM: ${NAMES[$uuid]}"
|
|
virsh shutdown $uuid 1>/dev/null 2>&1
|
|
done
|
|
# wait until VMs are stopped
|
|
waitfor running
|
|
|
|
# graceful shutdown of suspended VMs
|
|
i=0; uuid=($(vmlist all))
|
|
while IFS='\n' read -r state; do
|
|
# check explicitely for suspended VMs
|
|
if [[ $state == pmsuspended ]]; then
|
|
echo "Stopping suspended VM: ${NAMES[${uuid[i]}]}"
|
|
virsh destroy ${uuid[i]} --graceful 1>/dev/null 2>&1
|
|
fi
|
|
((i++))
|
|
done <<< $(vmstate)
|
|
# wait until VMs are stopped
|
|
waitfor other pmsuspended
|
|
|
|
# forced shutdown of rogue VMs
|
|
for uuid in $(vmlist running paused other); do
|
|
echo "Forced shutting down VM: ${NAMES[$uuid]}"
|
|
virsh destroy $uuid 1>/dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
check_processor() {
|
|
egrep 'vmx' /proc/cpuinfo > /dev/null
|
|
|
|
if [ "$?" -eq "0" ];then
|
|
MODULE="kvm_intel"
|
|
fi
|
|
|
|
check=$?
|
|
|
|
egrep 'svm' /proc/cpuinfo > /dev/null
|
|
|
|
if [ "$?" -eq "0" ];then
|
|
MODULE="kvm_amd"
|
|
fi
|
|
|
|
check=$(expr $check + $?)
|
|
|
|
if [ $check -eq "2" ];then
|
|
echo "Your system does not support KVM!"
|
|
fi
|
|
}
|
|
|
|
test() {
|
|
check_processor
|
|
if [ -z "$MODULE" ]; then
|
|
exit 1;
|
|
fi
|
|
if lsmod | grep -q "^$MODULE" ; then
|
|
echo $MODULE
|
|
exit 0;
|
|
fi
|
|
modprobe $MODULE
|
|
if lsmod | grep -q "^$MODULE" ; then
|
|
modprobe -r $MODULE
|
|
echo $MODULE
|
|
exit 0;
|
|
fi
|
|
exit 1
|
|
}
|
|
|
|
waitstop() {
|
|
# wait for daemon to exit
|
|
PIDFILE=$1
|
|
PNAME=$2
|
|
for n in {1..15}; do
|
|
sleep 1
|
|
if [[ ! -f "$PIDFILE" || $(ps -p $(cat "$PIDFILE") -o comm= 2>/dev/null) != "$PNAME" ]]; then
|
|
rm -f "$PIDFILE"
|
|
return 0
|
|
fi
|
|
echo "waiting for $PNAME to die ..."
|
|
done
|
|
echo "$PNAME will not die!"
|
|
return 1
|
|
}
|
|
|
|
version() {
|
|
echo $1 | awk -F. '{printf("%03d%03d", $1,$2);}'
|
|
}
|
|
|
|
start_libvirtd() {
|
|
if [[ -f $LIBVIRTD_PIDFILE ]]; then
|
|
echo "libvirt is already running..."
|
|
exit 1
|
|
fi
|
|
if ! mountpoint /etc/libvirt &> /dev/null ; then
|
|
echo "no image mounted at /etc/libvirt"
|
|
exit 1
|
|
fi
|
|
# convert libvirt 1.3.1 w/ eric's hyperv vendor id patch to how libvirt does it in libvirt 1.3.3+
|
|
sed -ri "s/<vendor id='none'\/>/<vendor_id state='on' value='none'\/>/g" /etc/libvirt/qemu/*.xml &> /dev/null
|
|
# remove <locked/> from xml because libvirt + virlogd + virlockd has an issue with locked
|
|
sed -ri "s/<locked\/>//g" /etc/libvirt/qemu/*.xml &> /dev/null
|
|
# Remove "<watchdog model='itco' action='reset'/>" if reverting from later release.
|
|
. /etc/unraid-version
|
|
if [[ $(version $version) -le $(version "6.12") ]]; then
|
|
sed -ri "/<watchdog model='itco' action='reset'\/>/d" /etc/libvirt/qemu/*.xml &> /dev/null
|
|
fi
|
|
# update interface section((s) of VM configuration files
|
|
for XML in /etc/libvirt/qemu/*.xml; do
|
|
# get all interface sections
|
|
ROW=($(grep -nhP '<interface type=' "$XML"|grep -Pom1 '^[0-9]+'))
|
|
# get all source sections
|
|
CAT=($(grep -nhP '<source (bridge|dev)=' "$XML"|awk '{print $1$3}'))
|
|
for i in ${!ROW[@]}; do
|
|
ROW2=$(echo ${CAT[$i]}|grep -Pom1 '^[0-9]+')
|
|
DEV=$(echo ${CAT[$i]}|grep -Pom1 "^.+='\K[^']+")
|
|
if [[ ! -e $SYSTEM/$DEV ]]; then
|
|
NAME=${DEV//[0-9.]/}
|
|
if [[ $NAME == br ]]; then
|
|
# change to macvtap
|
|
logger -t $(basename $0) "change $DEV to macvtap in $XML"
|
|
sed -ri "${ROW[$i]} s/<interface type='bridge'>/<interface type='direct' trustGuestRxFilters='yes'>/; $ROW2 s/<source bridge='$DEV'\/>/<source dev='${DEV/$NAME/vhost}' mode='bridge'\/>/" "$XML"
|
|
else
|
|
# change to bridge
|
|
logger -t $(basename $0) "change $DEV to bridge in $XML"
|
|
sed -ri "${ROW[$i]} s/<interface type='direct'( trustGuestRxFilters='yes')?>/<interface type='bridge'>/; $ROW2 s/<source dev='$DEV' mode='bridge'\/>/<source bridge='${DEV/$NAME/br}'\/>/" "$XML"
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
# copy any new conf files we dont currently have
|
|
cp -n /etc/libvirt-/*.conf /etc/libvirt &> /dev/null
|
|
# ensure tpm-states path exists
|
|
mkdir -p /etc/libvirt/qemu/swtpm/tpm-states
|
|
echo "Starting libvirtd..."
|
|
mkdir -p $(dirname $LIBVIRTD_PIDFILE)
|
|
check_processor
|
|
/sbin/modprobe -a $MODULE $MODULES
|
|
/usr/sbin/libvirtd -d -l $LIBVIRTD_OPTS
|
|
}
|
|
|
|
stop_libvirtd() {
|
|
if [[ ! -f $LIBVIRTD_PIDFILE ]]; then
|
|
echo "libvirt is not running..."
|
|
exit 2
|
|
fi
|
|
stop_running_machines
|
|
echo "Stopping libvirtd..."
|
|
for network in $(/usr/sbin/virsh net-list --uuid | grep -v ^$); do
|
|
/usr/sbin/virsh net-destroy $network
|
|
done
|
|
kill -TERM $(cat $LIBVIRTD_PIDFILE)
|
|
waitstop $LIBVIRTD_PIDFILE "libvirtd"
|
|
check_processor
|
|
/sbin/modprobe -ra $MODULE $MODULES 2>/dev/null
|
|
}
|
|
|
|
start_virtlogd() {
|
|
if [[ -f $VIRTLOGD_PIDFILE ]]; then
|
|
echo "virtlogd is already running..."
|
|
exit 1
|
|
fi
|
|
echo "Starting virtlogd..."
|
|
mkdir -p $(dirname $VIRTLOGD_PIDFILE)
|
|
/usr/sbin/virtlogd -d $VIRTLOGD_OPTS
|
|
}
|
|
|
|
stop_virtlogd() {
|
|
if [[ ! -f $VIRTLOGD_PIDFILE ]]; then
|
|
echo "virtlogd is not running..."
|
|
exit 2
|
|
fi
|
|
echo "Stopping virtlogd..."
|
|
kill -TERM $(cat $VIRTLOGD_PIDFILE)
|
|
waitstop $VIRTLOGD_PIDFILE "virtlogd"
|
|
}
|
|
|
|
start_virtlockd() {
|
|
if [[ -f $VIRTLOCKD_PIDFILE ]]; then
|
|
echo "virtlockd is already running..."
|
|
exit 1
|
|
fi
|
|
echo "Starting virtlockd..."
|
|
mkdir -p $(dirname $VIRTLOCKD_PIDFILE)
|
|
/usr/sbin/virtlockd -d $VIRTLOCKD_OPTS
|
|
}
|
|
|
|
stop_virtlockd() {
|
|
if [[ ! -f $VIRTLOCKD_PIDFILE ]]; then
|
|
echo "virtlockd is not running..."
|
|
exit 2
|
|
fi
|
|
echo "Stopping virtlockd..."
|
|
kill -TERM $(cat $VIRTLOCKD_PIDFILE)
|
|
waitstop $VIRTLOCKD_PIDFILE "virtlockd"
|
|
}
|
|
|
|
cleanup() {
|
|
find /run/libvirt -type f -exec rm {} \;
|
|
}
|
|
|
|
case $1 in
|
|
test)
|
|
test
|
|
;;
|
|
start)
|
|
start_virtlockd
|
|
start_virtlogd
|
|
start_libvirtd
|
|
;;
|
|
stop)
|
|
stop_libvirtd
|
|
stop_virtlogd
|
|
stop_virtlockd
|
|
cleanup
|
|
;;
|
|
restart)
|
|
stop_libvirtd
|
|
stop_virtlogd
|
|
stop_virtlockd
|
|
cleanup
|
|
sleep 1
|
|
start_virtlockd
|
|
start_virtlogd
|
|
start_libvirtd
|
|
;;
|
|
status)
|
|
[ -f $LIBVIRTD_PIDFILE ]
|
|
;;
|
|
*)
|
|
echo "Usage: $0 (test|start|stop|restart|status)"
|
|
;;
|
|
esac
|