summaryrefslogtreecommitdiffstats
path: root/src/main/java/org/openslx/util/vm
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/openslx/util/vm')
-rw-r--r--src/main/java/org/openslx/util/vm/DiskImage.java86
-rw-r--r--src/main/java/org/openslx/util/vm/QemuConfig.java7
-rw-r--r--src/main/java/org/openslx/util/vm/QemuMetaData.java93
-rw-r--r--src/main/java/org/openslx/util/vm/VboxConfig.java184
-rw-r--r--src/main/java/org/openslx/util/vm/VboxMetaData.java91
-rw-r--r--src/main/java/org/openslx/util/vm/VmMetaData.java626
-rw-r--r--src/main/java/org/openslx/util/vm/VmwareMetaData.java1100
7 files changed, 1272 insertions, 915 deletions
diff --git a/src/main/java/org/openslx/util/vm/DiskImage.java b/src/main/java/org/openslx/util/vm/DiskImage.java
index ca016f2..30fea99 100644
--- a/src/main/java/org/openslx/util/vm/DiskImage.java
+++ b/src/main/java/org/openslx/util/vm/DiskImage.java
@@ -71,9 +71,14 @@ public class DiskImage
LOGGER.debug( "Validating disk file: " + disk.getAbsolutePath() );
try ( RandomAccessFile file = new RandomAccessFile( disk, "r" ) ) {
// vmdk
- if ( file.readInt() == VMDK_MAGIC ) {
- file.seek( 512 );
- byte[] buffer = new byte[ 2048 ];
+ boolean isVmdkMagic = ( file.readInt() == VMDK_MAGIC );
+ if ( isVmdkMagic || file.length() < 4096 ) {
+ if ( isVmdkMagic ) {
+ file.seek( 512 );
+ } else {
+ file.seek( 0 );
+ }
+ byte[] buffer = new byte[ (int)Math.min( 2048, file.length() ) ];
file.readFully( buffer );
VmwareConfig config;
try {
@@ -82,20 +87,23 @@ public class DiskImage
config = null;
}
if ( config != null ) {
- subFormat = config.get( "createType" );
+ String sf = config.get( "createType" );
String parent = config.get( "parentCID" );
- this.isStandalone = isStandaloneCreateType( subFormat, parent );
- this.isCompressed = subFormat != null && subFormat.equalsIgnoreCase( "streamOptimized" );
- this.isSnapshot = parent != null && !parent.equalsIgnoreCase( "ffffffff" );
- this.format = ImageFormat.VMDK;
- String hwv = config.get( "ddb.virtualHWVersion" );
- if ( hwv == null ) {
- this.hwVersion = 10;
- } else {
- this.hwVersion = Util.parseInt( hwv, 10 );
+ if ( sf != null || parent != null ) {
+ subFormat = sf;
+ this.isStandalone = isStandaloneCreateType( subFormat, parent );
+ this.isCompressed = subFormat != null && subFormat.equalsIgnoreCase( "streamOptimized" );
+ this.isSnapshot = parent != null && !parent.equalsIgnoreCase( "ffffffff" );
+ this.format = ImageFormat.VMDK;
+ String hwv = config.get( "ddb.virtualHWVersion" );
+ if ( hwv == null ) {
+ this.hwVersion = 10;
+ } else {
+ this.hwVersion = Util.parseInt( hwv, 10 );
+ }
+ this.diskDescription = null;
+ return;
}
- this.diskDescription = null;
- return;
}
}
// Format spec from: https://forums.virtualbox.org/viewtopic.php?t=8046
@@ -152,30 +160,30 @@ public class DiskImage
return;
}
- file.seek(0);
- //TODO: Standalone & Snapshot
- if (file.readInt() == QEMU_MAGIC) {
- //skip the next 14 ints as they don't interest us
- // - QFI version (4 bytes)
- // - backing file offset (8 bytes)
- // - backing (8 bytes)
- // - crypt method (4 bytes)
- // - l1 size (4 bytes)
- // - l1 table offset (8 bytes)
- // - refcount table offset (8 bytes)
- // - refcount cluster (4 bytes)
- file.skipBytes( 14 * 4 );
- this.isSnapshot = file.readInt() > 0;
- //skip the next 14 ints as they don't interest us
- file.seek(374);
- this.isCompressed = file.read() == 1;
- this.diskDescription = null;
- this.format = ImageFormat.QCOW2;
- this.isStandalone = true;
- this.subFormat = null;
- this.hwVersion = 0;
- return;
- }
+ file.seek(0);
+ //TODO: Standalone & Snapshot
+ if (file.readInt() == QEMU_MAGIC) {
+ //skip the next 14 ints as they don't interest us
+ // - QFI version (4 bytes)
+ // - backing file offset (8 bytes)
+ // - backing (8 bytes)
+ // - crypt method (4 bytes)
+ // - l1 size (4 bytes)
+ // - l1 table offset (8 bytes)
+ // - refcount table offset (8 bytes)
+ // - refcount cluster (4 bytes)
+ file.skipBytes( 14 * 4 );
+ this.isSnapshot = file.readInt() > 0;
+ //skip the next 14 ints as they don't interest us
+ file.seek(374);
+ this.isCompressed = file.read() == 1;
+ this.diskDescription = null;
+ this.format = ImageFormat.QCOW2;
+ this.isStandalone = true;
+ this.subFormat = null;
+ this.hwVersion = 0;
+ return;
+ }
}
throw new UnknownImageFormatException();
}
diff --git a/src/main/java/org/openslx/util/vm/QemuConfig.java b/src/main/java/org/openslx/util/vm/QemuConfig.java
index ceb3285..89df62c 100644
--- a/src/main/java/org/openslx/util/vm/QemuConfig.java
+++ b/src/main/java/org/openslx/util/vm/QemuConfig.java
@@ -297,8 +297,8 @@ public final class QemuConfig {
case "scsi":
bus = DriveBusType.SCSI;
break;
- case "virtio":
- bus = DriveBusType.VIRTIO;
+// case "virtio":
+ // bus = DriveBusType.VIRTIO;
case "sata":
//not available for Qemu. Others : sd, mtd, floppy, pflash
break;
@@ -340,9 +340,6 @@ public final class QemuConfig {
case SCSI:
controllerDevice = "scsi-generic";
break;
- case VIRTIO:
- controllerDevice = "virtio-9p-device";
- break;
default:
controllerDevice = "scsi-generic";
break;
diff --git a/src/main/java/org/openslx/util/vm/QemuMetaData.java b/src/main/java/org/openslx/util/vm/QemuMetaData.java
index 8855f9c..814bfa4 100644
--- a/src/main/java/org/openslx/util/vm/QemuMetaData.java
+++ b/src/main/java/org/openslx/util/vm/QemuMetaData.java
@@ -51,8 +51,19 @@ class QemuSoundCardMeta {
value = val;
}
}
+class QemuUSBMeta {
-public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAccelMeta, QemuHWVersionMeta, QemuEthernetDevTypeMeta> {
+ public final String value;
+ public final int speed;
+
+ public QemuUSBMeta(String value, int speed) {
+
+ this.value = value;
+ this.speed = speed;
+ }
+}
+
+public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAccelMeta, QemuHWVersionMeta, QemuEthernetDevTypeMeta, QemuUSBMeta> {
private static final Logger LOGGER = Logger.getLogger(QemuMetaData.class);
@@ -288,6 +299,7 @@ public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAcce
@Override
public void setEthernetDevType(int cardIndex, VmMetaData.EthernetDevType type) {
+ /*
//TODO
QemuEthernetDevTypeMeta dev = networkCards.get(type);
header = new LinkedHashMap<>();
@@ -297,6 +309,7 @@ public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAcce
//option.put("netdev", "net" + cardIndex);
config.set(header, option);
netdevCounter++;
+ */
}
@Override
@@ -363,25 +376,45 @@ public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAcce
return virtualizer;
}
- @Override
- public void enableUsb(boolean enabled) {
- option = new TreeMap<>();
- if (enabled) {
- option.put("usb", "on");
- } else {
- option.put("usb", "off");
- }
-
- header = new LinkedHashMap<>();
- header.put(MACHINE.getHeader(), MACHINE.getID());
- config.set(header, option);
- }
-
- @Override
- public boolean disableSuspend() {
- return false;
- }
-
+// @Override
+// public void enableUsb(boolean enabled) {
+// option = new TreeMap<>();
+// if (enabled) {
+// option.put("usb", "on");
+// } else {
+// option.put("usb", "off");
+// }
+//
+// header = new LinkedHashMap<>();
+// header.put(MACHINE.getHeader(), MACHINE.getID());
+// config.set(header, option);
+// }
+
+// @Override
+// public boolean disableSuspend() {
+// return false;
+// }
+ @Override
+ public boolean tweakForNonPersistent() {
+ return false;
+ }
+ public void setMaxUsbSpeed( VmMetaData.UsbSpeed speed )
+ {
+ // TODO: Actual speed setting?
+ if ( speed == null || speed == VmMetaData.UsbSpeed.NONE ) {
+ option.remove( "usb" );
+ } else {
+ option.put( "usb", "" );
+ }
+ }
+
+ @Override
+ public VmMetaData.UsbSpeed getMaxUsbSpeed()
+ {
+ if (option.containsKey( "usb" ) )
+ return VmMetaData.UsbSpeed.USB2_0; // TODO
+ return VmMetaData.UsbSpeed.NONE;
+ }
@Override
public void registerVirtualHW() {
soundCards.put(VmMetaData.SoundCardType.NONE, new QemuSoundCardMeta(false, null));
@@ -390,16 +423,20 @@ public final class QemuMetaData extends VmMetaData<QemuSoundCardMeta, QemuDDAcce
soundCards.put(VmMetaData.SoundCardType.ES, new QemuSoundCardMeta(true, "es1370"));
soundCards.put(VmMetaData.SoundCardType.SOUND_BLASTER, new QemuSoundCardMeta(true, "sb16"));
- ddacc.put(DDAcceleration.OFF, new QemuDDAccelMeta(false));
- ddacc.put(DDAcceleration.ON, new QemuDDAccelMeta(true));
+ ddacc.put(VmMetaData.DDAcceleration.OFF, new QemuDDAccelMeta(false));
+ ddacc.put(VmMetaData.DDAcceleration.ON, new QemuDDAccelMeta(true));
- hwversion.put(HWVersion.DEFAULT, new QemuHWVersionMeta(0));
+ hwversion.put(VmMetaData.HWVersion.DEFAULT, new QemuHWVersionMeta(0));
- networkCards.put(EthernetDevType.VIRTIO, new QemuEthernetDevTypeMeta("virtio-net-pci"));
- networkCards.put(EthernetDevType.E1000, new QemuEthernetDevTypeMeta("e1000"));
- networkCards.put(EthernetDevType.PCNET32, new QemuEthernetDevTypeMeta("pcnet"));
- networkCards.put(EthernetDevType.RTL8139, new QemuEthernetDevTypeMeta("rtl8139"));
+ usbSpeeds.put(VmMetaData.UsbSpeed.NONE, new QemuUSBMeta(null, 0));
+ usbSpeeds.put(VmMetaData.UsbSpeed.USB1_1, new QemuUSBMeta("usb", 1));
+ usbSpeeds.put(VmMetaData.UsbSpeed.USB2_0, new QemuUSBMeta("ehci", 2));
+ usbSpeeds.put(VmMetaData.UsbSpeed.USB3_0, new QemuUSBMeta("usb_xhci", 3));
- }
+ //networkCards.put(VmMetaData.EthernetDevType.VIRTIO, new QemuEthernetDevTypeMeta("virtio-net-pci"));
+ networkCards.put(VmMetaData.EthernetDevType.E1000, new QemuEthernetDevTypeMeta("e1000"));
+ networkCards.put(VmMetaData.EthernetDevType.PCNET32, new QemuEthernetDevTypeMeta("pcnet"));
+ //networkCards.put(VmMetaData.EthernetDevType.RTL8139, new QemuEthernetDevTypeMeta("rtl8139"));
+ }
}
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 );
+ }
+ }
+ }
}
diff --git a/src/main/java/org/openslx/util/vm/VboxMetaData.java b/src/main/java/org/openslx/util/vm/VboxMetaData.java
index 00ca8ad..da5189e 100644
--- a/src/main/java/org/openslx/util/vm/VboxMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VboxMetaData.java
@@ -7,6 +7,7 @@ import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
+import java.util.Map.Entry;
import java.util.UUID;
import org.apache.log4j.Logger;
@@ -14,6 +15,7 @@ import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.thrifthelper.TConst;
import org.openslx.util.vm.VboxConfig.PlaceHolder;
+import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
@@ -62,7 +64,18 @@ class VBoxEthernetDevTypeMeta
}
}
-public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta, VBoxHWVersionMeta, VBoxEthernetDevTypeMeta>
+class VBoxUsbSpeedMeta
+{
+ public final String value;
+ public final int speed;
+ public VBoxUsbSpeedMeta( String value, int speed )
+ {
+ this.value = value;
+ this.speed = speed;
+ }
+}
+
+public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta, VBoxHWVersionMeta, VBoxEthernetDevTypeMeta, VBoxUsbSpeedMeta>
{
private static final Logger LOGGER = Logger.getLogger( VboxMetaData.class );
@@ -114,16 +127,6 @@ public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta,
}
@Override
- public void enableUsb( boolean enabled )
- {
- if ( !enabled ) {
- config.disableUsb();
- } else {
- config.enableUsb();
- }
- }
-
- @Override
public void applySettingsForLocalEdit()
{
// TODO Auto-generated method stub
@@ -415,6 +418,7 @@ public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta,
public void registerVirtualHW()
{
// none type needs to have a valid value; it takes the value of AC97; if value is left null or empty vm will not start because value is not valid
+ // TODO: Maybe just remove the entire section from the XML? Same for ethernet...
soundCards.put( VmMetaData.SoundCardType.NONE, new VBoxSoundCardMeta( false, "AC97" ) );
soundCards.put( VmMetaData.SoundCardType.SOUND_BLASTER, new VBoxSoundCardMeta( true, "SB16" ) );
soundCards.put( VmMetaData.SoundCardType.HD_AUDIO, new VBoxSoundCardMeta( true, "HDA" ) );
@@ -433,6 +437,11 @@ public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta,
networkCards.put( VmMetaData.EthernetDevType.PRO1000TS, new VBoxEthernetDevTypeMeta( true, "82543GC" ) );
networkCards.put( VmMetaData.EthernetDevType.PRO1000MTS, new VBoxEthernetDevTypeMeta( true, "82545EM" ) );
networkCards.put( VmMetaData.EthernetDevType.PARAVIRT, new VBoxEthernetDevTypeMeta( true, "virtio" ) );
+
+ usbSpeeds.put( VmMetaData.UsbSpeed.NONE, new VBoxUsbSpeedMeta( null, 0 ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB1_1, new VBoxUsbSpeedMeta( "OHCI", 1 ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB2_0, new VBoxUsbSpeedMeta( "EHCI", 2 ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB3_0, new VBoxUsbSpeedMeta( "XHCI", 3 ) );
}
@Override
@@ -447,12 +456,66 @@ public class VboxMetaData extends VmMetaData<VBoxSoundCardMeta, VBoxDDAccelMeta,
}
@Override
- public boolean disableSuspend()
+ public boolean tweakForNonPersistent()
{
- // TODO how??
- // short answer is: you can't
+ // Cannot disable suspend
// https://forums.virtualbox.org/viewtopic.php?f=6&t=77169
// https://forums.virtualbox.org/viewtopic.php?f=8&t=80338
+ // But some other stuff that won't make sense in non-persistent mode
+ config.setExtraData( "GUI/LastCloseAction", "PowerOff" );
+ // Could use "Default" instead of "Last" above, but you won't get any confirmation dialog in that case
+ config.setExtraData( "GUI/RestrictedRuntimeHelpMenuActions", "All" );
+ config.setExtraData( "GUI/RestrictedRuntimeMachineMenuActions", "TakeSnapshot,Pause,SaveState" );
+ config.setExtraData( "GUI/RestrictedRuntimeMenus", "Help" );
+ config.setExtraData( "GUI/PreventSnapshotOperations", "true" );
+ config.setExtraData( "GUI/PreventApplicationUpdate", "true" );
+ config.setExtraData( "GUI/RestrictedCloseActions", "SaveState,PowerOffRestoringSnapshot,Detach" );
return true;
}
+
+ @Override
+ public void setMaxUsbSpeed( VmMetaData.UsbSpeed speed )
+ {
+ // Wipe existing ones
+ config.removeNodes( "/VirtualBox/Machine/Hardware", "USB" );
+ if ( speed == null || speed == VmMetaData.UsbSpeed.NONE ) {
+ // Add marker so we know it's not an old config and we really want no USB
+ Element node = config.createNodeRecursive( "/VirtualBox/OpenSLX/USB" );
+ if ( node != null ) {
+ node.setAttribute( "disabled", "true" );
+ }
+ return; // NO USB
+ }
+ Element node = config.createNodeRecursive( "/VirtualBox/Machine/Hardware/USB/Controllers/Controller" );
+ VBoxUsbSpeedMeta vboxSpeed = usbSpeeds.get( speed );
+ node.setAttribute( "type", vboxSpeed.value );
+ node.setAttribute( "name", vboxSpeed.value );
+ if ( speed == UsbSpeed.USB2_0 ) {
+ // If EHCI (2.0) is selected, VBox adds an OHCI controller too...
+ node.setAttribute( "type", "OHCI" );
+ node.setAttribute( "name", "OHCI" );
+ }
+ }
+
+ @Override
+ public VmMetaData.UsbSpeed getMaxUsbSpeed()
+ {
+ NodeList nodes = config.findNodes( "/VirtualBox/Machine/Hardware/USB/Controllers/Controller/@type" );
+ int maxSpeed = 0;
+ VmMetaData.UsbSpeed maxItem = VmMetaData.UsbSpeed.NONE;
+ for ( int i = 0; i < nodes.getLength(); ++i ) {
+ if ( nodes.item( i ).getNodeType() != Node.ATTRIBUTE_NODE ) {
+ LOGGER.info( "Not ATTRIBUTE type" );
+ continue;
+ }
+ String type = ((Attr)nodes.item( i )).getValue();
+ for ( Entry<VmMetaData.UsbSpeed, VBoxUsbSpeedMeta> s : usbSpeeds.entrySet() ) {
+ if ( s.getValue().speed > maxSpeed && type.equals( s.getValue().value ) ) {
+ maxSpeed = s.getValue().speed;
+ maxItem = s.getKey();
+ }
+ }
+ }
+ return maxItem;
+ }
}
diff --git a/src/main/java/org/openslx/util/vm/VmMetaData.java b/src/main/java/org/openslx/util/vm/VmMetaData.java
index c17df89..714a7e4 100644
--- a/src/main/java/org/openslx/util/vm/VmMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VmMetaData.java
@@ -18,96 +18,133 @@ import org.openslx.bwlp.thrift.iface.Virtualizer;
* Describes a configured virtual machine. This class is parsed from a machine
* description, like a *.vmx for VMware machines.
*/
-public abstract class VmMetaData<T, U, V, W> {
-
+public abstract class VmMetaData<T, U, V, W, X>
+{
private static final Logger LOGGER = Logger.getLogger(VmMetaData.class);
/*
* Helper types
- */
- protected Map<SoundCardType, T> soundCards = new HashMap<>();
- protected Map<DDAcceleration, U> ddacc = new HashMap<>();
- protected Map<HWVersion, V> hwversion = new HashMap<>();
- protected Map<EthernetDevType, W> networkCards = new HashMap<>();
-
- /**
- * Virtual sound cards types
- */
- public static enum SoundCardType {
- NONE("None"), DEFAULT("(default)"), SOUND_BLASTER("Sound Blaster 16"), ES("ES 1371"), HD_AUDIO("Intel Integrated HD Audio"), AC("Intel ICH Audio Codec 97");
-
- public final String displayName;
-
- private SoundCardType(String dName) {
- this.displayName = dName;
- }
- }
-
- /**
- * 3D acceleration types
- */
- public static enum DDAcceleration {
- OFF("Off"), ON("On");
-
- public final String displayName;
-
- private DDAcceleration(String dName) {
- this.displayName = dName;
- }
- }
-
- /**
- * Virtual hardware version - currently only in use for VMPlayer
- */
- public static enum HWVersion {
- NONE("(invalid)"), THREE(" 3 (Workstation 4/5, Player 1)"), FOUR(" 4 (Workstation 4/5, Player 1/2, Fusion 1)"), SIX(" 6 (Workstation 6)"), SEVEN(
- " 7 (Workstation 6.5/7, Player 3, Fusion 2/3)"), EIGHT(" 8 (Workstation 8, Player/Fusion 4)"), NINE(" 9 (Workstation 9, Player/Fusion 5)"), TEN(
- "10 (Workstation 10, Player/Fusion 6)"), ELEVEN(
- "11 (Workstation 11, Player/Fusion 7)"), TWELVE("12 (Workstation/Player 12, Fusion 8)"), DEFAULT("default");
-
- public final String displayName;
-
- private HWVersion(String dName) {
- this.displayName = dName;
- }
- }
-
- /**
- * Virtual network cards
- */
- public static enum EthernetDevType {
- AUTO("(default)"), PCNET32("AMD PCnet32"), E1000("Intel E1000 (PCI)"), E1000E("Intel E1000e (PCI-Express)"), VMXNET("VMXnet"), VMXNET3("VMXnet 3"), PCNETPCI2(
- "PCnet-PCI II"), PCNETFAST3("PCnet-FAST III"), PRO1000MTD("Intel PRO/1000 MT Desktop"), PRO1000TS(
- "Intel PRO/1000 T Server"), PRO1000MTS("Intel PRO/1000 MT Server"), PARAVIRT("Paravirtualized Network"), VIRTIO("Virtual High Performance Ethernet card"), RTL8139("Realtek Fast Ethernet "), NONE("No Network Card");
-
- public final String displayName;
-
- private EthernetDevType(String dName) {
- this.displayName = dName;
- }
- }
-
- public static enum DriveBusType {
- SCSI, IDE, SATA, VIRTIO;
- }
-
- public static class HardDisk {
-
- public final String chipsetDriver;
- public final DriveBusType bus;
- public final String diskImage;
-
- public HardDisk(String chipsetDriver, DriveBusType bus, String diskImage) {
- this.chipsetDriver = chipsetDriver;
- this.bus = bus;
- this.diskImage = diskImage;
- }
- }
-
- public static enum EtherType {
- NAT, BRIDGED, HOST_ONLY;
- }
- /*
+ */
+ protected Map<SoundCardType, T> soundCards = new HashMap<>();
+ protected Map<DDAcceleration, U> ddacc = new HashMap<>();
+ protected Map<HWVersion, V> hwversion = new HashMap<>();
+ protected Map<EthernetDevType, W> networkCards = new HashMap<>();
+ protected Map<UsbSpeed, X> usbSpeeds = new HashMap<>();
+
+ /**
+ * Virtual sound cards types
+ */
+ public static enum SoundCardType
+ {
+ NONE( "None" ), DEFAULT( "(default)" ), SOUND_BLASTER( "Sound Blaster 16" ), ES( "ES 1371" ), HD_AUDIO( "Intel Integrated HD Audio" ), AC( "Intel ICH Audio Codec 97" );
+
+ public final String displayName;
+
+ private SoundCardType( String dName )
+ {
+ this.displayName = dName;
+ }
+ }
+
+ /**
+ * 3D acceleration types
+ */
+ public static enum DDAcceleration
+ {
+ OFF( "Off" ), ON( "On" );
+
+ public final String displayName;
+
+ private DDAcceleration( String dName )
+ {
+ this.displayName = dName;
+ }
+ }
+
+ /**
+ * Virtual hardware version - currently only in use for VMPlayer
+ */
+ public static enum HWVersion
+ {
+ NONE( "(invalid)" ),
+ THREE( " 3 (Workstation 4/5, Player 1)" ),
+ FOUR( " 4 (Workstation 4/5, Player 1/2, Fusion 1)" ),
+ SIX( " 6 (Workstation 6)" ),
+ SEVEN( " 7 (Workstation 6.5/7, Player 3, Fusion 2/3)" ),
+ EIGHT( " 8 (Workstation 8, Player/Fusion 4)" ),
+ NINE( " 9 (Workstation 9, Player/Fusion 5)" ),
+ TEN( "10 (Workstation 10, Player/Fusion 6)" ),
+ ELEVEN( "11 (Workstation 11, Player/Fusion 7)" ),
+ TWELVE( "12 (Workstation/Player 12, Fusion 8)" ),
+ FOURTEEN( "14 (Workstation/Player 14, Fusion 10)"),
+ FIFTEEN( "15 (Workstation/Player 15, Fusion 11)"),
+ FIFTEEN_ONE( "16 (Workstation/Player 15.1, Fusion 11.1)"),
+ DEFAULT( "default" );
+
+ public final String displayName;
+
+ private HWVersion( String dName )
+ {
+ this.displayName = dName;
+ }
+ }
+
+ /**
+ * Virtual network cards
+ */
+ public static enum EthernetDevType
+ {
+ AUTO( "(default)" ), PCNET32( "AMD PCnet32" ), E1000( "Intel E1000 (PCI)" ), E1000E( "Intel E1000e (PCI-Express)" ), VMXNET( "VMXnet" ), VMXNET3( "VMXnet 3" ), PCNETPCI2(
+ "PCnet-PCI II" ), PCNETFAST3( "PCnet-FAST III" ), PRO1000MTD( "Intel PRO/1000 MT Desktop" ), PRO1000TS(
+ "Intel PRO/1000 T Server" ), PRO1000MTS( "Intel PRO/1000 MT Server" ), PARAVIRT( "Paravirtualized Network" ), NONE( "No Network Card" );
+
+ public final String displayName;
+
+ private EthernetDevType( String dName )
+ {
+ this.displayName = dName;
+ }
+ }
+
+ public static enum UsbSpeed
+ {
+ NONE( "None" ),
+ USB1_1( "USB 1.1" ),
+ USB2_0( "USB 2.0" ),
+ USB3_0( "USB 3.0" );
+
+ public final String displayName;
+
+ private UsbSpeed( String dName )
+ {
+ this.displayName = dName;
+ }
+ }
+
+ public static enum DriveBusType
+ {
+ SCSI, IDE, SATA;
+ }
+
+ public static class HardDisk
+ {
+ public final String chipsetDriver;
+ public final DriveBusType bus;
+ public final String diskImage;
+
+ public HardDisk( String chipsetDriver, DriveBusType bus, String diskImage )
+ {
+ this.chipsetDriver = chipsetDriver;
+ this.bus = bus;
+ this.diskImage = diskImage;
+ }
+ }
+
+ public static enum EtherType
+ {
+ NAT, BRIDGED, HOST_ONLY;
+ }
+ /*
* Members
*/
@@ -123,53 +160,67 @@ public abstract class VmMetaData<T, U, V, W> {
/*
* Getters for virtual hardware
- */
- public List<SoundCardType> getSupportedSoundCards() {
- ArrayList<SoundCardType> availables = new ArrayList<SoundCardType>(soundCards.keySet());
- Collections.sort(availables);
- return availables;
- }
-
- public List<DDAcceleration> getSupportedDDAccs() {
- ArrayList<DDAcceleration> availables = new ArrayList<DDAcceleration>(ddacc.keySet());
- Collections.sort(availables);
- return availables;
- }
-
- public List<HWVersion> getSupportedHWVersions() {
- ArrayList<HWVersion> availables = new ArrayList<HWVersion>(hwversion.keySet());
- Collections.sort(availables);
- return availables;
- }
-
- public List<EthernetDevType> getSupportedEthernetDevices() {
- ArrayList<EthernetDevType> availables = new ArrayList<EthernetDevType>(networkCards.keySet());
- Collections.sort(availables);
- return availables;
- }
-
- /**
- * Get operating system of this VM.
- */
- public OperatingSystem getOs() {
- return os;
- }
-
- /**
- * Get all hard disks of this VM.
- */
- public List<HardDisk> getHdds() {
- return Collections.unmodifiableList(hdds);
- }
-
- /**
- * Get display name of VM.
- */
- public String getDisplayName() {
- return displayName;
- }
-
- /*
+ */
+ public List<SoundCardType> getSupportedSoundCards()
+ {
+ ArrayList<SoundCardType> availables = new ArrayList<SoundCardType>( soundCards.keySet() );
+ Collections.sort( availables );
+ return availables;
+ }
+
+ public List<DDAcceleration> getSupportedDDAccs()
+ {
+ ArrayList<DDAcceleration> availables = new ArrayList<DDAcceleration>( ddacc.keySet() );
+ Collections.sort( availables );
+ return availables;
+ }
+
+ public List<HWVersion> getSupportedHWVersions()
+ {
+ ArrayList<HWVersion> availables = new ArrayList<HWVersion>( hwversion.keySet() );
+ Collections.sort( availables );
+ return availables;
+ }
+
+ public List<EthernetDevType> getSupportedEthernetDevices()
+ {
+ ArrayList<EthernetDevType> availables = new ArrayList<EthernetDevType>( networkCards.keySet() );
+ Collections.sort( availables );
+ return availables;
+ }
+
+ public List<UsbSpeed> getSupportedUsbSpeeds()
+ {
+ ArrayList<UsbSpeed> availables = new ArrayList<>( usbSpeeds.keySet() );
+ Collections.sort( availables );
+ return availables;
+ }
+
+ /**
+ * Get operating system of this VM.
+ */
+ public OperatingSystem getOs()
+ {
+ return os;
+ }
+
+ /**
+ * Get all hard disks of this VM.
+ */
+ public List<HardDisk> getHdds()
+ {
+ return Collections.unmodifiableList( hdds );
+ }
+
+ /**
+ * Get display name of VM.
+ */
+ public String getDisplayName()
+ {
+ return displayName;
+ }
+
+ /*
* Getter for isMachineSnapshot
*/
public boolean isMachineSnapshot() {
@@ -191,156 +242,161 @@ public abstract class VmMetaData<T, U, V, W> {
/*
* Methods
- */
- public VmMetaData(List<OperatingSystem> osList) {
- this.osList = osList;
- }
-
- /**
- * Called from subclass to set the OS. If the OS cannot be determined from
- * the given parameters, it will not be set.
- *
- * @param virtId virtualizer, eg "vmware" for VMware
- * @param virtOsId the os identifier used by the virtualizer, eg.
- * windows7-64 for 64bit Windows 7 on VMware
- */
- protected final void setOs(String virtId, String virtOsId) {
- OperatingSystem lazyMatch = null;
- for (OperatingSystem os : osList) {
- if (os.getVirtualizerOsId() == null) {
- continue;
- }
- for (Entry<String, String> entry : os.getVirtualizerOsId().entrySet()) {
- if (!entry.getValue().equals(virtOsId)) {
- continue;
- }
- if (entry.getKey().equals(virtId)) {
- this.os = os;
- return;
- } else {
- lazyMatch = os;
- }
- }
- }
- this.os = lazyMatch;
- }
-
- /**
- * Apply config options that are desired when locally editing a VM. for
- * vmware, this disables automatic DPI scaling of the guest.
- */
- public abstract void applySettingsForLocalEdit();
-
- /**
- * Returns a VmMetaData instance of the given machine description given as
- * file
- *
- * @param osList List of supported operating systems
- * @param file VM's machine description file to get the metadata instance
- * from
- * @return VmMetaData object representing the relevant parts of the given
- * machine description
- */
- public static VmMetaData<?, ?, ?, ?> getInstance(List<OperatingSystem> osList, File file)
- throws IOException {
- try {
- return new VmwareMetaData(osList, file);
- } catch (UnsupportedVirtualizerFormatException e) {
- LOGGER.info("Not a VMware file", e);
- }
- try {
- return new VboxMetaData(osList, file);
- } catch (UnsupportedVirtualizerFormatException e) {
- LOGGER.info("Not a VirtualBox file", e);
- }
- try {
- return new QemuMetaData(osList, file);
- } catch (Exception e) {
- LOGGER.info("Not a QEmu file", e);
- }
- LOGGER.error("Could not detect any known virtualizer format");
- return null;
- }
-
- /**
- * Returns a VmMetaData instance of the given machine description given as a
- * byte array
- *
- * @param osList List of supported operating systems
- * @param vmContent VM's machine description as byte array (e.g. stored in
- * DB)
- * @param length length of the byte array given as vmContent
- * @return VmMetaData object representing the relevant parts of the given
- * machine description
- * @throws IOException
- */
- public static VmMetaData<?, ?, ?, ?> getInstance(List<OperatingSystem> osList, byte[] vmContent, int length) throws IOException {
- try {
- return new VmwareMetaData(osList, vmContent, length);
- } catch (UnsupportedVirtualizerFormatException e) {
- LOGGER.info("Not a VMware file", e);
- }
- try {
- return new VboxMetaData(osList, vmContent, length);
- } catch (UnsupportedVirtualizerFormatException e) {
- LOGGER.info("Not a VirtualBox file", e);
- }
- try {
- return new QemuMetaData(osList, vmContent, length);
- } catch (UnsupportedVirtualizerFormatException e) {
- LOGGER.info("Not a VirtualBox file", e);
- }
- // TODO QEmu -- hack above expects qcow2 file, so we can't do anything here yet
- LOGGER.error("Could not detect any known virtualizer format");
- return null;
- }
-
- public abstract boolean addHddTemplate(File diskImage, String hddMode, String redoDir);
-
- public abstract boolean addHddTemplate(String diskImagePath, String hddMode, String redoDir);
-
- public abstract boolean addDefaultNat();
-
- public abstract void setOs(String vendorOsId);
-
- public abstract boolean addDisplayName(String name);
-
- public abstract boolean addRam(int mem);
-
- public abstract void addFloppy(int index, String image, boolean readOnly);
-
- public abstract boolean addCdrom(String image);
-
- public abstract boolean addCpuCoreCount(int nrOfCores);
-
- public abstract void setSoundCard(SoundCardType type);
-
- public abstract SoundCardType getSoundCard();
-
- public abstract void setDDAcceleration(DDAcceleration type);
-
- public abstract DDAcceleration getDDAcceleration();
-
- public abstract void setHWVersion(HWVersion type);
-
- public abstract HWVersion getHWVersion();
-
- public abstract void setEthernetDevType(int cardIndex, EthernetDevType type);
-
- public abstract EthernetDevType getEthernetDevType(int cardIndex);
-
- public abstract byte[] getDefinitionArray();
-
- public abstract boolean addEthernet(EtherType type);
-
- public abstract Virtualizer getVirtualizer();
-
- public abstract void enableUsb(boolean enabled);
-
- public abstract boolean disableSuspend();
-
- /**
- * Function used to register virtual devices
- */
- public abstract void registerVirtualHW();
+ */
+
+ public VmMetaData( List<OperatingSystem> osList )
+ {
+ this.osList = osList;
+ }
+
+ /**
+ * Called from subclass to set the OS. If the OS cannot be determined from the
+ * given parameters, it will not be set.
+ *
+ * @param virtId
+ * virtualizer, eg "vmware" for VMware
+ * @param virtOsId
+ * the os identifier used by the virtualizer, eg. windows7-64 for
+ * 64bit Windows 7 on VMware
+ */
+ protected final void setOs( String virtId, String virtOsId )
+ {
+ OperatingSystem lazyMatch = null;
+ for ( OperatingSystem os : osList ) {
+ if ( os.getVirtualizerOsId() == null )
+ continue;
+ for ( Entry<String, String> entry : os.getVirtualizerOsId().entrySet() ) {
+ if ( !entry.getValue().equals( virtOsId ) )
+ continue;
+ if ( entry.getKey().equals( virtId ) ) {
+ this.os = os;
+ return;
+ } else {
+ lazyMatch = os;
+ }
+ }
+ }
+ this.os = lazyMatch;
+ }
+
+ /**
+ * Apply config options that are desired when locally editing a VM. for vmware,
+ * this disables automatic DPI scaling of the guest.
+ */
+ public abstract void applySettingsForLocalEdit();
+
+ /**
+ * Returns a VmMetaData instance of the given machine description given as file
+ *
+ * @param osList List of supported operating systems
+ * @param file VM's machine description file to get the metadata instance from
+ * @return VmMetaData object representing the relevant parts of the given machine description
+ */
+ public static VmMetaData<?, ?, ?, ?, ?> getInstance( List<OperatingSystem> osList, File file )
+ throws IOException
+ {
+ try {
+ return new VmwareMetaData( osList, file );
+ } catch ( UnsupportedVirtualizerFormatException e ) {
+ LOGGER.info( "Not a VMware file", e );
+ }
+ try {
+ return new VboxMetaData( osList, file );
+ } catch ( UnsupportedVirtualizerFormatException e ) {
+ LOGGER.info( "Not a VirtualBox file", e );
+ }
+ try {
+ return new QemuMetaData( osList, file );
+ } catch ( Exception e ) {
+ LOGGER.info( "Not a QEmu file", e );
+ }
+ LOGGER.error( "Could not detect any known virtualizer format" );
+ return null;
+ }
+
+ /**
+ * Returns a VmMetaData instance of the given machine description given as a byte array
+ *
+ * @param osList List of supported operating systems
+ * @param vmContent VM's machine description as byte array (e.g. stored in DB)
+ * @param length length of the byte array given as vmContent
+ * @return VmMetaData object representing the relevant parts of the given machine description
+ * @throws IOException
+ */
+ public static VmMetaData<?, ?, ?, ?, ?> getInstance( List<OperatingSystem> osList, byte[] vmContent, int length ) throws IOException
+ {
+ Map<String, Exception> exceptions = new HashMap<>();
+ try {
+ return new VmwareMetaData( osList, vmContent, length );
+ } catch ( UnsupportedVirtualizerFormatException e ) {
+ exceptions.put( "Not a VMware file", e );
+ }
+ try {
+ return new VboxMetaData( osList, vmContent, length );
+ } catch ( UnsupportedVirtualizerFormatException e ) {
+ exceptions.put( "Not a VirtualBox file", e );
+ }
+ try {
+ return new QemuMetaData( osList, vmContent, length );
+ } catch ( UnsupportedVirtualizerFormatException e ) {
+ exceptions.put( "Not a QEMU file", e );
+ }
+ // TODO QEmu -- hack above expects qcow2 file, so we can't do anything here yet
+ LOGGER.error( "Could not detect any known virtualizer format" );
+ for ( Entry<String, Exception> e : exceptions.entrySet() ) {
+ LOGGER.error( e.getKey(), e.getValue() );
+ }
+ return null;
+ }
+
+ public abstract boolean addHddTemplate( File diskImage, String hddMode, String redoDir );
+
+ public abstract boolean addHddTemplate( String diskImagePath, String hddMode, String redoDir );
+
+ public abstract boolean addDefaultNat();
+
+ public abstract void setOs( String vendorOsId );
+
+ public abstract boolean addDisplayName( String name );
+
+ public abstract boolean addRam( int mem );
+
+ public abstract void addFloppy( int index, String image, boolean readOnly );
+
+ public abstract boolean addCdrom( String image );
+
+ public abstract boolean addCpuCoreCount( int nrOfCores );
+
+ public abstract void setSoundCard( SoundCardType type );
+
+ public abstract SoundCardType getSoundCard();
+
+ public abstract void setDDAcceleration( DDAcceleration type );
+
+ public abstract DDAcceleration getDDAcceleration();
+
+ public abstract void setHWVersion( HWVersion type );
+
+ public abstract HWVersion getHWVersion();
+
+ public abstract void setEthernetDevType( int cardIndex, EthernetDevType type );
+
+ public abstract EthernetDevType getEthernetDevType( int cardIndex );
+
+ public abstract void setMaxUsbSpeed( UsbSpeed speed );
+
+ public abstract UsbSpeed getMaxUsbSpeed();
+
+ public abstract byte[] getDefinitionArray();
+
+ public abstract boolean addEthernet( EtherType type );
+
+ public abstract Virtualizer getVirtualizer();
+
+ public abstract boolean tweakForNonPersistent();
+
+ /**
+ * Function used to register virtual devices
+ */
+ public abstract void registerVirtualHW();
}
diff --git a/src/main/java/org/openslx/util/vm/VmwareMetaData.java b/src/main/java/org/openslx/util/vm/VmwareMetaData.java
index c54ded8..fab90de 100644
--- a/src/main/java/org/openslx/util/vm/VmwareMetaData.java
+++ b/src/main/java/org/openslx/util/vm/VmwareMetaData.java
@@ -55,505 +55,605 @@ class VmWareEthernetDevTypeMeta {
}
}
-public class VmwareMetaData extends VmMetaData<VmWareSoundCardMeta, VmWareDDAccelMeta, VmWareHWVersionMeta, VmWareEthernetDevTypeMeta> {
-
- private static final Logger LOGGER = Logger.getLogger(VmwareMetaData.class);
-
- private static final Virtualizer virtualizer = new Virtualizer(TConst.VIRT_VMWARE, "VMware");
-
- private static final Pattern hddKey = Pattern.compile("^(ide\\d|scsi\\d|sata\\d):?(\\d)?\\.(.*)", Pattern.CASE_INSENSITIVE);
-
- // Lowercase list of allowed settings for upload (as regex)
- private static final Pattern[] whitelist;
-
- private final VmwareConfig config;
-
- // Init static members
- static {
- String[] list = {"^guestos", "^uuid\\.bios", "^config\\.version", "^ehci\\.", "^mks\\.enable3d", "^virtualhw\\.", "^sound\\.", "\\.pcislotnumber$", "^pcibridge",
- "\\.virtualdev$", "^tools\\.syncTime$", "^time\\.synchronize", "^bios\\.bootDelay", "^rtc\\.", "^xhci\\."};
- whitelist = new Pattern[list.length];
- for (int i = 0; i < list.length; ++i) {
- whitelist[i] = Pattern.compile(list[i].toLowerCase());
- }
- }
-
- public static enum EthernetType {
- NAT("vmnet1"), BRIDGED("vmnet0"), HOST_ONLY("vmnet2");
-
- public final String vmnet;
-
- private EthernetType(String vnet) {
- this.vmnet = vnet;
- }
- }
-
- private final Map<String, Controller> disks = new HashMap<>();
-
- public VmwareMetaData(List<OperatingSystem> osList, File file) throws IOException, UnsupportedVirtualizerFormatException {
- super(osList);
- this.config = new VmwareConfig(file);
- init();
- }
-
- public VmwareMetaData(List<OperatingSystem> osList, byte[] vmxContent, int length) throws UnsupportedVirtualizerFormatException {
- super(osList);
- this.config = new VmwareConfig(vmxContent, length); // still unfiltered
- init(); // now filtered
- }
-
- private void init() {
- registerVirtualHW();
-
- for (Entry<String, ConfigEntry> entry : config.entrySet()) {
- handleLoadEntry(entry);
- }
- // if we find this tag, we already went through the hdd's - so we're done.
- if (config.get("#SLX_HDD_BUS") != null) {
- return;
- }
- // Now find the HDDs and add to list
- for (Entry<String, Controller> cEntry : disks.entrySet()) {
- Controller controller = cEntry.getValue();
- String controllerType = cEntry.getKey();
- if (!controller.present) {
- continue;
- }
- for (Entry<String, Device> dEntry : controller.devices.entrySet()) {
- Device device = dEntry.getValue();
- if (!device.present) {
- continue; // Not present
- }
- if (device.deviceType != null && !device.deviceType.toLowerCase().endsWith("disk")) {
- continue; // Not a HDD
- }
- DriveBusType bus = null;
- if (controllerType.startsWith("ide")) {
- bus = DriveBusType.IDE;
- } else if (controllerType.startsWith("scsi")) {
- bus = DriveBusType.SCSI;
- } else if (controllerType.startsWith("sata")) {
- bus = DriveBusType.SATA;
- }
- hdds.add(new HardDisk(controller.virtualDev, bus, device.filename));
- }
- }
- // TODO check if this machine is in a paused/suspended state
- this.isMachineSnapshot = false;
-
- // Add HDD to cleaned vmx
- if (!hdds.isEmpty()) {
- HardDisk hdd = hdds.get(0);
- addFiltered("#SLX_HDD_BUS", hdd.bus.toString());
- if (hdd.chipsetDriver != null) {
- addFiltered("#SLX_HDD_CHIP", hdd.chipsetDriver);
- }
- }
- }
-
- private void addFiltered(String key, String value) {
- config.set(key, value).filtered(true);
- }
-
- private boolean isSetAndTrue(String key) {
- String value = config.get(key);
- return value != null && value.equalsIgnoreCase("true");
- }
-
- private void handleLoadEntry(Entry<String, ConfigEntry> entry) {
- String lowerKey = entry.getKey().toLowerCase();
- // Cleaned vmx construction
- for (Pattern exp : whitelist) {
- if (exp.matcher(lowerKey).find()) {
- entry.getValue().filtered(true);
- break;
- }
- }
- //
- // Dig Usable meta data
- String value = entry.getValue().getValue();
- if (lowerKey.equals("guestos")) {
- setOs(value);
- return;
- }
- if (lowerKey.equals("displayname")) {
- displayName = value;
- return;
- }
- Matcher hdd = hddKey.matcher(entry.getKey());
- if (hdd.find()) {
- handleHddEntry(hdd.group(1).toLowerCase(), hdd.group(2), hdd.group(3), value);
- }
- }
-
- private void handleHddEntry(String controllerStr, String deviceStr, String property, String value) {
- Controller controller = disks.get(controllerStr);
- if (controller == null) {
- controller = new Controller();
- disks.put(controllerStr, controller);
- }
- if (deviceStr == null || deviceStr.isEmpty()) {
- // Controller property
- if (property.equalsIgnoreCase("present")) {
- controller.present = Boolean.parseBoolean(value);
- } else if (property.equalsIgnoreCase("virtualDev")) {
- controller.virtualDev = value;
- }
- return;
- }
- // Device property
- Device device = controller.devices.get(deviceStr);
- if (device == null) {
- device = new Device();
- controller.devices.put(deviceStr, device);
- }
- if (property.equalsIgnoreCase("deviceType")) {
- device.deviceType = value;
- } else if (property.equalsIgnoreCase("filename")) {
- device.filename = value;
- } else if (property.equalsIgnoreCase("present")) {
- device.present = Boolean.parseBoolean(value);
- }
- }
-
- @Override
- public boolean addHddTemplate(File diskImage, String hddMode, String redoDir) {
- return addHddTemplate(diskImage.getName(), hddMode, redoDir);
- }
-
- @Override
- public boolean addHddTemplate(String diskImagePath, String hddMode, String redoDir) {
- if (diskImagePath.isEmpty()) {
- LOGGER.error("Empty disk image path given!");
- return false;
- }
- DriveBusType bus;
- try {
- bus = DriveBusType.valueOf(config.get("#SLX_HDD_BUS"));
- } catch (Exception e) {
- LOGGER.warn("Unknown bus type: " + config.get("#SLX_HDD_BUS") + ". Cannot add hdd config.");
- return false;
- }
- String chipset = config.get("#SLX_HDD_CHIP");
- String prefix;
- switch (bus) {
- case IDE:
- prefix = "ide0:0";
- addFiltered("ide0.present", "TRUE");
- break;
- case SATA:
- // Cannot happen?... use lsisas1068
- case SCSI:
- prefix = "scsi0:0";
- addFiltered("scsi0.present", "TRUE");
- if (chipset != null) {
- addFiltered("scsi0.virtualDev", chipset);
- }
- break;
- default:
- LOGGER.warn("Unknown HDD bus type: " + bus.toString());
- return false;
- }
- // Gen
- addFiltered(prefix + ".present", "TRUE");
- addFiltered(prefix + ".deviceType", "disk");
- addFiltered(prefix + ".fileName", diskImagePath);
- if (hddMode != null) {
- addFiltered(prefix + ".mode", hddMode);
- addFiltered(prefix + ".redo", "");
- addFiltered(prefix + ".redoLogDir", redoDir);
- }
- config.remove("#SLX_HDD_BUS");
- config.remove("#SLX_HDD_CHIP");
- return true;
- }
-
- public boolean addDefaultNat() {
- addFiltered("ethernet0.present", "TRUE");
- addFiltered("ethernet0.connectionType", "nat");
- return true;
- }
-
- public boolean addEthernet(VmMetaData.EtherType type) {
- boolean ret = false;
- int index = 0;
- for (;; ++index) {
- if (config.get("ethernet" + index + ".present") == null) {
- break;
- }
- }
- switch (type) {
- case NAT:
- ret = addEthernet(index, EthernetType.NAT);
- break;
- case BRIDGED:
- ret = addEthernet(index, EthernetType.BRIDGED);
- break;
- case HOST_ONLY:
- ret = addEthernet(index, EthernetType.HOST_ONLY);
- break;
- default:
- // Should not come to this...
- break;
- }
- return ret;
- }
-
- public boolean addEthernet(int index, EthernetType type) {
- String ether = "ethernet" + index;
- addFiltered(ether + ".present", "TRUE");
- addFiltered(ether + ".connectionType", "custom");
- addFiltered(ether + ".vnet", type.vmnet);
- if (config.get(ether + ".virtualDev") == null) {
- String dev = config.get("ethernet0.virtualDev");
- if (dev != null) {
- addFiltered(ether + ".virtualDev", dev);
- }
- }
- return true;
- }
-
- public void addFloppy(int index, String image, boolean readOnly) {
- String pre = "floppy" + index;
- addFiltered(pre + ".present", "TRUE");
- if (image == null) {
- addFiltered(pre + ".startConnected", "FALSE");
- addFiltered(pre + ".fileType", "device");
- config.remove(pre + ".fileName");
- config.remove(pre + ".readonly");
- addFiltered(pre + ".autodetect", "TRUE");
- } else {
- addFiltered(pre + ".startConnected", "TRUE");
- addFiltered(pre + ".fileType", "file");
- addFiltered(pre + ".fileName", image);
- addFiltered(pre + ".readonly", vmBoolean(readOnly));
- config.remove(pre + ".autodetect");
- }
- }
-
- public boolean addCdrom(String image) {
- for (String port : new String[]{"ide0:0", "ide0:1", "ide1:0", "ide1:1", "scsi0:1"}) {
- if (!isSetAndTrue(port + ".present")) {
- addFiltered(port + ".present", "TRUE");
- if (image == null) {
- addFiltered(port + ".autodetect", "TRUE");
- addFiltered(port + ".deviceType", "cdrom-raw");
- config.remove(port + ".fileName");
- } else {
- config.remove(port + ".autodetect");
- addFiltered(port + ".deviceType", "cdrom-image");
- addFiltered(port + ".fileName", image);
- }
- return true;
- }
- }
- return false;
- }
-
- private static String vmBoolean(boolean var) {
- return Boolean.toString(var).toUpperCase();
- }
-
- private static String vmInteger(int val) {
- return Integer.toString(val);
- }
-
- @Override
- public boolean disableSuspend() {
- addFiltered("suspend.disabled", "TRUE");
- return true;
- }
-
- @Override
- public boolean addDisplayName(String name) {
- addFiltered("displayName", name);
- return true;
- }
-
- @Override
- public boolean addRam(int mem) {
- addFiltered("memsize", Integer.toString(mem));
- return true;
- }
-
- public void setOs(String vendorOsId) {
- addFiltered("guestOS", vendorOsId);
- setOs(TConst.VIRT_VMWARE, vendorOsId);
- }
-
- @Override
- public byte[] getFilteredDefinitionArray() {
- return config.toString(true, false).getBytes(StandardCharsets.UTF_8);
- }
-
- public byte[] getDefinitionArray() {
- return config.toString(false, false).getBytes(StandardCharsets.UTF_8);
- }
-
- @Override
- public Virtualizer getVirtualizer() {
- return virtualizer;
- }
-
- private static class Device {
-
- public boolean present = false;
- public String deviceType = null;
- public String filename = null;
-
- @Override
- public String toString() {
- return filename + " is " + deviceType + " (present: " + present + ")";
- }
- }
-
- private static class Controller {
-
- public boolean present = true; // Seems to be implicit, seen at least for IDE...
- public String virtualDev = null;
- Map<String, Device> devices = new HashMap<>();
-
- @Override
- public String toString() {
- return virtualDev + " is (present: " + present + "): " + devices.toString();
- }
- }
-
- @Override
- public void enableUsb(boolean enabled) {
- addFiltered("usb.present", vmBoolean(enabled));
- addFiltered("ehci.present", vmBoolean(enabled));
- }
-
- @Override
- public void applySettingsForLocalEdit() {
- addFiltered("gui.applyHostDisplayScalingToGuest", "FALSE");
- }
-
- public String getValue(String key) {
- return config.get(key);
- }
-
- public void setSoundCard(VmMetaData.SoundCardType type) {
- VmWareSoundCardMeta soundCardMeta = soundCards.get(type);
- addFiltered("sound.present", vmBoolean(soundCardMeta.isPresent));
- if (soundCardMeta.value != null) {
- addFiltered("sound.virtualDev", soundCardMeta.value);
- } else {
- config.remove("sound.virtualDev");
- }
- }
-
- public VmMetaData.SoundCardType getSoundCard() {
- if (!isSetAndTrue("sound.present") || !isSetAndTrue("sound.autodetect")) {
- return VmMetaData.SoundCardType.NONE;
- }
- String current = config.get("sound.virtualDev");
- if (current != null) {
- VmWareSoundCardMeta soundCardMeta = null;
- for (VmMetaData.SoundCardType type : VmMetaData.SoundCardType.values()) {
- soundCardMeta = soundCards.get(type);
- if (soundCardMeta != null) {
- if (current.equals(soundCardMeta.value)) {
- return type;
- }
- }
- }
- }
- return VmMetaData.SoundCardType.DEFAULT;
- }
-
- public void setDDAcceleration(VmMetaData.DDAcceleration type) {
- VmWareDDAccelMeta ddaMeta = ddacc.get(type);
- addFiltered("mks.enable3d", vmBoolean(ddaMeta.isPresent));
- }
-
- public VmMetaData.DDAcceleration getDDAcceleration() {
- if (isSetAndTrue("mks.enable3d")) {
- return VmMetaData.DDAcceleration.ON;
- } else {
- return VmMetaData.DDAcceleration.OFF;
- }
- }
-
- public void setHWVersion(VmMetaData.HWVersion type) {
- VmWareHWVersionMeta hwVersionMeta = hwversion.get(type);
- addFiltered("virtualHW.version", vmInteger(hwVersionMeta.version));
- }
-
- public VmMetaData.HWVersion getHWVersion() {
- int currentValue = Util.parseInt(config.get("virtualHW.version"), -1);
- VmWareHWVersionMeta hwVersionMeta = null;
- for (VmMetaData.HWVersion ver : VmMetaData.HWVersion.values()) {
- hwVersionMeta = hwversion.get(ver);
- if (hwVersionMeta == null) {
- continue;
- }
- if (currentValue == hwVersionMeta.version) {
- return ver;
- }
- }
- return HWVersion.NONE;
- }
-
- public void setEthernetDevType(int cardIndex, VmMetaData.EthernetDevType type) {
- VmWareEthernetDevTypeMeta ethernetDevTypeMeta = networkCards.get(type);
- if (ethernetDevTypeMeta.value != null) {
- addFiltered("ethernet" + cardIndex + ".virtualDev", ethernetDevTypeMeta.value);
- } else {
- config.remove("ethernet" + cardIndex + ".virtualDev");
- }
- }
-
- public EthernetDevType getEthernetDevType(int cardIndex) {
- String temp = config.get("ethernet" + cardIndex + ".virtualDev");
- if (temp != null) {
- VmWareEthernetDevTypeMeta ethernetDevTypeMeta = null;
- for (EthernetDevType type : VmMetaData.EthernetDevType.values()) {
- ethernetDevTypeMeta = networkCards.get(type);
- if (ethernetDevTypeMeta == null) {
- continue;
- }
- if (temp.equals(ethernetDevTypeMeta.value)) {
- return type;
- }
- }
- }
- return EthernetDevType.AUTO;
- }
-
- @Override
- public boolean addCpuCoreCount(int numCores) {
- // TODO actually add the cpu core count to the machine description
- return false;
- }
+class VmwareUsbSpeed
+{
+ public final String keyName;
+ public final int speedNumeric;
+
+ public VmwareUsbSpeed( int speed, String key )
+ {
+ this.keyName = key + ".present";
+ this.speedNumeric = speed;
+ }
+}
- public void registerVirtualHW() {
- soundCards.put(VmMetaData.SoundCardType.NONE, new VmWareSoundCardMeta(false, null));
- soundCards.put(VmMetaData.SoundCardType.DEFAULT, new VmWareSoundCardMeta(true, null));
- soundCards.put(VmMetaData.SoundCardType.SOUND_BLASTER, new VmWareSoundCardMeta(true, "sb16"));
- soundCards.put(VmMetaData.SoundCardType.ES, new VmWareSoundCardMeta(true, "es1371"));
- soundCards.put(VmMetaData.SoundCardType.HD_AUDIO, new VmWareSoundCardMeta(true, "hdaudio"));
-
- ddacc.put(VmMetaData.DDAcceleration.OFF, new VmWareDDAccelMeta(false));
- ddacc.put(VmMetaData.DDAcceleration.ON, new VmWareDDAccelMeta(true));
-
- hwversion.put(VmMetaData.HWVersion.NONE, new VmWareHWVersionMeta(0));
- hwversion.put(VmMetaData.HWVersion.THREE, new VmWareHWVersionMeta(3));
- hwversion.put(VmMetaData.HWVersion.FOUR, new VmWareHWVersionMeta(4));
- hwversion.put(VmMetaData.HWVersion.SIX, new VmWareHWVersionMeta(6));
- hwversion.put(VmMetaData.HWVersion.SEVEN, new VmWareHWVersionMeta(7));
- hwversion.put(VmMetaData.HWVersion.EIGHT, new VmWareHWVersionMeta(8));
- hwversion.put(VmMetaData.HWVersion.NINE, new VmWareHWVersionMeta(9));
- hwversion.put(VmMetaData.HWVersion.TEN, new VmWareHWVersionMeta(10));
- hwversion.put(VmMetaData.HWVersion.ELEVEN, new VmWareHWVersionMeta(11));
- hwversion.put(VmMetaData.HWVersion.TWELVE, new VmWareHWVersionMeta(12));
-
- networkCards.put(VmMetaData.EthernetDevType.AUTO, new VmWareEthernetDevTypeMeta(null));
- networkCards.put(VmMetaData.EthernetDevType.PCNET32, new VmWareEthernetDevTypeMeta("vlance"));
- networkCards.put(VmMetaData.EthernetDevType.E1000, new VmWareEthernetDevTypeMeta("e1000"));
- networkCards.put(VmMetaData.EthernetDevType.E1000E, new VmWareEthernetDevTypeMeta("e1000e"));
- networkCards.put(VmMetaData.EthernetDevType.VMXNET, new VmWareEthernetDevTypeMeta("vmxnet"));
- networkCards.put(VmMetaData.EthernetDevType.VMXNET3, new VmWareEthernetDevTypeMeta("vmxnet3"));
- }
+public class VmwareMetaData extends VmMetaData<VmWareSoundCardMeta, VmWareDDAccelMeta, VmWareHWVersionMeta, VmWareEthernetDevTypeMeta, VmwareUsbSpeed>
+{
+
+ private static final Logger LOGGER = Logger.getLogger( VmwareMetaData.class );
+
+ private static final Virtualizer virtualizer = new Virtualizer( TConst.VIRT_VMWARE, "VMware" );
+
+ private static final Pattern hddKey = Pattern.compile( "^(ide\\d|scsi\\d|sata\\d):?(\\d)?\\.(.*)", Pattern.CASE_INSENSITIVE );
+
+ // Lowercase list of allowed settings for upload (as regex)
+ private static final Pattern[] whitelist;
+
+ private final VmwareConfig config;
+
+ // Init static members
+ static {
+ String[] list = { "^guestos", "^uuid\\.bios", "^config\\.version", "^ehci[.:]", "^mks\\.enable3d", "^virtualhw\\.",
+ "^sound[.:]", "\\.pcislotnumber$", "^pcibridge", "\\.virtualdev$", "^tools\\.syncTime$", "^time\\.synchronize",
+ "^bios\\.bootDelay", "^rtc\\.", "^xhci[.:]", "^usb_xhci[.:]", "\\.deviceType$", "\\.port$", "\\.parent$", "^usb[.:]",
+ "^firmware" };
+ whitelist = new Pattern[ list.length ];
+ for ( int i = 0; i < list.length; ++i ) {
+ whitelist[i] = Pattern.compile( list[i].toLowerCase() );
+ }
+ }
+
+ public static enum EthernetType
+ {
+ NAT( "vmnet1" ), BRIDGED( "vmnet0" ), HOST_ONLY( "vmnet2" );
+
+ public final String vmnet;
+
+ private EthernetType( String vnet )
+ {
+ this.vmnet = vnet;
+ }
+ }
+
+ private final Map<String, Controller> disks = new HashMap<>();
+
+ public VmwareMetaData( List<OperatingSystem> osList, File file ) throws IOException, UnsupportedVirtualizerFormatException
+ {
+ super( osList );
+ this.config = new VmwareConfig( file );
+ init();
+ }
+
+ public VmwareMetaData( List<OperatingSystem> osList, byte[] vmxContent, int length ) throws UnsupportedVirtualizerFormatException
+ {
+ super( osList );
+ this.config = new VmwareConfig( vmxContent, length ); // still unfiltered
+ init(); // now filtered
+ }
+
+ private void init()
+ {
+ registerVirtualHW();
+
+ for ( Entry<String, ConfigEntry> entry : config.entrySet() ) {
+ handleLoadEntry( entry );
+ }
+ // Fix accidentally filtered USB config if we see EHCI is present
+ if ( isSetAndTrue( "ehci.present" ) && !isSetAndTrue( "usb.present" ) ) {
+ addFiltered( "usb.present", "TRUE" );
+ }
+ // if we find this tag, we already went through the hdd's - so we're done.
+ if ( config.get( "#SLX_HDD_BUS" ) != null ) {
+ return;
+ }
+ // Now find the HDDs and add to list
+ for ( Entry<String, Controller> cEntry : disks.entrySet() ) {
+ Controller controller = cEntry.getValue();
+ String controllerType = cEntry.getKey();
+ if ( !controller.present )
+ continue;
+ for ( Entry<String, Device> dEntry : controller.devices.entrySet() ) {
+ Device device = dEntry.getValue();
+ if ( !device.present )
+ continue; // Not present
+ if ( device.deviceType != null && !device.deviceType.toLowerCase().endsWith( "disk" ) )
+ continue; // Not a HDD
+ DriveBusType bus = null;
+ if ( controllerType.startsWith( "ide" ) ) {
+ bus = DriveBusType.IDE;
+ } else if ( controllerType.startsWith( "scsi" ) ) {
+ bus = DriveBusType.SCSI;
+ } else if ( controllerType.startsWith( "sata" ) ) {
+ bus = DriveBusType.SATA;
+ }
+ hdds.add( new HardDisk( controller.virtualDev, bus, device.filename ) );
+ }
+ }
+ // TODO check if this machine is in a paused/suspended state
+ this.isMachineSnapshot = false;
+
+ // Add HDD to cleaned vmx
+ if ( !hdds.isEmpty() ) {
+ HardDisk hdd = hdds.get( 0 );
+ addFiltered( "#SLX_HDD_BUS", hdd.bus.toString() );
+ if ( hdd.chipsetDriver != null ) {
+ addFiltered( "#SLX_HDD_CHIP", hdd.chipsetDriver );
+ }
+ }
+ }
+
+ private void addFiltered( String key, String value )
+ {
+ config.set( key, value ).filtered( true );
+ }
+
+ private boolean isSetAndTrue( String key )
+ {
+ String value = config.get( key );
+ return value != null && value.equalsIgnoreCase( "true" );
+ }
+
+ private void handleLoadEntry( Entry<String, ConfigEntry> entry )
+ {
+ String lowerKey = entry.getKey().toLowerCase();
+ // Cleaned vmx construction
+ for ( Pattern exp : whitelist ) {
+ if ( exp.matcher( lowerKey ).find() ) {
+ entry.getValue().filtered( true );
+ break;
+ }
+ }
+ //
+ // Dig Usable meta data
+ String value = entry.getValue().getValue();
+ if ( lowerKey.equals( "guestos" ) ) {
+ setOs( value );
+ return;
+ }
+ if ( lowerKey.equals( "displayname" ) ) {
+ displayName = value;
+ return;
+ }
+ Matcher hdd = hddKey.matcher( entry.getKey() );
+ if ( hdd.find() ) {
+ handleHddEntry( hdd.group( 1 ).toLowerCase(), hdd.group( 2 ), hdd.group( 3 ), value );
+ }
+ }
+
+ private void handleHddEntry( String controllerStr, String deviceStr, String property, String value )
+ {
+ Controller controller = disks.get( controllerStr );
+ if ( controller == null ) {
+ controller = new Controller();
+ disks.put( controllerStr, controller );
+ }
+ if ( deviceStr == null || deviceStr.isEmpty() ) {
+ // Controller property
+ if ( property.equalsIgnoreCase( "present" ) ) {
+ controller.present = Boolean.parseBoolean( value );
+ } else if ( property.equalsIgnoreCase( "virtualDev" ) ) {
+ controller.virtualDev = value;
+ }
+ return;
+ }
+ // Device property
+ Device device = controller.devices.get( deviceStr );
+ if ( device == null ) {
+ device = new Device();
+ controller.devices.put( deviceStr, device );
+ }
+ if ( property.equalsIgnoreCase( "deviceType" ) ) {
+ device.deviceType = value;
+ } else if ( property.equalsIgnoreCase( "filename" ) ) {
+ device.filename = value;
+ } else if ( property.equalsIgnoreCase( "present" ) ) {
+ device.present = Boolean.parseBoolean( value );
+ }
+ }
+
+ @Override
+ public boolean addHddTemplate( File diskImage, String hddMode, String redoDir )
+ {
+ return addHddTemplate( diskImage.getName(), hddMode, redoDir );
+ }
+
+ @Override
+ public boolean addHddTemplate( String diskImagePath, String hddMode, String redoDir )
+ {
+ if ( diskImagePath.isEmpty() ) {
+ LOGGER.error( "Empty disk image path given!" );
+ return false;
+ }
+ DriveBusType bus;
+ try {
+ bus = DriveBusType.valueOf( config.get( "#SLX_HDD_BUS" ) );
+ } catch ( Exception e ) {
+ LOGGER.warn( "Unknown bus type: " + config.get( "#SLX_HDD_BUS" ) + ". Cannot add hdd config." );
+ return false;
+ }
+ String chipset = config.get( "#SLX_HDD_CHIP" );
+ String prefix;
+ switch ( bus ) {
+ case IDE:
+ prefix = "ide0:0";
+ addFiltered( "ide0.present", "TRUE" );
+ break;
+ case SATA:
+ // Cannot happen?... use lsisas1068
+ case SCSI:
+ prefix = "scsi0:0";
+ addFiltered( "scsi0.present", "TRUE" );
+ if ( chipset != null ) {
+ addFiltered( "scsi0.virtualDev", chipset );
+ }
+ break;
+ default:
+ LOGGER.warn( "Unknown HDD bus type: " + bus.toString() );
+ return false;
+ }
+ // Gen
+ addFiltered( prefix + ".present", "TRUE" );
+ addFiltered( prefix + ".deviceType", "disk" );
+ addFiltered( prefix + ".fileName", diskImagePath );
+ if ( hddMode != null ) {
+ addFiltered( prefix + ".mode", hddMode );
+ addFiltered( prefix + ".redo", "" );
+ addFiltered( prefix + ".redoLogDir", redoDir );
+ }
+ config.remove( "#SLX_HDD_BUS" );
+ config.remove( "#SLX_HDD_CHIP" );
+ return true;
+ }
+
+ public boolean addDefaultNat()
+ {
+ addFiltered( "ethernet0.present", "TRUE" );
+ addFiltered( "ethernet0.connectionType", "nat" );
+ return true;
+ }
+
+ public boolean addEthernet( VmMetaData.EtherType type )
+ {
+ boolean ret = false;
+ int index = 0;
+ for ( ;; ++index ) {
+ if ( config.get( "ethernet" + index + ".present" ) == null )
+ break;
+ }
+ switch ( type ) {
+ case NAT:
+ ret = addEthernet( index, EthernetType.NAT );
+ break;
+ case BRIDGED:
+ ret = addEthernet( index, EthernetType.BRIDGED );
+ break;
+ case HOST_ONLY:
+ ret = addEthernet( index, EthernetType.HOST_ONLY );
+ break;
+ default:
+ // Should not come to this...
+ break;
+ }
+ return ret;
+ }
+
+ public boolean addEthernet( int index, EthernetType type )
+ {
+ String ether = "ethernet" + index;
+ addFiltered( ether + ".present", "TRUE" );
+ addFiltered( ether + ".connectionType", "custom" );
+ addFiltered( ether + ".vnet", type.vmnet );
+ if ( config.get( ether + ".virtualDev" ) == null ) {
+ String dev = config.get( "ethernet0.virtualDev" );
+ if ( dev != null ) {
+ addFiltered( ether + ".virtualDev", dev );
+ }
+ }
+ return true;
+ }
+
+ public void addFloppy( int index, String image, boolean readOnly )
+ {
+ String pre = "floppy" + index;
+ addFiltered( pre + ".present", "TRUE" );
+ if ( image == null ) {
+ addFiltered( pre + ".startConnected", "FALSE" );
+ addFiltered( pre + ".fileType", "device" );
+ config.remove( pre + ".fileName" );
+ config.remove( pre + ".readonly" );
+ addFiltered( pre + ".autodetect", "TRUE" );
+ } else {
+ addFiltered( pre + ".startConnected", "TRUE" );
+ addFiltered( pre + ".fileType", "file" );
+ addFiltered( pre + ".fileName", image );
+ addFiltered( pre + ".readonly", vmBoolean( readOnly ) );
+ config.remove( pre + ".autodetect" );
+ }
+ }
+
+ public boolean addCdrom( String image )
+ {
+ for ( String port : new String[] { "ide0:0", "ide0:1", "ide1:0", "ide1:1", "scsi0:1" } ) {
+ if ( !isSetAndTrue( port + ".present" ) ) {
+ addFiltered( port + ".present", "TRUE" );
+ if ( image == null ) {
+ addFiltered( port + ".autodetect", "TRUE" );
+ addFiltered( port + ".deviceType", "cdrom-raw" );
+ config.remove( port + ".fileName" );
+ } else {
+ config.remove( port + ".autodetect" );
+ addFiltered( port + ".deviceType", "cdrom-image" );
+ addFiltered( port + ".fileName", image );
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static String vmBoolean( boolean var )
+ {
+ return Boolean.toString( var ).toUpperCase();
+ }
+
+ private static String vmInteger( int val )
+ {
+ return Integer.toString( val );
+ }
+
+ @Override
+ public boolean tweakForNonPersistent()
+ {
+ addFiltered( "suspend.disabled", "TRUE" );
+ return true;
+ }
+
+ @Override
+ public boolean addDisplayName( String name )
+ {
+ addFiltered( "displayName", name );
+ return true;
+ }
+
+ @Override
+ public boolean addRam( int mem )
+ {
+ addFiltered( "memsize", Integer.toString( mem ) );
+ return true;
+ }
+
+ public void setOs( String vendorOsId )
+ {
+ addFiltered( "guestOS", vendorOsId );
+ setOs( TConst.VIRT_VMWARE, vendorOsId );
+ }
+
+ @Override
+ public byte[] getFilteredDefinitionArray()
+ {
+ return config.toString( true, false ).getBytes( StandardCharsets.UTF_8 );
+ }
+
+ public byte[] getDefinitionArray()
+ {
+ return config.toString( false, false ).getBytes( StandardCharsets.UTF_8 );
+ }
+
+ @Override
+ public Virtualizer getVirtualizer()
+ {
+ return virtualizer;
+ }
+
+ private static class Device
+ {
+ public boolean present = false;
+ public String deviceType = null;
+ public String filename = null;
+
+ @Override
+ public String toString()
+ {
+ return filename + " is " + deviceType + " (present: " + present + ")";
+ }
+ }
+
+ private static class Controller
+ {
+ public boolean present = true; // Seems to be implicit, seen at least for IDE...
+ public String virtualDev = null;
+ Map<String, Device> devices = new HashMap<>();
+
+ @Override
+ public String toString()
+ {
+ return virtualDev + " is (present: " + present + "): " + devices.toString();
+ }
+ }
+
+ @Override
+ public void applySettingsForLocalEdit()
+ {
+ addFiltered( "gui.applyHostDisplayScalingToGuest", "FALSE" );
+ }
+
+ public String getValue( String key )
+ {
+ return config.get( key );
+ }
+
+ public void setSoundCard( VmMetaData.SoundCardType type )
+ {
+ VmWareSoundCardMeta soundCardMeta = soundCards.get( type );
+ addFiltered( "sound.present", vmBoolean( soundCardMeta.isPresent ) );
+ if ( soundCardMeta.value != null ) {
+ addFiltered( "sound.virtualDev", soundCardMeta.value );
+ } else {
+ config.remove( "sound.virtualDev" );
+ }
+ }
+
+ public VmMetaData.SoundCardType getSoundCard()
+ {
+ if ( !isSetAndTrue( "sound.present" ) || !isSetAndTrue( "sound.autodetect" ) ) {
+ return VmMetaData.SoundCardType.NONE;
+ }
+ String current = config.get( "sound.virtualDev" );
+ if ( current != null ) {
+ VmWareSoundCardMeta soundCardMeta = null;
+ for ( VmMetaData.SoundCardType type : VmMetaData.SoundCardType.values() ) {
+ soundCardMeta = soundCards.get( type );
+ if ( soundCardMeta != null ) {
+ if ( current.equals( soundCardMeta.value ) ) {
+ return type;
+ }
+ }
+ }
+ }
+ return VmMetaData.SoundCardType.DEFAULT;
+ }
+
+ public void setDDAcceleration( VmMetaData.DDAcceleration type )
+ {
+ VmWareDDAccelMeta ddaMeta = ddacc.get( type );
+ addFiltered( "mks.enable3d", vmBoolean( ddaMeta.isPresent ) );
+ }
+
+ public VmMetaData.DDAcceleration getDDAcceleration()
+ {
+ if ( isSetAndTrue( "mks.enable3d" ) ) {
+ return VmMetaData.DDAcceleration.ON;
+ } else {
+ return VmMetaData.DDAcceleration.OFF;
+ }
+ }
+
+ public void setHWVersion( VmMetaData.HWVersion type )
+ {
+ VmWareHWVersionMeta hwVersionMeta = hwversion.get( type );
+ addFiltered( "virtualHW.version", vmInteger( hwVersionMeta.version ) );
+ }
+
+ public VmMetaData.HWVersion getHWVersion()
+ {
+ int currentValue = Util.parseInt( config.get( "virtualHW.version" ), -1 );
+ VmWareHWVersionMeta hwVersionMeta = null;
+ for ( VmMetaData.HWVersion ver : VmMetaData.HWVersion.values() ) {
+ hwVersionMeta = hwversion.get( ver );
+ if ( hwVersionMeta == null ) {
+ continue;
+ }
+ if ( currentValue == hwVersionMeta.version ) {
+ return ver;
+ }
+ }
+ return HWVersion.NONE;
+ }
+
+ public void setEthernetDevType( int cardIndex, VmMetaData.EthernetDevType type )
+ {
+ VmWareEthernetDevTypeMeta ethernetDevTypeMeta = networkCards.get( type );
+ if ( ethernetDevTypeMeta.value != null ) {
+ addFiltered( "ethernet" + cardIndex + ".virtualDev", ethernetDevTypeMeta.value );
+ } else {
+ config.remove( "ethernet" + cardIndex + ".virtualDev" );
+ }
+ }
+
+ public VmMetaData.EthernetDevType getEthernetDevType( int cardIndex )
+ {
+ String temp = config.get( "ethernet" + cardIndex + ".virtualDev" );
+ if ( temp != null ) {
+ VmWareEthernetDevTypeMeta ethernetDevTypeMeta = null;
+ for ( VmMetaData.EthernetDevType type : VmMetaData.EthernetDevType.values() ) {
+ ethernetDevTypeMeta = networkCards.get( type );
+ if ( ethernetDevTypeMeta == null ) {
+ continue;
+ }
+ if ( temp.equals( ethernetDevTypeMeta.value ) ) {
+ return type;
+ }
+ }
+ }
+ return VmMetaData.EthernetDevType.AUTO;
+ }
+
+ @Override
+ public void setMaxUsbSpeed( VmMetaData.UsbSpeed newSpeed )
+ {
+ if ( newSpeed == null ) {
+ newSpeed = VmMetaData.UsbSpeed.NONE;
+ }
+ VmwareUsbSpeed newSpeedMeta = usbSpeeds.get( newSpeed );
+ if ( newSpeedMeta == null ) {
+ throw new RuntimeException( "USB Speed " + newSpeed.name() + " not registered with VMware" );
+ }
+ for ( VmwareUsbSpeed meta : usbSpeeds.values() ) {
+ if ( meta == null )
+ continue; // Should not happen
+ if ( meta.keyName == null )
+ continue; // "No USB" has no config entry, obviously
+ if ( meta.speedNumeric <= newSpeedMeta.speedNumeric ) {
+ // Enable desired speed class, plus all lower ones
+ addFiltered( meta.keyName, "TRUE" );
+ } else {
+ // This one is higher – remove
+ config.remove( meta.keyName );
+ }
+ }
+ // VMware 14+ needs this to use USB 3.0 devices at USB 3.0 ports in VMs configured for < 3.0
+ if ( newSpeedMeta.speedNumeric > 0 && newSpeedMeta.speedNumeric < 3 ) {
+ addFiltered( "usb.mangleUsb3Speed", "TRUE" );
+ }
+ }
+
+ @Override
+ public VmMetaData.UsbSpeed getMaxUsbSpeed()
+ {
+ int max = 0;
+ VmMetaData.UsbSpeed maxEnum = VmMetaData.UsbSpeed.NONE;
+ for ( Entry<VmMetaData.UsbSpeed, VmwareUsbSpeed> entry : usbSpeeds.entrySet() ) {
+ VmwareUsbSpeed v = entry.getValue();
+ if ( v.speedNumeric > max && isSetAndTrue( v.keyName ) ) {
+ max = v.speedNumeric;
+ maxEnum = entry.getKey();
+ }
+ }
+ return maxEnum;
+ }
+
+ @Override
+ public boolean addCpuCoreCount( int numCores )
+ {
+ // TODO actually add the cpu core count to the machine description
+ return false;
+ }
+
+ public void registerVirtualHW()
+ {
+ soundCards.put( VmMetaData.SoundCardType.NONE, new VmWareSoundCardMeta( false, null ) );
+ soundCards.put( VmMetaData.SoundCardType.DEFAULT, new VmWareSoundCardMeta( true, null ) );
+ soundCards.put( VmMetaData.SoundCardType.SOUND_BLASTER, new VmWareSoundCardMeta( true, "sb16" ) );
+ soundCards.put( VmMetaData.SoundCardType.ES, new VmWareSoundCardMeta( true, "es1371" ) );
+ soundCards.put( VmMetaData.SoundCardType.HD_AUDIO, new VmWareSoundCardMeta( true, "hdaudio" ) );
+
+ ddacc.put( VmMetaData.DDAcceleration.OFF, new VmWareDDAccelMeta( false ) );
+ ddacc.put( VmMetaData.DDAcceleration.ON, new VmWareDDAccelMeta( true ) );
+
+ hwversion.put( VmMetaData.HWVersion.NONE, new VmWareHWVersionMeta( 0 ) );
+ hwversion.put( VmMetaData.HWVersion.THREE, new VmWareHWVersionMeta( 3 ) );
+ hwversion.put( VmMetaData.HWVersion.FOUR, new VmWareHWVersionMeta( 4 ) );
+ hwversion.put( VmMetaData.HWVersion.SIX, new VmWareHWVersionMeta( 6 ) );
+ hwversion.put( VmMetaData.HWVersion.SEVEN, new VmWareHWVersionMeta( 7 ) );
+ hwversion.put( VmMetaData.HWVersion.EIGHT, new VmWareHWVersionMeta( 8 ) );
+ hwversion.put( VmMetaData.HWVersion.NINE, new VmWareHWVersionMeta( 9 ) );
+ hwversion.put( VmMetaData.HWVersion.TEN, new VmWareHWVersionMeta( 10 ) );
+ hwversion.put( VmMetaData.HWVersion.ELEVEN, new VmWareHWVersionMeta( 11 ) );
+ hwversion.put( VmMetaData.HWVersion.TWELVE, new VmWareHWVersionMeta( 12 ) );
+ hwversion.put( VmMetaData.HWVersion.FOURTEEN, new VmWareHWVersionMeta( 14 ) );
+ hwversion.put( VmMetaData.HWVersion.FIFTEEN, new VmWareHWVersionMeta( 15 ) );
+ hwversion.put( VmMetaData.HWVersion.FIFTEEN_ONE, new VmWareHWVersionMeta( 16 ) );
+
+ networkCards.put( VmMetaData.EthernetDevType.AUTO, new VmWareEthernetDevTypeMeta( null ) );
+ networkCards.put( VmMetaData.EthernetDevType.PCNET32, new VmWareEthernetDevTypeMeta( "vlance" ) );
+ networkCards.put( VmMetaData.EthernetDevType.E1000, new VmWareEthernetDevTypeMeta( "e1000" ) );
+ networkCards.put( VmMetaData.EthernetDevType.E1000E, new VmWareEthernetDevTypeMeta( "e1000e" ) );
+ networkCards.put( VmMetaData.EthernetDevType.VMXNET, new VmWareEthernetDevTypeMeta( "vmxnet" ) );
+ networkCards.put( VmMetaData.EthernetDevType.VMXNET3, new VmWareEthernetDevTypeMeta( "vmxnet3" ) );
+
+ usbSpeeds.put( VmMetaData.UsbSpeed.NONE, new VmwareUsbSpeed( 0, null ));
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB1_1, new VmwareUsbSpeed( 1, "usb" ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB2_0, new VmwareUsbSpeed( 2, "ehci" ) );
+ usbSpeeds.put( VmMetaData.UsbSpeed.USB3_0, new VmwareUsbSpeed( 3, "usb_xhci" ) );
+ }
}