Skip to content

Instantly share code, notes, and snippets.

@xenithorb
Last active March 10, 2018 17:40
Show Gist options
  • Save xenithorb/680d119eefcaa31cf4bebd6271079ec8 to your computer and use it in GitHub Desktop.
Save xenithorb/680d119eefcaa31cf4bebd6271079ec8 to your computer and use it in GitHub Desktop.
Move a libvirt VM from one host to another
#!/bin/bash
#
# Usage: ./virsh_offline_vm_xfer.sh <domain> <host>
#
# Requirements
# 1. The same user on the local and remote machine that are able to sudo
# 2. Both normal users belong to the libvirt group respectively or have
# global libvirtd access. (can access qemu:///system)
# 3. Assumes image paths can remain identical during transfer
#
# Author: Michael Goodwin Date: 2017-05-12
trap 'breakdown "$HOST"' EXIT SIGINT SIGQUIT SIGTERM
DOMAIN="$1"
HOST="$2"
LOCAL_LIBVIRT_URI="qemu:///system"
REMOTE_LIBVIRT_URI="qemu+ssh://${HOST}/system"
IMAGES_PATH="/var/lib/libvirt/images"
SUDOERS_PATH="/etc/sudoers.d/vmxfer_nopasswd"
CMD="/usr/bin/rsync"
push() {
virsh_xfer_xml() {
local domain="$1"
virsh -c "${LOCAL_LIBVIRT_URI}" dumpxml --migratable "$domain" \
| virsh -c "${REMOTE_LIBVIRT_URI}" define /dev/stdin
}
get_image_path() {
local domain="$1"
virsh -c "${LOCAL_LIBVIRT_URI}" domblklist --details "$domain" \
| awk '$1 == "file" && $2 == "disk" { print $NF }'
}
xfer_vm_image() {
local domain="$1" host="$2" path
get_image_path "$domain" | while read -r path; do
if [[ "$path" =~ ^/dev/mapper ]]; then
{ echo "Block devices not supported!"; exit 1; }
else
sudo rsync -aAXWPS --rsync-path='sudo rsync' \
"$path" "${USER}@${host}:${IMAGES_PATH}"
fi
done
}
setup_sudo_nopasswd() {
local host="$1" cmd
cmd="$( sed 's|"||g' <<< "$CMD" )"
sudoers_docu=$(
cat <<-EOF
${USER} ALL=(root) NOPASSWD: ${cmd}
${USER} ALL=(root) NOPASSWD: /bin/rm -v ${SUDOERS_PATH}
EOF
)
if echo "${sudoers_docu}" | visudo -cf-; then
#
mkscript() {
base64 <<-EOF
#!/bin/sh
echo '${sudoers_docu}' > "${SUDOERS_PATH}"
if ! visudo -cf "${SUDOERS_PATH}"; then
rm -v "${SUDOERS_PATH}"
else
exit 1
fi
EOF
}
# Places remote sudoers file for tar
remote_temp=$(
ssh -q "${USER}@${host}" -- '
tempfile=$(mktemp)
base64 -d > "$tempfile"
echo "$tempfile"' < <(mkscript)
)
# Reads pw from tty to actually use sudo to
# execute the temporary sudoers script
ssh -tq "${USER}@${host}" -- "\
sudo -- bash \"${remote_temp}\"
rm \"${remote_temp}\""
else
exit 1
fi
}
"$@"
}
breakdown() {
local host="$1"
ssh -q "${USER}@${host}" -- sudo -n -- "/bin/rm -v ${SUDOERS_PATH}"
}
push setup_sudo_nopasswd "$HOST" \
&& push xfer_vm_image "$DOMAIN" "$HOST" \
&& push virsh_xfer_xml "$DOMAIN" \
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment