From cdd849cc9a5c748627f7882974c9e3cb7e9457ba Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Thu, 11 Feb 2021 09:00:09 +0100 Subject: [qemu] Add command line argument parsing to 'qemu' runvirt plugin --- .../vmchooser/plugins/qemu/run-virt.include | 5 +- core/modules/qemu/runvirt-plugin-qemu/pom.xml | 17 + .../java/org/openslx/runvirt/plugin/qemu/App.java | 113 +++++- .../runvirt/plugin/qemu/cmdln/CommandLineArgs.java | 406 +++++++++++++++++++++ .../qemu/cmdln/CommandLineArgsException.java | 25 ++ .../org/openslx/runvirt/plugin/qemu/AppTest.java | 16 +- 6 files changed, 571 insertions(+), 11 deletions(-) create mode 100644 core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java create mode 100644 core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java diff --git a/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include index ee9d8e36..5b320bcc 100644 --- a/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include +++ b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include @@ -32,13 +32,12 @@ run_plugin() { isset VM_CLEANNAME && VIRTCMDOPTS+=( "-vmname" "${VM_CLEANNAME}" ) isset VM_DISPLAYNAME && VIRTCMDOPTS+=( "-vmdsplname" "${VM_DISPLAYNAME}" ) isset VM_OS_TYPE && VIRTCMDOPTS+=( "-vmos" "${VM_OS_TYPE}" ) - isset VM_RUN_FILE && VIRTCMDOPTS+=( "-vminpcfg" "${VM_RUN_FILE}" ) - isset vm_final_run_file && VIRTCMDOPTS+=( "-vmoutcfg" "${vm_final_run_file}" ) + isset VM_RUN_FILE && VIRTCMDOPTS+=( "-vmcfginp" "${VM_RUN_FILE}" ) + isset vm_final_run_file && VIRTCMDOPTS+=( "-vmcfgout" "${vm_final_run_file}" ) isset IMGUUID && VIRTCMDOPTS+=( "-vmuuid" "${IMGUUID}" ) isset CPU_CORES && VIRTCMDOPTS+=( "-vmncpus" "${CPU_CORES}" ) isset VM_MEM && VIRTCMDOPTS+=( "-vmmem" "${VM_MEM}" ) isset VM_MAC_ADDR && VIRTCMDOPTS+=( "-vmmac0" "${VM_MAC_ADDR}" ) - isset VM_ETH0_NETWORK && VIRTCMDOPTS+=( "-vmeth0" "${VM_ETH0_NETWORK}" ) isset VM_DISKFILE_RO && VIRTCMDOPTS+=( "-vmhdd0" "${VM_DISKFILE_RO}" ) isset FLOPPY_0 && VIRTCMDOPTS+=( "-vmfloppy0" "${FLOPPY_0}" ) isset SLX_FLOPPY_IMG && VIRTCMDOPTS+=( "-vmfloppy1" "${SLX_FLOPPY_IMG}" ) diff --git a/core/modules/qemu/runvirt-plugin-qemu/pom.xml b/core/modules/qemu/runvirt-plugin-qemu/pom.xml index d4aace6e..45b8f1d5 100644 --- a/core/modules/qemu/runvirt-plugin-qemu/pom.xml +++ b/core/modules/qemu/runvirt-plugin-qemu/pom.xml @@ -30,6 +30,23 @@ 5.7.1 test + + commons-cli + commons-cli + 1.4 + + + log4j + log4j + [1.2.10,1.2.20] + compile + + + org.slf4j + slf4j-log4j12 + 1.7.25 + compile + 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 ce6e7e12..fb72f18a 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 @@ -1,12 +1,121 @@ package org.openslx.runvirt.plugin.qemu; +import org.apache.log4j.BasicConfigurator; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +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; + /** - * Hello world! + * 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). + */ + private static final String APP_NAME = "run-virt QEMU plugin"; + + /** + * Stores description of the run-virt QEMU plugin (command line tool). + */ + private 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). + */ + private 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 ) { - System.out.println( "Hello World!" ); + // 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 ); + } + + /** + * 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() ); + final String longOptionArgument; + + // only request and log argument if option has an command line argument + if ( option.hasArgument() ) { + longOptionArgument = cmdLn.getArgument( option ); + } else { + longOptionArgument = new String( "[option has no argument]" ); + } + + LOGGER.debug( "\t" + paddedLongOption + ": " + longOptionArgument ); + } } } 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 new file mode 100644 index 00000000..13b8c0e2 --- /dev/null +++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java @@ -0,0 +1,406 @@ +package org.openslx.runvirt.plugin.qemu.cmdln; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** + * Command line argument parser for the run-virt QEMU plugin (command line tool). + * + * @author Manuel Bentele + * @version 1.0 + */ +public class CommandLineArgs +{ + /** + * Parser for parsing command line arguments. + */ + private CommandLineParser cmdLnParser = null; + + /** + * Stores specified command line options. + */ + private Options cmdLnOptions = null; + + /** + * Stores the parsed command line arguments. + */ + private CommandLine cmdLn = null; + + /** + * Creates a new command line argument parser for the run-virt QEMU plugin. + * + * @implNote Please call {@link CommandLineArgs#parseCmdLnArgs(String[])} manually after + * obtaining the command line argument parser from this method. + */ + public CommandLineArgs() + { + this.createCmdLnParser(); + this.createCmdLnOptions(); + } + + /** + * Creates a new command line argument parser for the run-virt QEMU plugin and parses the command + * line arguments. + * + * @param args command line arguments submitted to the application. + * + * @throws CommandLineArgsException parsing of command line arguments failed. + */ + public CommandLineArgs( String[] args ) throws CommandLineArgsException + { + this(); + this.parseCmdLnArgs( args ); + } + + /** + * Creates a new parser and empty command line options for parsing command line arguments. + */ + private void createCmdLnParser() + { + this.cmdLnParser = new DefaultParser(); + this.cmdLnOptions = new Options(); + } + + /** + * Creates command line options specified by {@link CmdLnOption}. + */ + private void createCmdLnOptions() + { + for ( CmdLnOption option : CmdLnOption.values() ) { + this.cmdLnOptions.addOption( option.getShortOption(), option.getLongOption(), option.hasArgument(), + option.getDescription() ); + } + } + + /** + * Prints command line help for the current application. + * + * @param appName name of the current application. + * @param header header for the command line help. + * @param footer footer for the command line help. + */ + public void printHelp( String appName, String header, String footer ) + { + HelpFormatter formatter = new HelpFormatter(); + formatter.setLeftPadding( 2 ); + formatter.printHelp( appName, header, this.cmdLnOptions, footer, true ); + } + + /** + * Parses command line arguments from a given argument {@link String}. + * + * @param args command line arguments submitted to the application. + * + * @throws CommandLineArgsException parsing of command line arguments failed. + */ + public void parseCmdLnArgs( String[] args ) throws CommandLineArgsException + { + try { + this.cmdLn = this.cmdLnParser.parse( this.cmdLnOptions, args ); + } catch ( ParseException e ) { + throw new CommandLineArgsException( e.getLocalizedMessage() ); + } + } + + /** + * Returns the parsed argument of the specified command line option. + * + * @param cmdLnOption command line option for that the parsed argument should be returned. + * @return parsed argument of the command line option. + */ + public String getArgument( CmdLnOption cmdLnOption ) + { + return this.cmdLn.getOptionValue( cmdLnOption.getShortOption() ); + } + + /** + * Returns the presence of the command line option {@link CmdLnOption#HELP}. + * + * @return presence of the command line option {@link CmdLnOption#HELP}. + */ + public boolean isHelpAquired() + { + return this.cmdLn.hasOption( CmdLnOption.HELP.getShortOption() ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_CFGINP}. + * + * @return argument of the command line option {@link CmdLnOption#VM_CFGINP}. + */ + public String getVmCfgInpFileName() + { + return this.getArgument( CmdLnOption.VM_CFGINP ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_CFGOUT}. + * + * @return argument of the command line option {@link CmdLnOption#VM_CFGOUT}. + */ + public String getVmCfgOutFileName() + { + return this.getArgument( CmdLnOption.VM_CFGOUT ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_NAME}. + * + * @return argument of the command line option {@link CmdLnOption#VM_NAME}. + */ + public String getVmName() + { + return this.getArgument( CmdLnOption.VM_NAME ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_UUID}. + * + * @return argument of the command line option {@link CmdLnOption#VM_UUID}. + */ + public String getVmUuid() + { + return this.getArgument( CmdLnOption.VM_UUID ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_DSPLNAME}. + * + * @return argument of the command line option {@link CmdLnOption#VM_DSPLNAME}. + */ + public String getVmDisplayName() + { + return this.getArgument( CmdLnOption.VM_DSPLNAME ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_OS}. + * + * @return argument of the command line option {@link CmdLnOption#VM_OS}. + */ + public String getVmOperatingSystem() + { + return this.getArgument( CmdLnOption.VM_OS ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_NCPUS}. + * + * @return argument of the command line option {@link CmdLnOption#VM_NCPUS}. + */ + public int getVmNumCpus() + { + final String numCpus = this.getArgument( CmdLnOption.VM_NCPUS ); + return Integer.parseInt( numCpus ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_MEM}. + * + * @return argument of the command line option {@link CmdLnOption#VM_MEM}. + */ + public String getVmMemory() + { + return this.getArgument( CmdLnOption.VM_MEM ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_HDD0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_HDD0}. + */ + public String getVmDiskFileNameHDD0() + { + return this.getArgument( CmdLnOption.VM_HDD0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_FLOPPY0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_FLOPPY0}. + */ + public String getVmDiskFileNameFloppy0() + { + return this.getArgument( CmdLnOption.VM_FLOPPY0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_FLOPPY1}. + * + * @return argument of the command line option {@link CmdLnOption#VM_FLOPPY1}. + */ + public String getVmDiskFileNameFloppy1() + { + return this.getArgument( CmdLnOption.VM_FLOPPY1 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_CDROM0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_CDROM0}. + */ + public String getVmDiskFileNameCdrom0() + { + return this.getArgument( CmdLnOption.VM_CDROM0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_CDROM1}. + * + * @return argument of the command line option {@link CmdLnOption#VM_CDROM1}. + */ + public String getVmDiskFileNameCdrom1() + { + return this.getArgument( CmdLnOption.VM_CDROM1 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_PARALLEL0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_SERIAL0}. + */ + public String getVmDeviceParallel0() + { + return this.getArgument( CmdLnOption.VM_PARALLEL0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_SERIAL0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_SERIAL0}. + */ + public String getVmDeviceSerial0() + { + return this.getArgument( CmdLnOption.VM_SERIAL0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_MAC0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_MAC0}. + */ + public String getVmMacAddress0() + { + return this.getArgument( CmdLnOption.VM_MAC0 ); + } + + /** + * Returns the argument of the command line option {@link CmdLnOption#VM_AUDIO0}. + * + * @return argument of the command line option {@link CmdLnOption#VM_AUDIO0}. + */ + public String getVmModelSoundCard0() + { + return this.getArgument( CmdLnOption.VM_AUDIO0 ); + } + + /** + * Command line options for the run-virt QEMU plugin (command line tool). + * + * @author Manuel Bentele + * @version 1.0 + */ + public enum CmdLnOption + { + // @formatter:off + HELP ( 'h', "help", false, "" ), + VM_CFGINP ( 'i', "vmcfginp", true, "File name of an existing and filtered Libvirt domain XML configuration file" ), + VM_CFGOUT ( 'o', "vmcfgout", true, "File name to output a finalized Libvirt domain XML configuration file" ), + VM_NAME ( 'n', "vmname", true, "Name for the virtual machine" ), + VM_UUID ( 'u', "vmuuid", true, "UUID for the virtual machine" ), + VM_DSPLNAME ( 'd', "vmdsplname", true, "Display name for the virtual machine" ), + VM_OS ( 's', "vmos", true, "Operating system running in the virtual machine" ), + VM_NCPUS ( 'c', "vmncpus", true, "Number of virtual CPUs for the virtual machine" ), + VM_MEM ( 'm', "vmmem", true, "Amount of memory for the virtual machine" ), + VM_HDD0 ( 'r', "vmhdd0", true, "Disk image for the first HDD device" ), + VM_FLOPPY0 ( 'f', "vmfloppy0", true, "Disk image for the first floppy drive" ), + VM_FLOPPY1 ( 'g', "vmfloppy1", true, "Disk image for the second floppy drive" ), + VM_CDROM0 ( 'k', "vmcdrom0", true, "Disk image for the first CDROM drive" ), + VM_CDROM1 ( 'l', "vmcdrom1", true, "Disk image for the second CDROM drive" ), + VM_PARALLEL0( 'p', "vmparallel0", true, "Device for the first parallel port interface" ), + VM_SERIAL0 ( 'q', "vmserial0", true, "Device for the first serial port interface" ), + VM_MAC0 ( 'a', "vmmac0", true, "MAC address for the first network interface" ), + VM_AUDIO0 ( 'x', "vmaudio0", true, "Hardware model for the first sound card" ); + // @formatter:on + + /** + * Stores the {@link Character} of the short command line option. + */ + private final char shortOption; + + /** + * Stores the {@link String} of the long command line option. + */ + private final String longOption; + + /** + * Stores the presence of an argument for the command line option. + */ + private final boolean hasArgument; + + /** + * Stores the textual description of the command line option. + */ + private final String description; + + /** + * Creates a new command line option for the run-virt QEMU plugin (command line tool). + * + * @param shortOption {@link Character} for the short command line option. + * @param longOption {@link String} for the long command line option. + * @param hasArgument presence of an argument for the command line option. + * @param description textual description of the command line option. + */ + CmdLnOption( char shortOption, String longOption, boolean hasArgument, String description ) + { + this.shortOption = shortOption; + this.longOption = longOption; + this.hasArgument = hasArgument; + this.description = description; + } + + /** + * Returns the {@link Character} of the short command line option. + * + * @return {@link Character} of the short command line option. + */ + public String getShortOption() + { + return Character.toString( this.shortOption ); + } + + /** + * Returns the {@link String} of the long command line option. + * + * @return {@link String} of the long command line option. + */ + public String getLongOption() + { + return this.longOption; + } + + /** + * Returns the presence of an argument for the command line option. + * + * @return presence of an argument for the command line option. + */ + public boolean hasArgument() + { + return this.hasArgument; + } + + /** + * Returns the textual description of the command line option. + * + * @return textual description of the command line option. + */ + public String getDescription() + { + return this.description; + } + } +} diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java new file mode 100644 index 00000000..a327b813 --- /dev/null +++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java @@ -0,0 +1,25 @@ +package org.openslx.runvirt.plugin.qemu.cmdln; + +/** + * An exception during the parsing of command line arguments. + * + * @author Manuel Bentele + * @version 1.0 + */ +public class CommandLineArgsException extends Exception +{ + /** + * Version number for serialization. + */ + private static final long serialVersionUID = 8371924151602194406L; + + /** + * Creates an command line argument parsing exception including an error message. + * + * @param errorMsg message to describe a specific parsing error. + */ + public CommandLineArgsException( String errorMsg ) + { + super( errorMsg ); + } +} 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 90b658cd..110fb639 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 @@ -2,16 +2,20 @@ package org.openslx.runvirt.plugin.qemu; import static org.junit.jupiter.api.Assertions.assertTrue; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -/** - * Unit test for simple App. - */ public class AppTest { - /** - * Rigorous Test :-) - */ + @BeforeAll + public static void setUp() + { + // disable logging with log4j + LogManager.getRootLogger().setLevel( Level.OFF ); + } + @Test public void shouldAnswerWithTrue() { -- cgit v1.2.3-55-g7522