summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2021-04-26 13:51:35 +0200
committerManuel Bentele2021-04-26 13:51:35 +0200
commite815ad917e3adeb2be387c7ef6ed2dd74602d69b (patch)
tree6c4cff0860ce981871ef94969ca22d67454af262
parentRefactors and abstracts version information in config logic and disk image (diff)
downloadmaster-sync-shared-e815ad917e3adeb2be387c7ef6ed2dd74602d69b.tar.gz
master-sync-shared-e815ad917e3adeb2be387c7ef6ed2dd74602d69b.tar.xz
master-sync-shared-e815ad917e3adeb2be387c7ef6ed2dd74602d69b.zip
Add supported virtualizer versions for Libvirt/QEMU
-rw-r--r--src/main/java/org/openslx/virtualization/Version.java30
-rw-r--r--src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java26
-rw-r--r--src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java150
-rw-r--r--src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java15
-rw-r--r--src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java58
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-no-os.xml136
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-old-os.xml140
7 files changed, 550 insertions, 5 deletions
diff --git a/src/main/java/org/openslx/virtualization/Version.java b/src/main/java/org/openslx/virtualization/Version.java
index 7d4d016..efc23af 100644
--- a/src/main/java/org/openslx/virtualization/Version.java
+++ b/src/main/java/org/openslx/virtualization/Version.java
@@ -133,6 +133,19 @@ public class Version implements Comparable<Version>
}
/**
+ * Returns a version from a list of supported versions filtered by its given filter predicate.
+ *
+ * @param byFilter filter predicate.
+ * @param supportedVersions list of supported versions.
+ * @return version from a list of supported versions filtered by its given filter predicate.
+ */
+ private static Version getInstanceByPredicateFromVersions( Predicate<Version> byFilter,
+ List<Version> supportedVersions )
+ {
+ return supportedVersions.stream().filter( byFilter ).findFirst().orElse( null );
+ }
+
+ /**
* Returns a version from a list of supported versions by its given major version.
*
* @param major version.
@@ -142,7 +155,22 @@ public class Version implements Comparable<Version>
public static Version getInstanceByMajorFromVersions( short major, List<Version> supportedVersions )
{
final Predicate<Version> byMajor = version -> major == version.getMajor();
- return supportedVersions.stream().filter( byMajor ).findFirst().orElse( null );
+ return Version.getInstanceByPredicateFromVersions( byMajor, supportedVersions );
+ }
+
+ /**
+ * Returns a version from a list of supported versions by its given major and minor version.
+ *
+ * @param major version.
+ * @param minor version.
+ * @param supportedVersions list of supported versions.
+ * @return version from a list of supported versions by its given major and minor version.
+ */
+ public static Version getInstanceByMajorMinorFromVersions( short major, short minor,
+ List<Version> supportedVersions )
+ {
+ final Predicate<Version> byMajorMinor = version -> major == version.getMajor() && minor == version.getMinor();
+ return supportedVersions.stream().filter( byMajorMinor ).findFirst().orElse( null );
}
@Override
diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
index 37186b9..bd25f79 100644
--- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
+++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
@@ -611,14 +611,34 @@ public class VirtualizationConfigurationQemu extends
@Override
public void setVirtualizerVersion( Version type )
{
- // NOT supported by the QEMU hypervisor
+ if ( type != null ) {
+ final String osMachine = this.vmConfig.getOsMachine();
+ final String osMachineName = VirtualizationConfigurationQemuUtils.getOsMachineName( osMachine );
+
+ if ( osMachineName != null && !osMachineName.isEmpty() ) {
+ final String modifiedOsMachineVersion = VirtualizationConfigurationQemuUtils.getOsMachineVersion( type );
+ final String modifiedOsMachine = VirtualizationConfigurationQemuUtils.getOsMachine( osMachineName,
+ modifiedOsMachineVersion );
+ this.vmConfig.setOsMachine( modifiedOsMachine );
+ }
+ }
}
@Override
public Version getVirtualizerVersion()
{
- // NOT supported by the QEMU hypervisor
- return null;
+ final String osMachine = this.vmConfig.getOsMachine();
+ final Version uncheckedVersion = VirtualizationConfigurationQemuUtils.getOsMachineVersion( osMachine );
+ final Version checkedVersion;
+
+ if ( uncheckedVersion == null ) {
+ checkedVersion = null;
+ } else {
+ checkedVersion = Version.getInstanceByMajorMinorFromVersions( uncheckedVersion.getMajor(),
+ uncheckedVersion.getMinor(), this.getVirtualizer().getSupportedVersions() );
+ }
+
+ return checkedVersion;
}
@Override
diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
index a29005c..3abc2f3 100644
--- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
+++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
@@ -1,10 +1,13 @@
package org.openslx.virtualization.configuration;
import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.openslx.libvirt.domain.device.Disk;
import org.openslx.libvirt.domain.device.Interface;
import org.openslx.libvirt.domain.device.Disk.BusType;
+import org.openslx.virtualization.Version;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.DriveBusType;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.EthernetDevType;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.SoundCardType;
@@ -19,6 +22,11 @@ import org.openslx.libvirt.domain.device.Sound;
public class VirtualizationConfigurationQemuUtils
{
/**
+ * Separator symbol between Libvirt/QEMU machine name and machine version.
+ */
+ private static final String OS_MACHINE_NAME_VERSION_SEPARATOR = "-";
+
+ /**
* Converts a Libvirt disk device bus type to a VM metadata driver bus type.
*
* @param busType Libvirt disk device bus type.
@@ -188,4 +196,146 @@ public class VirtualizationConfigurationQemuUtils
return devicePrefix + ( 'a' + deviceNumber );
}
+
+ /**
+ * Data container to store a Libvirt/QEMU machine name with version information.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+ static class OsMachineNameAndVersion
+ {
+ /**
+ * Stores the machine name.
+ */
+ final private String osMachineName;
+
+ /**
+ * Stores the machine version.
+ */
+ final private Version osMachineVersion;
+
+ /**
+ * Creates a data container for a machine name with version information.
+ *
+ * @param osMachineName name of the machine.
+ * @param osMachineVersion version of the machine.
+ */
+ public OsMachineNameAndVersion( String osMachineName, Version osMachineVersion )
+ {
+ this.osMachineName = osMachineName;
+ this.osMachineVersion = osMachineVersion;
+ }
+
+ /**
+ * Returns the machine name.
+ *
+ * @return machine name.
+ */
+ public String getOsMachineName()
+ {
+ return this.osMachineName;
+ }
+
+ /**
+ * Returns the version information.
+ *
+ * @return version information.
+ */
+ public Version getOsMachineVersion()
+ {
+ return this.osMachineVersion;
+ }
+ }
+
+ /**
+ * Parses a machine name with version information from a Libvirt/QEMU machine description.
+ *
+ * @param osMachine Libvirt/QEMU machine description as {@link String}.
+ * @return data container containing the parsed machine name with version information.
+ */
+ private static OsMachineNameAndVersion parseOsMachineNameAndVersion( String osMachine )
+ {
+ final String osMachineName;
+ final Version osMachineVersion;
+
+ if ( osMachine == null || osMachine.isEmpty() ) {
+ // there is no machine description given, so we can not parse anything
+ osMachineName = null;
+ osMachineVersion = null;
+ } else {
+ // create regular expression based matcher to extract machine name and version number
+ final Pattern osMachineNameAndVersionPattern = Pattern.compile( "^([a-z0-9\\-]+)"
+ + VirtualizationConfigurationQemuUtils.OS_MACHINE_NAME_VERSION_SEPARATOR + "([0-9]+).([0-9]+)$" );
+ final Matcher osMachineNameAndVersionMatcher = osMachineNameAndVersionPattern.matcher( osMachine );
+
+ final boolean matches = osMachineNameAndVersionMatcher.find();
+
+ if ( matches ) {
+ // get results of regular expression based matcher
+ osMachineName = osMachineNameAndVersionMatcher.group( 1 );
+ final String osMachineMajorString = osMachineNameAndVersionMatcher.group( 2 );
+ final String osMachineMinorString = osMachineNameAndVersionMatcher.group( 3 );
+
+ // create version representation
+ final short osMachineMajor = Short.valueOf( osMachineMajorString );
+ final short osMachineMinor = Short.valueOf( osMachineMinorString );
+ osMachineVersion = new Version( osMachineMajor, osMachineMinor );
+ } else {
+ osMachineName = null;
+ osMachineVersion = null;
+ }
+ }
+
+ return new OsMachineNameAndVersion( osMachineName, osMachineVersion );
+ }
+
+ /**
+ * Parses a machine name from a Libvirt/QEMU machine description.
+ *
+ * @param osMachine Libvirt/QEMU machine description as {@link String}.
+ * @return parsed machine name.
+ */
+ public static String getOsMachineName( String osMachine )
+ {
+ final OsMachineNameAndVersion machineNameAndVersion = VirtualizationConfigurationQemuUtils
+ .parseOsMachineNameAndVersion( osMachine );
+ return machineNameAndVersion.getOsMachineName();
+ }
+
+ /**
+ * Parses a machine version from a Libvirt/QEMU machine description.
+ *
+ * @param osMachine Libvirt/QEMU machine description as {@link String}.
+ * @return parsed machine version.
+ */
+ public static Version getOsMachineVersion( String osMachine )
+ {
+ final OsMachineNameAndVersion machineNameAndVersion = VirtualizationConfigurationQemuUtils
+ .parseOsMachineNameAndVersion( osMachine );
+ return machineNameAndVersion.getOsMachineVersion();
+ }
+
+ /**
+ * Combines a machine name with a machine version and returns a Libvirt/QEMU machine description.
+ *
+ * @param osMachineName name of the machine.
+ * @param osMachineVersion version of the machine.
+ * @return Libvirt/QEMU machine description.
+ */
+ public static String getOsMachine( String osMachineName, String osMachineVersion )
+ {
+ return osMachineName + VirtualizationConfigurationQemuUtils.OS_MACHINE_NAME_VERSION_SEPARATOR + osMachineVersion;
+ }
+
+ /**
+ * Converts a {@link Version} to a Libvirt/QEMU machine version.
+ *
+ * @param version Libvirt/QEMU machine version as {@link Version}.
+ * @return Libvirt/QEMU machine version.
+ */
+ public static String getOsMachineVersion( Version version )
+ {
+ return String.format( "%d.%d", version.getMajor(), version.getMinor() );
+ }
}
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
index 4456538..fcce392 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
@@ -31,7 +31,20 @@ public class VirtualizerQemu extends Virtualizer
/**
* List of supported versions of the QEMU virtualizer.
*/
- private static final List<Version> VIRTUALIZER_SUPPORTED_VERSIONS = null;
+ private static final List<Version> VIRTUALIZER_SUPPORTED_VERSIONS = Collections.unmodifiableList(
+ Arrays.asList(
+ new Version( Short.valueOf( "2" ), Short.valueOf( "1" ), "QEMU 2.1" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "4" ), "QEMU 2.4" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "5" ), "QEMU 2.5" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "6" ), "QEMU 2.6" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "7" ), "QEMU 2.7" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "8" ), "QEMU 2.8" ),
+ new Version( Short.valueOf( "2" ), Short.valueOf( "9" ), "QEMU 2.9" ),
+ new Version( Short.valueOf( "3" ), Short.valueOf( "0" ), "QEMU 3.0" ),
+ new Version( Short.valueOf( "3" ), Short.valueOf( "1" ), "QEMU 3.1" ),
+ new Version( Short.valueOf( "4" ), Short.valueOf( "0" ), "QEMU 4.0" ),
+ new Version( Short.valueOf( "4" ), Short.valueOf( "1" ), "QEMU 4.1" ),
+ new Version( Short.valueOf( "4" ), Short.valueOf( "2" ), "QEMU 4.2" ) ) );
/**
* Creates a new QEMU virtualizer.
diff --git a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
index 0412002..93f3750 100644
--- a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
+++ b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuTest.java
@@ -3,6 +3,7 @@ package org.openslx.virtualization.configuration;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;
@@ -32,6 +33,7 @@ import org.openslx.libvirt.domain.device.DiskStorage;
import org.openslx.libvirt.domain.device.Interface;
import org.openslx.libvirt.domain.device.Sound;
import org.openslx.libvirt.xml.LibvirtXmlTestResources;
+import org.openslx.virtualization.Version;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.EtherType;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.EthernetDevType;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.SoundCardType;
@@ -518,4 +520,60 @@ public class VirtualizationConfigurationQemuTest
assertDoesNotThrow( () -> vmLibvirtDomainConfig.validateXml() );
}
+
+ @ParameterizedTest
+ @DisplayName( "Test get virtualizer HW version from VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm-old-os.xml", "qemu-kvm_default-archlinux-vm-no-os.xml" } )
+ public void testQemuMetaDataGetVirtualizerVersion( String xmlFileName )
+ throws VirtualizationConfigurationException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ VirtualizationConfigurationQemu vmConfig = new VirtualizationConfigurationQemu( null, file );
+
+ final Domain vmLibvirtDomainConfig = VirtualizationConfigurationQemuTest
+ .getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final Version machineVersion = vmConfig.getVirtualizerVersion();
+
+ if ( vmLibvirtDomainConfig.getOsMachine() == null ) {
+ assertNull( machineVersion );
+ } else {
+ assertEquals( new Version( Short.valueOf( "3" ), Short.valueOf( "1" ) ), machineVersion );
+ }
+
+ assertDoesNotThrow( () -> vmLibvirtDomainConfig.validateXml() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test set virtualizer HW version in VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm-old-os.xml", "qemu-kvm_default-archlinux-vm-no-os.xml" } )
+ public void testQemuMetaDataSetVirtualizerVersion( String xmlFileName )
+ throws VirtualizationConfigurationException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ VirtualizationConfigurationQemu vmConfig = new VirtualizationConfigurationQemu( null, file );
+
+ final Domain vmLibvirtDomainConfig = VirtualizationConfigurationQemuTest
+ .getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final String originalOsMachine = vmLibvirtDomainConfig.getOsMachine();
+ if ( originalOsMachine != null ) {
+ assertEquals( "pc-q35-3.1", originalOsMachine );
+ }
+
+ final Version modifiedVersion = new Version( Short.valueOf( "4" ), Short.valueOf( "1" ) );
+ vmConfig.setVirtualizerVersion( modifiedVersion );
+
+ final String modifiedOsMachine = vmLibvirtDomainConfig.getOsMachine();
+ if ( modifiedOsMachine == null ) {
+ assertNull( vmConfig.getVirtualizerVersion() );
+ } else {
+ assertEquals( modifiedVersion, vmConfig.getVirtualizerVersion() );
+ assertEquals( "pc-q35-4.1", modifiedOsMachine );
+ }
+
+ assertDoesNotThrow( () -> vmLibvirtDomainConfig.validateXml() );
+ }
}
diff --git a/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-no-os.xml b/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-no-os.xml
new file mode 100644
index 0000000..b34924d
--- /dev/null
+++ b/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-no-os.xml
@@ -0,0 +1,136 @@
+<domain type='kvm'>
+ <name>archlinux</name>
+ <uuid>22bbd81f-b31b-4242-9907-8840844944bf</uuid>
+ <metadata>
+ <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
+ <libosinfo:os id="http://archlinux.org/archlinux/rolling"/>
+ </libosinfo:libosinfo>
+ </metadata>
+ <memory unit='KiB'>4194304</memory>
+ <currentMemory unit='KiB'>4194304</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state='off'/>
+ </features>
+ <cpu mode='host-model' check='partial'/>
+ <clock offset='utc'>
+ <timer name='rtc' tickpolicy='catchup'/>
+ <timer name='pit' tickpolicy='delay'/>
+ <timer name='hpet' present='no'/>
+ </clock>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <pm>
+ <suspend-to-mem enabled='no'/>
+ <suspend-to-disk enabled='no'/>
+ </pm>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/var/lib/libvirt/images/archlinux.qcow2'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0' model='qemu-xhci' ports='15'>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='sata' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='1' port='0x10'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='2' port='0x11'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='3' port='0x12'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='4' port='0x13'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/>
+ </controller>
+ <controller type='pci' index='5' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='5' port='0x14'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/>
+ </controller>
+ <controller type='pci' index='6' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='6' port='0x15'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/>
+ </controller>
+ <controller type='pci' index='7' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='7' port='0x16'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x6'/>
+ </controller>
+ <interface type='network'>
+ <mac address='52:54:00:c1:4e:70'/>
+ <source network='test'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target type='isa-serial' port='0'>
+ <model name='isa-serial'/>
+ </target>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <channel type='unix'>
+ <target type='virtio' name='org.qemu.guest_agent.0'/>
+ <address type='virtio-serial' controller='0' bus='0' port='1'/>
+ </channel>
+ <channel type='spicevmc'>
+ <target type='virtio' name='com.redhat.spice.0'/>
+ <address type='virtio-serial' controller='0' bus='0' port='2'/>
+ </channel>
+ <input type='tablet' bus='usb'>
+ <address type='usb' bus='0' port='1'/>
+ </input>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='spice' autoport='yes'>
+ <listen type='address'/>
+ <image compression='off'/>
+ </graphics>
+ <sound model='ich9'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
+ </sound>
+ <video>
+ <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+ </video>
+ <redirdev bus='usb' type='spicevmc'>
+ <address type='usb' bus='0' port='2'/>
+ </redirdev>
+ <redirdev bus='usb' type='spicevmc'>
+ <address type='usb' bus='0' port='3'/>
+ </redirdev>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </memballoon>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
+ </rng>
+ </devices>
+</domain>
+
diff --git a/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-old-os.xml b/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-old-os.xml
new file mode 100644
index 0000000..5efe9b2
--- /dev/null
+++ b/src/test/resources/libvirt/xml/qemu-kvm_default-archlinux-vm-old-os.xml
@@ -0,0 +1,140 @@
+<domain type='kvm'>
+ <name>archlinux</name>
+ <uuid>22bbd81f-b31b-4242-9907-8840844944bf</uuid>
+ <metadata>
+ <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
+ <libosinfo:os id="http://archlinux.org/archlinux/rolling"/>
+ </libosinfo:libosinfo>
+ </metadata>
+ <memory unit='KiB'>4194304</memory>
+ <currentMemory unit='KiB'>4194304</currentMemory>
+ <vcpu placement='static'>2</vcpu>
+ <os>
+ <type arch='x86_64' machine='pc-q35-3.1'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state='off'/>
+ </features>
+ <cpu mode='host-model' check='partial'/>
+ <clock offset='utc'>
+ <timer name='rtc' tickpolicy='catchup'/>
+ <timer name='pit' tickpolicy='delay'/>
+ <timer name='hpet' present='no'/>
+ </clock>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <pm>
+ <suspend-to-mem enabled='no'/>
+ <suspend-to-disk enabled='no'/>
+ </pm>
+ <devices>
+ <emulator>/usr/bin/qemu-system-x86_64</emulator>
+ <disk type='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/var/lib/libvirt/images/archlinux.qcow2'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
+ </disk>
+ <controller type='usb' index='0' model='qemu-xhci' ports='15'>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='sata' index='0'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
+ </controller>
+ <controller type='pci' index='0' model='pcie-root'/>
+ <controller type='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='pci' index='1' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='1' port='0x10'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='pci' index='2' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='2' port='0x11'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/>
+ </controller>
+ <controller type='pci' index='3' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='3' port='0x12'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/>
+ </controller>
+ <controller type='pci' index='4' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='4' port='0x13'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/>
+ </controller>
+ <controller type='pci' index='5' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='5' port='0x14'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/>
+ </controller>
+ <controller type='pci' index='6' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='6' port='0x15'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/>
+ </controller>
+ <controller type='pci' index='7' model='pcie-root-port'>
+ <model name='pcie-root-port'/>
+ <target chassis='7' port='0x16'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x6'/>
+ </controller>
+ <interface type='network'>
+ <mac address='52:54:00:c1:4e:70'/>
+ <source network='test'/>
+ <model type='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+ </interface>
+ <serial type='pty'>
+ <target type='isa-serial' port='0'>
+ <model name='isa-serial'/>
+ </target>
+ </serial>
+ <console type='pty'>
+ <target type='serial' port='0'/>
+ </console>
+ <channel type='unix'>
+ <target type='virtio' name='org.qemu.guest_agent.0'/>
+ <address type='virtio-serial' controller='0' bus='0' port='1'/>
+ </channel>
+ <channel type='spicevmc'>
+ <target type='virtio' name='com.redhat.spice.0'/>
+ <address type='virtio-serial' controller='0' bus='0' port='2'/>
+ </channel>
+ <input type='tablet' bus='usb'>
+ <address type='usb' bus='0' port='1'/>
+ </input>
+ <input type='mouse' bus='ps2'/>
+ <input type='keyboard' bus='ps2'/>
+ <graphics type='spice' autoport='yes'>
+ <listen type='address'/>
+ <image compression='off'/>
+ </graphics>
+ <sound model='ich9'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
+ </sound>
+ <video>
+ <model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
+ </video>
+ <redirdev bus='usb' type='spicevmc'>
+ <address type='usb' bus='0' port='2'/>
+ </redirdev>
+ <redirdev bus='usb' type='spicevmc'>
+ <address type='usb' bus='0' port='3'/>
+ </redirdev>
+ <memballoon model='virtio'>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </memballoon>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
+ </rng>
+ </devices>
+</domain>
+