VirtualBox

source: vbox/trunk/src/VBox/Main/testcase/tstOVF.cpp@ 99569

Last change on this file since 99569 was 99569, checked in by vboxsync, 19 months ago

Main/testcase/tstOVF.cpp: Improve error message to identify the
unexpected VirtualSystemDescriptionType enum value in aTypes[] when
failing to import an OVF-based appliance.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.9 KB
Line 
1/* $Id: tstOVF.cpp 99569 2023-05-02 19:17:43Z vboxsync $ */
2/** @file
3 *
4 * tstOVF - testcases for OVF import and export
5 */
6
7/*
8 * Copyright (C) 2010-2023 Oracle and/or its affiliates.
9 *
10 * This file is part of VirtualBox base platform packages, as
11 * available from https://www.virtualbox.org.
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation, in version 3 of the
16 * License.
17 *
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see <https://www.gnu.org/licenses>.
25 *
26 * SPDX-License-Identifier: GPL-3.0-only
27 */
28
29#include <VBox/com/VirtualBox.h>
30
31#include <VBox/com/com.h>
32#include <VBox/com/array.h>
33#include <VBox/com/string.h>
34#include <VBox/com/ErrorInfo.h>
35#include <VBox/com/errorprint.h>
36
37#include <iprt/initterm.h>
38#include <iprt/stream.h>
39#include <iprt/file.h>
40#include <iprt/path.h>
41#include <iprt/param.h>
42
43#include <list>
44
45using namespace com;
46
47// main
48///////////////////////////////////////////////////////////////////////////////
49
50/**
51 * Quick hack exception structure.
52 *
53 */
54struct MyError
55{
56 MyError(HRESULT rc,
57 const char *pcsz,
58 IProgress *pProgress = NULL)
59 : m_rc(rc)
60 {
61 m_str = "ERROR: ";
62 m_str += pcsz;
63
64 if (pProgress)
65 {
66 com::ProgressErrorInfo info(pProgress);
67 com::GluePrintErrorInfo(info);
68 }
69 else if (rc != S_OK)
70 {
71 com::ErrorInfo info;
72 if (!info.isFullAvailable() && !info.isBasicAvailable())
73 com::GluePrintRCMessage(rc);
74 else
75 com::GluePrintErrorInfo(info);
76 }
77 }
78
79 Utf8Str m_str;
80 HRESULT m_rc;
81};
82
83/**
84 * Imports the given OVF file, with all bells and whistles.
85 * Throws MyError on errors.
86 * @param pcszPrefix Descriptive short prefix string for console output.
87 * @param pVirtualBox VirtualBox instance.
88 * @param pcszOVF0 File to import.
89 * @param llMachinesCreated out: UUIDs of machines that were created so that caller can clean up.
90 */
91void importOVF(const char *pcszPrefix,
92 ComPtr<IVirtualBox> &pVirtualBox,
93 const char *pcszOVF0,
94 std::list<Guid> &llMachinesCreated)
95{
96 char szAbsOVF[RTPATH_MAX];
97 RTPathExecDir(szAbsOVF, sizeof(szAbsOVF));
98 RTPathAppend(szAbsOVF, sizeof(szAbsOVF), pcszOVF0);
99
100 RTPrintf("%s: reading appliance \"%s\"...\n", pcszPrefix, szAbsOVF);
101 ComPtr<IAppliance> pAppl;
102 HRESULT rc = pVirtualBox->CreateAppliance(pAppl.asOutParam());
103 if (FAILED(rc)) throw MyError(rc, "failed to create appliance\n");
104
105 ComPtr<IProgress> pProgress;
106 rc = pAppl->Read(Bstr(szAbsOVF).raw(), pProgress.asOutParam());
107 if (FAILED(rc)) throw MyError(rc, "Appliance::Read() failed\n");
108 rc = pProgress->WaitForCompletion(-1);
109 if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n");
110 LONG rc2;
111 pProgress->COMGETTER(ResultCode)(&rc2);
112 if (FAILED(rc2)) throw MyError(rc2, "Appliance::Read() failed\n", pProgress);
113
114 RTPrintf("%s: interpreting appliance \"%s\"...\n", pcszPrefix, szAbsOVF);
115 rc = pAppl->Interpret();
116 if (FAILED(rc)) throw MyError(rc, "Appliance::Interpret() failed\n");
117
118 com::SafeIfaceArray<IVirtualSystemDescription> aDescriptions;
119 rc = pAppl->COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(aDescriptions));
120 for (uint32_t u = 0;
121 u < aDescriptions.size();
122 ++u)
123 {
124 ComPtr<IVirtualSystemDescription> pVSys = aDescriptions[u];
125
126 com::SafeArray<VirtualSystemDescriptionType_T> aTypes;
127 com::SafeArray<BSTR> aRefs;
128 com::SafeArray<BSTR> aOvfValues;
129 com::SafeArray<BSTR> aVBoxValues;
130 com::SafeArray<BSTR> aExtraConfigValues;
131 rc = pVSys->GetDescription(ComSafeArrayAsOutParam(aTypes),
132 ComSafeArrayAsOutParam(aRefs),
133 ComSafeArrayAsOutParam(aOvfValues),
134 ComSafeArrayAsOutParam(aVBoxValues),
135 ComSafeArrayAsOutParam(aExtraConfigValues));
136 if (FAILED(rc)) throw MyError(rc, "VirtualSystemDescription::GetDescription() failed\n");
137
138 for (uint32_t u2 = 0;
139 u2 < aTypes.size();
140 ++u2)
141 {
142 const char *pcszType;
143
144 VirtualSystemDescriptionType_T t = aTypes[u2];
145 switch (t)
146 {
147 case VirtualSystemDescriptionType_OS:
148 pcszType = "ostype";
149 break;
150
151 case VirtualSystemDescriptionType_Name:
152 pcszType = "name";
153 break;
154
155 case VirtualSystemDescriptionType_Product:
156 pcszType = "product";
157 break;
158
159 case VirtualSystemDescriptionType_ProductUrl:
160 pcszType = "producturl";
161 break;
162
163 case VirtualSystemDescriptionType_Vendor:
164 pcszType = "vendor";
165 break;
166
167 case VirtualSystemDescriptionType_VendorUrl:
168 pcszType = "vendorurl";
169 break;
170
171 case VirtualSystemDescriptionType_Version:
172 pcszType = "version";
173 break;
174
175 case VirtualSystemDescriptionType_Description:
176 pcszType = "description";
177 break;
178
179 case VirtualSystemDescriptionType_License:
180 pcszType = "license";
181 break;
182
183 case VirtualSystemDescriptionType_CPU:
184 pcszType = "cpu";
185 break;
186
187 case VirtualSystemDescriptionType_Memory:
188 pcszType = "memory";
189 break;
190
191 case VirtualSystemDescriptionType_HardDiskControllerIDE:
192 pcszType = "ide";
193 break;
194
195 case VirtualSystemDescriptionType_HardDiskControllerSATA:
196 pcszType = "sata";
197 break;
198
199 case VirtualSystemDescriptionType_HardDiskControllerSAS:
200 pcszType = "sas";
201 break;
202
203 case VirtualSystemDescriptionType_HardDiskControllerSCSI:
204 pcszType = "scsi";
205 break;
206
207 case VirtualSystemDescriptionType_HardDiskControllerVirtioSCSI:
208 pcszType = "virtio-scsi";
209 break;
210
211 case VirtualSystemDescriptionType_HardDiskImage:
212 pcszType = "hd";
213 break;
214
215 case VirtualSystemDescriptionType_CDROM:
216 pcszType = "cdrom";
217 break;
218
219 case VirtualSystemDescriptionType_Floppy:
220 pcszType = "floppy";
221 break;
222
223 case VirtualSystemDescriptionType_NetworkAdapter:
224 pcszType = "net";
225 break;
226
227 case VirtualSystemDescriptionType_USBController:
228 pcszType = "usb";
229 break;
230
231 case VirtualSystemDescriptionType_SoundCard:
232 pcszType = "sound";
233 break;
234
235 case VirtualSystemDescriptionType_SettingsFile:
236 pcszType = "settings";
237 break;
238
239 case VirtualSystemDescriptionType_BaseFolder:
240 pcszType = "basefolder";
241 break;
242
243 case VirtualSystemDescriptionType_PrimaryGroup:
244 pcszType = "primarygroup";
245 break;
246
247 default:
248 throw MyError(E_UNEXPECTED, Utf8StrFmt("Invalid VirtualSystemDescriptionType (enum=%d)\n", t).c_str());
249 break;
250 }
251
252 RTPrintf(" vsys %2u item %2u: type %2d (%s), ovf: \"%ls\", vbox: \"%ls\", extra: \"%ls\"\n",
253 u, u2, t, pcszType,
254 aOvfValues[u2],
255 aVBoxValues[u2],
256 aExtraConfigValues[u2]);
257 }
258 }
259
260 RTPrintf("%s: importing %d machine(s)...\n", pcszPrefix, aDescriptions.size());
261 SafeArray<ImportOptions_T> sfaOptions;
262 rc = pAppl->ImportMachines(ComSafeArrayAsInParam(sfaOptions), pProgress.asOutParam());
263 if (FAILED(rc)) throw MyError(rc, "Appliance::ImportMachines() failed\n");
264 rc = pProgress->WaitForCompletion(-1);
265 if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n");
266 pProgress->COMGETTER(ResultCode)(&rc2);
267 if (FAILED(rc2)) throw MyError(rc2, "Appliance::ImportMachines() failed\n", pProgress);
268
269 com::SafeArray<BSTR> aMachineUUIDs;
270 rc = pAppl->COMGETTER(Machines)(ComSafeArrayAsOutParam(aMachineUUIDs));
271 if (FAILED(rc)) throw MyError(rc, "Appliance::GetMachines() failed\n");
272
273 for (size_t u = 0;
274 u < aMachineUUIDs.size();
275 ++u)
276 {
277 RTPrintf("%s: created machine %u: %ls\n", pcszPrefix, u, aMachineUUIDs[u]);
278 llMachinesCreated.push_back(Guid(Bstr(aMachineUUIDs[u])));
279 }
280
281 RTPrintf("%s: success!\n", pcszPrefix);
282}
283
284/**
285 * Copies ovf-testcases/ovf-dummy.vmdk to the given target and appends that
286 * target as a string to the given list so that the caller can delete it
287 * again later.
288 * @param llFiles2Delete List of strings to append the target file path to.
289 * @param pcszDest Target for dummy VMDK.
290 */
291void copyDummyDiskImage(const char *pcszPrefix,
292 std::list<Utf8Str> &llFiles2Delete,
293 const char *pcszDest)
294{
295 char szSrc[RTPATH_MAX];
296 RTPathExecDir(szSrc, sizeof(szSrc));
297 RTPathAppend(szSrc, sizeof(szSrc), "ovf-testcases/ovf-dummy.vmdk");
298
299 char szDst[RTPATH_MAX];
300 RTPathExecDir(szDst, sizeof(szDst));
301 RTPathAppend(szDst, sizeof(szDst), pcszDest);
302 RTPrintf("%s: copying ovf-dummy.vmdk to \"%s\"...\n", pcszPrefix, pcszDest);
303
304 /* Delete the destination file if it exists or RTFileCopy will fail. */
305 if (RTFileExists(szDst))
306 {
307 RTPrintf("Deleting file %s...\n", szDst);
308 RTFileDelete(szDst);
309 }
310
311 int vrc = RTFileCopy(szSrc, szDst);
312 if (RT_FAILURE(vrc)) throw MyError(0, Utf8StrFmt("Cannot copy ovf-dummy.vmdk to %s: %Rra\n", pcszDest, vrc).c_str());
313 llFiles2Delete.push_back(szDst);
314}
315
316/**
317 *
318 * @param argc
319 * @param argv[]
320 * @return
321 */
322int main(int argc, char *argv[])
323{
324 RTR3InitExe(argc, &argv, 0);
325
326 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
327 HRESULT rc = S_OK;
328
329 std::list<Utf8Str> llFiles2Delete;
330 std::list<Guid> llMachinesCreated;
331
332 ComPtr<IVirtualBoxClient> pVirtualBoxClient;
333 ComPtr<IVirtualBox> pVirtualBox;
334
335 try
336 {
337 RTPrintf("Initializing COM...\n");
338 rc = com::Initialize();
339 if (FAILED(rc)) throw MyError(rc, "failed to initialize COM!\n");
340
341 ComPtr<ISession> pSession;
342
343 RTPrintf("Creating VirtualBox object...\n");
344 rc = pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
345 if (SUCCEEDED(rc))
346 rc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam());
347 if (FAILED(rc)) throw MyError(rc, "failed to create the VirtualBox object!\n");
348
349 rc = pSession.createInprocObject(CLSID_Session);
350 if (FAILED(rc)) throw MyError(rc, "failed to create a session object!\n");
351
352 // for each testcase, we will copy the dummy VMDK image to the subdirectory with the OVF testcase
353 // so that the import will find the disks it expects; this is just for testing the import since
354 // the imported machines will obviously not be usable.
355 // llFiles2Delete receives the paths of all the files that we need to clean up later.
356
357 // testcase 1: import ovf-joomla-0.9/joomla-1.1.4-ovf.ovf
358 copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-0.vmdk");
359 copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-1.vmdk");
360 importOVF("joomla-0.9", pVirtualBox, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf", llMachinesCreated);
361
362 // testcase 2: import ovf-winxp-vbox-sharedfolders/winxp.ovf
363 copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/Windows 5.1 XP 1 merged.vmdk");
364 copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/smallvdi.vmdk");
365 importOVF("winxp-vbox-sharedfolders", pVirtualBox, "ovf-testcases/ovf-winxp-vbox-sharedfolders/winxp.ovf", llMachinesCreated);
366
367 // testcase 3: import ovf-winxp-vbox-sharedfolders/winxp.ovf
368 importOVF("winhost-audio-nodisks", pVirtualBox, "ovf-testcases/ovf-winhost-audio-nodisks/WinXP.ovf", llMachinesCreated);
369
370 RTPrintf("Machine imports done, no errors. Cleaning up...\n");
371 }
372 catch (MyError &e)
373 {
374 rc = e.m_rc;
375 RTPrintf("%s", e.m_str.c_str());
376 rcExit = RTEXITCODE_FAILURE;
377 }
378
379 try
380 {
381 // clean up the machines created
382 for (std::list<Guid>::const_iterator it = llMachinesCreated.begin();
383 it != llMachinesCreated.end();
384 ++it)
385 {
386 const Guid &uuid = *it;
387 Bstr bstrUUID(uuid.toUtf16());
388 ComPtr<IMachine> pMachine;
389 rc = pVirtualBox->FindMachine(bstrUUID.raw(), pMachine.asOutParam());
390 if (FAILED(rc)) throw MyError(rc, "VirtualBox::FindMachine() failed\n");
391
392 RTPrintf(" Deleting machine %ls...\n", bstrUUID.raw());
393 SafeIfaceArray<IMedium> sfaMedia;
394 rc = pMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly,
395 ComSafeArrayAsOutParam(sfaMedia));
396 if (FAILED(rc)) throw MyError(rc, "Machine::Unregister() failed\n");
397
398 ComPtr<IProgress> pProgress;
399 rc = pMachine->DeleteConfig(ComSafeArrayAsInParam(sfaMedia), pProgress.asOutParam());
400 if (FAILED(rc)) throw MyError(rc, "Machine::DeleteSettings() failed\n");
401 rc = pProgress->WaitForCompletion(-1);
402 if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n");
403 }
404 }
405 catch (MyError &e)
406 {
407 rc = e.m_rc;
408 RTPrintf("%s", e.m_str.c_str());
409 rcExit = RTEXITCODE_FAILURE;
410 }
411
412 // clean up the VMDK copies that we made in copyDummyDiskImage()
413 for (std::list<Utf8Str>::const_iterator it = llFiles2Delete.begin();
414 it != llFiles2Delete.end();
415 ++it)
416 {
417 const Utf8Str &strFile = *it;
418 RTPrintf("Deleting file %s...\n", strFile.c_str());
419 RTFileDelete(strFile.c_str());
420 }
421
422 pVirtualBox.setNull();
423 pVirtualBoxClient.setNull();
424
425 RTPrintf("Shutting down COM...\n");
426 com::Shutdown();
427 RTPrintf("tstOVF all done: %s\n", rcExit ? "ERROR" : "SUCCESS");
428
429 return rcExit;
430}
431
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