ApplianceImpl.cpp revision 50453af238fcec34bf98f91cc4c32bf57f738bd3
/* $Id$ */
/** @file
*
* IAppliance and IVirtualSystem COM class implementations.
*/
/*
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
#include "ApplianceImpl.h"
#include "VirtualBoxImpl.h"
#include "GuestOSTypeImpl.h"
#include "ProgressImpl.h"
#include "MachineImpl.h"
#include "HostNetworkInterfaceImpl.h"
#include "Logging.h"
using namespace std;
////////////////////////////////////////////////////////////////////////////////
//
// hardware definitions
//
////////////////////////////////////////////////////////////////////////////////
struct DiskImage
{
// (maximum size for dynamic images, I guess; we always translate this to bytes)
// (actual used size of disk, always in bytes; can be an estimate of used disk
// space, but cannot be larger than iCapacity)
// typically http://www.vmware.com/specifications/vmdk.html#sparse
// fields from /References/File; the spec says the file reference from disk can be empty,
// so in that case, strFilename will be empty, then a new disk should be created
Utf8Str strHref; // value from /References/File/@href (filename); if empty, then the remaining fields are ignored
int64_t iSize; // value from /References/File/@size (optional according to spec; then we set -1 here)
Utf8Str strCompression; // value from /References/File/@compression (optional, can be "gzip" according to spec)
};
struct VirtualHardwareItem
{
Utf8Str strHostResource; // "Abstractly specifies how a device shall connect to a resource on the deployment platform.
// Not all devices need a backing." Used with disk items, for which this references a virtual
// disk from the Disks section.
bool fAutomaticAllocation;
bool fAutomaticDeallocation;
Utf8Str strConnection; // "All Ethernet adapters that specify the same abstract network connection name within an OVF
// package shall be deployed on the same network. The abstract network connection name shall be
// listed in the NetworkSection at the outermost envelope level." We ignore this and only set up
// a network adapter depending on the network name.
Utf8Str strAllocationUnits; // "Specifies the units of allocation used. For example, “byte * 2^20”."
uint64_t ullVirtualQuantity; // "Specifies the quantity of resources presented. For example, “256”."
uint64_t ullReservation; // "Specifies the minimum quantity of resources guaranteed to be available."
uint64_t ullWeight; // "Specifies a relative priority for this allocation in relation to other allocations."
: ulInstanceID(0), fAutomaticAllocation(false), fAutomaticDeallocation(false), ullVirtualQuantity(0), ullReservation(0), ullLimit(0), ullWeight(0), ulBusNumber(0), ulLineNumber(0)
{};
};
struct VirtualSystem;
struct HardDiskController
{
Utf8Str strControllerType; // controller subtype (Item/ResourceSubType); e.g. "LsiLogic"; can be empty (esp. for IDE)
: idController(0),
ulBusNumber(0)
{
}
};
struct VirtualDisk
{
// points into VirtualSystem.mapControllers
// and possibly higher for disks attached to SCSI controllers (untested)
// this receives the <id> component; points to one of the
// references in Appliance::Data.mapDisks
};
struct EthernetAdapter
{
};
struct VirtualSystem
{
Utf8Str strVirtualSystemType; // generic hardware description; OVF says this can be something like "vmx-4" or "xen";
// VMware Workstation 6.5 is "vmx-07"
EthernetAdaptersList llEthernetAdapters; // (one for each VirtualSystem/Item[@ResourceType=10]element)
// list of hard disk controllers
// (one for each VirtualSystem/Item[@ResourceType=6] element with accumulated data from children)
// (one for each VirtualSystem/Item[@ResourceType=17] element with accumulated data from children)
bool fHasFloppyDrive; // true if there's a floppy item in mapHardwareItems
bool fHasCdromDrive; // true if there's a CD-ROM item in mapHardwareItems; ISO images are not yet supported by OVFtool
bool fHasUsbController; // true if there's a USB controller item in mapHardwareItems
Utf8Str strSoundCardType; // if not empty, then the system wants a soundcard; this then specifies the hardware;
// VMware Workstation 6.5 uses "ensoniq1371" for example
Utf8Str strLicenseText; // license info if any; receives contents of VirtualSystem/EulaSection/License
: ullMemorySize(0), cCPUs(1), fHasFloppyDrive(false), fHasCdromDrive(false), fHasUsbController(false)
{
}
};
////////////////////////////////////////////////////////////////////////////////
//
// Appliance data definition
//
////////////////////////////////////////////////////////////////////////////////
// opaque private instance data of Appliance class
{
};
struct VirtualSystemDescription::Data
{
};
////////////////////////////////////////////////////////////////////////////////
//
// internal helpers
//
////////////////////////////////////////////////////////////////////////////////
{
return str2;
}
static const struct
{
const char *pcszVbox;
}
g_osTypes[] =
{
// { CIMOSType_CIMOS_TurboLinux_64, },
// { CIMOSType_CIMOS_Linux_64, },
// osTypeVBox = VBOXOSTYPE_Linux_x64;
// break;
};
/**
* Private helper func that suggests a VirtualBox guest OS type
* for the given OVF operating system type.
* @param osTypeVBox
* @param c
*/
{
{
{
return;
}
}
}
/**
* Private helper func that suggests a VirtualBox guest OS type
* for the given OVF operating system type.
* @param osTypeVBox
* @param c
*/
{
{
}
return CIMOSType_CIMOS_Other;
}
////////////////////////////////////////////////////////////////////////////////
//
// IVirtualBox public methods
//
////////////////////////////////////////////////////////////////////////////////
// This code is here so we won't have to include the appliance headers in the
// IVirtualBox implementation.
/**
* Implementation for IVirtualBox::createAppliance.
*
* @param anAppliance IAppliance object created if S_OK is returned.
* @return S_OK or error.
*/
{
return rc;
}
////////////////////////////////////////////////////////////////////////////////
//
// Appliance constructor / destructor
//
////////////////////////////////////////////////////////////////////////////////
struct shutup {};
/**
* Appliance COM initializer.
* @param
* @return
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* Weak reference to a VirtualBox object */
// initialize data
m = new Data;
/* Confirm a successful initialization */
return S_OK;
}
/**
* Appliance COM uninitializer.
* @return
*/
{
delete m;
m = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// Appliance private methods
//
////////////////////////////////////////////////////////////////////////////////
/**
* Private helper method that goes thru the elements of the given "current" element in the OVF XML
* and handles the contained child elements (which can be "Section" or "Content" elements).
*
* @param pcszPath Path spec of the XML file, for error messages.
* @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
* @param pCurElem Element whose children are to be analyzed here.
* @return
*/
{
{
const char *pcszTypeAttr = "";
)
)
{
return rc;
}
)
)
{
return rc;
}
{
// TODO
}
{
// child of VirtualSystemCollection -- TODO
}
{
// child of VirtualSystemCollection -- TODO
}
{
// child of VirtualSystemCollection -- TODO
}
)
)
{
return rc;
}
)
)
{
// TODO ResourceAllocationSection
// recurse for this, since it has VirtualSystem elements as children
return rc;
}
}
return S_OK;
}
/**
* Private helper method that handles disk sections in the OVF XML.
* Gets called indirectly from IAppliance::read().
*
* @param pcszPath Path spec of the XML file, for error messages.
* @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
* @param pSectionElem Section element for which this helper is getting called.
* @return
*/
{
// contains "Disk" child elements
{
DiskImage d;
pcszBad = "diskId";
pcszBad = "format";
pcszBad = "capacity";
else
{
// optional
d.iPopulatedSize = -1;
{
// look up corresponding /References/File nodes (list built above)
if ( pReferencesElem
)
{
// copy remaining values from file node then
const char *pcszBadInFile = NULL;
pcszBadInFile = "href";
// if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
if (pcszBadInFile)
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
pFileElem->getLineNumber());
}
else
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
strFileRef.c_str(),
pelmDisk->getLineNumber());
}
}
if (pcszBad)
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
pelmDisk->getLineNumber());
}
return S_OK;
}
/**
* Private helper method that handles network sections in the OVF XML.
* Gets called indirectly from IAppliance::read().
*
* @param pcszPath Path spec of the XML file, for error messages.
* @param pSectionElem Section element for which this helper is getting called.
* @return
*/
{
// we ignore network sections for now
// xml::NodesLoop loopNetworks(*pSectionElem, "Network");
// const xml::Node *pelmNetwork;
// while ((pelmNetwork = loopNetworks.forAllNodes()))
// {
// Network n;
// if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
// return setError(VBOX_E_FILE_ERROR,
// tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
// pcszPath,
// pelmNetwork->getLineNumber());
//
// m->mapNetworks[n.strNetworkName] = n;
// }
return S_OK;
}
/**
* Private helper method that handles a "VirtualSystem" element in the OVF XML.
* Gets called indirectly from IAppliance::read().
*
* @param pcszPath
* @param pContentElem
* @return
*/
{
if (pIdAttr)
{
)
{
/* <EulaSection>
<Info ovf:msgid="6">License agreement for the Virtual System.</Info>
<License ovf:msgid="1">License terms can go in here.</License>
</EulaSection> */
)
{
}
}
)
{
{
/* <System>
<vssd:Description>Description of the virtual hardware section.</vssd:Description>
<vssd:ElementName>vmware</vssd:ElementName>
<vssd:InstanceID>1</vssd:InstanceID>
<vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
<vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
</System>*/
}
{
{
)
{
}
else
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
i.ulLineNumber);
}
// store!
}
// now go thru all hardware items and handle them according to their type;
// in this first loop we handle all items _except_ hard disk images,
// which we'll handle in a second loop below
++itH)
{
// do some analysis
switch (i.resourceType)
{
case OVFResourceType_Processor: // 3
/* <rasd:Caption>1 virtual CPU</rasd:Caption>
<rasd:Description>Number of virtual CPUs</rasd:Description>
<rasd:ElementName>virtual CPU</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
if (i.ullVirtualQuantity < UINT16_MAX)
else
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
i.ulLineNumber);
break;
case OVFResourceType_Memory: // 4
)
else
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
i.strAllocationUnits.c_str(),
i.ulLineNumber);
break;
case OVFResourceType_IDEController: // 5
{
/* <Item>
<rasd:Caption>ideController0</rasd:Caption>
<rasd:Description>IDE Controller</rasd:Description>
<rasd:InstanceId>5</rasd:InstanceId>
<rasd:ResourceType>5</rasd:ResourceType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item> */
}
break;
case OVFResourceType_ParallelSCSIHBA: // 6 SCSI controller
{
/* <Item>
<rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
<rasd:Description>SCI Controller</rasd:Description>
<rasd:ElementName>SCSI controller</rasd:ElementName>
<rasd:InstanceID>4</rasd:InstanceID>
<rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
<rasd:ResourceType>6</rasd:ResourceType>
</Item> */
}
break;
case OVFResourceType_EthernetAdapter: // 10
{
/* <Item>
<rasd:Caption>Ethernet adapter on 'Bridged'</rasd:Caption>
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
<rasd:Connection>Bridged</rasd:Connection>
<rasd:InstanceID>6</rasd:InstanceID>
<rasd:ResourceType>10</rasd:ResourceType>
<rasd:ResourceSubType>E1000</rasd:ResourceSubType>
</Item>
OVF spec DSP 0243 page 21:
"For an Ethernet adapter, this specifies the abstract network connection name
for the virtual machine. All Ethernet adapters that specify the same abstract
network connection name within an OVF package shall be deployed on the same
network. The abstract network connection name shall be listed in the NetworkSection
at the outermost envelope level." */
// only store the name
}
break;
case OVFResourceType_FloppyDrive: // 14
break;
case OVFResourceType_CDDrive: // 15
/* <Item ovf:required="false">
<rasd:Caption>cdrom1</rasd:Caption>
<rasd:InstanceId>7</rasd:InstanceId>
<rasd:ResourceType>15</rasd:ResourceType>
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
<rasd:Parent>5</rasd:Parent>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
</Item> */
// I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
// but then the ovftool dies with "Device backing not supported". So I guess if
// VMware can't export ISOs, then we don't need to be able to import them right now.
break;
case OVFResourceType_HardDisk: // 17
// handled separately in second loop below
break;
case OVFResourceType_OtherStorageDevice: // 20 SATA controller
{
/* <Item>
<rasd:Description>SATA Controller</rasd:Description>
<rasd:Caption>sataController0</rasd:Caption>
<rasd:InstanceID>4</rasd:InstanceID>
<rasd:ResourceType>20</rasd:ResourceType>
<rasd:ResourceSubType>AHCI</rasd:ResourceSubType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item> */
{
}
else
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": Host resource of type \"Other Storage Device (%d)\" is supported with SATA AHCI controllers only, line %d"),
i.ulLineNumber);
}
break;
case OVFResourceType_USBController: // 23
/* <Item ovf:required="false">
<rasd:Caption>usb</rasd:Caption>
<rasd:Description>USB Controller</rasd:Description>
<rasd:InstanceId>3</rasd:InstanceId>
<rasd:ResourceType>23</rasd:ResourceType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item> */
break;
case OVFResourceType_SoundCard: // 35
/* <Item ovf:required="false">
<rasd:Caption>sound</rasd:Caption>
<rasd:Description>Sound Card</rasd:Description>
<rasd:InstanceId>10</rasd:InstanceId>
<rasd:ResourceType>35</rasd:ResourceType>
<rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
<rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
<rasd:AddressOnParent>3</rasd:AddressOnParent>
</Item> */
break;
default:
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
i.resourceType,
i.ulLineNumber);
} // end switch
}
// now run through the items for a second time, but handle only
// hard disk images; otherwise the code would fail if a hard
// disk image appears in the OVF before its hard disk controller
++itH)
{
// do some analysis
switch (i.resourceType)
{
case OVFResourceType_HardDisk: // 17
{
/* <Item>
<rasd:Caption>Harddisk 1</rasd:Caption>
<rasd:Description>HD</rasd:Description>
<rasd:ElementName>Hard Disk</rasd:ElementName>
<rasd:InstanceID>5</rasd:InstanceID>
<rasd:Parent>4</rasd:Parent>
<rasd:ResourceType>17</rasd:ResourceType>
</Item> */
// look up the hard disk controller element whose InstanceID equals our Parent;
// this is how the connection is specified in OVF
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
i.ulInstanceID,
i.ulParent,
i.ulLineNumber);
//const HardDiskController &hdc = it->second;
// 123456789012345
)
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
i.ulInstanceID,
i.strHostResource.c_str(),
i.ulLineNumber);
}
break;
}
}
}
)
{
return setError(VBOX_E_FILE_ERROR,
tr("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
pelmThis->getLineNumber());
}
)
{
}
}
// now create the virtual system
return S_OK;
}
////////////////////////////////////////////////////////////////////////////////
//
// IAppliance public methods
//
////////////////////////////////////////////////////////////////////////////////
/**
* Public method implementation.
* @param
* @return
*/
{
if (!aPath)
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
return S_OK;
}
/**
* Public method implementation.
* @param
* @return
*/
{
AutoCaller autoCaller(this);
AutoReadLock alock(this);
size_t i = 0;
++it, ++i)
{
// create a string representing this disk
"%s\t"
"%RI64\t"
"%RI64\t"
"%s\t"
"%s\t"
"%RI64\t"
"%RI64\t"
"%s",
d.iCapacity,
d.iSize,
d.iChunkSize,
d.strCompression.c_str());
// push to safearray
}
return S_OK;
}
/**
* Public method implementation.
* @param
* @return
*/
STDMETHODIMP Appliance::COMGETTER(VirtualSystemDescriptions)(ComSafeArrayOut(IVirtualSystemDescription*, aVirtualSystemDescriptions))
{
AutoCaller autoCaller(this);
AutoReadLock alock(this);
return S_OK;
}
/**
* Public method implementation.
* @param path
* @return
*/
{
if (!path)
return E_POINTER;
AutoCaller autoCaller(this);
AutoWriteLock alock(this);
// see if we can handle this file; for now we insist it has an ".ovf" extension
return setError(VBOX_E_FILE_ERROR,
tr("Appliance file must have .ovf extension"));
try
{
doc);
return setError(VBOX_E_FILE_ERROR,
tr("Root element in OVF file must be \"Envelope\"."));
// OVF has the following rough layout:
/*
-- <References> .... files referenced from other parts of the file, such as VMDK images
-- Metadata, comprised of several section commands
-- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
-- optionally <Strings> for localization
*/
// get all "File" child elements of "References" section so we can look up files easily;
// first find the "References" sections so we can look up files
// now go though the sections
return rc;
}
{
return setError(VBOX_E_FILE_ERROR,
x.what());
}
return S_OK;
}
/**
* Public method implementation.
* @return
*/
{
// @todo:
// - don't use COM methods but the methods directly (faster, but needs appropriate locking of that objects itself (s. HardDisk))
// - Appropriate handle errors like not supported file formats
AutoCaller autoCaller(this);
AutoWriteLock(this);
/* Clear any previous virtual system descriptions */
/* We need the default path for storing disk images */
try
{
/* Iterate through all virtual systems */
++it)
{
/* Guest OS type */
"",
/* VM name */
/* If the there isn't any name specified create a default one out of
* the OS type */
"",
nameVBox);
/* VM description */
"",
/* VM license */
"",
/* Now that we know the OS type, get our internal defaults based on that. */
/* CPU count */
/* Check for the constrains */
{
addWarning(tr("The virtual system \"%s\" claims support for %u CPU's, but VirtualBox has support for max %u CPU's only."),
}
cpuCountVBox = 1;
"",
/* RAM */
/* Check for the constrains */
if (ullMemSizeVBox != 0 &&
{
addWarning(tr("The virtual system \"%s\" claims support for %llu MB RAM size, but VirtualBox has support for min %u & max %u MB RAM size only."),
}
if (vsysThis.ullMemorySize == 0)
{
/* If the RAM of the OVF is zero, use our predefined values */
/* VBox stores that in MByte */
}
"",
/* Audio */
/* Currently we set the AC97 always.
@todo: figure out the hardware which could be possible */
"",
#ifdef VBOX_WITH_USB
/* USB Controller */
#endif /* VBOX_WITH_USB */
/* Network Controller */
if (cEthernetAdapters > 0)
{
/* Check for the constrains */
addWarning(tr("The virtual system \"%s\" claims support for %u network adapters, but VirtualBox has support for max %u network adapter only."),
/* Get the default network adapter type for the selected guest OS */
/* Iterate through all abstract networks. We support 8 network
* adapters at the maximum, so the first 8 will be added only. */
size_t a = 0;
++itEA, ++a)
{
// make sure it's one of these two
)
strNetwork = "NAT";
/* Figure out the hardware type */
{
/* If the default adapter is already one of the two
* PCNet adapters use the default one. If not use the
* Am79C970A as fallback. */
if (!(defaultAdapterVBox == NetworkAdapterType_Am79C970A ||
}
#ifdef VBOX_WITH_E1000
{
/* If the default adapter is already one of the two
* E1000 adapters use the default one. If not use the
* I82540EM as fallback. */
if (!(defaultAdapterVBox == NetworkAdapterType_I82540EM ||
}
#endif /* VBOX_WITH_E1000 */
"", // ref
strNetwork, // orig
0,
}
}
/* Floppy Drive */
if (vsysThis.fHasFloppyDrive)
/* CD Drive */
/* @todo: I can't disable the CDROM. So nothing to do for now */
/*
if (vsysThis.fHasCdromDrive)
pNewDesc->addEntry(VirtualSystemDescriptionType_CDROM, "", "", "");*/
/* Hard disk Controller */
/* Iterate through all hard disk controllers */
++hdcIt)
{
{
case HardDiskController::IDE:
{
/* Check for the constrains */
/* @todo: I'm very confused! Are these bits *one* controller or
if (cIDEused < 4)
{
// @todo: figure out the IDE types
/* Use PIIX4 as default */
strType = "PIIX3";
strType = "ICH6";
strType);
}
else
{
/* Warn only once */
if (cIDEused == 1)
addWarning(tr("The virtual \"%s\" system requests support for more than one IDE controller, but VirtualBox has support for only one."),
}
++cIDEused;
break;
}
#ifdef VBOX_WITH_AHCI
case HardDiskController::SATA:
{
/* Check for the constrains */
if (cSATAused < 1)
{
// @todo: figure out the SATA types
/* We only support a plain AHCI controller, so use them always */
"AHCI");
}
else
{
/* Warn only once */
if (cSATAused == 1)
addWarning(tr("The virtual system \"%s\" requests support for more than one SATA controller, but VirtualBox has support for only one"),
}
++cSATAused;
break;
}
#endif /* VBOX_WITH_AHCI */
case HardDiskController::SCSI:
{
/* Check for the constrains */
if (cSCSIused < 1)
{
hdcController = "BusLogic";
}
else
addWarning(tr("The virtual system \"%s\" requests support for an additional SCSI controller of type \"%s\" with ID %s, but VirtualBox presently supports only one SCSI controller."),
strControllerID.c_str());
++cSCSIused;
break;
}
}
}
/* Hard disks */
{
/* Iterate through all hard disks ()*/
++itVD)
{
/* Get the associated disk image */
// @todo:
// - figure out all possible vmdk formats we also support
// - figure out if there is a url specifier for vhd already
// - we need a url specifier for the vdi format
if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
{
/* If the href is empty use the VM name as filename */
if (!strFilename.length())
/* Construct a unique target path */
strFilename.c_str());
/* find the description for the hard disk controller
* that has the same ID as hd.idController */
tr("Cannot find hard disk controller with OVF instance ID %RI32 to which disk \"%s\" should be attached"),
/* controller to attach to, and the bus within that controller */
}
else
throw setError(VBOX_E_FILE_ERROR,
}
}
}
}
{
/* On error we clear the list & return */
}
return rc;
}
struct Appliance::TaskImportMachines
{
: pAppliance(aThat)
{}
~TaskImportMachines() {}
};
{
"Appliance::Task");
return S_OK;
}
/**
* Public method implementation.
* @param aProgress
* @return
*/
{
AutoCaller autoCaller(this);
AutoReadLock(this);
try
{
/* Initialize our worker task */
//AssertComRCThrowRC (task->autoCaller.rc());
}
{
}
/* Return progress to the caller */
return rc;
}
struct MyHardDiskAttachment
{
};
/**
* Worker thread implementation for ImportMachines().
* @param aThread
* @param pvUser
*/
/* static */
{
// rollback for errors:
bool fSessionOpen = false;
/* Iterate through all virtual systems of that appliance */
size_t i = 0;
{
/* Catch possible errors */
try
{
/* How many sub notifications are necessary? */
/* Guest OS type */
throw setError(VBOX_E_FILE_ERROR,
tr("Missing guest OS type"));
/* Now that we know the base system get our internal defaults based on that. */
/* Create the machine */
/* First get the name */
std::list<VirtualSystemDescriptionEntry*> vsdeName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
throw setError(VBOX_E_FILE_ERROR,
tr("Missing VM name"));
// and the description
std::list<VirtualSystemDescriptionEntry*> vsdeDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
if (vsdeDescription.size())
{
}
/* CPU count (ignored for now) */
// EntriesList vsdeCPU = vsd->findByType (VirtualSystemDescriptionType_CPU);
/* RAM */
std::list<VirtualSystemDescriptionEntry*> vsdeRAM = vsdescThis->findByType(VirtualSystemDescriptionType_Memory);
/* VRAM */
/* Get the recommended VRAM for this guest OS type */
/* Set the VRAM */
/* Audio Adapter */
std::list<VirtualSystemDescriptionEntry*> vsdeAudioAdapter = vsdescThis->findByType(VirtualSystemDescriptionType_SoundCard);
/* @todo: we support one audio adapter only */
if (vsdeAudioAdapter.size() > 0)
{
{
}
}
#ifdef VBOX_WITH_USB
/* USB Controller */
std::list<VirtualSystemDescriptionEntry*> vsdeUSBController = vsdescThis->findByType(VirtualSystemDescriptionType_USBController);
// USB support is enabled if there's at least one such entry; to disable USB support,
// the type of the USB item would have been changed to "ignore"
#endif /* VBOX_WITH_USB */
/* Change the network adapters */
std::list<VirtualSystemDescriptionEntry*> vsdeNW = vsdescThis->findByType(VirtualSystemDescriptionType_NetworkAdapter);
{
/* No network adapters, so we have to disable our default one */
}
else
{
/* Iterate through all network cards. We support 8 network adapters
* at the maximum. (@todo: warn if there are more!) */
size_t a = 0;
++nwIt, ++a)
{
/* Enable the network card & set the adapter type */
// default is NAT; change to "bridged" if extra conf says so
{
/* Attach to the right interface */
/* We search for the first host network interface which
* is usable for bridged networking */
{
{
/* Set the interface name to attach to */
break;
}
}
}
/* Next test for host only interfaces */
{
/* Attach to the right interface */
/* We search for the first host network interface which
* is usable for host only networking */
{
{
/* Set the interface name to attach to */
break;
}
}
}
}
}
/* Floppy drive */
std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsdescThis->findByType(VirtualSystemDescriptionType_Floppy);
// Floppy support is enabled if there's at least one such entry; to disable floppy support,
// the type of the floppy item would have been changed to "ignore"
/* CDROM drive */
/* @todo: I can't disable the CDROM. So nothing to do for now */
// std::list<VirtualSystemDescriptionEntry*> vsdeFloppy = vsd->findByType(VirtualSystemDescriptionType_CDROM);
/* Hard disk controller IDE */
std::list<VirtualSystemDescriptionEntry*> vsdeHDCIDE = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerIDE);
throw setError(VBOX_E_FILE_ERROR,
tr("Too many IDE controllers in OVF; VirtualBox only supports one"));
{
else
throw setError(VBOX_E_FILE_ERROR,
tr("Invalid IDE controller type \"%s\""),
}
#ifdef VBOX_WITH_AHCI
/* Hard disk controller SATA */
std::list<VirtualSystemDescriptionEntry*> vsdeHDCSATA = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSATA);
throw setError(VBOX_E_FILE_ERROR,
tr("Too many SATA controllers in OVF; VirtualBox only supports one"));
if (vsdeHDCSATA.size() > 0)
{
if (hdcVBox == "AHCI")
{
}
else
throw setError(VBOX_E_FILE_ERROR,
tr("Invalid SATA controller type \"%s\""),
}
#endif /* VBOX_WITH_AHCI */
/* Hard disk controller SCSI */
std::list<VirtualSystemDescriptionEntry*> vsdeHDCSCSI = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskControllerSCSI);
throw setError(VBOX_E_FILE_ERROR,
tr("Too many SCSI controllers in OVF; VirtualBox only supports one"));
if (vsdeHDCSCSI.size() > 0)
{
if (hdcVBox == "LsiLogic")
else if (hdcVBox == "BusLogic")
else
throw setError(VBOX_E_FILE_ERROR,
tr("Invalid SCSI controller type \"%s\""),
}
/* Now its time to register the machine before we add any hard disks */
// store new machine for roll-back in case of errors
/* Create the hard disks & connect them to the appropriate controllers. */
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
{
/* If in the next block an error occur we have to deregister
bool fSourceHdNeedsClosing = false;
try
{
/* In order to attach hard disks we need to open a session
* for the new machine */
fSessionOpen = true;
/* The disk image has to be on the same place as the OVF file. So
* strip the filename out of the full file path. */
/* Iterate over all given disk images */
++itHD)
{
/* Check if the destination file exists already or the
* destination path is empty. */
if ( !(*pcszDstFilePath)
)
/* This isn't allowed */
throw setError(VBOX_E_FILE_ERROR,
tr("Destination file '%s' exists",
/* Find the disk from the OVF's disk list */
/* vsdeHD->strRef contains the disk identifier (e.g. "vmdisk1"), which should exist
in the virtual system's disks map under that ID and also in the global images map. */
)
tr("Internal inconsistency looking up disk images."));
/* Make sure all target directories exists */
throw rc;
/* If strHref is empty we have to create a new file */
{
/* Which format to use? */
if ( di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#sparse", Utf8Str::CaseInsensitive)
|| di.strFormat.compare("http://www.vmware.com/specifications/vmdk.html#compressed", Utf8Str::CaseInsensitive))
srcFormat = L"VMDK";
/* Create an empty hard disk */
/* Create a dynamic growing disk image with the given capacity */
rc = dstHdVBox->CreateBaseStorage(di.iCapacity / _1M, HardDiskVariant_Standard, progress.asOutParam());
/* Advance to the next operation */
}
else
{
/* Construct the source file path */
/* Check if the source file exists */
/* This isn't allowed */
throw setError(VBOX_E_FILE_ERROR,
tr("Source virtual disk image file '%s' doesn't exist"),
strSrcFilePath.c_str());
/* Clone the disk image (this is necessary cause the id has
* to be recreated for the case the same hard disk is
* attached already from a previous import) */
/* First open the existing disk image */
srcHdVBox.asOutParam());
fSourceHdNeedsClosing = true;
/* We need the format description of the source disk image */
/* Create a new hard disk interface for the destination disk image */
/* Clone the source disk image */
/* Advance to the next operation */
task->progress->setNextOperation(BstrFmt(tr("Importing virtual disk image '%s'"), strSrcFilePath.c_str()),
}
// now loop until the asynchronous operation completes and then
// report its result
{
if (fCompleted)
break;
/* Make sure the loop is not too tight */
}
// report result of asynchronous operation
// if the thread of the progress object has an error, then
// retrieve the error info from there, or it'll be lost
{
pcsz);
throw rc2;
}
{
fSourceHdNeedsClosing = false;
}
/* Now use the new uuid to attach the disk image to our new machine */
/* For now we assume we have one controller of every type only */
// this is for rollback later
{
case HardDiskController::IDE:
// For the IDE bus, the channel parameter can be either 0 or 1, to specify the primary
// or secondary IDE controller, respectively. For the primary controller of the IDE bus,
// the device number can be either 0 or 1, to specify the master or the slave device,
// respectively. For the secondary IDE controller, the device number is always 1 because
// the master device is reserved for the CD-ROM drive.
switch (vd.ulAddressOnParent)
{
case 0: // interpret this as primary master
break;
case 1: // interpret this as primary slave
break;
case 2: // interpret this as secondary slave
break;
default:
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Invalid channel %RI16 specified; IDE controllers support only 0, 1 or 2"), vd.ulAddressOnParent);
break;
}
break;
case HardDiskController::SATA:
break;
case HardDiskController::SCSI:
break;
default: break;
}
Log(("Attaching disk %s to channel %d on device %d\n", pcszDstFilePath, mhda.lChannel, mhda.lDevice));
} // end for (itHD = avsdeHDs.begin();
// only now that we're done with all disks, close the session
fSessionOpen = false;
}
catch(HRESULT /* aRC */)
{
if (fSessionOpen)
throw;
}
}
}
{
}
break;
} // for (it = pAppliance->m->llVirtualSystems.begin(),
{
// with _whatever_ error we've had, do a complete roll-back of
// machines and disks we've created; unfortunately this is
// not so trivially done...
// detach all hard disks from all machines we created
++itM)
{
{
{
}
}
}
// now clean up all hard disks we created
++itHD)
{
}
// finally, deregister and remove all machines
++itID)
{
}
}
return VINF_SUCCESS;
}
struct Appliance::TaskWriteOVF
{
: pAppliance(aThat)
{}
~TaskWriteOVF() {}
};
{
"Appliance::Task");
return S_OK;
}
{
AutoCaller autoCaller(this);
AutoWriteLock(this);
// see if we can handle this file; for now we insist it has an ".ovf" extension
return setError(VBOX_E_FILE_ERROR,
tr("Appliance file must have .ovf extension"));
try
{
/* Initialize our worker task */
//AssertComRCThrowRC (task->autoCaller.rc());
}
{
}
/* Return progress to the caller */
return rc;
}
/**
* Worker thread implementation for Write() (ovf writer).
* @param aThread
* @param pvUser
*/
/* static */
{
try
{
pelmRoot->setAttribute("xmlns:rasd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData");
pelmRoot->setAttribute("xmlns:vssd", "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData");
pelmRoot->setAttribute("xsi:schemaLocation", "http://schemas.dmtf.org/ovf/envelope/1 ../ovf-envelope.xsd");
// <Envelope>/<References>
/* <Envelope>/<DiskSection>:
<DiskSection>
<Info>List of the virtual disks used in the package</Info>
<Disk ovf:capacity="4294967296" ovf:diskId="lamp" ovf:format="http://www.vmware.com/specifications/vmdk.html#compressed" ovf:populatedSize="1924967692"/>
</DiskSection> */
// for now, set up a map so we have a list of unique disk names (to make
// sure the same disk name is only added once)
/* <Envelope>/<NetworkSection>:
<NetworkSection>
<Info>Logical networks used in the package</Info>
<Network ovf:name="VM Network">
<Description>The network that the LAMP Service will be available on</Description>
</Network>
</NetworkSection> */
// for now, set up a map so we have a list of unique network names (to make
// sure the same network name is only added once)
// we fill this later below when we iterate over the networks
// and here come the virtual systems:
/* xml::AttributeNode *pattrVirtualSystemCollectionId = */ pelmVirtualSystemCollection->setAttribute("ovf:id", "ExportedVirtualBoxMachines"); // whatever
/* Iterate through all virtual systems of that appliance */
++it)
{
/*xml::ElementNode *pelmVirtualSystemInfo =*/ pelmVirtualSystem->createChild("Info")->addContent("A virtual machine");
std::list<VirtualSystemDescriptionEntry*> llName = vsdescThis->findByType(VirtualSystemDescriptionType_Name);
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Missing VM name"));
// description
std::list<VirtualSystemDescriptionEntry*> llDescription = vsdescThis->findByType(VirtualSystemDescriptionType_Description);
if (llDescription.size())
{
/* <Section ovf:required="false" xsi:type="ovf:AnnotationSection_Type">
<Info>A human-readable annotation</Info>
<Annotation>Plan 9</Annotation>
</Section> */
}
// license
std::list<VirtualSystemDescriptionEntry*> llLicense = vsdescThis->findByType(VirtualSystemDescriptionType_License);
{
/* <EulaSection>
<Info ovf:msgid="6">License agreement for the Virtual System.</Info>
<License ovf:msgid="1">License terms can go in here.</License>
</EulaSection> */
pelmAnnotationSection->createChild("Info")->addContent("License agreement for the Virtual System.");
}
// operating system
std::list<VirtualSystemDescriptionEntry*> llOS = vsdescThis->findByType(VirtualSystemDescriptionType_OS);
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Missing OS type"));
/* <OperatingSystemSection ovf:id="82">
<Info>Guest Operating System</Info>
<Description>Linux 2.6.x</Description>
</OperatingSystemSection> */
xml::ElementNode *pelmOperatingSystemSection = pelmVirtualSystem->createChild("OperatingSystemSection");
// pelmOperatingSystemSection->createChild("Info")->addContent("blah"); // @todo
// pelmOperatingSystemSection->createChild("Description")->addContent("blah"); // @todo
// <VirtualHardwareSection ovf:id="hw1" ovf:transport="iso">
xml::ElementNode *pelmVirtualHardwareSection = pelmVirtualSystem->createChild("VirtualHardwareSection");
/* <System>
<vssd:Description>Description of the virtual hardware section.</vssd:Description>
<vssd:ElementName>vmware</vssd:ElementName>
<vssd:InstanceID>1</vssd:InstanceID>
<vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
<vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
</System> */
// <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
// loop thru all description entries twice; once to write out all
// devices _except_ disk images, and a second time to assign the
// disk images; this is because disk images need to reference
// IDE controllers, and we can't know their instance IDs without
// assigning them first
uint32_t idIDEController = 0;
uint32_t idSATAController = 0;
uint32_t idSCSIController = 0;
uLoop <= 2;
++uLoop)
{
int32_t lIndexThis = 0;
++itD, ++lIndexThis)
{
{
/* <Item>
<rasd:Caption>1 virtual CPU</rasd:Caption>
<rasd:Description>Number of virtual CPUs</rasd:Description>
<rasd:ElementName>virtual CPU</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
</Item> */
if (uLoop == 1)
{
strDescription = "Number of virtual CPUs";
lVirtualQuantity = 1;
}
break;
/* <Item>
<rasd:AllocationUnits>MegaBytes</rasd:AllocationUnits>
<rasd:Caption>256 MB of memory</rasd:Caption>
<rasd:Description>Memory Size</rasd:Description>
<rasd:ElementName>Memory</rasd:ElementName>
<rasd:InstanceID>2</rasd:InstanceID>
<rasd:ResourceType>4</rasd:ResourceType>
<rasd:VirtualQuantity>256</rasd:VirtualQuantity>
</Item> */
if (uLoop == 1)
{
strDescription = "Memory Size";
strAllocationUnits = "MegaBytes";
}
break;
/* <Item>
<rasd:Caption>ideController1</rasd:Caption>
<rasd:Description>IDE Controller</rasd:Description>
<rasd:InstanceId>5</rasd:InstanceId>
<rasd:ResourceType>5</rasd:ResourceType>
<rasd:Address>1</rasd:Address>
<rasd:BusNumber>1</rasd:BusNumber>
</Item> */
if (uLoop == 1)
{
strDescription = "IDE Controller";
// it seems that OVFTool always writes these two, and since we can only
// have one IDE controller, we'll use this as well
lAddress = 1;
lBusNumber = 1;
// remember this ID
}
break;
/* <Item>
<rasd:Caption>sataController0</rasd:Caption>
<rasd:Description>SATA Controller</rasd:Description>
<rasd:InstanceId>4</rasd:InstanceId>
<rasd:ResourceType>20</rasd:ResourceType>
<rasd:ResourceSubType>ahci</rasd:ResourceSubType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item>
*/
if (uLoop == 1)
{
strDescription = "SATA Controller";
strCaption = "sataController0";
// it seems that OVFTool always writes these two, and since we can only
// have one SATA controller, we'll use this as well
lAddress = 0;
lBusNumber = 0;
)
strResourceSubType = "AHCI";
else
throw setError(VBOX_E_NOT_SUPPORTED,
// remember this ID
}
break;
/* <Item>
<rasd:Caption>scsiController0</rasd:Caption>
<rasd:Description>SCSI Controller</rasd:Description>
<rasd:InstanceId>4</rasd:InstanceId>
<rasd:ResourceType>6</rasd:ResourceType>
<rasd:ResourceSubType>buslogic</rasd:ResourceSubType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item>
*/
if (uLoop == 1)
{
strDescription = "SCSI Controller";
strCaption = "scsiController0";
// it seems that OVFTool always writes these two, and since we can only
// have one SATA controller, we'll use this as well
lAddress = 0;
lBusNumber = 0;
)
strResourceSubType = "lsilogic";
strResourceSubType = "buslogic";
else
throw setError(VBOX_E_NOT_SUPPORTED,
// remember this ID
}
break;
/* <Item>
<rasd:Caption>disk1</rasd:Caption>
<rasd:InstanceId>8</rasd:InstanceId>
<rasd:ResourceType>17</rasd:ResourceType>
<rasd:Parent>4</rasd:Parent>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
</Item> */
if (uLoop == 2)
{
strDescription = "Disk Image";
// the following references the "<Disks>" XML block
// controller=<index>;channel=<c>
{
if (lControllerIndex == lIDEControllerIndex)
else if (lControllerIndex == lSCSIControllerIndex)
else if (lControllerIndex == lSATAControllerIndex)
}
if ( !ulParent
|| lAddressOnParent == -1
)
throw setError(VBOX_E_NOT_SUPPORTED,
}
break;
if (uLoop == 1)
{
strDescription = "Floppy Drive";
lAutomaticAllocation = 0;
lAddressOnParent = 0; // this is what OVFTool writes
}
break;
if (uLoop == 2)
{
// we can't have a CD without an IDE controller
if (!idIDEController)
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Can't have CD-ROM without IDE controller"));
strDescription = "CD-ROM Drive";
lAutomaticAllocation = 1;
lAddressOnParent = 0; // this is what OVFTool writes
}
break;
/* <Item>
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
<rasd:Caption>Ethernet adapter on 'VM Network'</rasd:Caption>
<rasd:Connection>VM Network</rasd:Connection>
<rasd:ElementName>VM network</rasd:ElementName>
<rasd:InstanceID>3</rasd:InstanceID>
<rasd:ResourceType>10</rasd:ResourceType>
</Item> */
if (uLoop == 1)
{
lAutomaticAllocation = 1;
/* Set the hardware type to something useful.
* To be compatible with vmware & others we set
* PCNet32 for our PCNet types & E1000 for the
* E1000 cards. */
{
#ifdef VBOX_WITH_E1000
#endif /* VBOX_WITH_E1000 */
}
}
break;
/* <Item ovf:required="false">
<rasd:Caption>usb</rasd:Caption>
<rasd:Description>USB Controller</rasd:Description>
<rasd:InstanceId>3</rasd:InstanceId>
<rasd:ResourceType>23</rasd:ResourceType>
<rasd:Address>0</rasd:Address>
<rasd:BusNumber>0</rasd:BusNumber>
</Item> */
if (uLoop == 1)
{
strDescription = "USB Controller";
strCaption = "usb";
lAddress = 0; // this is what OVFTool writes
lBusNumber = 0; // this is what OVFTool writes
}
break;
/* <Item ovf:required="false">
<rasd:Caption>sound</rasd:Caption>
<rasd:Description>Sound Card</rasd:Description>
<rasd:InstanceId>10</rasd:InstanceId>
<rasd:ResourceType>35</rasd:ResourceType>
<rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
<rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
<rasd:AddressOnParent>3</rasd:AddressOnParent>
</Item> */
if (uLoop == 1)
{
strDescription = "Sound Card";
strCaption = "sound";
lAutomaticAllocation = 0;
}
break;
}
if (type)
{
if (!strDescription.isEmpty())
if (!strCaption.isEmpty())
if (!strAllocationUnits.isEmpty())
if (lAutomaticAllocation != -1)
pItem->createChild("rasd:AutomaticAllocation")->addContent( (lAutomaticAllocation) ? "true" : "false" );
if (!strConnection.isEmpty())
// <rasd:InstanceID>1</rasd:InstanceID>
++ulInstanceID;
// <rasd:ResourceType>3</rasd:ResourceType>
if (!strResourceSubType.isEmpty())
// <rasd:VirtualQuantity>1</rasd:VirtualQuantity>
if (lVirtualQuantity != -1)
if (lAddress != -1)
if (lBusNumber != -1)
if (ulParent)
if (lAddressOnParent != -1)
if (!strHostResource.isEmpty())
}
}
} // for (size_t uLoop = 0; ...
}
// finally, fill in the network section we set up empty above according
// to the networks we found with the hardware items
++itN)
{
}
++itS)
{
// source path: where the VBox image is
/* This isn't allowed */
throw setError(VBOX_E_FILE_ERROR,
tr("Source virtual disk image file '%s' doesn't exist"),
strSrcFilePath.c_str());
// output filename
// target path needs to be composed from where the output OVF is
// clone the disk:
/* We are always exporting to vmdfk stream optimized for now */
// create a new hard disk interface for the destination disk image
// the target disk is now registered and needs to be removed again,
// both after successful cloning or if anything goes bad!
try
{
// create a flat copy of the source disk image
rc = pSourceDisk->FlattenTo(pTargetDisk, HardDiskVariant_VmdkStreamOptimized, pProgress2.asOutParam());
// advance to the next operation
task->progress->setNextOperation(BstrFmt(tr("Exporting virtual disk image '%s'"), strSrcFilePath.c_str()),
// now loop until the asynchronous operation completes and then
// report its result
{
if (fCompleted)
break;
// make sure the loop is not too tight
}
// report result of asynchronous operation
// if the thread of the progress object has an error, then
// retrieve the error info from there, or it'll be lost
{
throw rc2;
}
}
{
// upon error after registereing, close the disk or
// it'll stick in the registry forever
pTargetDisk->Close();
throw rc3;
}
// we need the following for the XML
// capacity is reported in megabytes, so...
cbCapacity *= _1M;
// upon success, close the disk as well
// now handle the XML for the disk:
// <File ovf:href="WindowsXpProfessional-disk1.vmdk" ovf:id="file1" ovf:size="1710381056"/>
// add disk to XML Disks section
// <Disk ovf:capacity="8589934592" ovf:diskId="vmdisk1" ovf:fileRef="file1" ovf:format="http://www.vmware.com/specifications/vmdk.html#sparse"/>
}
// now go write the XML
}
{
x.what());
}
{
}
return VINF_SUCCESS;
}
/**
* Public method implementation.
* @return
*/
{
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
size_t i = 0;
++it, ++i)
{
}
return S_OK;
}
{
int i = 1;
/* @todo: Maybe too cost-intensive; try to find a lighter way */
{
++i;
}
return S_OK;
}
{
int i = 1;
/* Check if the file exists or if a file with this path is registered
* already */
/* @todo: Maybe too cost-intensive; try to find a lighter way */
while (RTPathExists(tmpName) ||
{
++i;
}
return S_OK;
}
/**
* Calculates the no. of operations for the IProgress objects in importMachines() and write().
* @return
*/
{
/* Create the progress object */
// use one percent for parsing the XML and one percent for each virtual system
// in the XML; use the rest (e.g. 97%) for the disk images
// weigh the disk images according to their sizes
++it)
{
/* One for every hard disk of the Virtual System */
std::list<VirtualSystemDescriptionEntry*> avsdeHDs = vsdescThis->findByType(VirtualSystemDescriptionType_HardDiskImage);
++itH)
{
++cDisks;
}
}
Log(("Setting up progress object: ulTotalMB = %d, cFixed = %d, cDisks = %d, => cOperations = %d, ulTotalOperationsWeight = %d, m->ulWeightPerOperation = %d\n",
ulTotalMB, cFixed, cDisks, cFixed + (ULONG)cDisks, ulTotalOperationsWeight, m->ulWeightPerOperation));
FALSE /* aCancelable */,
ulTotalOperationsWeight, // ULONG ulTotalOperationsWeight,
bstrDescription, // CBSTR bstrFirstOperationDescription,
m->ulWeightPerOperation); // ULONG ulFirstOperationWeight,
return rc;
}
{
}
////////////////////////////////////////////////////////////////////////////////
//
// IVirtualSystemDescription constructor / destructor
//
////////////////////////////////////////////////////////////////////////////////
struct shutup3 {};
/**
* COM initializer.
* @return
*/
{
/* Enclose the state transition NotReady->InInit->Ready */
AutoInitSpan autoInitSpan(this);
/* Initialize data */
m = new Data();
/* Confirm a successful initialization */
return S_OK;
}
/**
* COM uninitializer.
*/
void VirtualSystemDescription::uninit()
{
delete m;
m = NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// IVirtualSystemDescription public methods
//
////////////////////////////////////////////////////////////////////////////////
/**
* Public method implementation.
* @param
* @return
*/
{
if (!aCount)
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
return S_OK;
}
/**
* Public method implementation.
* @return
*/
STDMETHODIMP VirtualSystemDescription::GetDescription(ComSafeArrayOut(VirtualSystemDescriptionType_T, aTypes),
{
if (ComSafeArrayOutIsNull(aTypes) ||
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
size_t i = 0;
++it, ++i)
{
}
return S_OK;
}
/**
* Public method implementation.
* @return
*/
{
if (ComSafeArrayOutIsNull(aTypes) ||
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
size_t i = 0;
++it, ++i)
{
}
return S_OK;
}
/**
* Public method implementation.
* @return
*/
{
if (ComSafeArrayOutIsNull(aValues))
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
size_t i = 0;
++it, ++i)
{
switch (aWhich)
{
}
}
return S_OK;
}
/**
* Public method implementation.
* @return
*/
{
#ifndef RT_OS_WINDOWS
#endif /* RT_OS_WINDOWS */
AutoCaller autoCaller(this);
AutoWriteLock alock(this);
)
return E_INVALIDARG;
size_t i = 0;
++it, ++i)
{
if (aEnabled[i])
{
}
else
}
return S_OK;
}
/**
* Public method implementation.
* @return
*/
{
AutoCaller autoCaller(this);
AutoWriteLock alock(this);
return S_OK;
}
/**
* Internal method; adds a new description item to the member list.
* @param aType Type of description for the new item.
* @param strRef Reference item; only used with hard disk controllers.
* @param aOrigValue Corresponding original value from OVF.
* @param aAutoValue Initial configuration value (can be overridden by caller with setFinalValues).
* @param strExtraConfig Extra configuration; meaning dependent on type.
*/
const Utf8Str &aOrigValue,
const Utf8Str &aAutoValue,
{
vsde.ulIndex = (uint32_t)m->llDescriptions.size(); // each entry gets an index so the client side can reference them
}
/**
* Private method; returns a list of description items containing all the items from the member
* description items of this virtual system that match the given type.
* @param aType
* @return
*/
std::list<VirtualSystemDescriptionEntry*> VirtualSystemDescription::findByType(VirtualSystemDescriptionType_T aType)
{
++it)
{
}
return vsd;
}
/**
* Private method; looks thru the member hardware items for the IDE, SATA, or SCSI controller with
* the given reference ID. Useful when needing the controller for a particular
* virtual disk.
* @param id
* @return
*/
{
++it)
{
const VirtualSystemDescriptionEntry &d = *it;
switch (d.type)
{
return &d;
break;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
//
// IMachine public methods
//
////////////////////////////////////////////////////////////////////////////////
// This code is here so we won't have to include the appliance headers in the
// IMachine implementation, and we also need to access private appliance data.
/**
* Public method implementation.
* @param appliance
* @return
*/
{
if (!aAppliance)
return E_POINTER;
AutoCaller autoCaller(this);
AutoReadLock alock(this);
try
{
// get name
// get description
// get guest OS
// CPU count
// memory size in MB
// VRAM size?
// BIOS settings?
// 3D acceleration enabled?
// hardware virtualization enabled?
// nested paging enabled?
// HWVirtExVPIDEnabled?
// PAEEnabled?
// snapshotFolder?
// VRDPServer?
// floppy
// CD-ROM ?!?
// ComPtr<IDVDDrive> pDVDDrive;
fDVDEnabled = 1;
// this is more tricky so use the COM method
// create a new virtual system
/* Guest OS type */
"",
/* VM name */
"",
// description
"",
/* CPU count*/
"",
/* Memory */
"",
// <const name="HardDiskControllerIDE" value="6" />
switch(ctlr)
{
}
{
strVbox);
}
#ifdef VBOX_WITH_AHCI
// <const name="HardDiskControllerSATA" value="7" />
{
strVbox = "AHCI";
strVbox);
}
#endif // VBOX_WITH_AHCI
// <const name="HardDiskControllerSCSI" value="8" />
{
{
switch(ctlr)
{
}
strVbox);
}
else
throw rc;
}
// <const name="HardDiskImage" value="9" />
++itA)
{
// the attachment's data
// and how this translates to the virtual system
int32_t lControllerVsys = 0;
switch (storageBus)
{
case StorageBus_IDE:
// this is the exact reverse to what we're doing in Appliance::taskThreadImportMachines,
// and it must be updated when that is changed!
lChannelVsys = 0;
lChannelVsys = 1;
lChannelVsys = 2;
else
throw setError(VBOX_E_NOT_SUPPORTED,
break;
case StorageBus_SATA:
break;
case StorageBus_SCSI:
break;
default:
throw setError(VBOX_E_NOT_SUPPORTED,
tr("Cannot handle hard disk attachment: storageBus is %d, channel is %d, device is %d"), storageBus, lChannel, lDevice);
break;
}
strTargetVmdkName, // disk ID: let's use the name
strTargetVmdkName, // OVF value:
}
/* Floppy Drive */
if (fFloppyEnabled)
/* CD Drive */
if (fDVDEnabled)
// <const name="NetworkAdapter" />
size_t a;
for (a = 0;
++a)
{
/* Enable the network card & set the adapter type */
if (fEnabled)
{
switch (attachmentType)
{
strAttachmentType = "Null";
break;
strAttachmentType = "NAT";
break;
strAttachmentType = "Bridged";
break;
strAttachmentType = "Internal";
break;
strAttachmentType = "HostOnly";
break;
}
"", // ref
strAttachmentType, // orig
}
}
// <const name="USBController" />
#ifdef VBOX_WITH_USB
if (fUSBEnabled)
#endif /* VBOX_WITH_USB */
// <const name="SoundCard" />
if (fAudioEnabled)
{
"",
"ensoniq1371", // this is what OVFTool writes and VMware supports
}
// finally, add the virtual system to the appliance
/* We return the new description to the caller */
}
{
}
return rc;
}
/* vi: set tabstop=4 shiftwidth=4 expandtab: */