summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorralph isenmann2021-11-10 15:06:33 +0100
committerralph isenmann2021-11-10 15:06:33 +0100
commit4bff50ef7597453b94420b912b2859d06c00c060 (patch)
tree752c88e61eb3da3002826678d5c3301e983f357e
parent[container] refactoring (diff)
parentEnumerate target names of disk devices correctly (diff)
downloadmaster-sync-shared-4bff50ef7597453b94420b912b2859d06c00c060.tar.gz
master-sync-shared-4bff50ef7597453b94420b912b2859d06c00c060.tar.xz
master-sync-shared-4bff50ef7597453b94420b912b2859d06c00c060.zip
Merge branch 'master' of git.openslx.org:bwlp/master-sync-shared
-rw-r--r--src/main/java/org/openslx/libvirt/domain/Domain.java128
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Graphics.java63
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java12
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/Hostdev.java2
-rw-r--r--src/main/java/org/openslx/libvirt/domain/device/HostdevMdev.java32
-rw-r--r--src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java95
-rw-r--r--src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java40
-rw-r--r--src/main/java/org/openslx/virtualization/configuration/transformation/TransformationManager.java11
-rw-r--r--src/main/java/org/openslx/virtualization/hardware/ConfigurationGroups.java1
-rw-r--r--src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java8
-rw-r--r--src/test/java/org/openslx/libvirt/domain/DomainTest.java55
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml168
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_uefi.xml165
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_uefi.xml166
14 files changed, 915 insertions, 31 deletions
diff --git a/src/main/java/org/openslx/libvirt/domain/Domain.java b/src/main/java/org/openslx/libvirt/domain/Domain.java
index 7d49f14..e6049fa 100644
--- a/src/main/java/org/openslx/libvirt/domain/Domain.java
+++ b/src/main/java/org/openslx/libvirt/domain/Domain.java
@@ -8,6 +8,8 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import javax.xml.XMLConstants;
+
import org.openslx.libvirt.domain.device.Device;
import org.openslx.libvirt.domain.device.Controller;
import org.openslx.libvirt.domain.device.ControllerFloppy;
@@ -42,6 +44,8 @@ import org.openslx.libvirt.xml.LibvirtXmlNode;
import org.openslx.libvirt.xml.LibvirtXmlResources;
import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
@@ -57,6 +61,16 @@ import org.xml.sax.InputSource;
public class Domain extends LibvirtXmlDocument
{
/**
+ * XML namespace URI for QEMU command line elements in the Libvirt domain XML document.
+ */
+ private static final String XMLNS_QEMU_NS_URI = "http://libvirt.org/schemas/domain/qemu/1.0";
+
+ /**
+ * XML namespace prefix for QEMU command line elements in the Libvirt domain XML document.
+ */
+ private static final String XMLNS_QEMU_NS_PREFIX = "qemu";
+
+ /**
* Creates Libvirt domain XML document from {@link String} providing Libvirt domain XML content.
*
* @param xml {@link String} with Libvirt domain XML content.
@@ -491,6 +505,46 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Returns OS loader defined in the Libvirt domain XML document.
+ *
+ * @return OS loader of the virtual machine.
+ */
+ public String getOsLoader()
+ {
+ return this.getRootXmlNode().getXmlElementValue( "os/loader" );
+ }
+
+ /**
+ * Set OS loader in the Libvirt domain XML document.
+ *
+ * @param loader OS loader for the virtual machine.
+ */
+ public void setOsLoader( String loader )
+ {
+ this.getRootXmlNode().setXmlElementValue( "os/loader", loader );
+ }
+
+ /**
+ * Returns OS Nvram defined in the Libvirt domain XML document.
+ *
+ * @return OS Nvram of the virtual machine.
+ */
+ public String getOsNvram()
+ {
+ return this.getRootXmlNode().getXmlElementValue( "os/nvram" );
+ }
+
+ /**
+ * Set OS Nvram in the Libvirt domain XML document.
+ *
+ * @param nvram OS Nvram for the virtual machine.
+ */
+ public void setOsNvram( String nvram )
+ {
+ this.getRootXmlNode().setXmlElementValue( "os/nvram", nvram );
+ }
+
+ /**
* Operating system types specifiable for a virtual machine in the Libvirt domain XML document.
*
* @author Manuel Bentele
@@ -1052,6 +1106,35 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Returns the values of QEMU command line arguments from the Libvirt domain XML document.
+ *
+ * @return values of QEMU command line arguments from the Libvirt domain XML document.
+ */
+ public ArrayList<String> getQemuCmdlnArguments()
+ {
+ final Document xmlDocument = this.getRootXmlNode().getXmlDocument();
+ final ArrayList<String> qemuCmdlnArgs = new ArrayList<String>();
+
+ final NodeList qemuCmdlnNodes = xmlDocument.getElementsByTagNameNS( XMLNS_QEMU_NS_URI, "commandline" );
+ if ( qemuCmdlnNodes.getLength() > 0 ) {
+ final Node qemuCmdlnNode = qemuCmdlnNodes.item( 0 );
+ final NodeList qemuCmdlnArgNodes = qemuCmdlnNode.getChildNodes();
+ for ( int i = 0; i < qemuCmdlnArgNodes.getLength(); i++ ) {
+ final Node qemuCmdlnArgNode = qemuCmdlnArgNodes.item( i );
+ if ( qemuCmdlnArgNode.getNodeType() == Node.ELEMENT_NODE ) {
+ final Element qemuCmdlnArgElement = Element.class.cast( qemuCmdlnArgNode );
+ final String value = qemuCmdlnArgElement.getAttribute( "value" );
+ if ( value != null && !value.isEmpty() ) {
+ qemuCmdlnArgs.add( value );
+ }
+ }
+ }
+ }
+
+ return qemuCmdlnArgs;
+ }
+
+ /**
* Adds a virtual machine device to the Libvirt domain XML document.
*
* @param device virtual machine device that is added to the Libvirt domain XML document.
@@ -1345,6 +1428,39 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Adds an given value as QEMU command line argument to the Libvirt domain XML document.
+ *
+ * @param value QEMU command line argument value.
+ */
+ public void addQemuCmdlnArgument( final String value )
+ {
+ final Element rootElement = Element.class.cast( this.getRootXmlNode().getXmlBaseNode() );
+ final Document xmlDocument = this.getRootXmlNode().getXmlDocument();
+ final Element qemuCmdlnElement;
+
+ final NodeList qemuCmdlnNodes = rootElement.getElementsByTagNameNS( XMLNS_QEMU_NS_URI, "commandline" );
+ if ( qemuCmdlnNodes.getLength() < 1 ) {
+ // add missing <domain xmlns:qemu="..."> namespace attribute
+ rootElement.setAttributeNS( XMLConstants.XMLNS_ATTRIBUTE_NS_URI,
+ XMLConstants.XMLNS_ATTRIBUTE + ":" + XMLNS_QEMU_NS_PREFIX, XMLNS_QEMU_NS_URI );
+ // add missing <qemu:commandline> element
+ qemuCmdlnElement = xmlDocument.createElementNS( XMLNS_QEMU_NS_URI, "commandline" );
+ qemuCmdlnElement.setPrefix( XMLNS_QEMU_NS_PREFIX );
+ rootElement.appendChild( qemuCmdlnElement );
+ } else {
+ // use available <qemu:commandline> element
+ final Node qemuCmdlnNode = qemuCmdlnNodes.item( 0 );
+ assert ( qemuCmdlnNode.getNodeType() == Node.ELEMENT_NODE );
+ qemuCmdlnElement = Element.class.cast( qemuCmdlnNode );
+ }
+
+ // append <qemu:arg value='...'> element with attribute
+ final Element qemuCmdlnArgElement = xmlDocument.createElementNS( XMLNS_QEMU_NS_URI, "arg" );
+ qemuCmdlnArgElement.setAttribute( "value", value );
+ qemuCmdlnElement.appendChild( qemuCmdlnArgElement );
+ }
+
+ /**
* Removes boot oder entries in the Libvirt domain XML document.
*/
public void removeBootOrder()
@@ -1381,6 +1497,18 @@ public class Domain extends LibvirtXmlDocument
}
/**
+ * Removes specified Nvram file in the Libvirt domain XML document.
+ */
+ public void removeOsNvram()
+ {
+ final Node nvramElement = this.getRootXmlNode().getXmlElement( "os/nvram" );
+
+ if ( nvramElement != null ) {
+ nvramElement.getParentNode().removeChild( nvramElement );
+ }
+ }
+
+ /**
* Removes network source for all interface devices in the Libvirt domain XML document.
*/
public void removeInterfaceDevicesSource()
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Graphics.java b/src/main/java/org/openslx/libvirt/domain/device/Graphics.java
index d10eb3f..3fd2f81 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/Graphics.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/Graphics.java
@@ -1,5 +1,8 @@
package org.openslx.libvirt.domain.device;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
import org.openslx.libvirt.xml.LibvirtXmlNode;
/**
@@ -50,6 +53,66 @@ public class Graphics extends Device
}
/**
+ * Returns the listen address of the graphics device.
+ *
+ * @return listen address of the graphics device.
+ */
+ public InetAddress getListenAddress()
+ {
+ InetAddress parsedListenAddress = null;
+
+ if ( this.getListenType() == ListenType.ADDRESS ) {
+ // only read listen address, if address listen type is set
+ final String rawListenAddress = this.getXmlElementAttributeValue( "listen", "address" );
+
+ try {
+ parsedListenAddress = InetAddress.getByName( rawListenAddress );
+ } catch ( UnknownHostException e ) {
+ parsedListenAddress = null;
+ }
+ }
+
+ return parsedListenAddress;
+ }
+
+ /**
+ * Sets the listen address for the graphics device.
+ *
+ * @param listenAddress listen address for the graphics device.
+ */
+ public void setListenAddress( InetAddress listenAddress )
+ {
+ if ( this.getListenType() == ListenType.ADDRESS && listenAddress != null ) {
+ // only set listen address, if address listen type is set
+ this.setXmlElementAttributeValue( "listen", "address", listenAddress.getHostAddress() );
+ }
+ }
+
+ /**
+ * Returns the listen port of the graphics device.
+ *
+ * @return listen port of the graphics device.
+ */
+ public int getListenPort()
+ {
+ final String listenPort = this.getXmlElementAttributeValue( "port" );
+ return Integer.valueOf( listenPort );
+ }
+
+ /**
+ * Sets the listen port for the graphics device.
+ *
+ * @param listenPort listen port for the graphics device.
+ */
+ public void setListenPort( int listenPort )
+ {
+ if ( this.getListenType() == ListenType.ADDRESS ) {
+ // only set listen port, if address listen type is set
+ this.setXmlElementAttributeValue( "port", Integer.toString( listenPort ) );
+ }
+ }
+
+ /**
* Creates a non-existent graphics device as Libvirt XML device element.
*
* @param graphics graphics device that is created.
diff --git a/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java b/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
index fbd115b..2c6068a 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/GraphicsSpice.java
@@ -1,5 +1,7 @@
package org.openslx.libvirt.domain.device;
+import java.net.InetAddress;
+
import org.openslx.libvirt.xml.LibvirtXmlNode;
/**
@@ -11,6 +13,16 @@ import org.openslx.libvirt.xml.LibvirtXmlNode;
public class GraphicsSpice extends Graphics
{
/**
+ * Default address of a SPICE graphics listener.
+ */
+ public static final InetAddress DEFAULT_ADDRESS = InetAddress.getLoopbackAddress();
+
+ /**
+ * Default port of a SPICE graphics listener.
+ */
+ public static final int DEFAULT_PORT = 5900;
+
+ /**
* Creates an empty graphics SPICE device.
*/
public GraphicsSpice()
diff --git a/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java b/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
index 11e74c3..dc9cf5e 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/Hostdev.java
@@ -78,7 +78,7 @@ public class Hostdev extends Device
if ( hostdev instanceof HostdevMdev ) {
xmlNode.setXmlElementAttributeValue( "type", Type.MDEV.toString() );
- addedHostdev = HostdevPci.createInstance( xmlNode );
+ addedHostdev = HostdevMdev.createInstance( xmlNode );
} else if ( hostdev instanceof HostdevPci ) {
xmlNode.setXmlElementAttributeValue( "type", Type.PCI.toString() );
addedHostdev = HostdevPci.createInstance( xmlNode );
diff --git a/src/main/java/org/openslx/libvirt/domain/device/HostdevMdev.java b/src/main/java/org/openslx/libvirt/domain/device/HostdevMdev.java
index d25a6eb..082ea5b 100644
--- a/src/main/java/org/openslx/libvirt/domain/device/HostdevMdev.java
+++ b/src/main/java/org/openslx/libvirt/domain/device/HostdevMdev.java
@@ -50,6 +50,26 @@ public class HostdevMdev extends Hostdev implements HostdevAddressableSource<Hos
}
/**
+ * Checks whether the hostdev mediated device memory framebuffer is on or off.
+ *
+ * @return state whether the hostdev mediated device memory framebuffer is on or off.
+ */
+ public boolean isMemoryFramebufferOn()
+ {
+ return this.getXmlElementAttributeValueAsBool( "ramfb" );
+ }
+
+ /**
+ * Sets the state of the hostdev mediated device memory framebuffer.
+ *
+ * @param on state whether the hostdev mediated device memory framebuffer is on or off.
+ */
+ public void setMemoryFramebufferOn( boolean on )
+ {
+ this.setXmlElementAttributeValueOnOff( "ramfb", on );
+ }
+
+ /**
* Returns the hostdev mediated device model.
*
* @return hostdev mediated device model.
@@ -80,7 +100,7 @@ public class HostdevMdev extends Hostdev implements HostdevAddressableSource<Hos
@Override
public void setSource( HostdevMdevDeviceAddress source )
{
- this.setXmlElementAttributeValue( "source/address", "domain", source.getDeviceAddressAsString() );
+ this.setXmlElementAttributeValue( "source/address", "uuid", source.getDeviceAddressAsString() );
}
/**
@@ -89,9 +109,9 @@ public class HostdevMdev extends Hostdev implements HostdevAddressableSource<Hos
* @param xmlNode Libvirt XML node of the Libvirt XML device that is created.
* @return created hostdev mediated device instance.
*/
- public static HostdevPci createInstance( LibvirtXmlNode xmlNode )
+ public static HostdevMdev createInstance( LibvirtXmlNode xmlNode )
{
- return HostdevPci.newInstance( xmlNode );
+ return HostdevMdev.newInstance( xmlNode );
}
/**
@@ -101,9 +121,9 @@ public class HostdevMdev extends Hostdev implements HostdevAddressableSource<Hos
* @param xmlNode existing Libvirt XML hostdev mediated device element.
* @return hostdev mediated device instance.
*/
- public static HostdevPci newInstance( LibvirtXmlNode xmlNode )
+ public static HostdevMdev newInstance( LibvirtXmlNode xmlNode )
{
- return new HostdevPci( xmlNode );
+ return new HostdevMdev( xmlNode );
}
/**
@@ -112,7 +132,7 @@ public class HostdevMdev extends Hostdev implements HostdevAddressableSource<Hos
* @author Manuel Bentele
* @version 1.0
*/
- enum Model
+ public enum Model
{
// @formatter:off
VFIO_PCI( "vfio-pci" ),
diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
index bfa385e..706a083 100644
--- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
+++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemu.java
@@ -245,10 +245,12 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
if ( storageDiskDevice == null ) {
// HDD does not exist, so create new storage (HDD) device
+ final BusType devBusType = BusType.VIRTIO;
+ final String targetDevName = VirtualizationConfigurationQemuUtils.createDeviceName( this.vmConfig,
+ devBusType );
storageDiskDevice = this.vmConfig.addDiskStorageDevice();
storageDiskDevice.setReadOnly( false );
- storageDiskDevice.setBusType( BusType.VIRTIO );
- String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "vd", index );
+ storageDiskDevice.setBusType( devBusType );
storageDiskDevice.setTargetDevice( targetDevName );
if ( diskImagePath == null || diskImagePath.isEmpty() ) {
@@ -319,9 +321,11 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
if ( floppyDiskDevice == null ) {
// floppy device does not exist, so create new floppy device
+ final BusType devBusType = BusType.FDC;
+ final String targetDevName = VirtualizationConfigurationQemuUtils.createDeviceName( this.vmConfig,
+ devBusType );
floppyDiskDevice = this.vmConfig.addDiskFloppyDevice();
- floppyDiskDevice.setBusType( BusType.FDC );
- String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "fd", index );
+ floppyDiskDevice.setBusType( devBusType );
floppyDiskDevice.setTargetDevice( targetDevName );
floppyDiskDevice.setReadOnly( readOnly );
@@ -364,9 +368,11 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
if ( cdromDiskDevice == null ) {
// CDROM device does not exist, so create new CDROM device
+ final BusType devBusType = BusType.SATA;
+ final String targetDevName = VirtualizationConfigurationQemuUtils.createDeviceName( this.vmConfig,
+ devBusType );
cdromDiskDevice = this.vmConfig.addDiskCdromDevice();
- cdromDiskDevice.setBusType( BusType.SATA );
- String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "sd", index );
+ cdromDiskDevice.setBusType( devBusType );
cdromDiskDevice.setTargetDevice( targetDevName );
cdromDiskDevice.setReadOnly( true );
@@ -406,10 +412,55 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
return isVCpuSet;
}
-
- class QemuGfxType extends VirtOptionValue
+
+ class QemuGfxModel extends VirtOptionValue
{
+ public QemuGfxModel( Video.Model model, String displayName )
+ {
+ super( model.toString(), displayName );
+ }
+ @Override
+ public void apply()
+ {
+ final ArrayList<Video> videoDevices = vmConfig.getVideoDevices();
+
+ if ( videoDevices.isEmpty() ) {
+ // add new video device with disabled acceleration to VM configuration
+ final Video videoDevice = vmConfig.addVideoDevice();
+ videoDevice.setModel( Video.Model.fromString( this.getId() ) );
+ videoDevice.set2DAcceleration( false );
+ videoDevice.set3DAcceleration( false );
+ } else {
+ // change graphics model of existing video devices
+ for ( final Video videoDevice : videoDevices ) {
+ // remove all old model-related XML attributes
+ videoDevice.removeXmlElement( "model" );
+ // set new model
+ videoDevice.setModel( Video.Model.fromString( this.getId() ) );
+ }
+ }
+ }
+
+ @Override
+ public boolean isActive()
+ {
+ final ArrayList<Video> videoDevices = vmConfig.getVideoDevices();
+ boolean isActive = true;
+
+ for ( final Video videoDevice : videoDevices ) {
+ if ( !videoDevice.getModel().toString().equals( this.getId() ) ) {
+ isActive = false;
+ break;
+ }
+ }
+
+ return isActive;
+ }
+ }
+
+ class QemuGfxType extends VirtOptionValue
+ {
public QemuGfxType( String id, String displayName )
{
super( id, displayName );
@@ -497,7 +548,6 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
return this.id.equals( "false" );
}
}
-
}
@Override
@@ -535,7 +585,6 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
class QemuNicModel extends VirtOptionValue
{
-
private final int cardIndex;
public QemuNicModel( int cardIndex, Interface.Model model, String displayName )
@@ -574,10 +623,9 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
return networkDeviceModel.toString().equals( this.id ); // XXX: enum would allow simple ==
}
}
-
+
class QemuSoundCardModel extends VirtOptionValue
{
-
public QemuSoundCardModel( Sound.Model id, String displayName )
{
super( id.toString(), displayName );
@@ -614,12 +662,11 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
Sound.Model soundDeviceModel = soundDevices.get( 0 ).getModel();
return soundDeviceModel != null && soundDeviceModel.toString().equals( this.id );
}
-
+
}
-
+
class QemuUsbSpeed extends VirtOptionValue
{
-
public QemuUsbSpeed( ControllerUsb.Model id, String displayName )
{
super( id.toString(), displayName );
@@ -647,8 +694,6 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
public boolean isActive()
{
ArrayList<ControllerUsb> usbControllerDevices = vmConfig.getUsbControllerDevices();
- String maxUsbSpeed = null;
- int maxUsbSpeedNumeric = 0;
for ( ControllerUsb usbControllerDevice : usbControllerDevices ) {
ControllerUsb.Model usbControllerModel = usbControllerDevice.getModel();
@@ -662,7 +707,6 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
return false;
}
-
}
@Override
@@ -756,6 +800,9 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
{
// removes all referenced storage files of all specified CDROMs, Floppy drives and HDDs
this.vmConfig.removeDiskDevicesStorage();
+
+ // remove specified NVRAM file of OS loader (firmware)
+ this.vmConfig.removeOsNvram();
}
@Override
@@ -774,9 +821,15 @@ public class VirtualizationConfigurationQemu extends VirtualizationConfiguration
configurableOptions.add( new ConfigurableOptionGroup( ConfigurationGroups.SOUND_CARD_MODEL, list ) );
list = new ArrayList<>();
- // XXX This would greatly benefit from having more meaningful options for qemu instead of on/off
- list.add( new QemuGfxType( "false", "langsam" ) );
- list.add( new QemuGfxType( "true", "3D OpenGL" ) );
+ list.add( new QemuGfxModel( Video.Model.VGA, "VGA" ) );
+ list.add( new QemuGfxModel( Video.Model.QXL, "QXL" ) );
+ list.add( new QemuGfxModel( Video.Model.VMVGA, "VMware VGA" ) );
+ list.add( new QemuGfxModel( Video.Model.VIRTIO, "virtio-gpu" ) );
+ configurableOptions.add( new ConfigurableOptionGroup( ConfigurationGroups.GFX_MODEL, list ) );
+
+ list = new ArrayList<>();
+ list.add( new QemuGfxType( "false", "2D" ) );
+ list.add( new QemuGfxType( "true", "3D" ) );
configurableOptions.add( new ConfigurableOptionGroup( ConfigurationGroups.GFX_TYPE, list ) );
list = new ArrayList<>();
diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
index 06091c0..1befdc4 100644
--- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
+++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationQemuUtils.java
@@ -1,9 +1,11 @@
package org.openslx.virtualization.configuration;
import java.util.ArrayList;
+import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.openslx.libvirt.domain.Domain;
import org.openslx.libvirt.domain.device.Disk;
import org.openslx.libvirt.domain.device.Disk.BusType;
import org.openslx.virtualization.Version;
@@ -109,7 +111,7 @@ public class VirtualizationConfigurationQemuUtils
* @param deviceNumber number of the device.
* @return alphabetical device name.
*/
- public static String createAlphabeticalDeviceName( String devicePrefix, int deviceNumber )
+ private static String createAlphabeticalDeviceName( String devicePrefix, int deviceNumber )
{
if ( deviceNumber < 0 || deviceNumber >= ( 'z' - 'a' ) ) {
String errorMsg = new String( "Device number is out of range to be able to create a valid device name." );
@@ -120,6 +122,42 @@ public class VirtualizationConfigurationQemuUtils
}
/**
+ * Creates an alphabetical device name for a disk device with a bus <i>type</i> that is unique in
+ * a Libvirt domain XML configuration.
+ *
+ * @param config Libvirt domain XML configuration.
+ * @param type device type for device name.
+ * @return alphabetical device name.
+ */
+ public static String createDeviceName( final Domain config, final BusType type ) throws IllegalArgumentException
+ {
+ final String devicePrefix;
+ final int deviceNumber;
+
+ switch ( type ) {
+ case FDC:
+ devicePrefix = "fd";
+ break;
+ case IDE:
+ devicePrefix = "hd";
+ break;
+ case SATA:
+ devicePrefix = "sd";
+ break;
+ case VIRTIO:
+ devicePrefix = "vd";
+ break;
+ default:
+ return null;
+ }
+
+ final Predicate<Disk> bySpecifiedBusType = d -> d.getBusType() == type;
+ deviceNumber = Long.valueOf( config.getDiskDevices().stream().filter( bySpecifiedBusType ).count() ).intValue();
+
+ return VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( devicePrefix, deviceNumber );
+ }
+
+ /**
* Data container to store a Libvirt/QEMU machine name with version information.
*
* @author Manuel Bentele
diff --git a/src/main/java/org/openslx/virtualization/configuration/transformation/TransformationManager.java b/src/main/java/org/openslx/virtualization/configuration/transformation/TransformationManager.java
index 197796d..b28fb32 100644
--- a/src/main/java/org/openslx/virtualization/configuration/transformation/TransformationManager.java
+++ b/src/main/java/org/openslx/virtualization/configuration/transformation/TransformationManager.java
@@ -2,6 +2,8 @@ package org.openslx.virtualization.configuration.transformation;
import java.util.ArrayList;
+import org.apache.log4j.Logger;
+
/**
* A transformation manager is a class to manage several transformations and their application.
*
@@ -33,6 +35,11 @@ public class TransformationManager<T, R>
private R args;
/**
+ * Logger instance to log messages.
+ */
+ private static final Logger LOGGER = Logger.getLogger( TransformationManager.class );
+
+ /**
* Create a transformation manager.
*
* @param config configuration which will be transformed.
@@ -63,6 +70,9 @@ public class TransformationManager<T, R>
*/
public void register( Transformation<T, R> transformation, boolean enabled )
{
+ LOGGER.debug( "Register transformation '" + transformation.getName() + "' and "
+ + ( enabled ? "enable" : "do not enable" ) + " it" );
+
transformation.setEnabled( enabled );
this.transformations.add( transformation );
}
@@ -107,6 +117,7 @@ public class TransformationManager<T, R>
public void transform() throws TransformationException
{
for ( Transformation<T, R> transformation : this.transformations ) {
+ LOGGER.debug( "Apply transformation '" + transformation.getName() + "'" );
try {
transformation.apply( this.config, this.args );
} catch ( TransformationException e ) {
diff --git a/src/main/java/org/openslx/virtualization/hardware/ConfigurationGroups.java b/src/main/java/org/openslx/virtualization/hardware/ConfigurationGroups.java
index ad5b771..8a0ab13 100644
--- a/src/main/java/org/openslx/virtualization/hardware/ConfigurationGroups.java
+++ b/src/main/java/org/openslx/virtualization/hardware/ConfigurationGroups.java
@@ -6,6 +6,7 @@ public enum ConfigurationGroups
NIC_MODEL( "E0VirtDev" ),
USB_SPEED( "maxUSBSpeed" ),
SOUND_CARD_MODEL( "sound" ),
+ GFX_MODEL( "graphics" ),
GFX_TYPE( "3DAcceleration" ),
HW_VERSION( "HWVersion" );
diff --git a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
index d950111..5d933bb 100644
--- a/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
+++ b/src/main/java/org/openslx/virtualization/virtualizer/VirtualizerQemu.java
@@ -33,7 +33,6 @@ public class VirtualizerQemu extends Virtualizer
*/
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" ),
@@ -44,7 +43,12 @@ public class VirtualizerQemu extends Virtualizer
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" ) ) );
+ new Version( Short.valueOf( "4" ), Short.valueOf( "2" ), "QEMU 4.2" ),
+ new Version( Short.valueOf( "5" ), Short.valueOf( "0" ), "QEMU 5.0" ),
+ new Version( Short.valueOf( "5" ), Short.valueOf( "1" ), "QEMU 5.1" ),
+ new Version( Short.valueOf( "5" ), Short.valueOf( "2" ), "QEMU 5.2" ),
+ new Version( Short.valueOf( "6" ), Short.valueOf( "0" ), "QEMU 6.0" ),
+ new Version( Short.valueOf( "6" ), Short.valueOf( "1" ), "QEMU 6.1" ) ) );
/**
* Creates a new QEMU virtualizer.
diff --git a/src/test/java/org/openslx/libvirt/domain/DomainTest.java b/src/test/java/org/openslx/libvirt/domain/DomainTest.java
index e1fb73b..6b53125 100644
--- a/src/test/java/org/openslx/libvirt/domain/DomainTest.java
+++ b/src/test/java/org/openslx/libvirt/domain/DomainTest.java
@@ -238,6 +238,40 @@ public class DomainTest
}
@Test
+ @DisplayName( "Get VM's OS loader from libvirt XML file" )
+ public void testGetOsLoader()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm_uefi.xml" );
+ assertEquals( "/usr/share/edk2-ovmf/x64/OVMF_CODE.fd", vm.getOsLoader() );
+ }
+
+ @Test
+ @DisplayName( "Set VM's OS loader in libvirt XML file" )
+ public void testSetOsLoader()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm_uefi.xml" );
+ vm.setOsLoader( "/usr/share/qemu/edk2-x86_64-code.fd" );
+ assertEquals( "/usr/share/qemu/edk2-x86_64-code.fd", vm.getOsLoader() );
+ }
+
+ @Test
+ @DisplayName( "Get VM's OS Nvram from libvirt XML file" )
+ public void testGetOsNvram()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm_uefi.xml" );
+ assertEquals( "/var/lib/libvirt/nvram/guest_VARS.fd", vm.getOsNvram() );
+ }
+
+ @Test
+ @DisplayName( "Set VM's OS Nvram in libvirt XML file" )
+ public void testSetOsNvram()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm_uefi.xml" );
+ vm.setOsNvram( "/tmp/nvram-tmp/tmp_VARS.fd" );
+ assertEquals( "/tmp/nvram-tmp/tmp_VARS.fd", vm.getOsNvram() );
+ }
+
+ @Test
@DisplayName( "Get VM CPU model from libvirt XML file" )
public void testGetCpuModel()
{
@@ -392,4 +426,25 @@ public class DomainTest
Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" );
assertEquals( 1, vm.getVideoDevices().size() );
}
+
+ @Test
+ @DisplayName( "Get all QEMU command line arguments from libvirt XML file" )
+ public void testGetQemuCmdlnArguments()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml" );
+ assertEquals( 2, vm.getQemuCmdlnArguments().size() );
+ }
+
+ @Test
+ @DisplayName( "Set QEMU command line arguments in libvirt XML file" )
+ public void testAddQemuCmdlnArguments()
+ {
+ Domain vm = this.newDomainInstance( "qemu-kvm_default-ubuntu-20-04-vm.xml" );
+ assertEquals( 0, vm.getQemuCmdlnArguments().size() );
+
+ vm.addQemuCmdlnArgument( "-set" );
+ vm.addQemuCmdlnArgument( "device.hostdev0.x-igd-opregion=on" );
+
+ assertEquals( 2, vm.getQemuCmdlnArguments().size() );
+ }
}
diff --git a/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml
new file mode 100644
index 0000000..2670eac
--- /dev/null
+++ b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml
@@ -0,0 +1,168 @@
+<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
+ <name>ubuntu-20-04</name>
+ <uuid>8dc5433c-0228-49e4-b019-fa2b606aa544</uuid>
+ <title>Ubuntu 20.04</title>
+ <description>Ubuntu 20.04 desktop installation</description>
+ <metadata>
+ <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
+ <libosinfo:os id="http://ubuntu.com/ubuntu/20.04"/>
+ </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-5.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='block' device='disk'>
+ <driver name='qemu' type='raw' cache='none' io='native'/>
+ <source dev='/dev/data/ubuntu-20-04.img'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <target dev='sda' bus='sata'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <disk type='file' device='floppy'>
+ <driver name='qemu' type='raw'/>
+ <target dev='fda' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0' model='ich9-ehci1'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci1'>
+ <master startport='0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci2'>
+ <master startport='2'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci3'>
+ <master startport='4'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/>
+ </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='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='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='scsi' index='0' model='virtio-scsi'>
+ <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='fdc' index='0'/>
+ <interface type='network'>
+ <mac address='52:54:00:0d:90:0c'/>
+ <source network='default'/>
+ <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='0x04' slot='0x00' function='0x0'/>
+ </memballoon>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </rng>
+ </devices>
+ <qemu:commandline>
+ <qemu:arg value='-set'/>
+ <qemu:arg value='device.hostdev0.x-igd-opregion=on'/>
+ </qemu:commandline>
+</domain>
+
diff --git a/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_uefi.xml b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_uefi.xml
new file mode 100644
index 0000000..12f9747
--- /dev/null
+++ b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_uefi.xml
@@ -0,0 +1,165 @@
+<domain type="kvm">
+ <name>Test</name>
+ <uuid>8dc5433c-0228-49e4-b019-fa2b606aa544</uuid>
+ <title>Ubuntu 20.04</title>
+ <description>Ubuntu 20.04 desktop installation</description>
+ <metadata>
+ <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
+ <libosinfo:os id="http://ubuntu.com/ubuntu/20.04"/>
+ </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-5.1">hvm</type>
+ <loader readonly="yes" type="pflash">/usr/share/edk2-ovmf/x64/OVMF_CODE.fd</loader>
+ <boot dev="hd"/>
+ </os>
+ <features>
+ <acpi/>
+ <apic/>
+ <vmport state="off"/>
+ </features>
+ <cpu check="partial" mode="host-model"/>
+ <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 device="disk" type="block">
+ <driver cache="none" io="native" name="qemu" type="raw"/>
+ <target bus="virtio" dev="vda"/>
+ <address bus="0x03" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </disk>
+ <disk device="cdrom" type="file">
+ <driver name="qemu" type="raw"/>
+ <target bus="sata" dev="sda"/>
+ <readonly/>
+ <address bus="0" controller="0" target="0" type="drive" unit="0"/>
+ </disk>
+ <disk device="floppy" type="file">
+ <driver name="qemu" type="raw"/>
+ <target bus="fdc" dev="fda"/>
+ <address bus="0" controller="0" target="0" type="drive" unit="0"/>
+ </disk>
+ <controller index="0" model="ich9-ehci1" type="usb">
+ <address bus="0x00" domain="0x0000" function="0x7" slot="0x1d" type="pci"/>
+ </controller>
+ <controller index="0" model="ich9-uhci1" type="usb">
+ <master startport="0"/>
+ <address bus="0x00" domain="0x0000" function="0x0" multifunction="on" slot="0x1d" type="pci"/>
+ </controller>
+ <controller index="0" model="ich9-uhci2" type="usb">
+ <master startport="2"/>
+ <address bus="0x00" domain="0x0000" function="0x1" slot="0x1d" type="pci"/>
+ </controller>
+ <controller index="0" model="ich9-uhci3" type="usb">
+ <master startport="4"/>
+ <address bus="0x00" domain="0x0000" function="0x2" slot="0x1d" type="pci"/>
+ </controller>
+ <controller index="0" type="sata">
+ <address bus="0x00" domain="0x0000" function="0x2" slot="0x1f" type="pci"/>
+ </controller>
+ <controller index="0" model="pcie-root" type="pci"/>
+ <controller index="1" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="1" port="0x10"/>
+ <address bus="0x00" domain="0x0000" function="0x0" multifunction="on" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="2" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="2" port="0x11"/>
+ <address bus="0x00" domain="0x0000" function="0x1" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="3" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="3" port="0x12"/>
+ <address bus="0x00" domain="0x0000" function="0x2" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="4" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="4" port="0x13"/>
+ <address bus="0x00" domain="0x0000" function="0x3" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="5" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="5" port="0x14"/>
+ <address bus="0x00" domain="0x0000" function="0x4" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="6" model="pcie-root-port" type="pci">
+ <model name="pcie-root-port"/>
+ <target chassis="6" port="0x15"/>
+ <address bus="0x00" domain="0x0000" function="0x5" slot="0x02" type="pci"/>
+ </controller>
+ <controller index="0" type="virtio-serial">
+ <address bus="0x02" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </controller>
+ <controller index="0" model="virtio-scsi" type="scsi">
+ <address bus="0x06" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </controller>
+ <controller index="0" type="fdc"/>
+ <interface type="bridge">
+ <mac address="52:54:00:0d:90:0c"/>
+ <source bridge="nat1"/>
+ <model type="virtio"/>
+ <address bus="0x01" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </interface>
+ <serial type="pty">
+ <target port="0" type="isa-serial">
+ <model name="isa-serial"/>
+ </target>
+ </serial>
+ <console type="pty">
+ <target port="0" type="serial"/>
+ </console>
+ <channel type="unix">
+ <target name="org.qemu.guest_agent.0" type="virtio"/>
+ <address bus="0" controller="0" port="1" type="virtio-serial"/>
+ </channel>
+ <channel type="spicevmc">
+ <target name="com.redhat.spice.0" type="virtio"/>
+ <address bus="0" controller="0" port="2" type="virtio-serial"/>
+ </channel>
+ <input bus="usb" type="tablet">
+ <address bus="0" port="1" type="usb"/>
+ </input>
+ <input bus="ps2" type="mouse"/>
+ <input bus="ps2" type="keyboard"/>
+ <graphics autoport="yes" type="spice">
+ <listen type="address"/>
+ <image compression="off"/>
+ </graphics>
+ <sound model="ich9">
+ <address bus="0x00" domain="0x0000" function="0x0" slot="0x1b" type="pci"/>
+ </sound>
+ <video>
+ <model heads="1" primary="yes" ram="65536" type="qxl" vgamem="16384" vram="65536"/>
+ <address bus="0x00" domain="0x0000" function="0x0" slot="0x01" type="pci"/>
+ </video>
+ <redirdev bus="usb" type="spicevmc">
+ <address bus="0" port="2" type="usb"/>
+ </redirdev>
+ <redirdev bus="usb" type="spicevmc">
+ <address bus="0" port="3" type="usb"/>
+ </redirdev>
+ <memballoon model="virtio">
+ <address bus="0x04" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </memballoon>
+ <rng model="virtio">
+ <backend model="random">/dev/urandom</backend>
+ <address bus="0x05" domain="0x0000" function="0x0" slot="0x00" type="pci"/>
+ </rng>
+ </devices>
+</domain>
+
+
diff --git a/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_uefi.xml b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_uefi.xml
new file mode 100644
index 0000000..c4e2788
--- /dev/null
+++ b/src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_uefi.xml
@@ -0,0 +1,166 @@
+<domain type='kvm'>
+ <name>ubuntu-20-04</name>
+ <uuid>8dc5433c-0228-49e4-b019-fa2b606aa544</uuid>
+ <title>Ubuntu 20.04</title>
+ <description>Ubuntu 20.04 desktop installation</description>
+ <metadata>
+ <libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
+ <libosinfo:os id="http://ubuntu.com/ubuntu/20.04"/>
+ </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-5.1'>hvm</type>
+ <loader readonly='yes' type='pflash'>/usr/share/edk2-ovmf/x64/OVMF_CODE.fd</loader>
+ <nvram template='/usr/share/edk2-ovmf/OVMF_VARS.fd'>/var/lib/libvirt/nvram/guest_VARS.fd</nvram>
+ <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='block' device='disk'>
+ <driver name='qemu' type='raw' cache='none' io='native'/>
+ <source dev='/dev/data/ubuntu-20-04.img'/>
+ <target dev='vda' bus='virtio'/>
+ <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
+ </disk>
+ <disk type='file' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <target dev='sda' bus='sata'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <disk type='file' device='floppy'>
+ <driver name='qemu' type='raw'/>
+ <target dev='fda' bus='fdc'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0' model='ich9-ehci1'>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x7'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci1'>
+ <master startport='0'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x0' multifunction='on'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci2'>
+ <master startport='2'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x1'/>
+ </controller>
+ <controller type='usb' index='0' model='ich9-uhci3'>
+ <master startport='4'/>
+ <address type='pci' domain='0x0000' bus='0x00' slot='0x1d' function='0x2'/>
+ </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='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='virtio-serial' index='0'>
+ <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='scsi' index='0' model='virtio-scsi'>
+ <address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
+ </controller>
+ <controller type='fdc' index='0'/>
+ <interface type='network'>
+ <mac address='52:54:00:0d:90:0c'/>
+ <source network='default'/>
+ <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='0x04' slot='0x00' function='0x0'/>
+ </memballoon>
+ <rng model='virtio'>
+ <backend model='random'>/dev/urandom</backend>
+ <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
+ </rng>
+ </devices>
+</domain>
+