#!/sbin/openrc-run description="Virtual Machine Management (libvirt) Guests" depend() { use libvirtd } # set the default to QEMU [ -z "${LIBVIRT_URIS}" ] && LIBVIRT_URIS="qemu:///system" # default to suspending the VM via managedsave case "${LIBVIRT_SHUTDOWN}" in managedsave|shutdown|destroy) ;; *) LIBVIRT_SHUTDOWN="managedsave" ;; esac # default to 500 seconds [ -z ${LIBVIRT_MAXWAIT} ] && LIBVIRT_MAXWAIT=500 gueststatefile="/var/lib/libvirt/libvirt-guests.state" netstatefile="/var/lib/libvirt/libvirt-net.state" do_virsh() { local hvuri=$1 shift # if unset, default to qemu [ -z ${hvuri} ] && hvuri="qemu:///system" # if only qemu was supplied then correct the value [ "xqemu" = x${hvuri} ] && hvuri="qemu:///system" # Silence errors because virsh always throws an error about # not finding the hypervisor version when connecting to libvirtd # lastly strip the blank line at the end LC_ALL=C virsh -c ${hvuri} "$@" 2>/dev/null | head -n -1 } libvirtd_dom_list() { # Only work with domains by their UUIDs local hvuri=$1 shift # The grep is to remove dom0 for xen domains. Otherwise we never hit 0 do_virsh "${hvuri}" list --uuid $@ | grep -v 00000000-0000-0000-0000-000000000000 } libvirtd_dom_count() { local hvuri=$1 shift libvirtd_dom_list "${hvuri}" $@ | wc -l } libvirtd_net_list() { # Only work with networks by their UUIDs local hvuri=$1 shift do_virsh "${hvuri}" net-list --uuid $@ } libvirtd_net_count() { local hvuri=$1 shift libvirtd_net_list "${hvuri}" $@ | wc -l } libvirtd_dom_stop() { # stops all persistent or transient domains for a given URI # $1 - uri # $2 - persisent/transient local uri=$1 local persist=$2 local shutdown_type=${LIBVIRT_SHUTDOWN} local counter=${LIBVIRT_MAXWAIT} local dom_name= local dom_as= local dom_ids= local uuid= local dom_count= [ "${persist}" = "--transient" ] && shutdown_type="shutdown" [ -n "${counter}" ] || counter=500 einfo " Shutting down domain(s) ..." # grab all persistent or transient domains running dom_ids=$(libvirtd_dom_list ${uri} ${persist}) for uuid in ${dom_ids}; do # Get the name dom_name=$(do_virsh ${uri} domname ${uuid}) einfo " ${dom_name}" # Get autostart state dom_as=$(do_virsh ${uri} dominfo ${uuid} | \ awk '$1 == "Autostart:" { print $2 }') if [ "${persist}" = "--persistent" ]; then # Save our running state only if LIBVIRT_IGNORE_AUTOSTART != yes if [ "x${LIBVIRT_IGNORE_AUTOSTART}" = "xyes" ] && \ [ ${dom_as} = "enabled" ]; then : else echo "${uri} ${uuid}" >> ${gueststatefile} fi fi # Now let's stop it do_virsh "${uri}" ${shutdown_type} ${uuid} > /dev/null done dom_count="$(libvirtd_dom_count ${uri} ${persist})" while [ ${dom_count} -gt 0 ] && [ ${counter} -gt 0 ] ; do dom_count="$(libvirtd_dom_count ${uri} ${persist})" sleep 1 if [ "${shutdown_type}" = "shutdown" ]; then counter=$((${counter} - 1)) fi printf "." done if [ "${shutdown_type}" = "shutdown" ]; then # grab all domains still running dom_ids=$(libvirtd_dom_list ${uri} ${persist}) for uuid in ${dom_ids}; do dom_name=$(do_virsh ${uri} domname ${uuid}) eerror " ${dom_name} forcibly stopped" do_virsh "${uri}" destroy ${uuid} > /dev/null done fi } libvirtd_net_stop() { # stops all persistent or transient domains for a given URI # $1 - uri # $2 - persisent/transient local uri=$1 local persist=$2 local uuid= local net_name= if [ "${LIBVIRT_NET_SHUTDOWN}" != "no" ]; then einfo " Shutting down network(s):" for uuid in $(libvirtd_net_list ${uri} ${persist}); do net_name=$(do_virsh ${uri} net-name ${uuid}) einfo " ${net_name}" if [ "${persist}" = "--persistent" ]; then # Save our running state echo "${uri} ${uuid}" >> ${netstatefile} fi # Actually stop the network do_virsh qemu net-destroy ${uuid} > /dev/null done fi } start() { local uri= local uuid= local name= for uri in ${LIBVIRT_URIS}; do do_virsh "${uri}" connect if [ $? -ne 0 ]; then eerror "Failed to connect to '${uri}'. Domains may not start." fi done [ ! -e "${netstatefile}" ] && touch "${netstatefile}" [ ! -e "${gueststatefile}" ] && touch "${gueststatefile}" # if the user didn't want to start any guests up then respect their wish [ "x${LIBVIRT_START}" = "xno" ] && return 0 # start networks ebegin "Starting libvirt networks" while read -r uri uuid do # ignore trash [ -z "${uri}" ] || [ -z "${uuid}" ] && continue name=$(do_virsh "${uri}" net-name ${uuid}) einfo " ${name}" do_virsh "${uri}" net-start ${uuid} > /dev/null done <"${netstatefile}" eend 0 # start domains ebegin "Starting libvirt domains" while read -r uri uuid do # ignore trash [ -z "${uri}" ] || [ -z "${uuid}" ] && continue name=$(do_virsh "${uri}" domname ${uuid}) einfo " ${name}" do_virsh "${uri}" start ${uuid} > /dev/null do_virsh "${uri}" domtime --sync ${uuid} > /dev/null done <"${gueststatefile}" eend 0 } stop() { local counter= local dom_name= local net_name= local dom_ids= local uuid= local dom_count= rm -f "${gueststatefile}" [ $? -ne 0 ] && eerror "Unable to save domain state" rm -f "${netstatefile}" [ $? -ne 0 ] && eerror "Unable to save net state" for uri in ${LIBVIRT_URIS}; do einfo "Stopping libvirt domains and networks for ${uri}" libvirtd_dom_stop "${uri}" "--persistent" libvirtd_dom_stop "${uri}" "--transient" libvirtd_net_stop "${uri}" "--persistent" libvirtd_net_stop "${uri}" "--transient" einfo "Done stopping domains and networks for ${uri}" done }