summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/util/vm/VboxConfig.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openslx/util/vm/VboxConfig.java')
-rw-r--r--src/main/java/org/openslx/util/vm/VboxConfig.java184
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 );
+ }
+ }
+ }
}