diff options
author | Manuel Bentele | 2021-08-11 16:00:36 +0200 |
---|---|---|
committer | Manuel Bentele | 2021-08-11 16:00:36 +0200 |
commit | a5b5fa1dd56279c63d572bcf6037cb59527f5e4b (patch) | |
tree | 715bf10ed874ee7fbd7f47aad46f39ff2a8ae2b9 | |
parent | Implement blocking network.target and network-online.target (diff) | |
download | mltk-a5b5fa1dd56279c63d572bcf6037cb59527f5e4b.tar.gz mltk-a5b5fa1dd56279c63d572bcf6037cb59527f5e4b.tar.xz mltk-a5b5fa1dd56279c63d572bcf6037cb59527f5e4b.zip |
[qemu] Add transformation of Libvirt graphics type to local SPICE graphics
4 files changed, 215 insertions, 3 deletions
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 c9d47f5e..5d6bb136 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 @@ -26,6 +26,7 @@ import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuS import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericUuid; import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuArchitecture; import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGpuPassthroughNvidia; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGraphics; import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu; import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu.QemuSessionType; import org.openslx.runvirt.viewer.Viewer; @@ -141,6 +142,7 @@ public class App final LibvirtHypervisorQemu hypervisorQemu = LibvirtHypervisorQemu.class.cast( hypervisor ); transformationManager.register( new TransformationSpecificQemuArchitecture( hypervisorQemu ), true ); + transformationManager.register( new TransformationSpecificQemuGraphics( hypervisorQemu ), true ); transformationManager.register( new TransformationSpecificQemuSerialDevices( hypervisorQemu ), true ); transformationManager.register( new TransformationSpecificQemuGpuPassthroughNvidia( hypervisorQemu ), false ); } diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphics.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphics.java new file mode 100644 index 00000000..29727bfa --- /dev/null +++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphics.java @@ -0,0 +1,110 @@ +package org.openslx.runvirt.plugin.qemu.configuration; + +import org.openslx.libvirt.domain.Domain; +import org.openslx.libvirt.domain.device.Graphics.ListenType; +import org.openslx.libvirt.domain.device.GraphicsSpice; +import org.openslx.libvirt.domain.device.GraphicsSpice.ImageCompression; +import org.openslx.libvirt.domain.device.GraphicsSpice.StreamingMode; +import org.openslx.libvirt.domain.device.GraphicsVnc; +import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs; +import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu; +import org.openslx.virtualization.configuration.transformation.TransformationException; +import org.openslx.virtualization.configuration.transformation.TransformationSpecific; + +/** + * Specific graphics transformation for Libvirt/QEMU virtualization configurations. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class TransformationSpecificQemuGraphics + extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu> +{ + /** + * Name of the configuration transformation. + */ + private static final String NAME = "QEMU Graphics [GPU emulation, framebuffer, ...]"; + + /** + * Creates a new graphics transformation for Libvirt/QEMU virtualization configurations. + * + * @param hypervisor Libvirt/QEMU hypervisor. + */ + public TransformationSpecificQemuGraphics( LibvirtHypervisorQemu virtualizer ) + { + super( TransformationSpecificQemuGraphics.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 ) { + throw new TransformationException( "Virtualization configuration is missing!" ); + } + } + + /** + * Add a SPICE graphics device configured for local access through a Unix domain socket. + * + * @param config virtualization configuration into that the SPICE graphics device is added. + * @param openGlEnabled state whether OpenGL is enabled or not. + * + * @return created SPICE graphics device instance. + */ + public GraphicsSpice addLocalSpiceGraphics( Domain config, boolean openGlEnabled ) + { + final GraphicsSpice newGraphicsSpiceDevice = config.addGraphicsSpiceDevice(); + + // select local Unix domain socket access + newGraphicsSpiceDevice.setListenType( ListenType.NONE ); + + // disable optimizations (compressions) for local usage + newGraphicsSpiceDevice.setImageCompression( ImageCompression.OFF ); + newGraphicsSpiceDevice.setPlaybackCompression( false ); + newGraphicsSpiceDevice.setStreamingMode( StreamingMode.OFF ); + + // enable OpenGL acceleration if necessary + newGraphicsSpiceDevice.setOpenGl( openGlEnabled ); + + return newGraphicsSpiceDevice; + } + + @Override + public void transform( Domain config, CommandLineArgs args ) throws TransformationException + { + // validate configuration and input arguments + this.validateInputs( config, args ); + + // convert all VNC graphics devices to local SPICE graphics devices + for ( final GraphicsVnc graphicsVncDevice : config.getGraphicVncDevices() ) { + + // remove VNC graphics device + graphicsVncDevice.remove(); + + // add SPICE graphics device with local Unix domain socket access + this.addLocalSpiceGraphics( config, false ); + } + + // convert all SPICE graphics devices to local SPICE graphics devices + for ( final GraphicsSpice graphicsSpiceDevice : config.getGraphicSpiceDevices() ) { + + if ( graphicsSpiceDevice.getListenType() != ListenType.NONE ) { + + // save state of configured OpenGL option + final boolean openGlEnabled = graphicsSpiceDevice.isOpenGlEnabled(); + + // remove VNC graphics device + graphicsSpiceDevice.remove(); + + // add SPICE graphics device with local Unix domain socket access + this.addLocalSpiceGraphics( config, openGlEnabled ); + } + } + } +} diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphicsTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphicsTest.java new file mode 100644 index 00000000..c132f5a5 --- /dev/null +++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGraphicsTest.java @@ -0,0 +1,96 @@ +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.assertFalse; + +import java.util.ArrayList; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.openslx.libvirt.domain.Domain; +import org.openslx.libvirt.domain.device.Graphics; +import org.openslx.libvirt.domain.device.GraphicsSpice; +import org.openslx.libvirt.domain.device.GraphicsSpice.ImageCompression; +import org.openslx.libvirt.domain.device.GraphicsSpice.StreamingMode; +import org.openslx.libvirt.domain.device.GraphicsVnc; +import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs; +import org.openslx.virtualization.configuration.transformation.TransformationException; + +class TransformationSpecificQemuGraphicsStub extends TransformationSpecificQemuGraphics +{ + public TransformationSpecificQemuGraphicsStub() + { + super( null ); + } +} + +public class TransformationSpecificQemuGraphicsTest +{ + @Test + @DisplayName( "Test transformation of VM SPICE graphic device configuration" ) + public void testTransformationSpecificQemuGraphicsSpice() throws TransformationException + { + final TransformationSpecificQemuGraphicsStub transformation = new TransformationSpecificQemuGraphicsStub(); + final Domain config = TransformationTestUtils.getDefaultDomain(); + final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs(); + + final ArrayList<Graphics> devicesBeforeTransformation = config.getGraphicDevices(); + assertEquals( 1, devicesBeforeTransformation.size() ); + final ArrayList<GraphicsSpice> spiceDevicesBeforeTransformation = config.getGraphicSpiceDevices(); + assertEquals( 1, spiceDevicesBeforeTransformation.size() ); + final ArrayList<GraphicsVnc> vncDevicesBeforeTransformation = config.getGraphicVncDevices(); + assertEquals( 0, vncDevicesBeforeTransformation.size() ); + + transformation.transform( config, args ); + + final ArrayList<Graphics> devicesAfterTransformation = config.getGraphicDevices(); + assertEquals( 1, devicesAfterTransformation.size() ); + final ArrayList<GraphicsSpice> spiceDevicesAfterTransformation = config.getGraphicSpiceDevices(); + assertEquals( 1, spiceDevicesAfterTransformation.size() ); + final ArrayList<GraphicsVnc> vncDevicesAfterTransformation = config.getGraphicVncDevices(); + assertEquals( 0, vncDevicesAfterTransformation.size() ); + + final GraphicsSpice spiceDeviceAfterTransformation = spiceDevicesAfterTransformation.get( 0 ); + assertEquals( ImageCompression.OFF, spiceDeviceAfterTransformation.getImageCompression() ); + assertFalse( spiceDeviceAfterTransformation.isPlaybackCompressionOn() ); + assertEquals( StreamingMode.OFF, spiceDeviceAfterTransformation.getStreamingMode() ); + assertFalse( spiceDeviceAfterTransformation.isOpenGlEnabled() ); + + assertDoesNotThrow( () -> config.validateXml() ); + } + + @Test + @DisplayName( "Test transformation of VM VNC graphic device" ) + public void testTransformationSpecificQemuGraphicsVnc() throws TransformationException + { + final TransformationSpecificQemuGraphicsStub transformation = new TransformationSpecificQemuGraphicsStub(); + final Domain config = TransformationTestUtils + .getDomain( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent_vnc.xml" ); + final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs(); + + final ArrayList<Graphics> devicesBeforeTransformation = config.getGraphicDevices(); + assertEquals( 1, devicesBeforeTransformation.size() ); + final ArrayList<GraphicsSpice> spiceDevicesBeforeTransformation = config.getGraphicSpiceDevices(); + assertEquals( 0, spiceDevicesBeforeTransformation.size() ); + final ArrayList<GraphicsVnc> vncDevicesBeforeTransformation = config.getGraphicVncDevices(); + assertEquals( 1, vncDevicesBeforeTransformation.size() ); + + transformation.transform( config, args ); + + final ArrayList<Graphics> devicesAfterTransformation = config.getGraphicDevices(); + assertEquals( 1, devicesAfterTransformation.size() ); + final ArrayList<GraphicsSpice> spiceDevicesAfterTransformation = config.getGraphicSpiceDevices(); + assertEquals( 1, spiceDevicesAfterTransformation.size() ); + final ArrayList<GraphicsVnc> vncDevicesAfterTransformation = config.getGraphicVncDevices(); + assertEquals( 0, vncDevicesAfterTransformation.size() ); + + final GraphicsSpice spiceDeviceAfterTransformation = spiceDevicesAfterTransformation.get( 0 ); + assertEquals( ImageCompression.OFF, spiceDeviceAfterTransformation.getImageCompression() ); + assertFalse( spiceDeviceAfterTransformation.isPlaybackCompressionOn() ); + assertEquals( StreamingMode.OFF, spiceDeviceAfterTransformation.getStreamingMode() ); + assertFalse( spiceDeviceAfterTransformation.isOpenGlEnabled() ); + + assertDoesNotThrow( () -> config.validateXml() ); + } +} 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 597fd8d6..7bd76be5 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 @@ -102,13 +102,12 @@ public class TransformationTestUtils return TransformationTestUtils.getCmdLnArgs( new String[] {} ); } - public static Domain getDefaultDomain() + public static Domain getDomain( String fileName ) { Domain domain = null; try { - domain = new Domain( LibvirtXmlTestResources - .getLibvirtXmlStream( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent.xml" ) ); + domain = new Domain( LibvirtXmlTestResources.getLibvirtXmlStream( fileName ) ); } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) { fail( "Cannot prepare requested Libvirt domain XML file from the resources folder: " + e.getLocalizedMessage() ); @@ -116,4 +115,9 @@ public class TransformationTestUtils return domain; } + + public static Domain getDefaultDomain() + { + return TransformationTestUtils.getDomain( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent.xml" ); + } } |