diff options
Diffstat (limited to 'core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java')
-rw-r--r-- | core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java | 285 |
1 files changed, 285 insertions, 0 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 new file mode 100644 index 00000000..5ea7b720 --- /dev/null +++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java @@ -0,0 +1,285 @@ +package org.openslx.runvirt.plugin.qemu; + +import java.io.File; +import java.util.Arrays; + +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.openslx.libvirt.domain.Domain; +import org.openslx.libvirt.xml.LibvirtXmlDocumentException; +import org.openslx.libvirt.xml.LibvirtXmlSerializationException; +import org.openslx.libvirt.xml.LibvirtXmlValidationException; +import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs; +import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs.CmdLnOption; +import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgsException; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericCpu; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskCdromDevices; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskFloppyDevices; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskStorageDevices; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericFileSystemDevices; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericInterfaceDevices; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericMemory; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericName; +import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericParallelDevices; +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.TransformationSpecificQemuGpuPassthroughNvidia; +import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu; +import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu.QemuSessionType; +import org.openslx.runvirt.viewer.Viewer; +import org.openslx.runvirt.viewer.ViewerException; +import org.openslx.runvirt.viewer.ViewerLookingGlassClient; +import org.openslx.runvirt.viewer.ViewerVirtManager; +import org.openslx.runvirt.viewer.ViewerVirtViewer; +import org.openslx.runvirt.virtualization.LibvirtHypervisor; +import org.openslx.runvirt.virtualization.LibvirtHypervisorException; +import org.openslx.runvirt.virtualization.LibvirtVirtualMachine; +import org.openslx.runvirt.virtualization.LibvirtVirtualMachineException; +import org.openslx.virtualization.configuration.transformation.TransformationException; +import org.openslx.virtualization.configuration.transformation.TransformationManager; + +/** + * Run-virt QEMU plugin (command line tool) to finalize a Libvirt domain XML configuration. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class App +{ + /** + * Stores name of the run-virt QEMU plugin (command line tool). + */ + public static final String APP_NAME = "run-virt QEMU plugin"; + + /** + * Stores description of the run-virt QEMU plugin (command line tool). + */ + public static final String APP_DESC = "Finalize a Libvirt VM (domain XML) configuration and manage the VM."; + + /** + * Stores additional information for the run-virt QEMU plugin (command line tool). + */ + public static final String APP_INFO = "The " + APP_NAME + " is part of the bwLehrpool infrastructure."; + + /** + * Instance of a logger to log messages. + */ + private static final Logger LOGGER = LogManager.getLogger( App.class ); + + /** + * Entry point of the run-virt QEMU plugin (command line tool). + * + * @param args command line arguments passed to the run-virt QEMU plugin (command line tool). + */ + public static void main( String[] args ) + { + // initialize logging + BasicConfigurator.configure(); + + // parse command line arguments + CommandLineArgs cmdLn = new CommandLineArgs(); + + try { + cmdLn.parseCmdLnArgs( args ); + } catch ( CommandLineArgsException e ) { + LOGGER.error( "Parsing of command line arguments failed: " + e.getLocalizedMessage() ); + App.printUsage( cmdLn ); + System.exit( 1 ); + } + + // show help if 'help' command line option is set + if ( cmdLn.isHelpAquired() ) { + App.printUsage( cmdLn ); + System.exit( 0 ); + } + + // print command line arguments for debugging purposes + App.printCmdLnArgs( cmdLn ); + + // create connection to the QEMU hypervisor via Libvirt + LibvirtHypervisor hypervisor = null; + try { + hypervisor = new LibvirtHypervisorQemu( QemuSessionType.LOCAL_USER_SESSION ); + } catch ( LibvirtHypervisorException e ) { + LOGGER.error( "Failed to connect to the QEMU virtualizer (Libvirt daemon): " + e.getLocalizedMessage() ); + System.exit( 2 ); + } + + // read Libvirt XML domain configuration template + final String xmlInputFileName = cmdLn.getVmCfgInpFileName(); + Domain config = null; + try { + final File xmlInputFile = new File( xmlInputFileName ); + config = new Domain( xmlInputFile ); + } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) { + LOGGER.error( "Failed to read VM input configuration file: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 3 ); + } + + // create transformation manager to finalize VM configuration + final TransformationManager<Domain, CommandLineArgs> transformationManager; + transformationManager = new TransformationManager<Domain, CommandLineArgs>( config, cmdLn ); + + // register necessary transformations to finalize configuration template + transformationManager.register( new TransformationGenericName(), true ); + transformationManager.register( new TransformationGenericUuid(), true ); + transformationManager.register( new TransformationGenericCpu(), true ); + transformationManager.register( new TransformationGenericMemory(), true ); + transformationManager.register( new TransformationGenericDiskStorageDevices(), true ); + transformationManager.register( new TransformationGenericDiskCdromDevices(), true ); + transformationManager.register( new TransformationGenericDiskFloppyDevices(), true ); + transformationManager.register( new TransformationGenericInterfaceDevices(), true ); + transformationManager.register( new TransformationGenericParallelDevices(), true ); + transformationManager.register( new TransformationGenericFileSystemDevices(), true ); + + // register QEMU specific transformations to finalize configuration template + if ( hypervisor instanceof LibvirtHypervisorQemu ) { + final LibvirtHypervisorQemu hypervisorQemu = LibvirtHypervisorQemu.class.cast( hypervisor ); + + transformationManager.register( new TransformationSpecificQemuArchitecture( hypervisorQemu ), true ); + transformationManager.register( new TransformationSpecificQemuSerialDevices( hypervisorQemu ), true ); + transformationManager.register( new TransformationSpecificQemuGpuPassthroughNvidia( hypervisorQemu ), false ); + } + + // finalize Libvirt VM configuration template + try { + transformationManager.transform(); + } catch ( TransformationException e ) { + LOGGER.error( "Failed to finalize VM configuration file: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 4 ); + } + + // write finalized configuration to file if output file is specified + final String xmlOutputFileName = cmdLn.getVmCfgOutFileName(); + if ( xmlOutputFileName != null && !xmlOutputFileName.isEmpty() ) { + try { + final File xmlOutputFile = new File( xmlOutputFileName ); + config.toXml( xmlOutputFile ); + } catch ( LibvirtXmlSerializationException e ) { + LOGGER.error( "Failed to write VM output configuration file: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 5 ); + } + } + + // define Libvirt VM from finalized configuration + LibvirtVirtualMachine vm = null; + try { + vm = hypervisor.registerVm( config ); + } catch ( LibvirtHypervisorException e ) { + LOGGER.error( "Failed to define VM from configuration file: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 6 ); + } + + // start defined Libvirt VM + try { + vm.start(); + } catch ( LibvirtVirtualMachineException e ) { + LOGGER.error( "Failed to start defined VM: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 7 ); + } + + // create specific viewer to display Libvirt VM + final Viewer vmViewer; + if ( cmdLn.isNvidiaGpuPassthroughEnabled() ) { + // viewer for GPU passthrough (framebuffer access) is required + vmViewer = new ViewerLookingGlassClient( vm, hypervisor, cmdLn.isDebugEnabled() ); + } else { + // viewer for non-GPU passthrough (no framebuffer access) is required + if ( cmdLn.isDebugEnabled() ) { + // create specific Virtual Machine Manager viewer if debug mode is enabled + vmViewer = new ViewerVirtManager( vm, hypervisor ); + } else { + // create Virtual Viewer if debug mode is disabled + vmViewer = new ViewerVirtViewer( vm, hypervisor ); + } + } + + // display Libvirt VM with the specific viewer on the screen + try { + vmViewer.display(); + } catch ( ViewerException e ) { + LOGGER.error( "Failed to display VM: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 8 ); + } + + // undefine VM after usage + try { + hypervisor.deregisterVm( vm ); + } catch ( LibvirtHypervisorException | LibvirtVirtualMachineException e ) { + LOGGER.error( "Failed to undefine VM: " + e.getLocalizedMessage() ); + hypervisor.close(); + System.exit( 9 ); + } + + // close connection to hypervisor + hypervisor.close(); + + // return with successful exit code + System.exit( 0 ); + } + + /** + * Helper utility to print the run-virt QEMU plugin help text. + * + * @param cmdLn parsed command line arguments. + */ + public static void printUsage( CommandLineArgs cmdLn ) + { + final String newLine = System.lineSeparator(); + final String fullAppDesc = newLine + App.APP_DESC + newLine + newLine; + final String fullAppInfo = newLine + App.APP_INFO; + + cmdLn.printHelp( App.APP_NAME, fullAppDesc, fullAppInfo ); + } + + /** + * Helper utility to log the run-virt QEMU plugin's submitted command line arguments. + * + * @param cmdLn parsed command line arguments. + * + * @implNote This method is intended to be used for debugging purposes. + */ + public static void printCmdLnArgs( CommandLineArgs cmdLn ) + { + // determine length of longest command line option + int longOptionLengthMax = 0; + + for ( CmdLnOption option : CmdLnOption.values() ) { + // store length of current long option + final int longOptionLength = option.getLongOption().length(); + + // if length is longer than every length before, store this length as longest length + if ( longOptionLength > longOptionLengthMax ) { + longOptionLengthMax = longOptionLength; + } + } + + LOGGER.debug( "Command line arguments: --------------" ); + + for ( CmdLnOption option : CmdLnOption.values() ) { + final String paddedLongOption = String.format( "%-" + longOptionLengthMax + "s", option.getLongOption() ); + String[] longOptionArguments; + + // only request and log argument if option has an command line argument + if ( option.getNumArguments() > 0 ) { + longOptionArguments = cmdLn.getArguments( option ); + + if ( longOptionArguments == null ) { + longOptionArguments = new String[] { "no argument specified" }; + } + } else { + longOptionArguments = new String[] { "option has no argument" }; + } + + LOGGER.debug( "\t" + paddedLongOption + ": " + Arrays.toString( longOptionArguments ) ); + } + } +} |