Skip to content

Instantly share code, notes, and snippets.

@gildas
Last active March 8, 2023 14:03
Show Gist options
  • Save gildas/a11de614d66bf7f2c9bd1d4111709dcb to your computer and use it in GitHub Desktop.
Save gildas/a11de614d66bf7f2c9bd1d4111709dcb to your computer and use it in GitHub Desktop.
Migration of Windows Virtual Machines from Hyper-V to OpenStack

Migration guide for Windows VMs from Hyper-V

First get the virtual disk (vhdx) from the Hyper-V platform.

Use a Linux machine with libvirt installed.

Do not forget to install the UEFI firmware:

sudo apt install ovmf

Convert the disk

We need to convert the disk to the native format used by OpenStack:

qemu-img check -r all windows-disk.vhdx
qemu-img convert -O qcow2 windows-disk.vhdx windows-disk.qcow2

Inject the proper driver in the Virtual Machine

OpenStack (and KVM) use para-virtualized (virtio) drivers for the disk and the network. Although most modern Linux distributions have these drivers pre-loaded, Windows does not.

The best way to inject the drivers will be to do the following:

Get the virtio drivers for Windows:

curl -LO https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso

Create a dummy disk that will make Windows detect the virtio disk driver:

qemu-img create -f qcow2 dummy.qcow2 5G

Create a temporary Virtual Machine:

virt-install --connect qemu:///system \
  --ram 2048 \
  --vcpus 2 --cpu host \
  --network network=default,model=virtio \
  --disk path=windows-disk.qcow2,device=disk,format=qcow2,bus=ide \
  --disk path=dummy.qcow2,format=qcow2,device=disk,bus=virtio \
  --disk path=./iso/virtio-win.iso,device=cdrom,perms=ro \
  --graphics vnc,listen=0.0.0.0,password=1234 --noautoconsole \
  --boot uefi \
  --os-type windows --os-variant win2k12 \
  --import \
  --name myvm

Note: if the virtual disk is not an UEFI image, the --boot uefi should not be used.

Once the Virtual Machine has booted, log in and install the drivers:

d:
cd \balloon\2k12R2\amd64
pnputil -i -a *.inf
cd \NetKVM\2k12R2\amd64
pnputil -i -a *.inf
cd \viostor\2k12R2\amd64
pnputil -i -a *.inf

Then, stop the virtual machine from inside (Powershell: Stop-Computer).
And undefine it in KVM:

virsh undefine --nvram myvm

Finally, start the Virtual Machine again with the virtio bus:

virt-install --connect qemu:///system \
  --ram 2048 \
  --vcpus 2 --cpu host \
  --network network=default,model=virtio \
  --disk path=windows-disk.qcow2,device=disk,format=qcow2,bus=virtio \
  --graphics vnc,listen=0.0.0.0,password=1234 --noautoconsole \
  --boot uefi \
  --os-type windows --os-variant win2k12 \
  --import \
  --name myvm

Note: if the virtual disk is not an UEFI image, the --boot uefi should not be used.

Check the Virtual Machine to see if it is working fine.

Create the Virtual Machine in OpenStack

First Import the virtual disk into an Openstack Image:

openstack image create \
  --container-format bare \
  --disk-format qcow2  \
  --file windows-disk.qcow2 \
  myvm-disk

And, create a volume from that image:

openstack volume create \
  --image myvm-disk \
  --size 60G \
  myvm-disk

Check the progress with the Horizon web server or with: openstack volume list. Once the volume is ready, you can start the instance:

openstack server create
  --volume myvm-disk \
  --flavor w1.small \
  --security-group xxx \
  --property hw_firmware_type=uefi \
  myvm

Notes:

  • if the virtual disk is not an UEFI image, do not add the propery hw_firmware_type=uefi.
  • Don't forget to choose the appropriate security group!

Annex: Patch Nova to accept UEFI settings on the instance

Unfortunately, nova reads the UEFI settings only from the image of the instance. And, in our case, there is no base image as the instance is directly attached to a volume.

There might be ways to read the image from the volume, but I have not found it in nova's source code.

The best was to patch the source code to read the firmware type from the instance metadata.

Here is the patch to apply in /usr/lib/python2.7/dist-packages/nova/virt/libvirt:

--- driver.py   2020-10-08 19:45:10.847239335 +0900
+++ driver.py.new       2020-10-08 19:45:18.935288598 +0900
@@ -4895,6 +4895,8 @@
                 guest.sysinfo = self._get_guest_config_sysinfo(instance)
                 guest.os_smbios = vconfig.LibvirtConfigGuestSMBIOS()
             hw_firmware_type = image_meta.properties.get('hw_firmware_type')
+            if not hw_firmware_type:
+                hw_firmware_type = instance.get('metadata').get('hw_firmware_type')
             if caps.host.cpu.arch == fields.Architecture.AARCH64:
                 if not hw_firmware_type:
                     hw_firmware_type = fields.FirmwareType.UEFI

You apply it like this:

cd /usr/lib/python2.7/dist-packages/nova/virt/libvirt
sudo patch driver.py < driver.py.patch
sudo python -m compileall driver.py
sudo systemctl restart nova-compute.service
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment