From 15b7fb9f9e6770696f568b0239d2ffec34000e56 Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Mon, 10 May 2021 09:51:43 +0200 Subject: Fix HDD detection in VirtualBox configurations newer or equal than v1.17 --- .../java/org/openslx/virtualization/Version.java | 32 +++++ .../VirtualizationConfigurationVirtualBox.java | 5 + ...alizationConfigurationVirtualboxFileFormat.java | 55 +++++++- .../org/openslx/virtualization/VersionTest.java | 26 +++- .../VirtualizationConfigurationTestResources.java | 18 +++ .../VirtualizationConfigurationVirtualBoxTest.java | 144 +++++++++++++++++++ .../xml/virtualbox_default-ubuntu_v1-15.vbox | 155 +++++++++++++++++++++ .../xml/virtualbox_default-ubuntu_v1-16.vbox | 59 ++++++++ .../xml/virtualbox_default-ubuntu_v1-17.vbox | 59 ++++++++ .../xml/virtualbox_default-ubuntu_v1-18.vbox | 56 ++++++++ 10 files changed, 605 insertions(+), 4 deletions(-) create mode 100644 src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationTestResources.java create mode 100644 src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java create mode 100644 src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-15.vbox create mode 100644 src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-16.vbox create mode 100644 src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-17.vbox create mode 100644 src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-18.vbox (limited to 'src') diff --git a/src/main/java/org/openslx/virtualization/Version.java b/src/main/java/org/openslx/virtualization/Version.java index 698e22e..fbd1bda 100644 --- a/src/main/java/org/openslx/virtualization/Version.java +++ b/src/main/java/org/openslx/virtualization/Version.java @@ -200,6 +200,28 @@ public class Version implements Comparable return supportedVersions.stream().filter( byMajorMinor ).findFirst().orElse( null ); } + /** + * Checks if this version is smaller than a specified {@code version}. + * + * @param version for comparison. + * @return state whether this version is smaller than the specified {@code version} or not. + */ + public boolean isSmallerThan( Version version ) + { + return ( this.compareTo( version ) < 0 ) ? true : false; + } + + /** + * Checks if this version is greater than a specified {@code version}. + * + * @param version for comparison. + * @return state whether this version is greater than the specified {@code version} or not. + */ + public boolean isGreaterThan( Version version ) + { + return ( this.compareTo( version ) > 0 ) ? true : false; + } + /** * Creates a new version parsed from a {@link String}. * @@ -237,6 +259,16 @@ public class Version implements Comparable return parsedVersion; } + @Override + public String toString() + { + if ( this.getName() == null || this.getName().isEmpty() ) { + return String.format( "%d.%d", this.getMajor(), this.getMinor() ); + } else { + return String.format( "%d.%d %s", this.getMajor(), this.getMinor(), this.getName() ); + } + } + @Override public boolean equals( Object obj ) { diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBox.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBox.java index 8225af1..81b9af8 100644 --- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBox.java +++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBox.java @@ -382,6 +382,11 @@ public class VirtualizationConfigurationVirtualBox { } + public Version getConfigurationVersion() + { + return this.config.getVersion(); + } + @Override public Version getVirtualizerVersion() { diff --git a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualboxFileFormat.java b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualboxFileFormat.java index 5b74e52..56e0844 100644 --- a/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualboxFileFormat.java +++ b/src/main/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualboxFileFormat.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; @@ -20,6 +22,7 @@ import javax.xml.xpath.XPathExpressionException; import org.apache.log4j.Logger; import org.openslx.util.Util; import org.openslx.util.XmlHelper; +import org.openslx.virtualization.Version; import org.openslx.virtualization.configuration.VirtualizationConfiguration.DriveBusType; import org.openslx.virtualization.configuration.VirtualizationConfiguration.HardDisk; import org.w3c.dom.DOMException; @@ -43,6 +46,11 @@ public class VirtualizationConfigurationVirtualboxFileFormat // XPath and DOM parsing related members private Document doc = null; + /** + * Version of the configuration file format. + */ + private Version version = null; + // list of nodes to automatically remove when reading the vbox file private static String[] blacklist = { "/VirtualBox/Machine/Hardware/GuestProperties", @@ -53,6 +61,7 @@ public class VirtualizationConfigurationVirtualboxFileFormat "/VirtualBox/Machine/Hardware/Network/Adapter[@enabled='true']/*", "/VirtualBox/Machine/ExtraData", "/VirtualBox/Machine/StorageControllers/StorageController/AttachedDevice[not(@type='HardDisk')]", + "/VirtualBox/Machine/Hardware/StorageControllers/StorageController/AttachedDevice[not(@type='HardDisk')]", "/VirtualBox/Machine/MediaRegistry/FloppyImages", "/VirtualBox/Machine/MediaRegistry/DVDImages" }; @@ -139,6 +148,7 @@ public class VirtualizationConfigurationVirtualboxFileFormat throw new VirtualizationConfigurationException( "Machine doesn't have a name" ); } try { + this.parseConfigurationVersion(); ensureHardwareUuid(); setOsType(); fixUsb(); // Since we now support selecting specific speed @@ -154,6 +164,27 @@ public class VirtualizationConfigurationVirtualboxFileFormat } } + private void parseConfigurationVersion() throws XPathExpressionException, VirtualizationConfigurationException + { + final String versionText = XmlHelper.XPath.compile( "/VirtualBox/@version" ).evaluate( this.doc ); + + if ( versionText == null || versionText.isEmpty() ) { + throw new VirtualizationConfigurationException( "Configuration file does not contain any version number!" ); + } else { + // parse version information from textual description + final Pattern versionPattern = Pattern.compile( "^(\\d+\\.\\d+).*$" ); + final Matcher versionMatcher = versionPattern.matcher( versionText ); + + if ( versionMatcher.find() ) { + this.version = Version.valueOf( versionMatcher.group( 1 ) ); + } + + if ( this.version == null ) { + throw new VirtualizationConfigurationException( "Configuration file version number is not valid!" ); + } + } + } + private void fixUsb() { NodeList list = findNodes( "/VirtualBox/Machine/Hardware/USB/Controllers/Controller" ); @@ -216,6 +247,11 @@ public class VirtualizationConfigurationVirtualboxFileFormat } } + public Version getVersion() + { + return this.version; + } + /** * Self-explanatory. */ @@ -243,7 +279,14 @@ public class VirtualizationConfigurationVirtualboxFileFormat continue; String hddUuid = hdd.getAttribute( "uuid" ); hdd.setAttribute( "uuid", PlaceHolder.HDDUUID.toString() + i + "%" ); - NodeList images = findNodes( "/VirtualBox/Machine/StorageControllers/StorageController/AttachedDevice/Image" ); + final NodeList images; + if ( this.getVersion().isSmallerThan( Version.valueOf( "1.17" ) ) ) { + images = findNodes( "/VirtualBox/Machine/StorageControllers/StorageController/AttachedDevice/Image" ); + } else { + images = findNodes( + "/VirtualBox/Machine/Hardware/StorageControllers/StorageController/AttachedDevice/Image" ); + } + for ( int j = 0; j < images.getLength(); j++ ) { Element image = (Element)images.item( j ); if ( image == null ) @@ -340,7 +383,15 @@ public class VirtualizationConfigurationVirtualboxFileFormat */ public void setHdds() throws XPathExpressionException { - XPathExpression hddsExpr = XmlHelper.XPath.compile( "/VirtualBox/Machine/StorageControllers/StorageController/AttachedDevice[@type='HardDisk']/Image" ); + final XPathExpression hddsExpr; + if ( this.getVersion().isSmallerThan( Version.valueOf( "1.17" ) ) ) { + hddsExpr = XmlHelper.XPath.compile( + "/VirtualBox/Machine/StorageControllers/StorageController/AttachedDevice[@type='HardDisk']/Image" ); + } else { + hddsExpr = XmlHelper.XPath.compile( + "/VirtualBox/Machine/Hardware/StorageControllers/StorageController/AttachedDevice[@type='HardDisk']/Image" ); + } + NodeList nodes = (NodeList)hddsExpr.evaluate( this.doc, XPathConstants.NODESET ); if ( nodes == null ) { LOGGER.error( "Failed to find attached hard drives." ); diff --git a/src/test/java/org/openslx/virtualization/VersionTest.java b/src/test/java/org/openslx/virtualization/VersionTest.java index 988437a..21464d9 100644 --- a/src/test/java/org/openslx/virtualization/VersionTest.java +++ b/src/test/java/org/openslx/virtualization/VersionTest.java @@ -92,8 +92,19 @@ public class VersionTest } @Test - @DisplayName( "Test that version is larger than" ) - public void testVersionLargerThan() + @DisplayName( "Test that version is smaller than with helper method" ) + public void testVersionSmallerThanMethod() + { + final Version versionOne = new Version( Short.valueOf( "2" ), Short.valueOf( "3" ) ); + final Version versionTwo = new Version( Short.valueOf( "3" ), Short.valueOf( "2" ) ); + + assertTrue( versionOne.isSmallerThan( versionTwo ) ); + assertFalse( versionTwo.isSmallerThan( versionOne ) ); + } + + @Test + @DisplayName( "Test that version is greater than" ) + public void testVersionGreaterThan() { final Version versionOne = new Version( Short.valueOf( "3" ), Short.valueOf( "3" ) ); final Version versionTwo = new Version( Short.valueOf( "3" ), Short.valueOf( "2" ) ); @@ -102,6 +113,17 @@ public class VersionTest assertEquals( -1, versionTwo.compareTo( versionOne ) ); } + @Test + @DisplayName( "Test that version is greater than with helper method" ) + public void testVersionGreaterThanMethod() + { + final Version versionOne = new Version( Short.valueOf( "3" ), Short.valueOf( "3" ) ); + final Version versionTwo = new Version( Short.valueOf( "3" ), Short.valueOf( "2" ) ); + + assertTrue( versionOne.isGreaterThan( versionTwo ) ); + assertFalse( versionTwo.isGreaterThan( versionOne ) ); + } + @Test @DisplayName( "Test that versions are equal (compareTo)" ) public void testVersionEqualCompareTo() diff --git a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationTestResources.java b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationTestResources.java new file mode 100644 index 0000000..4dfd0b7 --- /dev/null +++ b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationTestResources.java @@ -0,0 +1,18 @@ +package org.openslx.virtualization.configuration; + +import java.io.File; + +import org.openslx.virtualization.configuration.logic.ConfigurationLogicTestResources; + +public class VirtualizationConfigurationTestResources +{ + public static File getVmwareVmxFile( String vmwareVmxFileName ) + { + return ConfigurationLogicTestResources.getVmwareVmxFile( vmwareVmxFileName ); + } + + public static File getVirtualBoxXmlFile( String virtualBoxXmlFileName ) + { + return ConfigurationLogicTestResources.getVirtualBoxXmlFile( virtualBoxXmlFileName ); + } +} diff --git a/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java new file mode 100644 index 0000000..496c080 --- /dev/null +++ b/src/test/java/org/openslx/virtualization/configuration/VirtualizationConfigurationVirtualBoxTest.java @@ -0,0 +1,144 @@ +package org.openslx.virtualization.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 static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.openslx.virtualization.Version; +import org.openslx.vm.disk.DiskImage.ImageFormat; + +public class VirtualizationConfigurationVirtualBoxTest +{ + @BeforeAll + public static void setUp() + { + // disable logging with log4j + LogManager.getRootLogger().setLevel( Level.OFF ); + } + + @ParameterizedTest + @DisplayName( "Test version from VM configuration" ) + @MethodSource( "configAndVersionProvider" ) + public void testVirtualizationConfigurationVirtualBoxGetConfigurationVersion( String configFileName, + Version configVersion ) + throws IOException, VirtualizationConfigurationException + { + final File configFile = VirtualizationConfigurationTestResources.getVirtualBoxXmlFile( configFileName ); + final VirtualizationConfigurationVirtualBox vmConfig = new VirtualizationConfigurationVirtualBox( null, + configFile ); + + assertEquals( configVersion, vmConfig.getConfigurationVersion() ); + + assertDoesNotThrow( () -> vmConfig.validate() ); + } + + @ParameterizedTest + @DisplayName( "Test display name from VM configuration" ) + @MethodSource( "configAndVersionProvider" ) + public void testVirtualizationConfigurationVirtualBoxGetDisplayName( String configFileName, Version configVersion ) + throws IOException, VirtualizationConfigurationException + { + final File configFile = VirtualizationConfigurationTestResources.getVirtualBoxXmlFile( configFileName ); + final VirtualizationConfigurationVirtualBox vmConfig = new VirtualizationConfigurationVirtualBox( null, + configFile ); + + final String displayName = vmConfig.getDisplayName(); + + assertEquals( VirtualizationConfigurationVirtualBoxTest.getVmName( configVersion ), displayName ); + + assertDoesNotThrow( () -> vmConfig.validate() ); + } + + @ParameterizedTest + @DisplayName( "Test machine snapshot state from VM configuration" ) + @MethodSource( "configAndVersionProvider" ) + public void testVirtualizationConfigurationVirtualBoxIsMachineSnapshot( String configFileName, + Version configVersion ) + throws IOException, VirtualizationConfigurationException + { + final File configFile = VirtualizationConfigurationTestResources.getVirtualBoxXmlFile( configFileName ); + final VirtualizationConfigurationVirtualBox vmConfig = new VirtualizationConfigurationVirtualBox( null, + configFile ); + + final boolean isVmSnapshot = vmConfig.isMachineSnapshot(); + + assertFalse( isVmSnapshot ); + + assertDoesNotThrow( () -> vmConfig.validate() ); + } + + @ParameterizedTest + @DisplayName( "Test supported image formats from VM configuration" ) + @MethodSource( "configAndVersionProvider" ) + public void testVirtualizationConfigurationVirtualBoxGetSupportedImageFormats( String configFileName, + Version configVersion ) + throws IOException, VirtualizationConfigurationException + { + final File configFile = VirtualizationConfigurationTestResources.getVirtualBoxXmlFile( configFileName ); + final VirtualizationConfigurationVirtualBox vmConfig = new VirtualizationConfigurationVirtualBox( null, + configFile ); + + final List supportedImageFormats = vmConfig.getVirtualizer().getSupportedImageFormats(); + + assertNotNull( supportedImageFormats ); + assertEquals( 1, supportedImageFormats.size() ); + assertTrue( supportedImageFormats.containsAll( Arrays.asList( ImageFormat.VDI ) ) ); + + assertDoesNotThrow( () -> vmConfig.validate() ); + } + + @ParameterizedTest + @DisplayName( "Test output of HDDs from VM configuration" ) + @MethodSource( "configAndVersionProvider" ) + public void testVirtualizationConfigurationVirtualBoxGetHdds( String configFileName, Version configVersion ) + throws IOException, VirtualizationConfigurationException + { + final File configFile = VirtualizationConfigurationTestResources.getVirtualBoxXmlFile( configFileName ); + final VirtualizationConfigurationVirtualBox vmConfig = new VirtualizationConfigurationVirtualBox( null, + configFile ); + + final List hdds = vmConfig.getHdds(); + + final String imageFileName = VirtualizationConfigurationVirtualBoxTest.getVmName( configVersion ) + ".vdi"; + + assertNotNull( hdds ); + assertEquals( 1, hdds.size() ); + assertEquals( imageFileName, hdds.get( 0 ).diskImage ); + + assertDoesNotThrow( () -> vmConfig.validate() ); + } + + static String getVmName( Version version ) + { + return "ubuntu_" + version.toString().replace( '.', '-' ); + } + + static Stream configAndVersionProvider() + { + return Stream.of( + arguments( "virtualbox_default-ubuntu_v1-15.vbox", + new Version( Short.valueOf( "1" ), Short.valueOf( "15" ) ) ), + arguments( "virtualbox_default-ubuntu_v1-16.vbox", + new Version( Short.valueOf( "1" ), Short.valueOf( "16" ) ) ), + arguments( "virtualbox_default-ubuntu_v1-17.vbox", + new Version( Short.valueOf( "1" ), Short.valueOf( "17" ) ) ), + arguments( "virtualbox_default-ubuntu_v1-18.vbox", + new Version( Short.valueOf( "1" ), Short.valueOf( "18" ) ) ) ); + } +} diff --git a/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-15.vbox b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-15.vbox new file mode 100644 index 0000000..5e04478 --- /dev/null +++ b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-15.vbox @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-16.vbox b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-16.vbox new file mode 100644 index 0000000..04213e8 --- /dev/null +++ b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-16.vbox @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-17.vbox b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-17.vbox new file mode 100644 index 0000000..d9218ab --- /dev/null +++ b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-17.vbox @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-18.vbox b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-18.vbox new file mode 100644 index 0000000..6d70339 --- /dev/null +++ b/src/test/resources/virtualbox/xml/virtualbox_default-ubuntu_v1-18.vbox @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3-55-g7522