VirtualBox

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

Last change on this file since 101381 was 99775, checked in by vboxsync, 13 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 KB
Line 
1/* $Id: tstOVF.cpp 99775 2023-05-12 12:21:58Z 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 */
91static void 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 */
291static void 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.

© 2023 Oracle
ContactPrivacy policyTerms of Use