summaryrefslogtreecommitdiffstats
path: root/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer')
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java118
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java35
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java105
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java65
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java75
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java97
6 files changed, 495 insertions, 0 deletions
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java
new file mode 100644
index 00000000..d23a9e11
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java
@@ -0,0 +1,118 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Representation of an viewer for virtual machines running on a host system.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public abstract class Viewer
+{
+ /**
+ * Name of the viewer.
+ */
+ private final String name;
+
+ /**
+ * Number of supported displays by the viewer.
+ */
+ private final int numSupportedDisplays;
+
+ /**
+ * The virtual machine to display.
+ */
+ private final LibvirtVirtualMachine machine;
+
+ /**
+ * Remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ private final LibvirtHypervisor hypervisor;
+
+ /**
+ * Creates a new viewer for a Libvirt virtual machine running on a Libvirt hypervisor.
+ *
+ * @param name textual name of the viewer.
+ * @param numSupportedDisplays number of supported displays by the viewer.
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public Viewer( String name, int numSupportedDisplays, LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ this.name = name;
+ this.numSupportedDisplays = numSupportedDisplays;
+ this.machine = machine;
+ this.hypervisor = hypervisor;
+ }
+
+ /**
+ * Returns the name of the viewer.
+ *
+ * @return name of the viewer.
+ */
+ public String getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * Returns the number of supported displays by the viewer.
+ *
+ * @return number of supported displays by the viewer.
+ */
+ public int getNumberOfSupportedDisplays()
+ {
+ return this.numSupportedDisplays;
+ }
+
+ /**
+ * Returns the virtual machine to display.
+ *
+ * @return virtual machine to display.
+ */
+ public LibvirtVirtualMachine getMachine()
+ {
+ return this.machine;
+ }
+
+ /**
+ * Returns the remote (hypervisor) endpoint for the viewer to connect to.
+ *
+ * @return remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public LibvirtHypervisor getHypervisor()
+ {
+ return this.hypervisor;
+ }
+
+ /**
+ * Displays all virtual machine's displays.
+ *
+ * @throws ViewerException failed to display all displays of a virtual machine.
+ *
+ * @apiNote A call to this method blocks until the implemented {@link #render()} process
+ * terminates.
+ */
+ public void display() throws ViewerException
+ {
+ this.render();
+ }
+
+ /**
+ * Returns the version of the viewer.
+ *
+ * @return version of the viewer.
+ * @throws ViewerException failed to get version of the viewer.
+ */
+ public abstract Version getVersion() throws ViewerException;
+
+ /**
+ * Renders the content of all displays from the virtual machine.
+ *
+ * @throws ViewerException failed to render all displays of a virtual machine.
+ */
+ protected abstract void render() throws ViewerException;
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java
new file mode 100644
index 00000000..0c178375
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java
@@ -0,0 +1,35 @@
+package org.openslx.runvirt.viewer;
+
+/**
+ * An exception of a viewer error during displaying all displays of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerException extends Exception
+{
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = 161091514643380414L;
+
+ /**
+ * Creates a new viewer exception including an error message.
+ *
+ * @param errorMsg message to describe a specific viewer error.
+ */
+ public ViewerException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+
+ /**
+ * Creates a new viewer exception by a copy of an existing viewer exception.
+ *
+ * @param e existing viewer exception.
+ */
+ public ViewerException( ViewerException e )
+ {
+ super( e );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java
new file mode 100644
index 00000000..cea9ccd8
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java
@@ -0,0 +1,105 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Looking Glass Client to view the exposed framebuffer (through a shared memory) of a virtual
+ * machine running the Looking Glass Host application.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerLookingGlassClient extends Viewer
+{
+ /**
+ * Name of the Looking Glass Client program.
+ */
+ private final static String NAME = "looking-glass-client";
+
+ /**
+ * Maximum number of supported displays by the Looking Glass Client.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = 1;
+
+ /**
+ * File name of the shared memory file to receive display content from the Looking Glass Host.
+ */
+ private final static String SHARED_MEMORY_FILENAME = "/dev/shm/looking-glass";
+
+ /**
+ * State whether showing debug information during virtual machine rendering or not.
+ */
+ private final boolean debug;
+
+ /**
+ * Creates a new Looking Glass Client for a Libvirt virtual machine running on a Libvirt
+ * hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerLookingGlassClient( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ this( machine, hypervisor, false );
+ }
+
+ /**
+ * Creates a new Looking Glass Client for a Libvirt virtual machine running on a Libvirt
+ * hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ * @param debug state whether showing debug information during virtual machine rendering or not.
+ */
+ public ViewerLookingGlassClient( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor, boolean debug )
+ {
+ super( ViewerLookingGlassClient.NAME, ViewerLookingGlassClient.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+
+ this.debug = debug;
+ }
+
+ /**
+ * Returns the state whether showing debug information during virtual machine rendering or not.
+ *
+ * @return state whether showing debug information during virtual machine rendering or not.
+ */
+ public boolean isDebugEnabled()
+ {
+ return this.debug;
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ return null;
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ // execute viewer process with arguments:
+ // in non-debug mode:
+ // "looking-glass-client app:shmFile=<SHARED-MEM-FILE> win:fullScreen=yes spice:enable=yes win:alerts=no"
+ // in debug mode:
+ // "looking-glass-client app:shmFile=<SHARED-MEM-FILE> win:fullScreen=yes spice:enable=yes win:alerts=yes win:showFPS=yes"
+ final String[] viewerParameters;
+ if ( this.isDebugEnabled() ) {
+ viewerParameters = new String[] {
+ "app:shmFile=" + ViewerLookingGlassClient.SHARED_MEMORY_FILENAME,
+ "win:fullScreen=yes",
+ "spice:enable=yes",
+ "win:alerts=no" };
+ } else {
+ viewerParameters = new String[] {
+ "app:shmFile=" + ViewerLookingGlassClient.SHARED_MEMORY_FILENAME,
+ "win:fullScreen=yes",
+ "spice:enable=yes",
+ "win:alerts=yes",
+ "win:showFPS=yes" };
+ }
+
+ ViewerUtils.executeViewer( ViewerLookingGlassClient.NAME, viewerParameters );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java
new file mode 100644
index 00000000..1ed5947a
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java
@@ -0,0 +1,65 @@
+package org.openslx.runvirt.viewer;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+/**
+ * Utils for viewing displays of virtual machines.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerUtils
+{
+ /**
+ * Synchronously executes a viewer program specified by a command line call.
+ * <p>
+ * The command line call of the viewer program consists of the program name and an optional list
+ * of submitted command line arguments for the viewer program. The result of the executed viewer
+ * program from the standard output is returned after the program has exited.
+ *
+ * @param viewerProgram name of the viewer program.
+ * @param viewerArguments optional command line arguments for the viewer program.
+ * @return result of the executed viewer program from the standard output.
+ * @throws ViewerException failed to execute the viewer program.
+ */
+ @SuppressWarnings( "deprecation" )
+ public static String executeViewer( String viewerProgram, String[] viewerArguments ) throws ViewerException
+ {
+ final CommandLine viewerCommandLine = new CommandLine( viewerProgram );
+ final DefaultExecutor viewerExecutor = new DefaultExecutor();
+
+ // prepare viewer command to execute
+ viewerCommandLine.addArguments( viewerArguments );
+
+ // set up temporary working directory for the viewer process
+ viewerExecutor.setWorkingDirectory( FileUtils.getTempDirectory() );
+
+ // set expected exit value of the viewer process indicating a successful operation
+ viewerExecutor.setExitValue( 0 );
+
+ // set up output stream handler to retrieve the content from the viewer's standard output
+ final ByteArrayOutputStream viewerOutputStream = new ByteArrayOutputStream();
+ final PumpStreamHandler viewerOutputStreamHandler = new PumpStreamHandler( viewerOutputStream );
+ viewerExecutor.setStreamHandler( viewerOutputStreamHandler );
+
+ // execute the viewer command as blocking process
+ try {
+ viewerExecutor.execute( viewerCommandLine );
+ } catch ( IOException e ) {
+ throw new ViewerException( "Failed to execute '" + viewerProgram + "': " + e.getLocalizedMessage() );
+ }
+
+ final String viewerOuput = viewerOutputStream.toString( StandardCharsets.UTF_8 );
+ IOUtils.closeQuietly( viewerOutputStream );
+
+ return viewerOuput;
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java
new file mode 100644
index 00000000..1848d975
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java
@@ -0,0 +1,75 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Virtual Machine Manager (virt-manager) to control and view a display of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerVirtManager extends Viewer
+{
+ /**
+ * Name of the Virtual Machine Manager program.
+ */
+ private final static String NAME = "virt-manager";
+
+ /**
+ * Maximum number of supported displays by the Virtual Machine Manager.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = 1;
+
+ /**
+ * Creates a new Virtual Machine Manager for a virtual machine running on a hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerVirtManager( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ super( ViewerVirtManager.NAME, ViewerVirtManager.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ // execute viewer process with arguments:
+ // "virt-manager --version"
+ final String versionOutput = ViewerUtils.executeViewer( ViewerVirtManager.NAME,
+ new String[] { "--version" } );
+
+ return Version.valueOf( versionOutput );
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ String connectionUri = null;
+ String machineUuid = null;
+
+ // get URI of the hypervisor connection and UUID of the machine
+ try {
+ connectionUri = this.getHypervisor().getConnectionUri();
+ machineUuid = this.getMachine().getConfiguration().getUuid();
+ } catch ( LibvirtHypervisorException e ) {
+ throw new ViewerException(
+ "Failed to retrieve the URI of the hypervisor backend or the UUID of the machine to display: "
+ + e.getLocalizedMessage() );
+ }
+
+ // check if URI of the hypervisor connection and UUID of the machine is specified, otherwise abort
+ if ( connectionUri == null || connectionUri.isEmpty() || machineUuid == null || machineUuid.isEmpty() ) {
+ throw new ViewerException(
+ "The URI of the hypervisor backend or the UUID of the machine to display is missing!" );
+ }
+
+ // execute viewer process with arguments:
+ // "virt-viewer --connect=<URI> --show-domain-console <DOMAIN-UUID>"
+ ViewerUtils.executeViewer( ViewerVirtManager.NAME,
+ new String[] { "--connect=" + connectionUri, "--show-domain-console", machineUuid } );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java
new file mode 100644
index 00000000..8f6e9481
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java
@@ -0,0 +1,97 @@
+package org.openslx.runvirt.viewer;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Virtual Viewer (virt-viewer) to view one or several displays of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerVirtViewer extends Viewer
+{
+ /**
+ * Name of the Virtual Machine Manager program.
+ */
+ private final static String NAME = "virt-viewer";
+
+ /**
+ * Maximum number of supported displays by the Virtual Viewer.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = Integer.MAX_VALUE;
+
+ /**
+ * Creates a new Virtual Viewer for a Libvirt virtual machine running on a Libvirt hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerVirtViewer( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ super( ViewerVirtViewer.NAME, ViewerVirtViewer.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ final Version version;
+
+ // execute viewer process with arguments:
+ // "virt-viewer --version"
+ final String versionOutput = ViewerUtils.executeViewer( ViewerVirtViewer.NAME,
+ new String[] { "--version" } );
+
+ if ( versionOutput == null ) {
+ version = null;
+ } else {
+ // parse version from the viewer's process output
+ final Pattern viewerVersionPattern = Pattern.compile( "(\\d+).(\\d+)" );
+ final Matcher viewerVersionMatcher = viewerVersionPattern.matcher( versionOutput );
+
+ // check if version pattern was found
+ if ( viewerVersionMatcher.find() ) {
+ final short major = Short.valueOf( viewerVersionMatcher.group( 1 ) );
+ final short minor = Short.valueOf( viewerVersionMatcher.group( 2 ) );
+ version = new Version( major, minor );
+ } else {
+ version = null;
+ }
+ }
+
+ return version;
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ String connectionUri = null;
+ String machineUuid = null;
+
+ // get URI of the hypervisor connection and UUID of the machine
+ try {
+ connectionUri = this.getHypervisor().getConnectionUri();
+ machineUuid = this.getMachine().getConfiguration().getUuid();
+ } catch ( LibvirtHypervisorException e ) {
+ throw new ViewerException(
+ "Failed to retrieve the URI of the hypervisor backend or the UUID of the machine to display: "
+ + e.getLocalizedMessage() );
+ }
+
+ // check if URI of the hypervisor connection and UUID of the machine is specified, otherwise abort
+ if ( connectionUri == null || connectionUri.isEmpty() || machineUuid == null || machineUuid.isEmpty() ) {
+ throw new ViewerException(
+ "The URI of the hypervisor backend or the UUID of the machine to display is missing!" );
+ }
+
+ // execute viewer process with arguments:
+ // "virt-viewer --full-screen --reconnect --wait --attach --connect=<URI> --domain-name -- <DOMAIN-UUID>"
+ ViewerUtils.executeViewer( ViewerVirtViewer.NAME, new String[] { "--full-screen", "--reconnect", "--wait",
+ "--attach", "--connect=" + connectionUri, "--uuid", "--", machineUuid } );
+ }
+}