diff options
Diffstat (limited to 'src/main/java/org/openslx/util/vm/VboxConfig.java')
-rw-r--r-- | src/main/java/org/openslx/util/vm/VboxConfig.java | 184 |
1 files changed, 140 insertions, 44 deletions
diff --git a/src/main/java/org/openslx/util/vm/VboxConfig.java b/src/main/java/org/openslx/util/vm/VboxConfig.java index 9d6e6f1..6153abf 100644 --- a/src/main/java/org/openslx/util/vm/VboxConfig.java +++ b/src/main/java/org/openslx/util/vm/VboxConfig.java @@ -6,6 +6,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.List; import javax.xml.XMLConstants; import javax.xml.transform.stream.StreamSource; @@ -47,7 +48,6 @@ public class VboxConfig "/VirtualBox/Machine/Hardware/GuestProperties", "/VirtualBox/Machine/Hardware/VideoCapture", "/VirtualBox/Machine/Hardware/HID", - "/VirtualBox/Machine/Hardware/USB", "/VirtualBox/Machine/Hardware/LPT", "/VirtualBox/Machine/Hardware/SharedFolders", "/VirtualBox/Machine/Hardware/Network/Adapter[@enabled='true']/*", @@ -143,6 +143,7 @@ public class VboxConfig try { ensureHardwareUuid(); setOsType(); + fixUsb(); // Since we now support selecting specific speed if ( checkForPlaceholders() ) { return; } @@ -154,6 +155,33 @@ public class VboxConfig return; } } + + private void fixUsb() + { + NodeList list = findNodes( "/VirtualBox/Machine/Hardware/USB/Controllers/Controller" ); + if ( list != null && list.getLength() != 0 ) { + LOGGER.info( "USB present, not fixing anything" ); + return; + } + // If there's no USB section, this can mean two things: + // 1) Old config that would always default to USB 2.0 for "USB enabled" or nothing for disabled + // 2) New config with USB disabled + list = findNodes( "/VirtualBox/OpenSLX/USB[@disabled]" ); + if ( list != null && list.getLength() != 0 ) { + LOGGER.info( "USB explicitly disabled" ); + return; // Explicitly marked as disabled, do nothing + } + // We assume case 1) and add USB 2.0 + LOGGER.info( "Fixing USB: Adding USB 2.0" ); + Element controller; + Element node = createNodeRecursive( "/VirtualBox/Machine/Hardware/USB/Controllers" ); + controller = addNewNode( node, "Controller" ); + controller.setAttribute( "name", "OHCI" ); + controller.setAttribute( "type", "OHCI" ); + controller = addNewNode( node, "Controller" ); + controller.setAttribute( "name", "EHCI" ); + controller.setAttribute( "type", "EHCI" ); + } /** * Saves the machine's uuid as hardware uuid to prevent VMs from @@ -308,24 +336,42 @@ public class VboxConfig } /** - * Search disk drives within the DOM using this class + * Search for attached hard drives and determine their controller and their path. * * @throws XPathExpressionException */ public void setHdds() throws XPathExpressionException { - XPathExpression hddsExpr = XmlHelper.XPath.compile( "/VirtualBox/Machine/MediaRegistry/HardDisks/*" ); + XPathExpression hddsExpr = XmlHelper.XPath.compile( "/VirtualBox/Machine/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." ); + return; + } for ( int i = 0; i < nodes.getLength(); i++ ) { Element hddElement = (Element)nodes.item( i ); if ( hddElement == null ) continue; - String fileName = hddElement.getAttribute( "location" ); - String type = hddElement.getAttribute( "type" ); + String uuid = hddElement.getAttribute( "uuid" ); + if ( uuid.isEmpty() ) + continue; + // got uuid, check if it was registered + XPathExpression hddsRegistered = XmlHelper.XPath.compile( "/VirtualBox/Machine/MediaRegistry/HardDisks/HardDisk[@uuid='" + uuid + "']" ); + NodeList hddsRegisteredNodes = (NodeList)hddsRegistered.evaluate( this.doc, XPathConstants.NODESET ); + if ( hddsRegisteredNodes == null || hddsRegisteredNodes.getLength() != 1 ) { + LOGGER.error( "Found hard disk with uuid '" + uuid + "' which does not appear (unique) in the Media Registry. Skipping." ); + continue; + } + Element hddElementReg = (Element)hddsRegisteredNodes.item( 0 ); + if ( hddElementReg == null ) + continue; + String fileName = hddElementReg.getAttribute( "location" ); + String type = hddElementReg.getAttribute( "type" ); if ( !type.equals( "Normal" ) && !type.equals( "Writethrough" ) ) { LOGGER.warn( "Type of the disk file is neither 'Normal' nor 'Writethrough' but: " + type ); LOGGER.warn( "This makes the image not directly modificable, which might lead to problems when editing it locally." ); } + // search if it is also attached to a controller Node hddDevice = hddElement.getParentNode(); if ( hddDevice == null ) { LOGGER.error( "HDD node had a null parent, shouldn't happen" ); @@ -336,18 +382,19 @@ public class VboxConfig LOGGER.error( "HDD node had a null parent, shouldn't happen" ); continue; } - String controllerDevice = hddController.getAttribute( "type" ); - String bus = hddController.getAttribute( "name" ); + String controllerMode = hddController.getAttribute( "type" ); + String controllerType = hddController.getAttribute( "name" ); DriveBusType busType = null; - if ( bus.equals( "IDE" ) ) { + if ( controllerType.equals( "IDE" ) ) { busType = DriveBusType.IDE; - } else if ( bus.equals( "SCSI" ) ) { + } else if ( controllerType.equals( "SCSI" ) ) { busType = DriveBusType.SCSI; - } else if ( bus.equals( "SATA" ) ) { + } else if ( controllerType.equals( "SATA" ) ) { busType = DriveBusType.SATA; - } - // add them together - hddsArray.add( new HardDisk( controllerDevice, busType, fileName ) ); + } else + continue; + LOGGER.info( "Adding hard disk with controller: " + busType + " (" + controllerMode + ") from file '" + fileName + "'." ); + hddsArray.add( new HardDisk( controllerMode, busType, fileName ) ); } } @@ -362,35 +409,6 @@ public class VboxConfig } /** - * Enable USB by adding the element /VirtualBox/Machine/Hardware/USB - * and adding controllers for OHCI and EHCI (thus enabling USB 2.0). - */ - public void enableUsb() - { - addNewNode( "/VirtualBox/Machine/Hardware", "USB" ); - addNewNode( "/VirtualBox/Machine/Hardware/USB", "Controllers" ); - // OHCI for USB 1.0 - Node ohci = addNewNode( "/VirtualBox/Machine/Hardware/USB/Controllers", "Controller" ); - addAttributeToNode( ohci, "name", "OHCI" ); - addAttributeToNode( ohci, "type", "OHCI" ); - // EHCI for USB 2.0 - Node ehci = addNewNode( "/VirtualBox/Machine/Hardware/USB/Controllers", "Controller" ); - addAttributeToNode( ehci, "name", "EHCI" ); - addAttributeToNode( ehci, "type", "EHCI" ); - } - - /** - * Removes all USB elements - */ - public void disableUsb() - { - NodeList usbList = findNodes( "/VirtualBox/Machine/Hardware/USB" ); - for ( int i = 0; i < usbList.getLength(); i++ ) { - removeNode( usbList.item( 0 ) ); - } - } - - /** * Detect if the vbox file has any machine snapshot by looking at * the existance of '/VirtualBox/Machine/Snapshot' elements. * @@ -485,6 +503,58 @@ public class VboxConfig return addNewNode( possibleParents.item( 0 ), childName ); } + public Element createNodeRecursive( String xPath ) + { + String[] nodeNames = xPath.split( "/" ); + Node parent = this.doc; + Element latest = null; + for ( int nodeIndex = 0; nodeIndex < nodeNames.length; ++nodeIndex ) { + if ( nodeNames[nodeIndex].length() == 0 ) + continue; + Node node = skipNonElementNodes( parent.getFirstChild() ); + while ( node != null ) { + if ( node.getNodeType() == Node.ELEMENT_NODE && nodeNames[nodeIndex].equals( node.getNodeName() ) ) + break; // Found existing + // Check next on same level + node = skipNonElementNodes( node.getNextSibling() ); + } + if ( node == null ) { + node = doc.createElement( nodeNames[nodeIndex] ); + parent.appendChild( node ); + } + parent = node; + latest = (Element)node; + } + return latest; + } + + private Element skipNonElementNodes( Node nn ) + { + while ( nn != null && nn.getNodeType() != Node.ELEMENT_NODE ) { + nn = nn.getNextSibling(); + } + return (Element)nn; + } + + public void setExtraData( String key, String value ) + { + NodeList nl = findNodes( "/VirtualBox/Machine/ExtraData/ExtraDataItem[@name='" + key + "']" ); + Element e = null; + for ( int i = 0; i < nl.getLength(); ++i ) { + Node n = nl.item( i ); + if ( n.getNodeType() == Node.ELEMENT_NODE ) { + e = (Element)n; + break; + } + } + if ( e == null ) { + Element p = createNodeRecursive( "/VirtualBox/Machine/ExtraData" ); + e = addNewNode( p, "ExtraDataItem" ); + e.setAttribute( "name", key ); + } + e.setAttribute( "value", value ); + } + /** * Creates a new element to the given parent node. * @@ -492,12 +562,12 @@ public class VboxConfig * @param childName name of the new element to create * @return the newly created node */ - public Node addNewNode( Node parent, String childName ) + public Element addNewNode( Node parent, String childName ) { if ( parent == null || parent.getNodeType() != Node.ELEMENT_NODE ) { return null; } - Node newNode = null; + Element newNode = null; try { newNode = doc.createElement( childName ); parent.appendChild( newNode ); @@ -531,4 +601,30 @@ public class VboxConfig { return XmlHelper.getXmlFromDocument( doc, prettyPrint ); } + + /** + * Remove all nodes with name childName from parentPath + * @param parentPath XPath to parent node of where child nodes are to be deleted + * @param childName Name of nodes to delete + */ + public void removeNodes( String parentPath, String childName ) + { + NodeList parentNodes = findNodes( parentPath ); + // XPath might match multiple nodes + for ( int i = 0; i < parentNodes.getLength(); ++i ) { + Node parent = parentNodes.item( i ); + List<Node> delList = new ArrayList<>( 0 ); + // Iterate over child nodes + for ( Node child = parent.getFirstChild(); child != null; child = child.getNextSibling() ) { + if ( childName.equals( child.getNodeName() ) ) { + // Remember all to be deleted (don't delete while iterating) + delList.add( child ); + } + } + // Now delete them all + for ( Node child : delList ) { + parent.removeChild( child ); + } + } + } } |