Skip to content

Vendor Image conversion

The cloud service uses RAW images for all the VMs hosted. If you upload any other different image type like QCOW2 or VMDK, it will be converted to RAW when the machine gets started the first time, or when it gets deployed to a volume that's also in RAW format.

All the servers of the cloud service are running KVM as hypervisor technology. In some scenarios, specially with providers, you may have an image prepared to be run on a different hypervisor like Microsoft HyperV, Xen, Oracle VirtualBox, VMware ESXi or VMware Workstation. In those cases, although the image data could be converted, it may not contain the drivers that allow it to boot or access the network. The direct result is that the machine may not boot or not have access to the network.

This procedure shows how to convert those images and inject the KVM drivers, also called virtio, inside the VM, so it can be used later as an image.

Let's use as an example that we have a vendor image called vendor.vmdk that we want to convert to be able to use it on the cloud service.

The procedure would be the following:

  1. Convert the image to QCOW2
  2. Upload the image to the cloud service
  3. Create a volume based on that image so we can edit it
  4. Create a helper VM to allow us to inject the drivers
  5. Attach the volume into the helper VM
  6. Inject virtio drivers into the volume using the helper VM
  7. Detach volume from helper VM
  8. Create image based on volume
  9. Cleanup

At the end, you would have an image with the proper drivers that you can use to boot additional machines.

Convert the image to compressed qcow2

With the image downloaded into aiadm or lxplus you can just convert the image before upload like this:

qemu-img convert -cpf vmdk -O qcow2 vendor.vmdk vendor.qcow2

Upload the image to the cloud service

You can upload the image to the OpenStack Glance image service. Please ensure than the minimum disk size has been set as the one specified in the command like:

openstack image create --min-disk 100 --file vendor.qcow2 --disk-format qcow2 --property architecture='x86_64' --property hw_architecture='x86_64' --progress vendor_original

On our example the min-disk value is set to 100GB and the architecture of the image is x86_64.

Create a volume using that image

Once the image is uploaded, you need to create a volume using that image as a source. You can do it with the below command:

Warning

Please make sure that the size of the disk matches with the min-disk size.

openstack volume create --type standard --size 100 --image vendor_original vendor_volume

This process may take a bit as it needs to copy the image data into the volume.

Create a helper VM

In order to inject the drivers, you need a helper VM. In this procedure we are using an alma9 x86_64 VM and using an already existing keypair to connect to the VM.

openstack server create --image 'ALMA9 - x86_64' --flavor m2.small --key-name mykeypair vendorhelperVM

Attach the volume into the helper VM

Once the machine has started, you need to attach the volume to the VM. You can do this with:

openstack server add volume vendorhelperVM vendor_volume

Inject drivers into the volume

Once you have connected to the machine as root using your keypair, you can see that there is an additional disk on it

$ lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda     252:0    0   20G  0 disk 
├─vda1  252:1    0 19.5G  0 part /
├─vda14 252:14   0    4M  0 part 
└─vda15 252:15   0  545M  0 part /boot/efi
vdb     252:32   0  100G  0 disk 
├─vdb1  252:33   0    1G  0 part 
└─vdb2  252:34   0   99G  0 part 

We should install lvm2 into the helper machine that will help us to identify the boot and root partitions

$ dnf install lvm2 -y

We can try to scan for LVM volumes, find the mountpoints and then enable them like this:

$ vgscan
  Found volume group "centos" using metadata type lvm2
$ lvdisplay | grep Path
  LV Path                /dev/centos/swap
  LV Path                /dev/centos/home
  LV Path                /dev/centos/root
$ vgchange -ay centos

So, it seems that in this particular case we have the following partition layout:

/dev/vdb1        => /boot
/dev/centos/home => /home
/dev/centos/root => /root

Once you've identified the partitions, we just need /boot and /root to install the drivers. We can mount them into the machine and then bind-mount your system paths into the root volume's mount point like this:

mkdir /mnt/root
mount /dev/centos/root /mnt/root
mount /dev/vdb1 /mnt/root/boot
for x in sys proc run dev tmp; do mount --bind /$x /mnt/root/$x; done

Now we can use dracut to update the initrd file. First we need to chroot and find the version of the kernel:

