summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2021-08-16 11:11:37 +0200
committerManuel Bentele2021-08-16 11:11:37 +0200
commit0877322403e7a122706abe4a2bcf39653675d352 (patch)
tree971658f9496afe5dcfec643cf137191b0faea830
parentAdd 'ramfb' option to Libvirt's mediated device representation (diff)
downloadmaster-sync-shared-0877322403e7a122706abe4a2bcf39653675d352.tar.gz
master-sync-shared-0877322403e7a122706abe4a2bcf39653675d352.tar.xz
master-sync-shared-0877322403e7a122706abe4a2bcf39653675d352.zip
Add Libvirt support for QEMU command line options
-rw-r--r--src/main/java/org/openslx/libvirt/domain/Domain.java76
-rw-r--r--src/test/java/org/openslx/libvirt/domain/DomainTest.java21
-rw-r--r--src/test/resources/libvirt/xml/qemu-kvm_default-ubuntu-20-04-vm_qemu-cmdln.xml168
3 files changed, 265 insertions, 0 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..d6f9a8f 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.
@@ -1052,6 +1066,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 +1388,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()
diff --git a/src/test/java/org/openslx/libvirt/domain/DomainTest.java b/src/test/java/org/openslx/libvirt/domain/DomainTest.java
index e1fb73b..c56759d 100644
--- a/src/test/java/org/openslx/libvirt/domain/DomainTest.java
+++ b/src/test/java/org/openslx/libvirt/domain/DomainTest.java
@@ -392,4 +392,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>
+