VirtualBox

source: vbox/trunk/src/VBox/Main/xml/ovfreader.cpp@ 24196

Last change on this file since 24196 was 22173, checked in by vboxsync, 15 years ago

Main: the big XML settings rework. Move XML reading/writing out of interface implementation code into separate layer so it can handle individual settings versions in the future.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.3 KB
Line 
1/* $Id: ovfreader.cpp 22173 2009-08-11 15:38:59Z vboxsync $ */
2/** @file
3 *
4 * OVF reader declarations. Depends only on IPRT, including the iprt::MiniString
5 * and IPRT XML classes.
6 */
7
8/*
9 * Copyright (C) 2008-2009 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include "ovfreader.h"
25
26using namespace std;
27using namespace iprt;
28
29////////////////////////////////////////////////////////////////////////////////
30//
31// OVF reader implemenation
32//
33////////////////////////////////////////////////////////////////////////////////
34
35OVFReader::OVFReader(const MiniString &path)
36 : m_strPath(path)
37{
38 xml::XmlFileParser parser;
39 xml::Document doc;
40 parser.read(m_strPath,
41 doc);
42
43 const xml::ElementNode *pRootElem = doc.getRootElement();
44 if (pRootElem && strcmp(pRootElem->getName(), "Envelope"))
45 throw OVFLogicError(N_("Root element in OVF file must be \"Envelope\"."));
46
47 // OVF has the following rough layout:
48 /*
49 -- <References> .... files referenced from other parts of the file, such as VMDK images
50 -- Metadata, comprised of several section commands
51 -- virtual machines, either a single <VirtualSystem>, or a <VirtualSystemCollection>
52 -- optionally <Strings> for localization
53 */
54
55 // get all "File" child elements of "References" section so we can look up files easily;
56 // first find the "References" sections so we can look up files
57 xml::ElementNodesList listFileElements; // receives all /Envelope/References/File nodes
58 const xml::ElementNode *pReferencesElem;
59 if ((pReferencesElem = pRootElem->findChildElement("References")))
60 pReferencesElem->getChildElements(listFileElements, "File");
61
62 // now go though the sections
63 LoopThruSections(pReferencesElem, pRootElem);
64}
65
66OVFReader::~OVFReader()
67{
68}
69
70/**
71 * Private helper method that goes thru the elements of the given "current" element in the OVF XML
72 * and handles the contained child elements (which can be "Section" or "Content" elements).
73 *
74 * @param pcszPath Path spec of the XML file, for error messages.
75 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
76 * @param pCurElem Element whose children are to be analyzed here.
77 * @return
78 */
79void OVFReader::LoopThruSections(const xml::ElementNode *pReferencesElem,
80 const xml::ElementNode *pCurElem)
81{
82 xml::NodesLoop loopChildren(*pCurElem);
83 const xml::ElementNode *pElem;
84 while ((pElem = loopChildren.forAllNodes()))
85 {
86 const char *pcszElemName = pElem->getName();
87 const char *pcszTypeAttr = "";
88 const xml::AttributeNode *pTypeAttr;
89 if ((pTypeAttr = pElem->findAttribute("type")))
90 pcszTypeAttr = pTypeAttr->getValue();
91
92 if ( (!strcmp(pcszElemName, "DiskSection"))
93 || ( (!strcmp(pcszElemName, "Section"))
94 && (!strcmp(pcszTypeAttr, "ovf:DiskSection_Type"))
95 )
96 )
97 {
98 HandleDiskSection(pReferencesElem, pElem);
99 }
100 else if ( (!strcmp(pcszElemName, "NetworkSection"))
101 || ( (!strcmp(pcszElemName, "Section"))
102 && (!strcmp(pcszTypeAttr, "ovf:NetworkSection_Type"))
103 )
104 )
105 {
106 HandleNetworkSection(pElem);
107 }
108 else if ( (!strcmp(pcszElemName, "DeploymentOptionSection")))
109 {
110 // TODO
111 }
112 else if ( (!strcmp(pcszElemName, "Info")))
113 {
114 // child of VirtualSystemCollection -- TODO
115 }
116 else if ( (!strcmp(pcszElemName, "ResourceAllocationSection")))
117 {
118 // child of VirtualSystemCollection -- TODO
119 }
120 else if ( (!strcmp(pcszElemName, "StartupSection")))
121 {
122 // child of VirtualSystemCollection -- TODO
123 }
124 else if ( (!strcmp(pcszElemName, "VirtualSystem"))
125 || ( (!strcmp(pcszElemName, "Content"))
126 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystem_Type"))
127 )
128 )
129 {
130 HandleVirtualSystemContent(pElem);
131 }
132 else if ( (!strcmp(pcszElemName, "VirtualSystemCollection"))
133 || ( (!strcmp(pcszElemName, "Content"))
134 && (!strcmp(pcszTypeAttr, "ovf:VirtualSystemCollection_Type"))
135 )
136 )
137 {
138 // TODO ResourceAllocationSection
139
140 // recurse for this, since it has VirtualSystem elements as children
141 LoopThruSections(pReferencesElem, pElem);
142 }
143 }
144}
145
146/**
147 * Private helper method that handles disk sections in the OVF XML.
148 * Gets called indirectly from IAppliance::read().
149 *
150 * @param pcszPath Path spec of the XML file, for error messages.
151 * @param pReferencesElement "References" element from OVF, for looking up file specifications; can be NULL if no such element is present.
152 * @param pSectionElem Section element for which this helper is getting called.
153 * @return
154 */
155void OVFReader::HandleDiskSection(const xml::ElementNode *pReferencesElem,
156 const xml::ElementNode *pSectionElem)
157{
158 // contains "Disk" child elements
159 xml::NodesLoop loopDisks(*pSectionElem, "Disk");
160 const xml::ElementNode *pelmDisk;
161 while ((pelmDisk = loopDisks.forAllNodes()))
162 {
163 DiskImage d;
164 const char *pcszBad = NULL;
165 const char *pcszDiskId;
166 const char *pcszFormat;
167 if (!(pelmDisk->getAttributeValue("diskId", pcszDiskId)))
168 pcszBad = "diskId";
169 else if (!(pelmDisk->getAttributeValue("format", pcszFormat)))
170 pcszBad = "format";
171 else if (!(pelmDisk->getAttributeValue("capacity", d.iCapacity)))
172 pcszBad = "capacity";
173 else
174 {
175 d.strDiskId = pcszDiskId;
176 d.strFormat = pcszFormat;
177
178 if (!(pelmDisk->getAttributeValue("populatedSize", d.iPopulatedSize)))
179 // optional
180 d.iPopulatedSize = -1;
181
182 const char *pcszFileRef;
183 if (pelmDisk->getAttributeValue("fileRef", pcszFileRef)) // optional
184 {
185 // look up corresponding /References/File nodes (list built above)
186 const xml::ElementNode *pFileElem;
187 if ( pReferencesElem
188 && ((pFileElem = pReferencesElem->findChildElementFromId(pcszFileRef)))
189 )
190 {
191 // copy remaining values from file node then
192 const char *pcszBadInFile = NULL;
193 const char *pcszHref;
194 if (!(pFileElem->getAttributeValue("href", pcszHref)))
195 pcszBadInFile = "href";
196 else if (!(pFileElem->getAttributeValue("size", d.iSize)))
197 d.iSize = -1; // optional
198
199 d.strHref = pcszHref;
200
201 // if (!(pFileElem->getAttributeValue("size", d.iChunkSize))) TODO
202 d.iChunkSize = -1; // optional
203 const char *pcszCompression;
204 if (pFileElem->getAttributeValue("compression", pcszCompression))
205 d.strCompression = pcszCompression;
206
207 if (pcszBadInFile)
208 throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'File' element, line %d"),
209 m_strPath.c_str(),
210 pcszBadInFile,
211 pFileElem->getLineNumber());
212 }
213 else
214 throw OVFLogicError(N_("Error reading \"%s\": cannot find References/File element for ID '%s' referenced by 'Disk' element, line %d"),
215 m_strPath.c_str(),
216 pcszFileRef,
217 pelmDisk->getLineNumber());
218 }
219 }
220
221 if (pcszBad)
222 throw OVFLogicError(N_("Error reading \"%s\": missing or invalid attribute '%s' in 'DiskSection' element, line %d"),
223 m_strPath.c_str(),
224 pcszBad,
225 pelmDisk->getLineNumber());
226
227 m_mapDisks[d.strDiskId] = d;
228 }
229}
230
231/**
232 * Private helper method that handles network sections in the OVF XML.
233 * Gets called indirectly from IAppliance::read().
234 *
235 * @param pcszPath Path spec of the XML file, for error messages.
236 * @param pSectionElem Section element for which this helper is getting called.
237 * @return
238 */
239void OVFReader::HandleNetworkSection(const xml::ElementNode * /* pSectionElem */)
240{
241 // we ignore network sections for now
242
243// xml::NodesLoop loopNetworks(*pSectionElem, "Network");
244// const xml::Node *pelmNetwork;
245// while ((pelmNetwork = loopNetworks.forAllNodes()))
246// {
247// Network n;
248// if (!(pelmNetwork->getAttributeValue("name", n.strNetworkName)))
249// return setError(VBOX_E_FILE_ERROR,
250// tr("Error reading \"%s\": missing 'name' attribute in 'Network', line %d"),
251// pcszPath,
252// pelmNetwork->getLineNumber());
253//
254// m->mapNetworks[n.strNetworkName] = n;
255// }
256}
257
258/**
259 * Private helper method that handles a "VirtualSystem" element in the OVF XML.
260 * Gets called indirectly from IAppliance::read().
261 *
262 * @param pcszPath
263 * @param pContentElem
264 * @return
265 */
266void OVFReader::HandleVirtualSystemContent(const xml::ElementNode *pelmVirtualSystem)
267{
268 VirtualSystem vsys;
269
270 const xml::AttributeNode *pIdAttr = pelmVirtualSystem->findAttribute("id");
271 if (pIdAttr)
272 vsys.strName = pIdAttr->getValue();
273
274 xml::NodesLoop loop(*pelmVirtualSystem); // all child elements
275 const xml::ElementNode *pelmThis;
276 while ((pelmThis = loop.forAllNodes()))
277 {
278 const char *pcszElemName = pelmThis->getName();
279 const xml::AttributeNode *pTypeAttr = pelmThis->findAttribute("type");
280 const char *pcszTypeAttr = (pTypeAttr) ? pTypeAttr->getValue() : "";
281
282 if ( (!strcmp(pcszElemName, "EulaSection"))
283 || (!strcmp(pcszTypeAttr, "ovf:EulaSection_Type"))
284 )
285 {
286 /* <EulaSection>
287 <Info ovf:msgid="6">License agreement for the Virtual System.</Info>
288 <License ovf:msgid="1">License terms can go in here.</License>
289 </EulaSection> */
290
291 const xml::ElementNode *pelmLicense;
292 if ((pelmLicense = pelmThis->findChildElement("License")))
293 vsys.strLicenseText = pelmLicense->getValue();
294 }
295 if ( (!strcmp(pcszElemName, "ProductSection"))
296 || (!strcmp(pcszTypeAttr, "ovf:ProductSection_Type"))
297 )
298 {
299 /* <Section ovf:required="false" xsi:type="ovf:ProductSection_Type">
300 <Info>Meta-information about the installed software</Info>
301 <Product>VAtest</Product>
302 <Vendor>SUN Microsystems</Vendor>
303 <Version>10.0</Version>
304 <ProductUrl>http://blogs.sun.com/VirtualGuru</ProductUrl>
305 <VendorUrl>http://www.sun.com</VendorUrl>
306 </Section> */
307 const xml::ElementNode *pelmProduct;
308 if ((pelmProduct = pelmThis->findChildElement("Product")))
309 vsys.strProduct = pelmProduct->getValue();
310 const xml::ElementNode *pelmVendor;
311 if ((pelmVendor = pelmThis->findChildElement("Vendor")))
312 vsys.strVendor = pelmVendor->getValue();
313 const xml::ElementNode *pelmVersion;
314 if ((pelmVersion = pelmThis->findChildElement("Version")))
315 vsys.strVersion = pelmVersion->getValue();
316 const xml::ElementNode *pelmProductUrl;
317 if ((pelmProductUrl = pelmThis->findChildElement("ProductUrl")))
318 vsys.strProductUrl = pelmProductUrl->getValue();
319 const xml::ElementNode *pelmVendorUrl;
320 if ((pelmVendorUrl = pelmThis->findChildElement("VendorUrl")))
321 vsys.strVendorUrl = pelmVendorUrl->getValue();
322 }
323 else if ( (!strcmp(pcszElemName, "VirtualHardwareSection"))
324 || (!strcmp(pcszTypeAttr, "ovf:VirtualHardwareSection_Type"))
325 )
326 {
327 const xml::ElementNode *pelmSystem, *pelmVirtualSystemType;
328 if ((pelmSystem = pelmThis->findChildElement("System")))
329 {
330 /* <System>
331 <vssd:Description>Description of the virtual hardware section.</vssd:Description>
332 <vssd:ElementName>vmware</vssd:ElementName>
333 <vssd:InstanceID>1</vssd:InstanceID>
334 <vssd:VirtualSystemIdentifier>MyLampService</vssd:VirtualSystemIdentifier>
335 <vssd:VirtualSystemType>vmx-4</vssd:VirtualSystemType>
336 </System>*/
337 if ((pelmVirtualSystemType = pelmSystem->findChildElement("VirtualSystemType")))
338 vsys.strVirtualSystemType = pelmVirtualSystemType->getValue();
339 }
340
341 xml::NodesLoop loopVirtualHardwareItems(*pelmThis, "Item"); // all "Item" child elements
342 const xml::ElementNode *pelmItem;
343 while ((pelmItem = loopVirtualHardwareItems.forAllNodes()))
344 {
345 VirtualHardwareItem i;
346
347 i.ulLineNumber = pelmItem->getLineNumber();
348
349 xml::NodesLoop loopItemChildren(*pelmItem); // all child elements
350 const xml::ElementNode *pelmItemChild;
351 while ((pelmItemChild = loopItemChildren.forAllNodes()))
352 {
353 const char *pcszItemChildName = pelmItemChild->getName();
354 if (!strcmp(pcszItemChildName, "Description"))
355 i.strDescription = pelmItemChild->getValue();
356 else if (!strcmp(pcszItemChildName, "Caption"))
357 i.strCaption = pelmItemChild->getValue();
358 else if (!strcmp(pcszItemChildName, "ElementName"))
359 i.strElementName = pelmItemChild->getValue();
360 else if ( (!strcmp(pcszItemChildName, "InstanceID"))
361 || (!strcmp(pcszItemChildName, "InstanceId"))
362 )
363 pelmItemChild->copyValue(i.ulInstanceID);
364 else if (!strcmp(pcszItemChildName, "HostResource"))
365 i.strHostResource = pelmItemChild->getValue();
366 else if (!strcmp(pcszItemChildName, "ResourceType"))
367 {
368 uint32_t ulType;
369 pelmItemChild->copyValue(ulType);
370 i.resourceType = (OVFResourceType_T)ulType;
371 }
372 else if (!strcmp(pcszItemChildName, "OtherResourceType"))
373 i.strOtherResourceType = pelmItemChild->getValue();
374 else if (!strcmp(pcszItemChildName, "ResourceSubType"))
375 i.strResourceSubType = pelmItemChild->getValue();
376 else if (!strcmp(pcszItemChildName, "AutomaticAllocation"))
377 i.fAutomaticAllocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
378 else if (!strcmp(pcszItemChildName, "AutomaticDeallocation"))
379 i.fAutomaticDeallocation = (!strcmp(pelmItemChild->getValue(), "true")) ? true : false;
380 else if (!strcmp(pcszItemChildName, "Parent"))
381 pelmItemChild->copyValue(i.ulParent);
382 else if (!strcmp(pcszItemChildName, "Connection"))
383 i.strConnection = pelmItemChild->getValue();
384 else if (!strcmp(pcszItemChildName, "Address"))
385 i.strAddress = pelmItemChild->getValue();
386 else if (!strcmp(pcszItemChildName, "AddressOnParent"))
387 i.strAddressOnParent = pelmItemChild->getValue();
388 else if (!strcmp(pcszItemChildName, "AllocationUnits"))
389 i.strAllocationUnits = pelmItemChild->getValue();
390 else if (!strcmp(pcszItemChildName, "VirtualQuantity"))
391 pelmItemChild->copyValue(i.ullVirtualQuantity);
392 else if (!strcmp(pcszItemChildName, "Reservation"))
393 pelmItemChild->copyValue(i.ullReservation);
394 else if (!strcmp(pcszItemChildName, "Limit"))
395 pelmItemChild->copyValue(i.ullLimit);
396 else if (!strcmp(pcszItemChildName, "Weight"))
397 pelmItemChild->copyValue(i.ullWeight);
398 else if (!strcmp(pcszItemChildName, "ConsumerVisibility"))
399 i.strConsumerVisibility = pelmItemChild->getValue();
400 else if (!strcmp(pcszItemChildName, "MappingBehavior"))
401 i.strMappingBehavior = pelmItemChild->getValue();
402 else if (!strcmp(pcszItemChildName, "PoolID"))
403 i.strPoolID = pelmItemChild->getValue();
404 else if (!strcmp(pcszItemChildName, "BusNumber"))
405 pelmItemChild->copyValue(i.ulBusNumber);
406 else
407 throw OVFLogicError(N_("Error reading \"%s\": unknown element \"%s\" under Item element, line %d"),
408 m_strPath.c_str(),
409 pcszItemChildName,
410 i.ulLineNumber);
411 }
412
413 // store!
414 vsys.mapHardwareItems[i.ulInstanceID] = i;
415 }
416
417 // now go thru all hardware items and handle them according to their type;
418 // in this first loop we handle all items _except_ hard disk images,
419 // which we'll handle in a second loop below
420 HardwareItemsMap::const_iterator itH;
421 for (itH = vsys.mapHardwareItems.begin();
422 itH != vsys.mapHardwareItems.end();
423 ++itH)
424 {
425 const VirtualHardwareItem &i = itH->second;
426
427 // do some analysis
428 switch (i.resourceType)
429 {
430 case OVFResourceType_Processor: // 3
431 /* <rasd:Caption>1 virtual CPU</rasd:Caption>
432 <rasd:Description>Number of virtual CPUs</rasd:Description>
433 <rasd:ElementName>virtual CPU</rasd:ElementName>
434 <rasd:InstanceID>1</rasd:InstanceID>
435 <rasd:ResourceType>3</rasd:ResourceType>
436 <rasd:VirtualQuantity>1</rasd:VirtualQuantity>*/
437 if (i.ullVirtualQuantity < UINT16_MAX)
438 vsys.cCPUs = (uint16_t)i.ullVirtualQuantity;
439 else
440 throw OVFLogicError(N_("Error reading \"%s\": CPU count %RI64 is larger than %d, line %d"),
441 m_strPath.c_str(),
442 i.ullVirtualQuantity,
443 UINT16_MAX,
444 i.ulLineNumber);
445 break;
446
447 case OVFResourceType_Memory: // 4
448 if ( (i.strAllocationUnits == "MegaBytes") // found in OVF created by OVF toolkit
449 || (i.strAllocationUnits == "MB") // found in MS docs
450 || (i.strAllocationUnits == "byte * 2^20") // suggested by OVF spec DSP0243 page 21
451 )
452 vsys.ullMemorySize = i.ullVirtualQuantity * 1024 * 1024;
453 else
454 throw OVFLogicError(N_("Error reading \"%s\": Invalid allocation unit \"%s\" specified with memory size item, line %d"),
455 m_strPath.c_str(),
456 i.strAllocationUnits.c_str(),
457 i.ulLineNumber);
458 break;
459
460 case OVFResourceType_IDEController: // 5
461 {
462 /* <Item>
463 <rasd:Caption>ideController0</rasd:Caption>
464 <rasd:Description>IDE Controller</rasd:Description>
465 <rasd:InstanceId>5</rasd:InstanceId>
466 <rasd:ResourceType>5</rasd:ResourceType>
467 <rasd:Address>0</rasd:Address>
468 <rasd:BusNumber>0</rasd:BusNumber>
469 </Item> */
470 HardDiskController hdc;
471 hdc.system = HardDiskController::IDE;
472 hdc.idController = i.ulInstanceID;
473 hdc.strControllerType = i.strResourceSubType;
474 hdc.strAddress = i.strAddress;
475 hdc.ulBusNumber = i.ulBusNumber;
476
477 vsys.mapControllers[i.ulInstanceID] = hdc;
478 }
479 break;
480
481 case OVFResourceType_ParallelSCSIHBA: // 6 SCSI controller
482 {
483 /* <Item>
484 <rasd:Caption>SCSI Controller 0 - LSI Logic</rasd:Caption>
485 <rasd:Description>SCI Controller</rasd:Description>
486 <rasd:ElementName>SCSI controller</rasd:ElementName>
487 <rasd:InstanceID>4</rasd:InstanceID>
488 <rasd:ResourceSubType>LsiLogic</rasd:ResourceSubType>
489 <rasd:ResourceType>6</rasd:ResourceType>
490 </Item> */
491 HardDiskController hdc;
492 hdc.system = HardDiskController::SCSI;
493 hdc.idController = i.ulInstanceID;
494 hdc.strControllerType = i.strResourceSubType;
495
496 vsys.mapControllers[i.ulInstanceID] = hdc;
497 }
498 break;
499
500 case OVFResourceType_EthernetAdapter: // 10
501 {
502 /* <Item>
503 <rasd:Caption>Ethernet adapter on 'Bridged'</rasd:Caption>
504 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
505 <rasd:Connection>Bridged</rasd:Connection>
506 <rasd:InstanceID>6</rasd:InstanceID>
507 <rasd:ResourceType>10</rasd:ResourceType>
508 <rasd:ResourceSubType>E1000</rasd:ResourceSubType>
509 </Item>
510
511 OVF spec DSP 0243 page 21:
512 "For an Ethernet adapter, this specifies the abstract network connection name
513 for the virtual machine. All Ethernet adapters that specify the same abstract
514 network connection name within an OVF package shall be deployed on the same
515 network. The abstract network connection name shall be listed in the NetworkSection
516 at the outermost envelope level." */
517
518 // only store the name
519 EthernetAdapter ea;
520 ea.strAdapterType = i.strResourceSubType;
521 ea.strNetworkName = i.strConnection;
522 vsys.llEthernetAdapters.push_back(ea);
523 }
524 break;
525
526 case OVFResourceType_FloppyDrive: // 14
527 vsys.fHasFloppyDrive = true; // we have no additional information
528 break;
529
530 case OVFResourceType_CDDrive: // 15
531 /* <Item ovf:required="false">
532 <rasd:Caption>cdrom1</rasd:Caption>
533 <rasd:InstanceId>7</rasd:InstanceId>
534 <rasd:ResourceType>15</rasd:ResourceType>
535 <rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
536 <rasd:Parent>5</rasd:Parent>
537 <rasd:AddressOnParent>0</rasd:AddressOnParent>
538 </Item> */
539 // I tried to see what happens if I set an ISO for the CD-ROM in VMware Workstation,
540 // but then the ovftool dies with "Device backing not supported". So I guess if
541 // VMware can't export ISOs, then we don't need to be able to import them right now.
542 vsys.fHasCdromDrive = true; // we have no additional information
543 break;
544
545 case OVFResourceType_HardDisk: // 17
546 // handled separately in second loop below
547 break;
548
549 case OVFResourceType_OtherStorageDevice: // 20 SATA controller
550 {
551 /* <Item>
552 <rasd:Description>SATA Controller</rasd:Description>
553 <rasd:Caption>sataController0</rasd:Caption>
554 <rasd:InstanceID>4</rasd:InstanceID>
555 <rasd:ResourceType>20</rasd:ResourceType>
556 <rasd:ResourceSubType>AHCI</rasd:ResourceSubType>
557 <rasd:Address>0</rasd:Address>
558 <rasd:BusNumber>0</rasd:BusNumber>
559 </Item> */
560 if ( i.strCaption.startsWith("sataController", MiniString::CaseInsensitive)
561 && !i.strResourceSubType.compare("AHCI", MiniString::CaseInsensitive)
562 )
563 {
564 HardDiskController hdc;
565 hdc.system = HardDiskController::SATA;
566 hdc.idController = i.ulInstanceID;
567 hdc.strControllerType = i.strResourceSubType;
568
569 vsys.mapControllers[i.ulInstanceID] = hdc;
570 }
571 else
572 throw OVFLogicError(N_("Error reading \"%s\": Host resource of type \"Other Storage Device (%d)\" is supported with SATA AHCI controllers only, line %d"),
573 m_strPath.c_str(),
574 OVFResourceType_OtherStorageDevice,
575 i.ulLineNumber);
576 }
577 break;
578
579 case OVFResourceType_USBController: // 23
580 /* <Item ovf:required="false">
581 <rasd:Caption>usb</rasd:Caption>
582 <rasd:Description>USB Controller</rasd:Description>
583 <rasd:InstanceId>3</rasd:InstanceId>
584 <rasd:ResourceType>23</rasd:ResourceType>
585 <rasd:Address>0</rasd:Address>
586 <rasd:BusNumber>0</rasd:BusNumber>
587 </Item> */
588 vsys.fHasUsbController = true; // we have no additional information
589 break;
590
591 case OVFResourceType_SoundCard: // 35
592 /* <Item ovf:required="false">
593 <rasd:Caption>sound</rasd:Caption>
594 <rasd:Description>Sound Card</rasd:Description>
595 <rasd:InstanceId>10</rasd:InstanceId>
596 <rasd:ResourceType>35</rasd:ResourceType>
597 <rasd:ResourceSubType>ensoniq1371</rasd:ResourceSubType>
598 <rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
599 <rasd:AddressOnParent>3</rasd:AddressOnParent>
600 </Item> */
601 vsys.strSoundCardType = i.strResourceSubType;
602 break;
603
604 default:
605 throw OVFLogicError(N_("Error reading \"%s\": Unknown resource type %d in hardware item, line %d"),
606 m_strPath.c_str(),
607 i.resourceType,
608 i.ulLineNumber);
609 } // end switch
610 }
611
612 // now run through the items for a second time, but handle only
613 // hard disk images; otherwise the code would fail if a hard
614 // disk image appears in the OVF before its hard disk controller
615 for (itH = vsys.mapHardwareItems.begin();
616 itH != vsys.mapHardwareItems.end();
617 ++itH)
618 {
619 const VirtualHardwareItem &i = itH->second;
620
621 // do some analysis
622 switch (i.resourceType)
623 {
624 case OVFResourceType_HardDisk: // 17
625 {
626 /* <Item>
627 <rasd:Caption>Harddisk 1</rasd:Caption>
628 <rasd:Description>HD</rasd:Description>
629 <rasd:ElementName>Hard Disk</rasd:ElementName>
630 <rasd:HostResource>ovf://disk/lamp</rasd:HostResource>
631 <rasd:InstanceID>5</rasd:InstanceID>
632 <rasd:Parent>4</rasd:Parent>
633 <rasd:ResourceType>17</rasd:ResourceType>
634 </Item> */
635
636 // look up the hard disk controller element whose InstanceID equals our Parent;
637 // this is how the connection is specified in OVF
638 ControllersMap::const_iterator it = vsys.mapControllers.find(i.ulParent);
639 if (it == vsys.mapControllers.end())
640 throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid parent %d, line %d"),
641 m_strPath.c_str(),
642 i.ulInstanceID,
643 i.ulParent,
644 i.ulLineNumber);
645 //const HardDiskController &hdc = it->second;
646
647 VirtualDisk vd;
648 vd.idController = i.ulParent;
649 i.strAddressOnParent.toInt(vd.ulAddressOnParent);
650 // ovf://disk/lamp
651 // 123456789012345
652 if (i.strHostResource.substr(0, 11) == "ovf://disk/")
653 vd.strDiskId = i.strHostResource.substr(11);
654 else if (i.strHostResource.substr(0, 10) == "ovf:/disk/")
655 vd.strDiskId = i.strHostResource.substr(10);
656 else if (i.strHostResource.substr(0, 6) == "/disk/")
657 vd.strDiskId = i.strHostResource.substr(6);
658
659 if ( !(vd.strDiskId.length())
660 || (m_mapDisks.find(vd.strDiskId) == m_mapDisks.end())
661 )
662 throw OVFLogicError(N_("Error reading \"%s\": Hard disk item with instance ID %d specifies invalid host resource \"%s\", line %d"),
663 m_strPath.c_str(),
664 i.ulInstanceID,
665 i.strHostResource.c_str(),
666 i.ulLineNumber);
667
668 vsys.mapVirtualDisks[vd.strDiskId] = vd;
669 }
670 break;
671 default: break;
672 }
673 }
674 }
675 else if ( (!strcmp(pcszElemName, "OperatingSystemSection"))
676 || (!strcmp(pcszTypeAttr, "ovf:OperatingSystemSection_Type"))
677 )
678 {
679 uint64_t cimos64;
680 if (!(pelmThis->getAttributeValue("id", cimos64)))
681 throw OVFLogicError(N_("Error reading \"%s\": missing or invalid 'ovf:id' attribute in operating system section element, line %d"),
682 m_strPath.c_str(),
683 pelmThis->getLineNumber());
684
685 vsys.cimos = (CIMOSType_T)cimos64;
686 const xml::ElementNode *pelmCIMOSDescription;
687 if ((pelmCIMOSDescription = pelmThis->findChildElement("Description")))
688 vsys.strCimosDesc = pelmCIMOSDescription->getValue();
689 }
690 else if ( (!strcmp(pcszElemName, "AnnotationSection"))
691 || (!strcmp(pcszTypeAttr, "ovf:AnnotationSection_Type"))
692 )
693 {
694 const xml::ElementNode *pelmAnnotation;
695 if ((pelmAnnotation = pelmThis->findChildElement("Annotation")))
696 vsys.strDescription = pelmAnnotation->getValue();
697 }
698 }
699
700 // now create the virtual system
701 m_llVirtualSystems.push_back(vsys);
702}
703
704////////////////////////////////////////////////////////////////////////////////
705//
706// Errors
707//
708////////////////////////////////////////////////////////////////////////////////
709
710OVFLogicError::OVFLogicError(const char *aFormat, ...)
711{
712 char *pszNewMsg;
713 va_list args;
714 va_start(args, aFormat);
715 RTStrAPrintfV(&pszNewMsg, aFormat, args);
716 setWhat(pszNewMsg);
717 RTStrFree(pszNewMsg);
718 va_end(args);
719}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette