Saturday, September 10, 2022

Migrating libvirt VMs

I recently moved a bunch of libvirt VMs from a CentOS 7 host to a CentOS Stream 9 host. Normally moving virtual machines from one libvirt host to another is pretty easy. All you need to do is stop the VM on the original host, copy the disk image from host to host (with rsync or whatever is convenient), dump the VM config (with virsh dumpxml guest), and import that config on the new host (with virsh define). It turns out a few things have changed that make that not quite work though...

The first thing (and the easiest to fix) was that a lot of old machine types that worked in CentOS 7's libvirt no longer work. The easy answer is to switch to the generic pc machine type.

The harder one to deal with was that Spice support was dropped. This meant switching the graphics to VNC, using virtio for the virtual video hardware, and removing all the other Spice-related devices.

The libvirt VM configuration is all XML, so I wrote a script that uses xmlstarlet to make all the necessary changes.


#!/bin/bash

set -e

remote="${REMOTE_HOST:?'Set REMOTE_HOST environment variable'}"

for guest in "$@" ; do
    xml="$( mktemp XXXXXXXX.xml )"
    trap "rm -fv '$xml'" EXIT
    ssh root@"$remote" virsh dumpxml "$guest" | \
        xmlstarlet ed \
            -u '/domain/os/type[starts-with(@machine, "pc-i440fx")]/@machine' -v pc \
            -u '/domain/os/type[starts-with(@machine, "rhel")]/@machine' -v pc \
            -u '/domain/devices/video/model[@type="qxl"]/@type' -v virtio \
            -d '/domain/devices/video/model[@type="virtio"]/@ram' \
            -d '/domain/devices/video/model[@type="virtio"]/@vram' \
            -d '/domain/devices/video/model[@type="virtio"]/@vgamem' \
            -d '/domain/devices/graphics[@type="spice"]/@port' \
            -i '/domain/devices/graphics[@type="spice"]' -t attr -n port -v -1 \
            -u '/domain/devices/graphics[@type="spice"]/@type' -v vnc \
            -d '/domain/devices/channel[@type="spicevmc"]' \
            -d '/domain/devices/redirdev[@type="spicevmc"]' \
        > "$xml"
    virsh define "$xml"
    rm -fv "$xml"
    trap - EXIT
    virsh autostart "$guest"
done

(The above script is also available at https://gist.github.com/silug/8c13cdfa0e50ca6e237333a79594be66.)