summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2021-01-29 12:25:44 +0100
committerManuel Bentele2021-01-29 12:25:44 +0100
commit706910e440527c22f176bcab0032c37c60357c25 (patch)
tree1173cdb610cb81bc17dccff3d2df4ba0ecd1c078
parentAdd implementation of Libvirt domain XML documents (diff)
downloadmaster-sync-shared-706910e440527c22f176bcab0032c37c60357c25.tar.gz
master-sync-shared-706910e440527c22f176bcab0032c37c60357c25.tar.xz
master-sync-shared-706910e440527c22f176bcab0032c37c60357c25.zip
Add support for QEMU VMs (based on Libvirt domain XML documents)
-rw-r--r--pom.xml27
-rw-r--r--src/main/java/org/openslx/util/vm/DiskImage.java35
-rw-r--r--src/main/java/org/openslx/util/vm/DockerMetaDataDummy.java16
-rw-r--r--src/main/java/org/openslx/util/vm/QemuMetaData.java796
-rw-r--r--src/main/java/org/openslx/util/vm/QemuMetaDataUtils.java188
-rw-r--r--src/main/java/org/openslx/util/vm/VboxMetaData.java14
-rw-r--r--src/main/java/org/openslx/util/vm/VmMetaData.java9
-rw-r--r--src/main/java/org/openslx/util/vm/VmwareMetaData.java16
-rw-r--r--src/main/resources/libvirt/xsl/xml-output-transformation.xsl12
-rw-r--r--src/test/java/org/openslx/util/vm/QemuMetaDataTest.java466
10 files changed, 1487 insertions, 92 deletions
diff --git a/pom.xml b/pom.xml
index 6daf903..4b8b3dc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -82,11 +82,21 @@
<version>3.0.0-M5</version>
</plugin>
</plugins>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/main/resources</directory>
+ <includes>
+ <include>libvirt/rng/*</include>
+ <include>libvirt/xsl/*</include>
+ </includes>
+ </resource>
+ </resources>
<testResources>
<testResource>
<directory>${basedir}/src/test/resources</directory>
<includes>
<include>disk/*</include>
+ <include>libvirt/xml/*</include>
</includes>
</testResource>
</testResources>
@@ -112,6 +122,12 @@
<scope>test</scope>
</dependency>
<dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-params</artifactId>
+ <version>5.5.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>[1.2.10,1.2.20]</version>
@@ -140,9 +156,14 @@
<version>2.8.0</version>
</dependency>
<dependency>
- <groupId>com.google.jimfs</groupId>
- <artifactId>jimfs</artifactId>
- <version>1.1</version>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.relaxng</groupId>
+ <artifactId>jing</artifactId>
+ <version>20181222</version>
</dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/openslx/util/vm/DiskImage.java b/src/main/java/org/openslx/util/vm/DiskImage.java
index 1602926..617fadd 100644
--- a/src/main/java/org/openslx/util/vm/DiskImage.java
+++ b/src/main/java/org/openslx/util/vm/DiskImage.java
@@ -5,6 +5,8 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
+import java.util.List;
+import java.util.function.Predicate;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.Virtualizer;
@@ -318,7 +320,40 @@ public class DiskImage
}
throw new UnknownImageFormatException();
}
+
+ /**
+ * Creates new disk image and checks if image is supported by hypervisor's image formats.
+ *
+ * @param disk file to a disk storing the virtual machine content.
+ * @param supportedImageTypes list of supported image types of a hypervisor's image format.
+ * @throws FileNotFoundException cannot find virtual machine image file.
+ * @throws IOException cannot access the virtual machine image file.
+ * @throws UnknownImageFormatException virtual machine image file has an unknown image format.
+ */
+ public DiskImage( File disk, List<ImageFormat> supportedImageTypes )
+ throws FileNotFoundException, IOException, UnknownImageFormatException
+ {
+ this( disk );
+ if ( !this.isSupportedByHypervisor( supportedImageTypes ) ) {
+ throw new UnknownImageFormatException();
+ }
+ }
+
+ /**
+ * Checks if image format is supported by a list of supported hypervisor image formats.
+ *
+ * @param supportedImageTypes list of supported image types of a hypervisor.
+ * @return <code>true</code> if image type is supported by the hypervisor; otherwise
+ * <code>false</code>.
+ */
+ public boolean isSupportedByHypervisor( List<ImageFormat> supportedImageTypes )
+ {
+ Predicate<ImageFormat> matchDiskFormat = supportedImageType -> supportedImageType.toString()
+ .equalsIgnoreCase( this.getImageFormat().toString() );
+ return supportedImageTypes.stream().anyMatch( matchDiskFormat );
+ }
+
private int findNull( byte[] buffer )
{
for ( int i = 0; i < buffer.length; ++i ) {
diff --git a/src/main/java/org/openslx/util/vm/DockerMetaDataDummy.java b/src/main/java/org/openslx/util/vm/DockerMetaDataDummy.java
index 3ee964f..9698c52 100644
--- a/src/main/java/org/openslx/util/vm/DockerMetaDataDummy.java
+++ b/src/main/java/org/openslx/util/vm/DockerMetaDataDummy.java
@@ -3,13 +3,23 @@ package org.openslx.util.vm;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.thrifthelper.TConst;
+import org.openslx.util.vm.DiskImage.ImageFormat;
import java.io.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
public class DockerMetaDataDummy extends VmMetaData {
// TODO Define DOCKER CONSTANT
+ /**
+ * List of supported image formats by the Docker hypervisor.
+ */
+ private static final List<DiskImage.ImageFormat> SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableList(
+ Arrays.asList( ImageFormat.DOCKER ) );
+
private static final Logger LOGGER = Logger.getLogger( DockerMetaDataDummy.class);
private final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_DOCKER, "Docker" );
@@ -41,6 +51,12 @@ public class DockerMetaDataDummy extends VmMetaData {
@Override public byte[] getFilteredDefinitionArray() {
return dockerfile;
}
+
+ @Override
+ public List<DiskImage.ImageFormat> getSupportedImageFormats()
+ {
+ return DockerMetaDataDummy.SUPPORTED_IMAGE_FORMATS;
+ }
@Override public void applySettingsForLocalEdit() {
diff --git a/src/main/java/org/openslx/util/vm/QemuMetaData.java b/src/main/java/org/openslx/util/vm/QemuMetaData.java
index 201ffd8..1e5dd33 100644
--- a/src/main/java/org/openslx/util/vm/QemuMetaData.java
+++ b/src/main/java/org/openslx/util/vm/QemuMetaData.java
@@ -1,233 +1,855 @@
package org.openslx.util.vm;
import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
+import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
-import java.util.Map;
+import java.util.Map.Entry;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.Virtualizer;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.ControllerUsb;
+import org.openslx.libvirt.domain.device.Disk.BusType;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskCdrom;
+import org.openslx.libvirt.domain.device.DiskFloppy;
+import org.openslx.libvirt.domain.device.DiskStorage;
+import org.openslx.libvirt.domain.device.Graphics;
+import org.openslx.libvirt.domain.device.GraphicsSpice;
+import org.openslx.libvirt.domain.device.Interface;
+import org.openslx.libvirt.domain.device.Sound;
+import org.openslx.libvirt.domain.device.Video;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
import org.openslx.thrifthelper.TConst;
import org.openslx.util.vm.DiskImage.ImageFormat;
-import org.openslx.util.vm.DiskImage.UnknownImageFormatException;
-public class QemuMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta, VBoxHWVersionMeta, VBoxEthernetDevTypeMeta, VBoxUsbSpeedMeta>
+/**
+ * Metadata to describe the hardware type of a QEMU sound card.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+class QemuSoundCardMeta
{
+ /**
+ * Stores the hardware model of the QEMU sound card.
+ */
+ private final Sound.Model model;
+
+ /**
+ * Creates metadata to describe the hardware model of a QEMU sound card.
+ *
+ * @param model hardware model of the QEMU sound card.
+ */
+ public QemuSoundCardMeta( Sound.Model model )
+ {
+ this.model = model;
+ }
- private final Map<String, String> arguments = new HashMap<String, String>();
- // the above map's elements will take the place of <args> in the config string
- private String config;
- private static final Logger LOGGER = Logger.getLogger( QemuMetaData.class );
+ /**
+ * Returns hardware model of the QEMU sound card.
+ *
+ * @return hardware model of the QEMU sound card.
+ */
+ public Sound.Model getModel()
+ {
+ return this.model;
+ }
+}
- private static final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_QEMU, "QEMU-KVM" );
+/**
+ * Metadata to describe the hardware acceleration state of QEMU virtual graphics.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+class QemuDDAccelMeta
+{
+ /**
+ * Stores state of the hardware acceleration for QEMU virtual graphics.
+ */
+ private final boolean enabled;
+
+ /**
+ * Creates metadata to describe the hardware acceleration state of QEMU virtual graphics.
+ *
+ * @param enabled state of the hardware acceleration for QEMU virtual graphics.
+ */
+ public QemuDDAccelMeta( boolean enabled )
+ {
+ this.enabled = enabled;
+ }
- public QemuMetaData( List<OperatingSystem> osList, File file ) throws FileNotFoundException, IOException, UnsupportedVirtualizerFormatException
+ /**
+ * Returns state of the hardware acceleration of QEMU virtual graphics.
+ *
+ * @return state of the hardware acceleration for QEMU virtual graphics.
+ */
+ public boolean isEnabled()
+ {
+ return this.enabled;
+ }
+}
+
+/**
+ * Metadata to describe the version of a QEMU virtual machine configuration.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+class QemuHWVersionMeta
+{
+ /**
+ * Stores the version of a QEMU virtual machine configuration.
+ */
+ private final int version;
+
+ /**
+ * Creates metadata to describe the version of a QEMU virtual machine configuration.
+ *
+ * @param version version of the QEMU virtual machine configuration.
+ */
+ public QemuHWVersionMeta( int version )
+ {
+ this.version = version;
+ }
+
+ /**
+ * Returns version of the QEMU virtual machine configuration.
+ *
+ * @return version of the QEMU virtual machine configuration.
+ */
+ public int getVersion()
+ {
+ return this.version;
+ }
+}
+
+/**
+ * Metadata to describe the hardware type of a QEMU ethernet device.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+class QemuEthernetDevTypeMeta
+{
+ /**
+ * Stores the hardware model of the QEMU ethernet device.
+ */
+ private final Interface.Model model;
+
+ /**
+ * Creates metadata to describe the hardware type of a QEMU ethernet device.
+ *
+ * @param model hardware type of the QEMU ethernet device.
+ */
+ public QemuEthernetDevTypeMeta( Interface.Model model )
+ {
+ this.model = model;
+ }
+
+ /**
+ * Returns the hardware type of a QEMU ethernet device.
+ *
+ * @return hardware type of the QEMU ethernet device.
+ */
+ public Interface.Model getModel()
+ {
+ return this.model;
+ }
+}
+
+/**
+ * Metadata to describe a QEMU USB controller.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+class QemuUsbSpeedMeta
+{
+ /**
+ * Stores the USB speed of the QEMU USB controller.
+ */
+ private final int speed;
+
+ /**
+ * Stores the QEMU hardware model of the USB controller.
+ */
+ private final ControllerUsb.Model model;
+
+ /**
+ * Creates metadata to describe a QEMU USB controller.
+ *
+ * @param speed USB speed of the QEMU USB controller.
+ * @param model QEMU hardware model of the USB controller.
+ */
+ public QemuUsbSpeedMeta( int speed, ControllerUsb.Model model )
+ {
+ this.speed = speed;
+ this.model = model;
+ }
+
+ /**
+ * Returns the speed of the QEMU USB controller.
+ *
+ * @return speed of the QEMU USB controller.
+ */
+ public int getSpeed()
+ {
+ return this.speed;
+ }
+
+ /**
+ * Returns QEMU hardware model of the USB controller.
+ *
+ * @return hardware model of the QEMU USB controller.
+ */
+ public ControllerUsb.Model getModel()
+ {
+ return this.model;
+ }
+}
+
+/**
+ * Virtual machine configuration (managed by Libvirt) for the QEMU hypervisor.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class QemuMetaData extends
+ VmMetaData<QemuSoundCardMeta, QemuDDAccelMeta, QemuHWVersionMeta, QemuEthernetDevTypeMeta, QemuUsbSpeedMeta>
+{
+ /**
+ * Default bridge name of the network bridge connected to the LAN.
+ */
+ public static final String NETWORK_DEFAULT_BRIDGE = "brBwLehrpool";
+
+ /**
+ * Default network name of the isolated host network (host only).
+ */
+ public static final String NETWORK_DEFAULT_HOST_ONLY = "host";
+
+ /**
+ * Default network name of the NAT network.
+ */
+ public static final String NETWORK_DEFAULT_NAT = "nat";
+
+ /**
+ * Default physical CDROM drive of the hypervisor host.
+ */
+ public static final String CDROM_DEFAULT_PHYSICAL_DRIVE = "/dev/sr0";
+
+ /**
+ * List of supported image formats by the QEMU hypervisor.
+ */
+ private static final List<DiskImage.ImageFormat> SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableList(
+ Arrays.asList( ImageFormat.QCOW2, ImageFormat.VMDK, ImageFormat.VDI ) );
+
+ /**
+ * Representation of a QEMU hypervisor (managed by Libvirt).
+ */
+ private static final Virtualizer VIRTUALIZER = new Virtualizer( TConst.VIRT_QEMU, "QEMU" );
+
+ /**
+ * Libvirt XML configuration file to modify configuration of virtual machine for QEMU.
+ */
+ private Domain vmConfig = null;
+
+ /**
+ * Stores current index of added HDD device to the Libvirt XML configuration file.
+ */
+ private int vmDeviceIndexHddAdd = 0;
+
+ /**
+ * Stores current index of added CDROM device to the Libvirt XML configuration file.
+ */
+ private int vmDeviceIndexCdromAdd = 0;
+
+ /**
+ * Stores current index of added ethernet device to the Libvirt XML configuration file.
+ */
+ private int vmDeviceIndexEthernetAdd = 0;
+
+ /**
+ * Creates new virtual machine configuration (managed by Libvirt) for the QEMU hypervisor.
+ *
+ * @param osList list of operating systems.
+ * @param file image file for the QEMU hypervisor.
+ * @throws UnsupportedVirtualizerFormatException Libvirt XML configuration cannot be processed.
+ */
+ public QemuMetaData( List<OperatingSystem> osList, File file ) throws UnsupportedVirtualizerFormatException
{
super( osList );
- DiskImage di;
+
try {
- di = new DiskImage( file );
- } catch ( UnknownImageFormatException e ) {
- di = null;
+ // read and parse Libvirt domain XML configuration document
+ this.vmConfig = new Domain( file );
+ } catch ( LibvirtXmlDocumentException e ) {
+ throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() );
+ } catch ( LibvirtXmlSerializationException e ) {
+ throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() );
+ } catch ( LibvirtXmlValidationException e ) {
+ throw new UnsupportedVirtualizerFormatException( e.getLocalizedMessage() );
}
- if ( di == null || di.format != ImageFormat.QCOW2 ) {
- throw new UnsupportedVirtualizerFormatException( "This is not a qcow2 disk image" );
+
+ // register virtual hardware models for graphical editing of virtual devices (GPU, sound, USB, ...)
+ this.registerVirtualHW();
+
+ // set display name of VM
+ this.displayName = vmConfig.getName();
+
+ // this property cannot be checked with the Libvirt domain XML configuration
+ // to check if machine is in a paused/suspended state, look in the QEMU qcow2 image for snapshots and machine states
+ this.isMachineSnapshot = false;
+
+ // add HDDs, SSDs to QEMU metadata
+ for ( DiskStorage storageDiskDevice : this.vmConfig.getDiskStorageDevices() ) {
+ this.addHddMetaData( storageDiskDevice );
}
- config = "qemu-system-i386 <args> <image> -enable-kvm\nqemu-system-x86_64 <args> <image> -enable-kvm";
- displayName = file.getName().substring( 0, file.getName().indexOf( "." ) );
- setOs( "anyOs" );
- hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, file.getAbsolutePath() ) );
- makeStartSequence();
}
- // initiates the arguments map with a default working sequence that will later be used in the definition array
- public void makeStartSequence()
+ /**
+ * Adds an existing and observed storage disk device to the HDD metadata.
+ *
+ * @param storageDiskDevice existing and observed storage disk that should be added to the
+ * metadata.
+ */
+ private void addHddMetaData( DiskStorage storageDiskDevice )
{
- arguments.put( "cpu", "host" );
- arguments.put( "smp", "2" );
- arguments.put( "m", "1024" );
- arguments.put( "vga", "std" );
+ String hddChipsetModel = null;
+ DriveBusType hddChipsetBus = QemuMetaDataUtils.convertBusType( storageDiskDevice.getBusType() );
+ String hddImagePath = storageDiskDevice.getStorageSource();
+
+ this.hdds.add( new HardDisk( hddChipsetModel, hddChipsetBus, hddImagePath ) );
}
- private String configWithArgs()
+ @Override
+ public byte[] getFilteredDefinitionArray()
{
- String tempString = "";
- for ( String key : arguments.keySet() ) {
- tempString += "-" + key + " " + arguments.get( key ) + " ";
- }
- return config.replaceAll( "<args>", tempString );
+ // remove UUID in Libvirt domain XML configuration
+ this.vmConfig.removeUuid();
+
+ // removes all specified boot order entries
+ this.vmConfig.removeBootOrder();
+
+ // removes all referenced storage files of all specified CDROMs, Floppy drives and HDDs
+ this.vmConfig.removeDiskDevicesStorage();
+
+ // removes all source networks of all specified network interfaces
+ this.vmConfig.removeInterfaceDevicesSource();
+
+ // output filtered Libvirt domain XML configuration
+ String configuration = this.vmConfig.toString();
+ return configuration.getBytes( StandardCharsets.UTF_8 );
}
@Override
- public byte[] getFilteredDefinitionArray()
+ public List<DiskImage.ImageFormat> getSupportedImageFormats()
{
- return configWithArgs().getBytes( StandardCharsets.UTF_8 );
+ return QemuMetaData.SUPPORTED_IMAGE_FORMATS;
}
@Override
public void applySettingsForLocalEdit()
{
+ // NOT implemented yet
}
@Override
public boolean addHddTemplate( File diskImage, String hddMode, String redoDir )
{
- String tempS = config.replaceAll( "<image>", diskImage.getAbsolutePath() );
- config = tempS;
- hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, diskImage.getAbsolutePath() ) );
- return true;
+ return this.addHddTemplate( diskImage.getAbsolutePath(), hddMode, redoDir );
}
@Override
public boolean addHddTemplate( String diskImagePath, String hddMode, String redoDir )
{
- String tempS = config.replaceAll( "<image>", diskImagePath );
- config = tempS;
- hdds.add( new HardDisk( "anychipset", DriveBusType.IDE, diskImagePath ) );
- return true;
+ return this.addHddTemplate( this.vmDeviceIndexHddAdd++, diskImagePath, hddMode, redoDir );
+ }
+
+ /**
+ * Adds hard disk drive (HDD) to the QEMU virtual machine configuration.
+ *
+ * @param index current index of HDD to be added to the virtual machine configuration.
+ * @param diskImagePath path to the virtual disk image for the HDD.
+ * @param hddMode operation mode of the HDD.
+ * @param redoDir directory for the redo log if an independent non-persistent
+ * <code>hddMode</code> is set.
+ * @return result state of adding the HDD.
+ */
+ public boolean addHddTemplate( int index, String diskImagePath, String hddMode, String redoDir )
+ {
+ ArrayList<DiskStorage> storageDiskDevices = this.vmConfig.getDiskStorageDevices();
+ DiskStorage storageDiskDevice = QemuMetaDataUtils.getArrayIndex( storageDiskDevices, index );
+
+ if ( storageDiskDevice == null ) {
+ // HDD does not exist, so create new storage (HDD) device
+ storageDiskDevice = this.vmConfig.addDiskStorageDevice();
+ storageDiskDevice.setReadOnly( false );
+ storageDiskDevice.setBusType( BusType.VIRTIO );
+ String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "vd", index );
+ storageDiskDevice.setTargetDevice( targetDevName );
+ storageDiskDevice.setStorage( StorageType.FILE, diskImagePath );
+
+ // add new created HDD to the metadata of the QemuMetaData object, too
+ this.addHddMetaData( storageDiskDevice );
+ } else {
+ // HDD exists, so update existing storage (HDD) device
+ storageDiskDevice.setStorage( StorageType.FILE, diskImagePath );
+ }
+
+ return false;
}
@Override
public boolean addDefaultNat()
{
- return true;
+ return this.addEthernet( EtherType.NAT );
}
@Override
public void setOs( String vendorOsId )
{
- setOs( TConst.VIRT_QEMU, vendorOsId );
+ this.setOs( vendorOsId );
}
@Override
public boolean addDisplayName( String name )
{
- // TODO Auto-generated method stub
- return false;
+ this.vmConfig.setName( name );
+
+ final boolean statusName = this.vmConfig.getName().equals( name );
+
+ return statusName;
}
@Override
public boolean addRam( int mem )
{
- this.arguments.put( "m", Integer.toString( mem ) );
- return true;
+ BigInteger memory = BigInteger.valueOf( mem );
+
+ this.vmConfig.setMemory( memory );
+ this.vmConfig.setCurrentMemory( memory );
+
+ final boolean isMemorySet = this.vmConfig.getMemory().toString().equals( memory.toString() );
+ final boolean isCurrentMemorySet = this.vmConfig.getCurrentMemory().toString().equals( memory.toString() );
+
+ return isMemorySet && isCurrentMemorySet;
}
@Override
public void addFloppy( int index, String image, boolean readOnly )
{
- // TODO Auto-generated method stub
-
+ ArrayList<DiskFloppy> floppyDiskDevices = this.vmConfig.getDiskFloppyDevices();
+ DiskFloppy floppyDiskDevice = QemuMetaDataUtils.getArrayIndex( floppyDiskDevices, index );
+
+ if ( floppyDiskDevice == null ) {
+ // floppy device does not exist, so create new floppy device
+ floppyDiskDevice = this.vmConfig.addDiskFloppyDevice();
+ floppyDiskDevice.setBusType( BusType.FDC );
+ String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "fd", index );
+ floppyDiskDevice.setTargetDevice( targetDevName );
+ floppyDiskDevice.setReadOnly( readOnly );
+ floppyDiskDevice.setStorage( StorageType.FILE, image );
+ } else {
+ // floppy device exists, so update existing floppy device
+ floppyDiskDevice.setReadOnly( readOnly );
+ floppyDiskDevice.setStorage( StorageType.FILE, image );
+ }
}
@Override
public boolean addCdrom( String image )
{
- // TODO Auto-generated method stub
+ return this.addCdrom( this.vmDeviceIndexCdromAdd++, image );
+ }
+
+ /**
+ * Adds CDROM drive to the QEMU virtual machine configuration.
+ *
+ * @param index current index of CDROM drive to be added to the virtual machine configuration.
+ * @param image path to a virtual image that will be inserted as CDROM into the drive.
+ * @return result state of adding the CDROM drive.
+ */
+ public boolean addCdrom( int index, String image )
+ {
+ ArrayList<DiskCdrom> cdromDiskDevices = this.vmConfig.getDiskCdromDevices();
+ DiskCdrom cdromDiskDevice = QemuMetaDataUtils.getArrayIndex( cdromDiskDevices, index );
+
+ if ( cdromDiskDevice == null ) {
+ // CDROM device does not exist, so create new CDROM device
+ cdromDiskDevice = this.vmConfig.addDiskCdromDevice();
+ cdromDiskDevice.setBusType( BusType.SATA );
+ String targetDevName = QemuMetaDataUtils.createAlphabeticalDeviceName( "sd", index );
+ cdromDiskDevice.setTargetDevice( targetDevName );
+ cdromDiskDevice.setReadOnly( true );
+
+ if ( image == null ) {
+ cdromDiskDevice.setStorage( StorageType.BLOCK, CDROM_DEFAULT_PHYSICAL_DRIVE );
+ } else {
+ cdromDiskDevice.setStorage( StorageType.FILE, image );
+ }
+ } else {
+ // CDROM device exists, so update existing CDROM device
+ cdromDiskDevice.setReadOnly( true );
+
+ if ( image == null ) {
+ cdromDiskDevice.setStorage( StorageType.BLOCK, CDROM_DEFAULT_PHYSICAL_DRIVE );
+ } else {
+ cdromDiskDevice.setStorage( StorageType.FILE, image );
+ }
+ }
+
return false;
}
@Override
public boolean addCpuCoreCount( int nrOfCores )
{
- this.arguments.put( "smp", Integer.toString( nrOfCores ) );
- return true;
+ this.vmConfig.setVCpu( nrOfCores );
+
+ boolean isVCpuSet = this.vmConfig.getVCpu() == nrOfCores;
+
+ return isVCpuSet;
}
@Override
- public void setSoundCard( VmMetaData.SoundCardType type )
+ public void setSoundCard( SoundCardType type )
{
+ QemuSoundCardMeta soundDeviceConfig = this.soundCards.get( type );
+ ArrayList<Sound> soundDevices = this.vmConfig.getSoundDevices();
+ Sound.Model soundDeviceModel = soundDeviceConfig.getModel();
+
+ if ( soundDevices.isEmpty() ) {
+ // create new sound device with 'soundDeviceModel' hardware
+ Sound soundDevice = this.vmConfig.addSoundDevice();
+ soundDevice.setModel( soundDeviceModel );
+ } else {
+ // update sound device model type of existing sound devices
+ for ( Sound soundDevice : soundDevices ) {
+ soundDevice.setModel( soundDeviceModel );
+ }
+ }
}
@Override
- public VmMetaData.SoundCardType getSoundCard()
+ public SoundCardType getSoundCard()
{
- return null;
+ ArrayList<Sound> soundDevices = this.vmConfig.getSoundDevices();
+ SoundCardType soundDeviceType = SoundCardType.DEFAULT;
+
+ if ( soundDevices.isEmpty() ) {
+ // the VM configuration does not contain a sound card device
+ soundDeviceType = SoundCardType.NONE;
+ } else {
+ // the VM configuration at least one sound card device, so return the type of the first one
+ Sound.Model soundDeviceModel = soundDevices.get( 0 ).getModel();
+ soundDeviceType = QemuMetaDataUtils.convertSoundDeviceModel( soundDeviceModel );
+ }
+
+ return soundDeviceType;
}
@Override
- public void setDDAcceleration( VmMetaData.DDAcceleration type )
+ public void setDDAcceleration( DDAcceleration type )
{
+ QemuDDAccelMeta accelerationConfig = this.ddacc.get( type );
+ ArrayList<Graphics> graphicDevices = this.vmConfig.getGraphicDevices();
+ ArrayList<Video> videoDevices = this.vmConfig.getVideoDevices();
+ final boolean accelerationEnabled = accelerationConfig.isEnabled();
+
+ boolean acceleratedGraphicsAvailable = false;
+
+ if ( graphicDevices.isEmpty() ) {
+ // add new graphics device with enabled acceleration to VM configuration
+ GraphicsSpice graphicSpiceDevice = this.vmConfig.addGraphicsSpiceDevice();
+ graphicSpiceDevice.setOpenGl( true );
+ acceleratedGraphicsAvailable = true;
+ } else {
+ // enable graphic acceleration of existing graphics devices
+ for ( Graphics graphicDevice : graphicDevices ) {
+ // set hardware acceleration for SPICE based graphics output
+ // other graphic devices do not support hardware acceleration
+ if ( graphicDevice instanceof GraphicsSpice ) {
+ GraphicsSpice.class.cast( graphicDevice ).setOpenGl( true );
+ acceleratedGraphicsAvailable = true;
+ }
+ }
+ }
+
+ // only configure hardware acceleration of video card(s) if graphics with hardware acceleration is available
+ if ( acceleratedGraphicsAvailable ) {
+ if ( videoDevices.isEmpty() ) {
+ // add new video device with enabled acceleration to VM configuration
+ Video videoDevice = this.vmConfig.addVideoDevice();
+ videoDevice.setModel( Video.Model.VIRTIO );
+ videoDevice.set2DAcceleration( true );
+ videoDevice.set3DAcceleration( true );
+ } else {
+ // enable graphic acceleration of existing graphics and video devices
+ for ( Video videoDevice : videoDevices ) {
+ // set hardware acceleration for Virtio GPUs
+ // other GPUs do not support hardware acceleration
+ if ( videoDevice.getModel() == Video.Model.VIRTIO ) {
+ videoDevice.set2DAcceleration( accelerationEnabled );
+ videoDevice.set3DAcceleration( accelerationEnabled );
+ }
+ }
+ }
+ }
}
@Override
- public VmMetaData.DDAcceleration getDDAcceleration()
+ public DDAcceleration getDDAcceleration()
{
- return null;
+ ArrayList<Graphics> graphicsDevices = this.vmConfig.getGraphicDevices();
+ ArrayList<Video> videoDevices = this.vmConfig.getVideoDevices();
+ DDAcceleration accelerationState = DDAcceleration.OFF;
+
+ boolean acceleratedGraphicsAvailable = false;
+ boolean acceleratedVideoDevAvailable = false;
+
+ // search for hardware accelerated graphics
+ for ( Graphics graphicDevice : graphicsDevices ) {
+ // only SPICE based graphic devices support hardware acceleration
+ if ( graphicDevice instanceof GraphicsSpice ) {
+ acceleratedGraphicsAvailable = true;
+ break;
+ }
+ }
+
+ // search for hardware accelerated video devices
+ for ( Video videoDevice : videoDevices ) {
+ // only Virtio based video devices support hardware acceleration
+ if ( videoDevice.getModel() == Video.Model.VIRTIO ) {
+ acceleratedVideoDevAvailable = true;
+ break;
+ }
+ }
+
+ // hardware acceleration is available if at least one accelerated graphics and video device is available
+ if ( acceleratedGraphicsAvailable && acceleratedVideoDevAvailable ) {
+ accelerationState = DDAcceleration.ON;
+ } else {
+ accelerationState = DDAcceleration.OFF;
+ }
+
+ return accelerationState;
}
@Override
- public void setHWVersion( VmMetaData.HWVersion type )
+ public void setHWVersion( HWVersion type )
{
+ // NOT supported by the QEMU hypervisor
}
@Override
- public VmMetaData.HWVersion getHWVersion()
+ public HWVersion getHWVersion()
{
+ // NOT supported by the QEMU hypervisor
return null;
}
@Override
- public void setEthernetDevType( int cardIndex, VmMetaData.EthernetDevType type )
+ public void setEthernetDevType( int cardIndex, EthernetDevType type )
{
+ QemuEthernetDevTypeMeta networkDeviceConfig = this.networkCards.get( type );
+ ArrayList<Interface> networkDevices = this.vmConfig.getInterfaceDevices();
+ Interface networkDevice = QemuMetaDataUtils.getArrayIndex( networkDevices, cardIndex );
+ Interface.Model networkDeviceModel = networkDeviceConfig.getModel();
+
+ if ( networkDevice != null ) {
+ networkDevice.setModel( networkDeviceModel );
+ }
}
@Override
- public VmMetaData.EthernetDevType getEthernetDevType( int cardIndex )
+ public EthernetDevType getEthernetDevType( int cardIndex )
{
- return null;
+ ArrayList<Interface> networkDevices = this.vmConfig.getInterfaceDevices();
+ Interface networkDevice = QemuMetaDataUtils.getArrayIndex( networkDevices, cardIndex );
+ EthernetDevType networkDeviceType = EthernetDevType.NONE;
+
+ if ( networkDevice == null ) {
+ // network interface device is not present
+ networkDeviceType = EthernetDevType.NONE;
+ } else {
+ // get model of existing network interface device
+ Interface.Model networkDeviceModel = networkDevice.getModel();
+ networkDeviceType = QemuMetaDataUtils.convertNetworkDeviceModel( networkDeviceModel );
+ }
+
+ return networkDeviceType;
}
@Override
- public byte[] getDefinitionArray()
+ public void setMaxUsbSpeed( UsbSpeed speed )
{
- return configWithArgs().getBytes( StandardCharsets.UTF_8 );
+ QemuUsbSpeedMeta usbControllerConfig = this.usbSpeeds.get( speed );
+ ArrayList<ControllerUsb> usbControllerDevices = this.vmConfig.getUsbControllerDevices();
+ ControllerUsb.Model usbControllerModel = usbControllerConfig.getModel();
+
+ if ( usbControllerDevices.isEmpty() ) {
+ // add new USB controller with specified speed 'usbControllerModel'
+ ControllerUsb usbControllerDevice = this.vmConfig.addControllerUsbDevice();
+ usbControllerDevice.setModel( usbControllerModel );
+ } else {
+ // update model of all USB controller devices to support the maximum speed
+ for ( ControllerUsb usbControllerDevice : usbControllerDevices ) {
+ usbControllerDevice.setModel( usbControllerModel );
+ }
+ }
}
@Override
- public boolean addEthernet( VmMetaData.EtherType type )
+ public UsbSpeed getMaxUsbSpeed()
{
- return false;
+ ArrayList<ControllerUsb> usbControllerDevices = this.vmConfig.getUsbControllerDevices();
+ UsbSpeed maxUsbSpeed = VmMetaData.UsbSpeed.NONE;
+ int maxUsbSpeedNumeric = 0;
+
+ for ( ControllerUsb usbControllerDevice : usbControllerDevices ) {
+ ControllerUsb.Model usbControllerModel = usbControllerDevice.getModel();
+
+ for ( Entry<UsbSpeed, QemuUsbSpeedMeta> usbSpeedEntry : this.usbSpeeds.entrySet() ) {
+ QemuUsbSpeedMeta usbSpeed = usbSpeedEntry.getValue();
+ if ( usbSpeed.getSpeed() > maxUsbSpeedNumeric && usbSpeed.getModel() == usbControllerModel ) {
+ maxUsbSpeed = usbSpeedEntry.getKey();
+ maxUsbSpeedNumeric = usbSpeed.getSpeed();
+ }
+ }
+ }
+
+ return maxUsbSpeed;
}
@Override
- public Virtualizer getVirtualizer()
+ public byte[] getDefinitionArray()
{
- return virtualizer;
+ String configuration = this.vmConfig.toString();
+
+ if ( configuration == null ) {
+ return null;
+ } else {
+ // append newline at the end of the XML content to match the structure of an original Libvirt XML file
+ configuration += System.lineSeparator();
+ return configuration.getBytes( StandardCharsets.UTF_8 );
+ }
}
@Override
- public boolean tweakForNonPersistent()
+ public boolean addEthernet( EtherType type )
+ {
+ return this.addEthernet( this.vmDeviceIndexEthernetAdd++, type );
+ }
+
+ /**
+ * Adds an ethernet card to the QEMU virtual machine configuration.
+ *
+ * @param index current index of the ethernet card to be added to the virtual machine
+ * configuration.
+ * @param type card model of the ethernet card.
+ * @return result state of adding the ethernet card.
+ */
+ public boolean addEthernet( int index, EtherType type )
{
+ QemuEthernetDevTypeMeta defaultNetworkDeviceConfig = this.networkCards.get( EthernetDevType.AUTO );
+ ArrayList<Interface> interfaceDevices = this.vmConfig.getInterfaceDevices();
+ Interface interfaceDevice = QemuMetaDataUtils.getArrayIndex( interfaceDevices, index );
+
+ final Interface.Model defaultNetworkDeviceModel = defaultNetworkDeviceConfig.getModel();
+
+ if ( interfaceDevice == null ) {
+ // network interface device does not exist, so create new network interface device
+ switch ( type ) {
+ case BRIDGED:
+ // add network bridge interface device
+ interfaceDevice = this.vmConfig.addInterfaceBridgeDevice();
+ interfaceDevice.setModel( defaultNetworkDeviceModel );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_BRIDGE );
+ break;
+ case HOST_ONLY:
+ // add network interface device with link to the isolated host network
+ interfaceDevice = this.vmConfig.addInterfaceNetworkDevice();
+ interfaceDevice.setModel( defaultNetworkDeviceModel );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_HOST_ONLY );
+ break;
+ case NAT:
+ // add network interface device with link to the NAT network
+ interfaceDevice = this.vmConfig.addInterfaceNetworkDevice();
+ interfaceDevice.setModel( defaultNetworkDeviceModel );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_NAT );
+ break;
+ }
+ } else {
+ // network interface device exists, so update existing network interface device
+ switch ( type ) {
+ case BRIDGED:
+ interfaceDevice.setType( Interface.Type.BRIDGE );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_BRIDGE );
+ break;
+ case HOST_ONLY:
+ interfaceDevice.setType( Interface.Type.NETWORK );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_HOST_ONLY );
+ break;
+ case NAT:
+ interfaceDevice.setType( Interface.Type.NETWORK );
+ interfaceDevice.setSource( QemuMetaData.NETWORK_DEFAULT_NAT );
+ break;
+ }
+ }
+
return false;
}
@Override
- public void registerVirtualHW()
+ public Virtualizer getVirtualizer()
{
+ return QemuMetaData.VIRTUALIZER;
}
@Override
- public void setMaxUsbSpeed( VmMetaData.UsbSpeed speed )
+ public boolean tweakForNonPersistent()
{
- // TODO: Actual speed setting?
- if ( speed == null || speed == VmMetaData.UsbSpeed.NONE ) {
- arguments.remove( "usb" );
- } else {
- arguments.put( "usb", "" );
- }
+ // NOT implemented yet
+ return false;
}
@Override
- public VmMetaData.UsbSpeed getMaxUsbSpeed()
+ public void registerVirtualHW()
{
- if ( arguments.containsKey( "usb" ) )
- return VmMetaData.UsbSpeed.USB2_0; // TODO
- return VmMetaData.UsbSpeed.NONE;
+ // @formatter:off
+ soundCards.put( VmMetaData.SoundCardType.NONE, new QemuSoundCardMeta( null ) );
+ soundCards.put( VmMetaData.SoundCardType.DEFAULT, new QemuSoundCardMeta( Sound.Model.ICH9 ) );
+ soundCards.put( VmMetaData.SoundCardType.SOUND_BLASTER, new QemuSoundCardMeta( Sound.Model.SB16 ) );
+ soundCards.put( VmMetaData.SoundCardType.ES, new QemuSoundCardMeta( Sound.Model.ES1370 ) );
+ soundCards.put( VmMetaData.SoundCardType.AC, new QemuSoundCardMeta( Sound.Model.AC97 ) );
+ soundCards.put( VmMetaData.SoundCardType.HD_AUDIO, new QemuSoundCardMeta( Sound.Model.ICH9 ) );
+
+ ddacc.put( VmMetaData.DDAcceleration.OFF, new QemuDDAccelMeta( false ) );
+ ddacc.put( VmMetaData.DDAcceleration.ON, new QemuDDAccelMeta( true ) );
+
+ hwversion.put( VmMetaData.HWVersion.DEFAULT, new QemuHWVersionMeta( 0 ) );
+
+ networkCards.put( VmMetaData.EthernetDevType.NONE, new QemuEthernetDevTypeMeta( null ) );
+ networkCards.put( VmMetaData.EthernetDevType.AUTO, new QemuEthernetDevTypeMeta( Interface.Model.VIRTIO_NET_PCI ) );
+ networkCards.put( VmMetaData.EthernetDevType.PCNETPCI2, new QemuEthernetDevTypeMeta( Interface.Model.PCNET ) );
+ networkCards.put( VmMetaData.EthernetDevType.E1000, new QemuEthernetDevTypeMeta( Interface.Model.E1000 ) );
+ networkCards.put( VmMetaData.EthernetDevType.E1000E, new QemuEthernetDevTypeMeta( Interface.Model.E1000E ) );
+ networkCards.put( VmMetaData.EthernetDevType.VMXNET3, new QemuEthernetDevTypeMeta( Interface.Model.VMXNET3 ) );
+ networkCards.put( VmMetaData.EthernetDevType.PARAVIRT, new QemuEthernetDevTypeMeta( Interface.Model.VIRTIO_NET_PCI ) );
+
+ usbSpeeds.put( VmMetaData.UsbSpeed.NONE, new QemuUsbSpeedMeta( 0, ControllerUsb.Model.NONE ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB1_1, new QemuUsbSpeedMeta( 1, ControllerUsb.Model.ICH9_UHCI1 ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB2_0, new QemuUsbSpeedMeta( 2, ControllerUsb.Model.ICH9_EHCI1 ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB3_0, new QemuUsbSpeedMeta( 3, ControllerUsb.Model.QEMU_XHCI ) );
+ // @formatter:on
}
-
}
diff --git a/src/main/java/org/openslx/util/vm/QemuMetaDataUtils.java b/src/main/java/org/openslx/util/vm/QemuMetaDataUtils.java
new file mode 100644
index 0000000..42c3fb6
--- /dev/null
+++ b/src/main/java/org/openslx/util/vm/QemuMetaDataUtils.java
@@ -0,0 +1,188 @@
+package org.openslx.util.vm;
+
+import java.util.ArrayList;
+
+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.libvirt.domain.device.Sound;
+import org.openslx.util.vm.VmMetaData.DriveBusType;
+import org.openslx.util.vm.VmMetaData.EthernetDevType;
+import org.openslx.util.vm.VmMetaData.SoundCardType;
+
+/**
+ * Collection of utils to convert data types from bwLehrpool to Libvirt and vice versa.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class QemuMetaDataUtils
+{
+ /**
+ * Converts a Libvirt disk device bus type to a VM metadata driver bus type.
+ *
+ * @param busType Libvirt disk device bus type.
+ * @return VM metadata bus type of the disk drive.
+ */
+ public static DriveBusType convertBusType( Disk.BusType busType )
+ {
+ DriveBusType type = null;
+
+ switch ( busType ) {
+ case IDE:
+ type = DriveBusType.IDE;
+ break;
+ case SATA:
+ type = DriveBusType.SATA;
+ break;
+ case SCSI:
+ type = DriveBusType.SCSI;
+ break;
+ default:
+ type = null;
+ break;
+ }
+
+ return type;
+ }
+
+ /**
+ * Converts a VM metadata driver bus type to a Libvirt disk device bus type.
+ *
+ * @param busType VM metadata bus type of the disk drive.
+ * @return Libvirt disk device bus type.
+ */
+ public static Disk.BusType convertBusType( DriveBusType busType )
+ {
+ Disk.BusType type = null;
+
+ switch ( busType ) {
+ case IDE:
+ type = BusType.IDE;
+ break;
+ case SATA:
+ type = BusType.SATA;
+ break;
+ case SCSI:
+ type = BusType.SCSI;
+ break;
+ }
+
+ return type;
+ }
+
+ /**
+ * Converts a Libvirt sound device model to a VM metadata sound card type.
+ *
+ * @param soundDeviceModel Libvirt sound device model.
+ * @return VM metadata sound card type.
+ */
+ public static SoundCardType convertSoundDeviceModel( Sound.Model soundDeviceModel )
+ {
+ SoundCardType type = SoundCardType.NONE;
+
+ switch ( soundDeviceModel ) {
+ case AC97:
+ type = SoundCardType.AC;
+ break;
+ case ES1370:
+ type = SoundCardType.ES;
+ break;
+ case ICH6:
+ type = SoundCardType.HD_AUDIO;
+ break;
+ case ICH9:
+ type = SoundCardType.HD_AUDIO;
+ break;
+ case SB16:
+ type = SoundCardType.SOUND_BLASTER;
+ break;
+ }
+
+ return type;
+ }
+
+ /**
+ * Converts a Libvirt network device model to a VM metadata ethernet device type.
+ *
+ * @param soundDeviceModel Libvirt network device model.
+ * @return VM metadata ethernet device type.
+ */
+ public static EthernetDevType convertNetworkDeviceModel( Interface.Model networkDeviceModel )
+ {
+ EthernetDevType type = EthernetDevType.NONE;
+
+ switch ( networkDeviceModel ) {
+ case E1000:
+ type = EthernetDevType.E1000;
+ break;
+ case E1000E:
+ type = EthernetDevType.E1000E;
+ break;
+ case PCNET:
+ type = EthernetDevType.PCNETPCI2;
+ break;
+ case VIRTIO:
+ type = EthernetDevType.PARAVIRT;
+ break;
+ case VIRTIO_NET_PCI:
+ type = EthernetDevType.PARAVIRT;
+ break;
+ case VIRTIO_NET_PCI_NON_TRANSITIONAL:
+ type = EthernetDevType.PARAVIRT;
+ break;
+ case VIRTIO_NET_PCI_TRANSITIONAL:
+ type = EthernetDevType.PARAVIRT;
+ break;
+ case VMXNET3:
+ type = EthernetDevType.VMXNET3;
+ break;
+ default:
+ type = EthernetDevType.AUTO;
+ break;
+ }
+
+ return type;
+ }
+
+ /**
+ * Returns an item from a given {@link ArrayList}.
+ *
+ * The item is selected by a given index. If the item is not available within the
+ * {@link ArrayList}, <code>null</code> is returned.
+ *
+ * @param <T> type of the {@link ArrayList}.
+ * @param array {@link ArrayList} of type <code>T</code>.
+ * @param index selects the item from the {@link ArrayList}.
+ * @return selected item of the {@link ArrayList}.
+ */
+ public static <T> T getArrayIndex( ArrayList<T> array, int index )
+ {
+ T ret;
+
+ try {
+ ret = array.get( index );
+ } catch ( IndexOutOfBoundsException e ) {
+ ret = null;
+ }
+
+ return ret;
+ }
+
+ /**
+ * Creates an alphabetical device name constructed from a device prefix and a device number.
+ *
+ * @param devicePrefix prefix of the constructed device name.
+ * @param deviceNumber number of the device.
+ * @return alphabetical device name.
+ */
+ public 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." );
+ throw new IllegalArgumentException( errorMsg );
+ }
+
+ return devicePrefix + ( 'a' + deviceNumber );
+ }
+}
diff --git a/src/main/java/org/openslx/util/vm/VboxMetaData.java b/src/main/java/org/openslx/util/vm/VboxMetaData.java
index da5189e..82936a7 100644
--- a/src/main/java/org/openslx/util/vm/VboxMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VboxMetaData.java
@@ -6,6 +6,7 @@ import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;
@@ -14,6 +15,7 @@ import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.thrifthelper.TConst;
+import org.openslx.util.vm.DiskImage.ImageFormat;
import org.openslx.util.vm.VboxConfig.PlaceHolder;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
@@ -77,6 +79,12 @@ class VBoxUsbSpeedMeta
public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta, VBoxHWVersionMeta, VBoxEthernetDevTypeMeta, VBoxUsbSpeedMeta>
{
+ /**
+ * List of supported image formats by the VirtualBox hypervisor.
+ */
+ private static final List<DiskImage.ImageFormat> SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableList(
+ Arrays.asList( ImageFormat.VDI ) );
+
private static final Logger LOGGER = Logger.getLogger( VboxMetaData.class );
private static final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_VIRTUALBOX, "VirtualBox" );
@@ -125,6 +133,12 @@ public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta,
{
return virtualizer;
}
+
+ @Override
+ public List<DiskImage.ImageFormat> getSupportedImageFormats()
+ {
+ return VboxMetaData.SUPPORTED_IMAGE_FORMATS;
+ }
@Override
public void applySettingsForLocalEdit()
diff --git a/src/main/java/org/openslx/util/vm/VmMetaData.java b/src/main/java/org/openslx/util/vm/VmMetaData.java
index c836697..c872450 100644
--- a/src/main/java/org/openslx/util/vm/VmMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VmMetaData.java
@@ -282,6 +282,13 @@ public abstract class VmMetaData<T, U, V, W, X>
}
/**
+ * Returns list of image formats supported by the VM's hypervisor.
+ *
+ * @return list of image formats.
+ */
+ public abstract List<DiskImage.ImageFormat> getSupportedImageFormats();
+
+ /**
* Apply config options that are desired when locally editing a VM. for vmware,
* this disables automatic DPI scaling of the guest.
*/
@@ -310,7 +317,7 @@ public abstract class VmMetaData<T, U, V, W, X>
try {
return new QemuMetaData( osList, file );
} catch ( Exception e ) {
- LOGGER.info( "Not a QEmu file", e );
+ LOGGER.info( "Not a Qemu file", e );
}
try {
// TODO This will work for each file because simple read as byte array
diff --git a/src/main/java/org/openslx/util/vm/VmwareMetaData.java b/src/main/java/org/openslx/util/vm/VmwareMetaData.java
index 2835e22..1793655 100644
--- a/src/main/java/org/openslx/util/vm/VmwareMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VmwareMetaData.java
@@ -3,6 +3,8 @@ package org.openslx.util.vm;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -15,6 +17,7 @@ import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.thrifthelper.TConst;
import org.openslx.util.Util;
+import org.openslx.util.vm.DiskImage.ImageFormat;
import org.openslx.util.vm.VmwareConfig.ConfigEntry;
class VmWareSoundCardMeta
@@ -73,7 +76,12 @@ class VmwareUsbSpeed
public class VmwareMetaData extends VmMetaData<VmWareSoundCardMeta, VmWareDDAccelMeta, VmWareHWVersionMeta, VmWareEthernetDevTypeMeta, VmwareUsbSpeed>
{
-
+ /**
+ * List of supported image formats by the VMware hypervisor.
+ */
+ private static final List<DiskImage.ImageFormat> SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableList(
+ Arrays.asList( ImageFormat.VMDK ) );
+
private static final Logger LOGGER = Logger.getLogger( VmwareMetaData.class );
private static final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_VMWARE, "VMware" );
@@ -246,6 +254,12 @@ public class VmwareMetaData extends VmMetaData<VmWareSoundCardMeta, VmWareDDAcce
}
@Override
+ public List<DiskImage.ImageFormat> getSupportedImageFormats()
+ {
+ return VmwareMetaData.SUPPORTED_IMAGE_FORMATS;
+ }
+
+ @Override
public boolean addHddTemplate( File diskImage, String hddMode, String redoDir )
{
return addHddTemplate( diskImage.getName(), hddMode, redoDir );
diff --git a/src/main/resources/libvirt/xsl/xml-output-transformation.xsl b/src/main/resources/libvirt/xsl/xml-output-transformation.xsl
new file mode 100644
index 0000000..febed54
--- /dev/null
+++ b/src/main/resources/libvirt/xsl/xml-output-transformation.xsl
@@ -0,0 +1,12 @@
+<xsl:stylesheet version="1.0"
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ xmlns:xalan="http://xml.apache.org/xalan">
+ <xsl:output method="xml" omit-xml-declaration="yes"
+ encoding="UTF-8" indent="yes" xalan:indent-amount="2" />
+ <xsl:strip-space elements="*" />
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*|node()" />
+ </xsl:copy>
+ </xsl:template>
+</xsl:stylesheet>
diff --git a/src/test/java/org/openslx/util/vm/QemuMetaDataTest.java b/src/test/java/org/openslx/util/vm/QemuMetaDataTest.java
new file mode 100644
index 0000000..f201a77
--- /dev/null
+++ b/src/test/java/org/openslx/util/vm/QemuMetaDataTest.java
@@ -0,0 +1,466 @@
+package org.openslx.util.vm;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.params.provider.Arguments.arguments;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.ControllerUsb;
+import org.openslx.libvirt.domain.device.DiskCdrom;
+import org.openslx.libvirt.domain.device.DiskFloppy;
+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.util.vm.DiskImage.ImageFormat;
+import org.openslx.util.vm.VmMetaData.EtherType;
+import org.openslx.util.vm.VmMetaData.EthernetDevType;
+import org.openslx.util.vm.VmMetaData.SoundCardType;
+import org.openslx.util.vm.VmMetaData.UsbSpeed;
+
+public class QemuMetaDataTest
+{
+ private static Domain getPrivateDomainFromQemuMetaData( QemuMetaData qemuMetadata )
+ throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
+ {
+ Field privateDomainField = QemuMetaData.class.getDeclaredField( "vmConfig" );
+ privateDomainField.setAccessible( true );
+ return Domain.class.cast( privateDomainField.get( qemuMetadata ) );
+ }
+
+ @BeforeAll
+ public static void setUp()
+ {
+ // disable logging with log4j
+ LogManager.getRootLogger().setLevel( Level.OFF );
+ }
+
+ @Test
+ @DisplayName( "Test display name from VM configuration" )
+ public void testQemuMetaDataGetDisplayName() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final String displayName = vmConfig.getDisplayName();
+
+ assertEquals( "archlinux", displayName );
+ }
+
+ @Test
+ @DisplayName( "Test machine snapshot state from VM configuration" )
+ public void testQemuMetaDataIsMachineSnapshot() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final boolean isVmSnapshot = vmConfig.isMachineSnapshot();
+
+ assertEquals( false, isVmSnapshot );
+ }
+
+ @Test
+ @DisplayName( "Test supported image formats from VM configuration" )
+ public void testQemuMetaDataGetSupportedImageFormats() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final List<DiskImage.ImageFormat> supportedImageFormats = vmConfig.getSupportedImageFormats();
+
+ assertNotNull( supportedImageFormats );
+ assertEquals( 3, supportedImageFormats.size() );
+ assertEquals( true, supportedImageFormats
+ .containsAll( Arrays.asList( ImageFormat.QCOW2, ImageFormat.VMDK, ImageFormat.VDI ) ) );
+ }
+
+ @Test
+ @DisplayName( "Test output of HDDs from VM configuration" )
+ public void testQemuMetaDataGetHdds() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final List<VmMetaData.HardDisk> hdds = vmConfig.getHdds();
+
+ assertNotNull( hdds );
+ assertEquals( 1, hdds.size() );
+ assertEquals( "/var/lib/libvirt/images/archlinux.qcow2", hdds.get( 0 ).diskImage );
+ }
+
+ @Test
+ @DisplayName( "Test output of unfiltered VM configuration" )
+ public void testQemuMetaDataGetDefinitionArray() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final String unfilteredXmlConfig = new String( vmConfig.getDefinitionArray(), StandardCharsets.UTF_8 );
+ final String originalXmlConfig = FileUtils.readFileToString( file, StandardCharsets.UTF_8 );
+
+ assertNotNull( unfilteredXmlConfig );
+
+ final int lengthUnfilteredXmlConfig = unfilteredXmlConfig.split( System.lineSeparator() ).length;
+ final int lengthOriginalXmlConfig = originalXmlConfig.split( System.lineSeparator() ).length;
+
+ assertEquals( lengthOriginalXmlConfig, lengthUnfilteredXmlConfig );
+ }
+
+ @Test
+ @DisplayName( "Test output of filtered VM configuration" )
+ public void testQemuMetaDataGetFilteredDefinitionArray() throws UnsupportedVirtualizerFormatException, IOException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ final int numberOfDeletedElements = 4;
+
+ final String filteredXmlConfig = new String( vmConfig.getFilteredDefinitionArray(), StandardCharsets.UTF_8 );
+ final String originalXmlConfig = FileUtils.readFileToString( file, StandardCharsets.UTF_8 );
+
+ assertNotNull( filteredXmlConfig );
+
+ final int lengthFilteredXmlConfig = filteredXmlConfig.split( System.lineSeparator() ).length;
+ final int lengthOriginalXmlConfig = originalXmlConfig.split( System.lineSeparator() ).length;
+
+ assertEquals( lengthOriginalXmlConfig, lengthFilteredXmlConfig + numberOfDeletedElements );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add HDD to VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-hdd.xml" } )
+ public void testQemuMetaDataAddHdd( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File diskFile = DiskImageTestResources.getDiskFile( "image-default.qcow2" );
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numHddsLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getDiskStorageDevices().size();
+ final int numHddsQemuMetaDataBeforeAdd = vmConfig.hdds.size();
+
+ vmConfig.addHddTemplate( diskFile, null, null );
+
+ final int numHddsLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getDiskStorageDevices().size();
+ final int numHddsQemuMetaDataAfterAdd = vmConfig.hdds.size();
+
+ assertTrue( numHddsLibvirtDomainXmlBeforeAdd == numHddsQemuMetaDataBeforeAdd );
+ assertTrue( numHddsLibvirtDomainXmlAfterAdd == numHddsQemuMetaDataAfterAdd );
+ assertTrue( numHddsQemuMetaDataBeforeAdd >= 0 );
+ assertTrue( numHddsQemuMetaDataAfterAdd > 0 );
+
+ if ( numHddsQemuMetaDataBeforeAdd >= 1 ) {
+ // update existing HDD in the Libvirt XML config, but do not add a new HDD
+ assertEquals( numHddsQemuMetaDataBeforeAdd, numHddsQemuMetaDataAfterAdd );
+ } else {
+ // numHddsQemuMetaDataBeforeAdd == 0
+ // add a HDD to the Libvirt XML config, since there was no HDD available
+ assertEquals( numHddsQemuMetaDataBeforeAdd + 1, numHddsQemuMetaDataAfterAdd );
+ }
+
+ DiskStorage addedStorageDevice = vmLibvirtDomainConfig.getDiskStorageDevices().get( 0 );
+ assertEquals( diskFile.getAbsolutePath(), addedStorageDevice.getStorageSource() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add CDROM to VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-cdrom.xml" } )
+ public void testQemuMetaDataAddCdrom( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File diskFile = DiskImageTestResources.getDiskFile( "image-default.qcow2" );
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numCdromsLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getDiskCdromDevices().size();
+
+ vmConfig.addCdrom( 0, diskFile.getAbsolutePath() );
+
+ final int numCdromsLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getDiskCdromDevices().size();
+
+ assertTrue( numCdromsLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numCdromsLibvirtDomainXmlAfterAdd > 0 );
+
+ DiskCdrom addedCdromDevice = vmLibvirtDomainConfig.getDiskCdromDevices().get( 0 );
+ assertEquals( diskFile.getAbsolutePath(), addedCdromDevice.getStorageSource() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add physical CDROM drive to VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-cdrom.xml" } )
+ public void testQemuMetaDataAddPhysicalCdromDrive( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numCdromsLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getDiskCdromDevices().size();
+
+ vmConfig.addCdrom( 0, null );
+
+ final int numCdromsLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getDiskCdromDevices().size();
+
+ assertTrue( numCdromsLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numCdromsLibvirtDomainXmlAfterAdd > 0 );
+
+ DiskCdrom addedCdromDevice = vmLibvirtDomainConfig.getDiskCdromDevices().get( 0 );
+ assertEquals( QemuMetaData.CDROM_DEFAULT_PHYSICAL_DRIVE, addedCdromDevice.getStorageSource() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add floppy to VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-floppy.xml" } )
+ public void testQemuMetaDataAddFloppy( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File diskFile = DiskImageTestResources.getDiskFile( "image-default.qcow2" );
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numFloppiesLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getDiskFloppyDevices().size();
+
+ vmConfig.addFloppy( 0, diskFile.getAbsolutePath(), true );
+
+ final int numFloppiesLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getDiskFloppyDevices().size();
+
+ assertTrue( numFloppiesLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numFloppiesLibvirtDomainXmlAfterAdd > 0 );
+
+ DiskFloppy addedFloppyDevice = vmLibvirtDomainConfig.getDiskFloppyDevices().get( 0 );
+ assertTrue( addedFloppyDevice.isReadOnly() );
+ assertEquals( diskFile.getAbsolutePath(), addedFloppyDevice.getStorageSource() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add CPU core count to VM configuration" )
+ @ValueSource( ints = { 2, 4, 6, 8 } )
+ public void testQemuMetaDataAddCpuCoreCount( int coreCount )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( "qemu-kvm_default-archlinux-vm.xml" );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ vmConfig.addCpuCoreCount( coreCount );
+
+ assertEquals( coreCount, vmLibvirtDomainConfig.getVCpu() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test get sound card from VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-sound.xml" } )
+ public void testQemuMetaDataGetSoundCardType( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ SoundCardType soundCardType = vmConfig.getSoundCard();
+
+ if ( vmLibvirtDomainConfig.getSoundDevices().isEmpty() ) {
+ assertEquals( SoundCardType.NONE, soundCardType );
+ } else {
+ assertEquals( SoundCardType.HD_AUDIO, soundCardType );
+ }
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test set sound card in VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-sound.xml" } )
+ public void testQemuMetaDataSetSoundCardType( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numSoundDevsLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getSoundDevices().size();
+
+ vmConfig.setSoundCard( SoundCardType.SOUND_BLASTER );
+
+ final int numSoundDevsLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getSoundDevices().size();
+
+ assertTrue( numSoundDevsLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numSoundDevsLibvirtDomainXmlAfterAdd > 0 );
+
+ Sound addedSoundDevice = vmLibvirtDomainConfig.getSoundDevices().get( 0 );
+ assertEquals( Sound.Model.SB16, addedSoundDevice.getModel() );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test get ethernet device type from VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-nic.xml" } )
+ public void testQemuMetaDataGetEthernetDevType( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ EthernetDevType ethernetDeviceType = vmConfig.getEthernetDevType( 0 );
+
+ if ( vmLibvirtDomainConfig.getInterfaceDevices().isEmpty() ) {
+ assertEquals( EthernetDevType.NONE, ethernetDeviceType );
+ } else {
+ assertEquals( EthernetDevType.PARAVIRT, ethernetDeviceType );
+ }
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test set ethernet device type in VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-nic.xml" } )
+ public void testQemuMetaDataSetEthernetDevType( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ vmConfig.setEthernetDevType( 0, EthernetDevType.E1000E );
+
+ if ( !vmLibvirtDomainConfig.getInterfaceDevices().isEmpty() ) {
+ Interface addedEthernetDevice = vmLibvirtDomainConfig.getInterfaceDevices().get( 0 );
+ assertEquals( Interface.Model.E1000E, addedEthernetDevice.getModel() );
+ }
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test get maximal USB speed from VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-usb.xml" } )
+ public void testQemuMetaDataGetMaxUsbSpeed( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ UsbSpeed maxUsbSpeed = vmConfig.getMaxUsbSpeed();
+
+ if ( vmLibvirtDomainConfig.getUsbControllerDevices().isEmpty() ) {
+ assertEquals( UsbSpeed.NONE, maxUsbSpeed );
+ } else {
+ assertEquals( UsbSpeed.USB3_0, maxUsbSpeed );
+ }
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test set maximal USB speed in VM configuration" )
+ @ValueSource( strings = { "qemu-kvm_default-archlinux-vm.xml", "qemu-kvm_default-archlinux-vm-no-usb.xml" } )
+ public void testQemuMetaDataSetMaxUsbSpeed( String xmlFileName )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numUsbControllersLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getUsbControllerDevices().size();
+
+ vmConfig.setMaxUsbSpeed( UsbSpeed.USB2_0 );
+
+ final int numUsbControllersLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getUsbControllerDevices().size();
+
+ assertTrue( numUsbControllersLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numUsbControllersLibvirtDomainXmlAfterAdd > 0 );
+
+ ControllerUsb addedUsbControllerDevice = vmLibvirtDomainConfig.getUsbControllerDevices().get( 0 );
+ assertEquals( ControllerUsb.Model.ICH9_EHCI1, addedUsbControllerDevice.getModel() );
+ }
+
+ static Stream<Arguments> configAndEthernetTypeProvider()
+ {
+ return Stream.of(
+ arguments( "qemu-kvm_default-archlinux-vm.xml", EtherType.BRIDGED ),
+ arguments( "qemu-kvm_default-archlinux-vm.xml", EtherType.HOST_ONLY ),
+ arguments( "qemu-kvm_default-archlinux-vm.xml", EtherType.NAT ),
+ arguments( "qemu-kvm_default-archlinux-vm-no-usb.xml", EtherType.BRIDGED ),
+ arguments( "qemu-kvm_default-archlinux-vm-no-usb.xml", EtherType.HOST_ONLY ),
+ arguments( "qemu-kvm_default-archlinux-vm-no-usb.xml", EtherType.NAT ) );
+ }
+
+ @ParameterizedTest
+ @DisplayName( "Test add ethernet device to VM configuration" )
+ @MethodSource( "configAndEthernetTypeProvider" )
+ public void testQemuMetaDataAddEthernet( String xmlFileName, EtherType ethernetType )
+ throws UnsupportedVirtualizerFormatException, NoSuchFieldException, SecurityException,
+ IllegalArgumentException, IllegalAccessException
+ {
+ File file = LibvirtXmlTestResources.getLibvirtXmlFile( xmlFileName );
+ QemuMetaData vmConfig = new QemuMetaData( null, file );
+
+ Domain vmLibvirtDomainConfig = QemuMetaDataTest.getPrivateDomainFromQemuMetaData( vmConfig );
+
+ final int numEthernetDevsLibvirtDomainXmlBeforeAdd = vmLibvirtDomainConfig.getInterfaceDevices().size();
+
+ vmConfig.addEthernet( ethernetType );
+
+ final int numEthernetDevsLibvirtDomainXmlAfterAdd = vmLibvirtDomainConfig.getInterfaceDevices().size();
+
+ assertTrue( numEthernetDevsLibvirtDomainXmlBeforeAdd >= 0 );
+ assertTrue( numEthernetDevsLibvirtDomainXmlAfterAdd > 0 );
+
+ Interface addedEthernetDevice = vmLibvirtDomainConfig.getInterfaceDevices().get( 0 );
+ switch ( ethernetType ) {
+ case BRIDGED:
+ assertEquals( Interface.Type.BRIDGE, addedEthernetDevice.getType() );
+ assertEquals( Interface.Model.VIRTIO, addedEthernetDevice.getModel() );
+ assertEquals( QemuMetaData.NETWORK_DEFAULT_BRIDGE, addedEthernetDevice.getSource() );
+ break;
+ case HOST_ONLY:
+ assertEquals( Interface.Type.NETWORK, addedEthernetDevice.getType() );
+ assertEquals( Interface.Model.VIRTIO, addedEthernetDevice.getModel() );
+ assertEquals( QemuMetaData.NETWORK_DEFAULT_HOST_ONLY, addedEthernetDevice.getSource() );
+ break;
+ case NAT:
+ assertEquals( Interface.Type.NETWORK, addedEthernetDevice.getType() );
+ assertEquals( Interface.Model.VIRTIO, addedEthernetDevice.getModel() );
+ assertEquals( QemuMetaData.NETWORK_DEFAULT_NAT, addedEthernetDevice.getSource() );
+ break;
+ }
+ }
+}