$ cd /mnt
$ chroot root bash
$ grep initramfs- /boot/grub2/grub.cfg
  initrd16 /initramfs-3.10.0-1160.36.2.el7.x86_64.img
  initrd16 /initramfs-3.10.0-1127.el7.x86_64.img
  initrd16 /initramfs-3.10.0-957.21.3.el7.x86_64.img
  initrd16 /initramfs-3.10.0-862.el7.x86_64.img
  initrd16 /initramfs-0-rescue-c582f3834dad4ee4819cb4ee1aa446aa.img
$ ls /boot/initramfs-* -l
-rw-------. 1 root root 64100034 Jul 31  2019 /boot/initramfs-0-rescue-c582f3834dad4ee4819cb4ee1aa446aa.img
-rw-------. 1 root root 21417154 Aug 26  2021 /boot/initramfs-3.10.0-1127.el7.x86_64.img
-rw-------. 1 root root 13915816 Aug 26  2021 /boot/initramfs-3.10.0-1127.el7.x86_64kdump.img
-rw-------. 1 root root 21422539 Aug 26  2021 /boot/initramfs-3.10.0-1160.36.2.el7.x86_64.img
-rw-------. 1 root root 13919120 Sep  9  2021 /boot/initramfs-3.10.0-1160.36.2.el7.x86_64kdump.img
-rw-------. 1 root root 21322813 Jul 31  2019 /boot/initramfs-3.10.0-862.el7.x86_64.img
-rw-------. 1 root root 13534097 Jul 31  2019 /boot/initramfs-3.10.0-862.el7.x86_64kdump.img
-rw-------. 1 root root 20976832 Apr 30  2020 /boot/initramfs-3.10.0-957.21.3.el7.x86_64.img
-rw-------. 1 root root 13551551 Apr 30  2020 /boot/initramfs-3.10.0-957.21.3.el7.x86_64kdump.img

In our case it's the most recent version in that list, so we can just inject the drivers in there:

dracut -f /boot/initramfs-3.10.0-1160.36.2.el7.x86_64.img 3.10.0-1160.36.2.el7.x86_64 --add-drivers "virtio virtio_pci virtio_blk virtio_net"

And check that they were injected properly:

$ lsinitrd /boot/initramfs-3.10.0-1160.36.2.el7.x86_64.img | grep virtio
Arguments: -f --add-drivers 'virtio virtio_pci virtio_blk virtio_net'
-rw-r--r--   1 root     root         8240 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/block/virtio_blk.ko.xz
-rw-r--r--   1 root     root        12968 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/char/virtio_console.ko.xz
drwxr-xr-x   2 root     root            0 Aug  2 14:49 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/gpu/drm/virtio
-rw-r--r--   1 root     root        24160 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/gpu/drm/virtio/virtio-gpu.ko.xz
-rw-r--r--   1 root     root        14216 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/net/virtio_net.ko.xz
-rw-r--r--   1 root     root         8224 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/scsi/virtio_scsi.ko.xz
drwxr-xr-x   2 root     root            0 Aug  2 14:49 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/virtio
-rw-r--r--   1 root     root         4548 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/virtio/virtio.ko.xz
-rw-r--r--   1 root     root         9896 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/virtio/virtio_pci.ko.xz
-rw-r--r--   1 root     root         8576 Jul 21  2021 usr/lib/modules/3.10.0-1160.36.2.el7.x86_64/kernel/drivers/virtio/virtio_ring.ko.xz

You can exit from chroot and then unmount everything

$ exit
$ for x in sys proc run dev tmp; do umount /mnt/root/$x; done
$ umount /mnt/root/boot
$ umount /mnt/root

In case of LVM you may also disable the volume group you've just enabled, so you can reattach the volume if you need additional fixes.

$ vgchange -an centos

Detach volume from helper VM

Once the machine has started, you need to attach the volume to the VM, you can do it with:

openstack server remove volume vendorhelperVM vendor_volume

Create image based on volume

Create an image based on the volume after the fix, so you can create new volumes or machines booted directly from this image:

openstack image create --min-disk 100 --volume vendor_volume --disk-format qcow2 --property architecture='x86_64' --property hw_architecture='x86_64' --progress vendor

Cleanup

Once the image has finished to be created, you can delete the original vendor volume and the helper VM you've used to get into this point.

openstack volume delete vendor_volume
openstack server delete vendorhelperVM

Now you can create machines booted from this image or from volumes using this image as a source.