VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id: tstOVF.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 *
4 * tstOVF - testcases for OVF import and export
5 */
6
7/*
8 * Copyright (C) 2010-2022 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 default:
236 throw MyError(E_UNEXPECTED, "Invalid VirtualSystemDescriptionType\n");
237 break;
238 }
239
240 RTPrintf(" vsys %2u item %2u: type %2d (%s), ovf: \"%ls\", vbox: \"%ls\", extra: \"%ls\"\n",
241 u, u2, t, pcszType,
242 aOvfValues[u2],
243 aVBoxValues[u2],
244 aExtraConfigValues[u2]);
245 }
246 }
247
248 RTPrintf("%s: importing %d machine(s)...\n", pcszPrefix, aDescriptions.size());
249 SafeArray<ImportOptions_T> sfaOptions;
250 rc = pAppl->ImportMachines(ComSafeArrayAsInParam(sfaOptions), pProgress.asOutParam());
251 if (FAILED(rc)) throw MyError(rc, "Appliance::ImportMachines() failed\n");
252 rc = pProgress->WaitForCompletion(-1);
253 if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n");
254 pProgress->COMGETTER(ResultCode)(&rc2);
255 if (FAILED(rc2)) throw MyError(rc2, "Appliance::ImportMachines() failed\n", pProgress);
256
257 com::SafeArray<BSTR> aMachineUUIDs;
258 rc = pAppl->COMGETTER(Machines)(ComSafeArrayAsOutParam(aMachineUUIDs));
259 if (FAILED(rc)) throw MyError(rc, "Appliance::GetMachines() failed\n");
260
261 for (size_t u = 0;
262 u < aMachineUUIDs.size();
263 ++u)
264 {
265 RTPrintf("%s: created machine %u: %ls\n", pcszPrefix, u, aMachineUUIDs[u]);
266 llMachinesCreated.push_back(Guid(Bstr(aMachineUUIDs[u])));
267 }
268
269 RTPrintf("%s: success!\n", pcszPrefix);
270}
271
272/**
273 * Copies ovf-testcases/ovf-dummy.vmdk to the given target and appends that
274 * target as a string to the given list so that the caller can delete it
275 * again later.
276 * @param llFiles2Delete List of strings to append the target file path to.
277 * @param pcszDest Target for dummy VMDK.
278 */
279void copyDummyDiskImage(const char *pcszPrefix,
280 std::list<Utf8Str> &llFiles2Delete,
281 const char *pcszDest)
282{
283 char szSrc[RTPATH_MAX];
284 char szDst[RTPATH_MAX];
285 RTPathExecDir(szSrc, sizeof(szSrc));
286 RTPathAppend(szSrc, sizeof(szSrc), "ovf-testcases/ovf-dummy.vmdk");
287 RTPathExecDir(szDst, sizeof(szDst));
288 RTPathAppend(szDst, sizeof(szDst), pcszDest);
289 RTPrintf("%s: copying ovf-dummy.vmdk to \"%s\"...\n", pcszPrefix, pcszDest);
290
291 int vrc = RTFileCopy(szSrc, szDst);
292 if (RT_FAILURE(vrc)) throw MyError(0, Utf8StrFmt("Cannot copy ovf-dummy.vmdk to %s: %Rra\n", pcszDest, vrc).c_str());
293 llFiles2Delete.push_back(szDst);
294}
295
296/**
297 *
298 * @param argc
299 * @param argv[]
300 * @return
301 */
302int main(int argc, char *argv[])
303{
304 RTR3InitExe(argc, &argv, 0);
305
306 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
307 HRESULT rc = S_OK;
308
309 std::list<Utf8Str> llFiles2Delete;
310 std::list<Guid> llMachinesCreated;
311
312 ComPtr<IVirtualBoxClient> pVirtualBoxClient;
313 ComPtr<IVirtualBox> pVirtualBox;
314
315 try
316 {
317 RTPrintf("Initializing COM...\n");
318 rc = com::Initialize();
319 if (FAILED(rc)) throw MyError(rc, "failed to initialize COM!\n");
320
321 ComPtr<ISession> pSession;
322
323 RTPrintf("Creating VirtualBox object...\n");
324 rc = pVirtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
325 if (SUCCEEDED(rc))
326 rc = pVirtualBoxClient->COMGETTER(VirtualBox)(pVirtualBox.asOutParam());
327 if (FAILED(rc)) throw MyError(rc, "failed to create the VirtualBox object!\n");
328
329 rc = pSession.createInprocObject(CLSID_Session);
330 if (FAILED(rc)) throw MyError(rc, "failed to create a session object!\n");
331
332 // for each testcase, we will copy the dummy VMDK image to the subdirectory with the OVF testcase
333 // so that the import will find the disks it expects; this is just for testing the import since
334 // the imported machines will obviously not be usable.
335 // llFiles2Delete receives the paths of all the files that we need to clean up later.
336
337 // testcase 1: import ovf-joomla-0.9/joomla-1.1.4-ovf.ovf
338 copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-0.vmdk");
339 copyDummyDiskImage("joomla-0.9", llFiles2Delete, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf-1.vmdk");
340 importOVF("joomla-0.9", pVirtualBox, "ovf-testcases/ovf-joomla-0.9/joomla-1.1.4-ovf.ovf", llMachinesCreated);
341
342 // testcase 2: import ovf-winxp-vbox-sharedfolders/winxp.ovf
343 copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/Windows 5.1 XP 1 merged.vmdk");
344 copyDummyDiskImage("winxp-vbox-sharedfolders", llFiles2Delete, "ovf-testcases/ovf-winxp-vbox-sharedfolders/smallvdi.vmdk");
345 importOVF("winxp-vbox-sharedfolders", pVirtualBox, "ovf-testcases/ovf-winxp-vbox-sharedfolders/winxp.ovf", llMachinesCreated);
346
347 // testcase 3: import ovf-winxp-vbox-sharedfolders/winxp.ovf
348 importOVF("winhost-audio-nodisks", pVirtualBox, "ovf-testcases/ovf-winhost-audio-nodisks/WinXP.ovf", llMachinesCreated);
349
350 RTPrintf("Machine imports done, no errors. Cleaning up...\n");
351 }
352 catch (MyError &e)
353 {
354 rc = e.m_rc;
355 RTPrintf("%s", e.m_str.c_str());
356 rcExit = RTEXITCODE_FAILURE;
357 }
358
359 try
360 {
361 // clean up the machines created
362 for (std::list<Guid>::const_iterator it = llMachinesCreated.begin();
363 it != llMachinesCreated.end();
364 ++it)
365 {
366 const Guid &uuid = *it;
367 Bstr bstrUUID(uuid.toUtf16());
368 ComPtr<IMachine> pMachine;
369 rc = pVirtualBox->FindMachine(bstrUUID.raw(), pMachine.asOutParam());
370 if (FAILED(rc)) throw MyError(rc, "VirtualBox::FindMachine() failed\n");
371
372 RTPrintf(" Deleting machine %ls...\n", bstrUUID.raw());
373 SafeIfaceArray<IMedium> sfaMedia;
374 rc = pMachine->Unregister(CleanupMode_DetachAllReturnHardDisksOnly,
375 ComSafeArrayAsOutParam(sfaMedia));
376 if (FAILED(rc)) throw MyError(rc, "Machine::Unregister() failed\n");
377
378 ComPtr<IProgress> pProgress;
379 rc = pMachine->DeleteConfig(ComSafeArrayAsInParam(sfaMedia), pProgress.asOutParam());
380 if (FAILED(rc)) throw MyError(rc, "Machine::DeleteSettings() failed\n");
381 rc = pProgress->WaitForCompletion(-1);
382 if (FAILED(rc)) throw MyError(rc, "Progress::WaitForCompletion() failed\n");
383 }
384 }
385 catch (MyError &e)
386 {
387 rc = e.m_rc;
388 RTPrintf("%s", e.m_str.c_str());
389 rcExit = RTEXITCODE_FAILURE;
390 }
391
392 // clean up the VMDK copies that we made in copyDummyDiskImage()
393 for (std::list<Utf8Str>::const_iterator it = llFiles2Delete.begin();
394 it != llFiles2Delete.end();
395 ++it)
396 {
397 const Utf8Str &strFile = *it;
398 RTPrintf("Deleting file %s...\n", strFile.c_str());
399 RTFileDelete(strFile.c_str());
400 }
401
402 pVirtualBox.setNull();
403 pVirtualBoxClient.setNull();
404
405 RTPrintf("Shutting down COM...\n");
406 com::Shutdown();
407 RTPrintf("tstOVF all done: %s\n", rcExit ? "ERROR" : "SUCCESS");
408
409 return rcExit;
410}
411
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use