summaryrefslogtreecommitdiffstats
path: root/core/modules/qemu
diff options
context:
space:
mode:
authorManuel Bentele2021-11-09 14:18:51 +0100
committerManuel Bentele2021-11-09 14:18:51 +0100
commit7a4522d6b59ad2936e5ce0ed466f57b8546991b3 (patch)
tree74cde08e0508f1c3e338a786fb8960a3c83cd60e /core/modules/qemu
parentsetup_target: Only install packages of selected modules (diff)
downloadmltk-7a4522d6b59ad2936e5ce0ed466f57b8546991b3.tar.gz
mltk-7a4522d6b59ad2936e5ce0ed466f57b8546991b3.tar.xz
mltk-7a4522d6b59ad2936e5ce0ed466f57b8546991b3.zip
[qemu] Add automatic firmware path transformation for UEFI based VMs
Diffstat (limited to 'core/modules/qemu')
-rw-r--r--core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemukvm/run-virt.include4
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/pom.xml6
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java2
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java11
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmware.java289
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java8
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java28
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmwareTest.java60
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java11
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java3
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-i386-secure.json34
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-x86_64-secure.json35
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-aarch64.json31
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-arm.json31
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-i386.json33
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-x86_64.json34
16 files changed, 610 insertions, 10 deletions
diff --git a/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemukvm/run-virt.include b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemukvm/run-virt.include
index 1f61f5d9..3e0aa68c 100644
--- a/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemukvm/run-virt.include
+++ b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemukvm/run-virt.include
@@ -54,6 +54,9 @@ run_plugin() {
writelog "Failed to set up mediated device (Intel GVT-g) for GPU passthrough!"
fi
+ # set path to QEMU firmware specification files
+ local firmware_path="/usr/share/qemu/firmware"
+
# set debug related options
if [ "${DEBUG}" = "true" ]; then
# write finalized config in debug mode to temporary folder for debugging purposes
@@ -75,6 +78,7 @@ run_plugin() {
VIRTCMDOPTS=( "-jar" "${QEMU_PLUGIN_DIR}/runvirt-plugin-qemu.jar" )
notempty DEBUG && VIRTCMDOPTS+=( "-debug" "${DEBUG}" )
+ notempty firmware_path && VIRTCMDOPTS+=( "-firmware" "${firmware_path}" )
notempty VM_CLEANNAME && VIRTCMDOPTS+=( "-vmname" "${VM_CLEANNAME}" )
notempty VM_DISPLAYNAME && VIRTCMDOPTS+=( "-vmdsplname" "${VM_DISPLAYNAME}" )
notempty VM_OS_TYPE && VIRTCMDOPTS+=( "-vmos" "${VM_OS_TYPE}" )
diff --git a/core/modules/qemu/runvirt-plugin-qemu/pom.xml b/core/modules/qemu/runvirt-plugin-qemu/pom.xml
index 893f8d5c..6354a4e9 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/pom.xml
+++ b/core/modules/qemu/runvirt-plugin-qemu/pom.xml
@@ -84,6 +84,11 @@
<scope>compile</scope>
</dependency>
<dependency>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ <version>2.8.8</version>
+ </dependency>
+ <dependency>
<groupId>com.ginsberg</groupId>
<artifactId>junit5-system-exit</artifactId>
<version>1.0.0</version>
@@ -226,6 +231,7 @@
<directory>${basedir}/src/test/resources</directory>
<includes>
<include>libvirt/xml/*</include>
+ <include>qemu/firmware/*</include>
</includes>
</testResource>
</testResources>
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
index e1c2e311..86ea6e58 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
@@ -25,6 +25,7 @@ import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericParall
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuSerialDevices;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericUuid;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuArchitecture;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuFirmware;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGpuPassthroughNvidia;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGraphics;
import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuMdevPassthroughIntel;
@@ -147,6 +148,7 @@ public class App
final LibvirtHypervisorQemu hypervisorQemu = LibvirtHypervisorQemu.class.cast( hypervisor );
transformationManager.register( new TransformationSpecificQemuArchitecture( hypervisorQemu ), true );
+ transformationManager.register( new TransformationSpecificQemuFirmware( hypervisorQemu ), true );
transformationManager.register( new TransformationSpecificQemuGraphics( hypervisorQemu ), true );
transformationManager.register( new TransformationSpecificQemuSerialDevices( hypervisorQemu ), true );
transformationManager.register( new TransformationSpecificQemuMdevPassthroughIntel( hypervisorQemu ), false );
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
index cc989c75..49825813 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
@@ -161,6 +161,16 @@ public class CommandLineArgs
}
/**
+ * Returns the argument of the command line option {@link CmdLnOption#FIRMWARE}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#FIRMWARE}.
+ */
+ public String getFirmware()
+ {
+ return this.getArgument( CmdLnOption.FIRMWARE );
+ }
+
+ /**
* Returns the argument of the command line option {@link CmdLnOption#VM_CFGINP}.
*
* @return argument of the command line option {@link CmdLnOption#VM_CFGINP}.
@@ -427,6 +437,7 @@ public class CommandLineArgs
// @formatter:off
HELP ( 'h', "help", 0, "" ),
DEBUG ( 'b', "debug", 1, "Enable or disable debug mode" ),
+ FIRMWARE ( 'x', "firmware", 1, "Path to QEMU firmware specifications directory" ),
VM_CFGINP ( 'i', "vmcfginp", 1, "File name of an existing and filtered Libvirt domain XML configuration file" ),
VM_CFGOUT ( 'o', "vmcfgout", 1, "File name to output a finalized Libvirt domain XML configuration file" ),
VM_NAME ( 'n', "vmname", 1, "Name for the virtual machine" ),
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmware.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmware.java
new file mode 100644
index 00000000..6be0368e
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmware.java
@@ -0,0 +1,289 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.Reader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.function.Predicate;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
+import org.openslx.util.LevenshteinDistance;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationSpecific;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.annotations.SerializedName;
+
+class QemuFirmware
+{
+ @SerializedName( "description" )
+ private String description;
+ @SerializedName( "interface-types" )
+ private ArrayList<String> interfaceTypes;
+ @SerializedName( "mapping" )
+ private QemuFirmwareMapping mapping;
+ @SerializedName( "targets" )
+ private ArrayList<QemuFirmwareTarget> targets;
+ @SerializedName( "features" )
+ private ArrayList<String> features;
+ @SerializedName( "tags" )
+ private ArrayList<String> tags;
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public ArrayList<String> getInterfaceTypes()
+ {
+ return interfaceTypes;
+ }
+
+ public QemuFirmwareMapping getMapping()
+ {
+ return mapping;
+ }
+
+ public ArrayList<QemuFirmwareTarget> getTargets()
+ {
+ return targets;
+ }
+
+ public ArrayList<String> getFeatures()
+ {
+ return features;
+ }
+
+ public ArrayList<String> getTags()
+ {
+ return tags;
+ }
+}
+
+class QemuFirmwareMapping
+{
+ @SerializedName( "device" )
+ private String device;
+ @SerializedName( "executable" )
+ private QemuFirmwareMappingExecutable executable;
+ @SerializedName( "nvram-template" )
+ private QemuFirmwareMappingNvramTemplate nvramTemplate;
+
+ public String getDevice()
+ {
+ return device;
+ }
+
+ public QemuFirmwareMappingExecutable getExecutable()
+ {
+ return executable;
+ }
+
+ public QemuFirmwareMappingNvramTemplate getNvramTemplate()
+ {
+ return nvramTemplate;
+ }
+}
+
+class QemuFirmwareMappingExecutable
+{
+ @SerializedName( "filename" )
+ private String fileName;
+ @SerializedName( "format" )
+ private String format;
+
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public String getFormat()
+ {
+ return format;
+ }
+}
+
+class QemuFirmwareMappingNvramTemplate
+{
+ @SerializedName( "filename" )
+ private String fileName;
+ @SerializedName( "format" )
+ private String format;
+
+ public String getFileName()
+ {
+ return fileName;
+ }
+
+ public String getFormat()
+ {
+ return format;
+ }
+}
+
+class QemuFirmwareTarget
+{
+ @SerializedName( "architecture" )
+ private String architecture;
+ @SerializedName( "machines" )
+ private ArrayList<String> machines;
+
+ public String getArchitecture()
+ {
+ return architecture;
+ }
+
+ public ArrayList<String> getMachines()
+ {
+ return machines;
+ }
+}
+
+/**
+ * Specific firmware transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationSpecificQemuFirmware
+ extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "QEMU Firmware [Seabios, UEFI (OVMF)]";
+
+ /**
+ * Creates a new firmware transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @param hypervisor Libvirt/QEMU hypervisor.
+ */
+ public TransformationSpecificQemuFirmware( LibvirtHypervisorQemu virtualizer )
+ {
+ super( TransformationSpecificQemuFirmware.NAME, virtualizer );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ } else if ( args.getFirmware() == null || args.getFirmware().isEmpty() ) {
+ throw new TransformationException( "Path to QEMU firmware specifications directory is not specified!" );
+ }
+ }
+
+ private String lookupTargetOsLoader( String firmwareSpecDirectory, String sourceOsLoader, String sourceOsArch,
+ String sourceOsMachine )
+ throws TransformationException
+ {
+ String lookupOsLoader = null;
+
+ // parse and check firmware specification directory
+ final File fwSpecDirectory = new File( firmwareSpecDirectory );
+ if ( !fwSpecDirectory.exists() || !fwSpecDirectory.isDirectory() ) {
+ throw new TransformationException( "Path to QEMU firmware specifications directory is invalid!" );
+ }
+
+ // get all firmware specification files
+ final FileFilter fwSpecFilesFilter = file -> !file.isDirectory() && file.getName().endsWith( ".json" );
+ final File[] fwSpecFiles = fwSpecDirectory.listFiles( fwSpecFilesFilter );
+
+ // get paths to firmware files from firmware specification files
+ if ( fwSpecFiles != null ) {
+ final ArrayList<QemuFirmware> uefiFirmwares = new ArrayList<QemuFirmware>();
+ final Gson gson = new Gson();
+ for ( final File fwSpecFile : fwSpecFiles ) {
+ QemuFirmware firmware = null;
+
+ try {
+ final Reader jsonContent = new FileReader( fwSpecFile );
+ firmware = gson.fromJson( jsonContent, QemuFirmware.class );
+ } catch ( FileNotFoundException | JsonSyntaxException | JsonIOException e ) {
+ throw new TransformationException( e.getLocalizedMessage() );
+ }
+
+ final Predicate<String> byInterfaceType = s -> s.toLowerCase().equals( "uefi" );
+ if ( firmware.getInterfaceTypes().stream().filter( byInterfaceType ).findAny().isPresent() ) {
+ // found valid UEFI firmware
+ // check if architecture and machine type of the VM is supported by the firmware
+ final Predicate<QemuFirmwareTarget> byArchitecture = t -> sourceOsArch.equals( t.getArchitecture() );
+ final Predicate<String> byMachineType = s -> sourceOsMachine.startsWith( s.replace( "*", "" ) );
+ final Predicate<QemuFirmwareTarget> byMachines = t -> t.getMachines().stream().filter( byMachineType )
+ .findAny().isPresent();
+
+ if ( firmware.getTargets().stream().filter( byArchitecture ).filter( byMachines ).findAny()
+ .isPresent() ) {
+ // found UEFI firmware supporting suitable architecture and machine type from VM
+ uefiFirmwares.add( firmware );
+ }
+ }
+ }
+
+ if ( uefiFirmwares.isEmpty() ) {
+ throw new TransformationException( "There aren't any suitable UEFI firmwares locally available!" );
+ } else {
+ final LevenshteinDistance distance = new LevenshteinDistance( 1, 1, 1 );
+ int minFileNameDistance = Integer.MAX_VALUE;
+ Path suitablestUefiFirmwarePath = null;
+
+ for ( final QemuFirmware uefiFirmware : uefiFirmwares ) {
+ final Path uefiFirmwarePath = Paths.get( uefiFirmware.getMapping().getExecutable().getFileName() );
+ final Path sourceOsLoaderPath = Paths.get( sourceOsLoader );
+ final String uefiFirmwareFileName = uefiFirmwarePath.getFileName().toString().toLowerCase();
+ final String sourceOsLoaderFileName = sourceOsLoaderPath.getFileName().toString().toLowerCase();
+
+ final int fileNameDistance = distance.calculateDistance( uefiFirmwareFileName, sourceOsLoaderFileName );
+ if ( fileNameDistance < minFileNameDistance ) {
+ minFileNameDistance = fileNameDistance;
+ suitablestUefiFirmwarePath = uefiFirmwarePath;
+ }
+ }
+
+ lookupOsLoader = suitablestUefiFirmwarePath.toString();
+ }
+ }
+
+ return lookupOsLoader;
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // get OS loader from VM
+ final String sourceOsLoader = config.getOsLoader();
+
+ // get OS architecture from VM
+ final String sourceOsArch = config.getOsArch();
+
+ // get OS machine type from VM
+ final String sourceOsMachine = config.getOsMachine();
+
+ // check if OS loader is specified
+ if ( sourceOsLoader != null && !sourceOsLoader.isEmpty() ) {
+ // OS loader is specified so transform path to specified firmware path
+ final String targetOsLoader = this.lookupTargetOsLoader( args.getFirmware(), sourceOsLoader, sourceOsArch,
+ sourceOsMachine );
+ if ( targetOsLoader != null && !targetOsLoader.isEmpty() ) {
+ config.setOsLoader( targetOsLoader );
+ }
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java
index a8618878..aca51d07 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java
@@ -63,7 +63,7 @@ public class AppTest
assertTrue( shortHelpOptionCorrectOutput.contains( App.APP_DESC ) );
// test that no error was logged and output is available
- assertEquals( 2655, shortHelpOptionCorrectOutput.length() );
+ assertEquals( 2740, shortHelpOptionCorrectOutput.length() );
assertEquals( 0, shortHelpOptionCorrectErrOutput.length() );
}
@@ -91,7 +91,7 @@ public class AppTest
assertTrue( longHelpOptionCorrectOutput.contains( App.APP_DESC ) );
// test that no error was logged and output is available
- assertEquals( 2655, longHelpOptionCorrectOutput.length() );
+ assertEquals( 2740, longHelpOptionCorrectOutput.length() );
assertEquals( 0, longHelpOptionCorrectErrOutput.length() );
}
@@ -119,7 +119,7 @@ public class AppTest
assertTrue( shortHelpOptionIncorrectOutput.contains( App.APP_DESC ) );
// test that error was logged and output is available
- assertEquals( 2655, shortHelpOptionIncorrectOutput.length() );
+ assertEquals( 2740, shortHelpOptionIncorrectOutput.length() );
assertEquals( 0, shortHelpOptionIncorrectErrOutput.length() );
}
@@ -147,7 +147,7 @@ public class AppTest
assertTrue( longHelpOptionIncorrectOutput.contains( App.APP_DESC ) );
// test that error was logged and output is available
- assertEquals( 2655, longHelpOptionIncorrectOutput.length() );
+ assertEquals( 2740, longHelpOptionIncorrectOutput.length() );
assertEquals( 0, longHelpOptionIncorrectErrOutput.length() );
}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java
index dc863088..b61e41d9 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java
@@ -142,6 +142,34 @@ public class CommandLineArgsTest
}
@Test
+ @DisplayName( "Test the parsing of the firmware path command line option (short version)" )
+ public void testCmdlnOptionFirmwareShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.FIRMWARE.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getFirmware() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the firmware command line option (long version)" )
+ public void testCmdlnOptionFirmwareLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.FIRMWARE.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getFirmware() );
+ }
+
+ @Test
@DisplayName( "Test the parsing of the VM configuration input command line option (short version)" )
public void testCmdlnOptionVmCfgInpShort() throws CommandLineArgsException
{
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmwareTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmwareTest.java
new file mode 100644
index 00000000..f469e3fc
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuFirmwareTest.java
@@ -0,0 +1,60 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import java.nio.file.Paths;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+class TransformationSpecificQemuFirmwareStub extends TransformationSpecificQemuFirmware
+{
+ public TransformationSpecificQemuFirmwareStub()
+ {
+ super( null );
+ }
+}
+
+public class TransformationSpecificQemuFirmwareTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM OS loader (firmware) configuration with specified input data" )
+ public void testTransformationSpecificQemuFirmwareUefiLoader() throws TransformationException
+ {
+ final TransformationSpecificQemuFirmwareStub transformation = new TransformationSpecificQemuFirmwareStub();
+ final Domain config = TransformationTestUtils
+ .getDomain( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_uefi.xml" );
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ assertEquals( Paths.get( "/usr/share/edk2-ovmf/x64/OVMF_CODE.fd" ).toString(), config.getOsLoader() );
+
+ transformation.transform( config, args );
+
+ assertEquals( Paths.get( "/usr/share/qemu/edk2-x86_64-code.fd" ).toString(), config.getOsLoader() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of missing VM OS loader (firmware) configuration" )
+ public void testTransformationSpecificQemuFirmwareNoLoader() throws TransformationException
+ {
+ final TransformationSpecificQemuFirmwareStub transformation = new TransformationSpecificQemuFirmwareStub();
+ final Domain config = TransformationTestUtils
+ .getDomain( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent.xml" );
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ assertNull( config.getOsLoader() );
+
+ transformation.transform( config, args );
+
+ assertNull( config.getOsLoader() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java
index b04685f9..2c278f23 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java
@@ -5,13 +5,12 @@ import java.net.URL;
public class TransformationTestResources
{
- private static final String LIBVIRT_PREFIX_PATH = File.separator + "libvirt";
- private static final String LIBVIRT_PREFIX_PATH_XML = LIBVIRT_PREFIX_PATH + File.separator + "xml";
+ private static final String QEMU_PREFIX_PATH = File.separator + "qemu";
+ private static final String QEMU_PREFIX_PATH_FW = QEMU_PREFIX_PATH + File.separator + "firmware";
- public static File getLibvirtXmlFile( String libvirtXmlFileName )
+ public static String getQemuFirmwareSpecPath()
{
- String libvirtXmlPath = TransformationTestResources.LIBVIRT_PREFIX_PATH_XML + File.separator + libvirtXmlFileName;
- URL libvirtXml = TransformationTestResources.class.getResource( libvirtXmlPath );
- return new File( libvirtXml.getFile() );
+ final URL qemuFwSpecPath = TransformationTestResources.class.getResource( QEMU_PREFIX_PATH_FW );
+ return qemuFwSpecPath.getFile();
}
}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java
index 2a811f2a..5123cae1 100644
--- a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java
@@ -15,6 +15,7 @@ import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgsTest;
public class TransformationTestUtils
{
// @formatter:off
+ public static final String DEFAULT_FW_PATH = TransformationTestResources.getQemuFirmwareSpecPath();
public static final String DEFAULT_VM_NAME = "archlinux";
public static final String DEFAULT_VM_UUID = "4ec504d5-5eac-482f-a344-dbf1dd4956c8";
public static final String DEFAULT_VM_DSPLNAME = "Archlinux";
@@ -40,6 +41,8 @@ public class TransformationTestUtils
// @formatter:on
private static final String[] DEFAULT_CMDLN_ARGS = {
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.FIRMWARE.getLongOption(),
+ TransformationTestUtils.DEFAULT_FW_PATH,
CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NAME.getLongOption(),
TransformationTestUtils.DEFAULT_VM_NAME,
CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_UUID.getLongOption(),
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-i386-secure.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-i386-secure.json
new file mode 100644
index 00000000..9838f16a
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-i386-secure.json
@@ -0,0 +1,34 @@
+{
+ "description": "UEFI firmware for i386, with Secure Boot and SMM",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-i386-secure-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-i386-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "i386",
+ "machines": [
+ "pc-q35-*"
+ ]
+ }
+ ],
+ "features": [
+ "acpi-s3",
+ "requires-smm",
+ "secure-boot",
+ "verbose-dynamic"
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-x86_64-secure.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-x86_64-secure.json
new file mode 100644
index 00000000..12fa688c
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/50-edk2-x86_64-secure.json
@@ -0,0 +1,35 @@
+{
+ "description": "UEFI firmware for x86_64, with Secure Boot and SMM",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-x86_64-secure-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-i386-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "x86_64",
+ "machines": [
+ "pc-q35-*"
+ ]
+ }
+ ],
+ "features": [
+ "acpi-s3",
+ "amd-sev",
+ "requires-smm",
+ "secure-boot",
+ "verbose-dynamic"
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-aarch64.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-aarch64.json
new file mode 100644
index 00000000..52a65c73
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-aarch64.json
@@ -0,0 +1,31 @@
+{
+ "description": "UEFI firmware for aarch64",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-aarch64-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-arm-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "aarch64",
+ "machines": [
+ "virt-*"
+ ]
+ }
+ ],
+ "features": [
+ "verbose-static"
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-arm.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-arm.json
new file mode 100644
index 00000000..8dc6e0f1
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-arm.json
@@ -0,0 +1,31 @@
+{
+ "description": "UEFI firmware for arm",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-arm-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-arm-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "arm",
+ "machines": [
+ "virt-*"
+ ]
+ }
+ ],
+ "features": [
+ "verbose-static"
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-i386.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-i386.json
new file mode 100644
index 00000000..f0929ed5
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-i386.json
@@ -0,0 +1,33 @@
+{
+ "description": "UEFI firmware for i386",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-i386-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-i386-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "i386",
+ "machines": [
+ "pc-i440fx-*",
+ "pc-q35-*"
+ ]
+ }
+ ],
+ "features": [
+ "acpi-s3",
+ "verbose-dynamic"
+ ],
+ "tags": [
+
+ ]
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-x86_64.json b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-x86_64.json
new file mode 100644
index 00000000..d0b6542c
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/resources/qemu/firmware/60-edk2-x86_64.json
@@ -0,0 +1,34 @@
+{
+ "description": "UEFI firmware for x86_64",
+ "interface-types": [
+ "uefi"
+ ],
+ "mapping": {
+ "device": "flash",
+ "executable": {
+ "filename": "/usr/share/qemu/edk2-x86_64-code.fd",
+ "format": "raw"
+ },
+ "nvram-template": {
+ "filename": "/usr/share/qemu/edk2-i386-vars.fd",
+ "format": "raw"
+ }
+ },
+ "targets": [
+ {
+ "architecture": "x86_64",
+ "machines": [
+ "pc-i440fx-*",
+ "pc-q35-*"
+ ]
+ }
+ ],
+ "features": [
+ "acpi-s3",
+ "amd-sev",
+ "verbose-dynamic"
+ ],
+ "tags": [
+
+ ]
+}