VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageCloud.cpp@ 85708

Last change on this file since 85708 was 85650, checked in by vboxsync, 4 years ago

IPRT/http,VBoxManage,CloudGateway: Corrections to the proxy information retrival interface. Main problem was that it did not include the possibility of indicating that no proxying was needed. Corrected user code to not use uProxyPort when it's set to UINT32_MAX. Bunch of cleanups. Completely untested. bugref:9469

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 100.7 KB
Line 
1/* $Id: VBoxManageCloud.cpp 85650 2020-08-08 14:06:23Z vboxsync $ */
2/** @file
3 * VBoxManageCloud - The cloud related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include <VBox/com/com.h>
19#include <VBox/com/string.h>
20#include <VBox/com/Guid.h>
21#include <VBox/com/array.h>
22#include <VBox/com/ErrorInfo.h>
23#include <VBox/com/errorprint.h>
24#include <VBox/com/VirtualBox.h>
25
26#include <iprt/ctype.h>
27#include <iprt/getopt.h>
28#include <iprt/stream.h>
29#include <iprt/string.h>
30#include <iprt/thread.h>
31#include <iprt/uuid.h>
32#include <iprt/file.h>
33#include <iprt/http.h>
34#include <VBox/log.h>
35
36#include <iprt/cpp/path.h>
37
38#include "VBoxManage.h"
39
40#include <list>
41
42using namespace com;//at least for Bstr
43
44/**
45 * Common Cloud options.
46 */
47typedef struct
48{
49 struct {
50 const char *pszProviderName;
51 ComPtr<ICloudProvider> pCloudProvider;
52 }provider;
53 struct {
54 const char *pszProfileName;
55 ComPtr<ICloudProfile> pCloudProfile;
56 }profile;
57
58} CLOUDCOMMONOPT;
59typedef CLOUDCOMMONOPT *PCLOUDCOMMONOPT;
60
61static HRESULT checkAndSetCommonOptions(HandlerArg *a, PCLOUDCOMMONOPT pCommonOpts)
62{
63 HRESULT hrc = S_OK;
64
65 Bstr bstrProvider(pCommonOpts->provider.pszProviderName);
66 Bstr bstrProfile(pCommonOpts->profile.pszProfileName);
67
68 /* check for required options */
69 if (bstrProvider.isEmpty())
70 {
71 errorSyntax(USAGE_S_NEWCMD, "Parameter --provider is required");
72 return E_FAIL;
73 }
74 if (bstrProfile.isEmpty())
75 {
76 errorSyntax(USAGE_S_NEWCMD, "Parameter --profile is required");
77 return E_FAIL;
78 }
79
80 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
81 ComPtr<ICloudProviderManager> pCloudProviderManager;
82 CHECK_ERROR2_RET(hrc, pVirtualBox,
83 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
84 RTEXITCODE_FAILURE);
85
86 ComPtr<ICloudProvider> pCloudProvider;
87 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
88 GetProviderByShortName(bstrProvider.raw(), pCloudProvider.asOutParam()),
89 RTEXITCODE_FAILURE);
90 pCommonOpts->provider.pCloudProvider = pCloudProvider;
91
92 ComPtr<ICloudProfile> pCloudProfile;
93 CHECK_ERROR2_RET(hrc, pCloudProvider,
94 GetProfileByName(bstrProfile.raw(), pCloudProfile.asOutParam()),
95 RTEXITCODE_FAILURE);
96 pCommonOpts->profile.pCloudProfile = pCloudProfile;
97
98 return hrc;
99}
100
101
102/**
103 * List all available cloud instances for the specified cloud provider.
104 * Available cloud instance is one which state whether "running" or "stopped".
105 *
106 * @returns RTEXITCODE
107 * @param a is the list of passed arguments
108 * @param iFirst is the position of the first unparsed argument in the arguments list
109 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
110 * arguments which have been already parsed before
111 */
112static RTEXITCODE listCloudInstances(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
113{
114 static const RTGETOPTDEF s_aOptions[] =
115 {
116 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
117 { "--state", 's', RTGETOPT_REQ_STRING },
118 { "help", 1001, RTGETOPT_REQ_NOTHING },
119 { "--help", 1002, RTGETOPT_REQ_NOTHING }
120 };
121 RTGETOPTSTATE GetState;
122 RTGETOPTUNION ValueUnion;
123 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
124 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
125 if (a->argc == iFirst)
126 {
127 RTPrintf("Empty command parameter list, show help.\n");
128 printHelp(g_pStdOut);
129 return RTEXITCODE_SUCCESS;
130 }
131
132 Utf8Str strCompartmentId;
133 com::SafeArray<CloudMachineState_T> machineStates;
134
135 int c;
136 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
137 {
138 switch (c)
139 {
140 case 'c':
141 strCompartmentId = ValueUnion.psz;
142 break;
143
144 case 's':
145 {
146 const char * const pszState = ValueUnion.psz;
147
148 if (RTStrICmp(pszState, "creatingimage") == 0)
149 machineStates.push_back(CloudMachineState_CreatingImage);
150 else if (RTStrICmp(pszState, "paused") == 0) /* XXX */
151 machineStates.push_back(CloudMachineState_Stopped);
152 else if (RTStrICmp(pszState, "provisioning") == 0)
153 machineStates.push_back(CloudMachineState_Provisioning);
154 else if (RTStrICmp(pszState, "running") == 0)
155 machineStates.push_back(CloudMachineState_Running);
156 else if (RTStrICmp(pszState, "starting") == 0)
157 machineStates.push_back(CloudMachineState_Starting);
158 else if (RTStrICmp(pszState, "stopped") == 0)
159 machineStates.push_back(CloudMachineState_Stopped);
160 else if (RTStrICmp(pszState, "stopping") == 0)
161 machineStates.push_back(CloudMachineState_Stopping);
162 else if (RTStrICmp(pszState, "terminated") == 0)
163 machineStates.push_back(CloudMachineState_Terminated);
164 else if (RTStrICmp(pszState, "terminating") == 0)
165 machineStates.push_back(CloudMachineState_Terminating);
166 else
167 return errorArgument("Unknown cloud instance state \"%s\"", pszState);
168 break;
169 }
170 case 1001:
171 case 1002:
172 printHelp(g_pStdOut);
173 return RTEXITCODE_SUCCESS;
174 case VINF_GETOPT_NOT_OPTION:
175 return errorUnknownSubcommand(ValueUnion.psz);
176
177 default:
178 return errorGetOpt(c, &ValueUnion);
179 }
180 }
181
182 HRESULT hrc = S_OK;
183
184 /* Delayed check. It allows us to print help information.*/
185 hrc = checkAndSetCommonOptions(a, pCommonOpts);
186 if (FAILED(hrc))
187 return RTEXITCODE_FAILURE;
188
189 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
190
191 ComPtr<ICloudProviderManager> pCloudProviderManager;
192 CHECK_ERROR2_RET(hrc, pVirtualBox,
193 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
194 RTEXITCODE_FAILURE);
195
196 ComPtr<ICloudProvider> pCloudProvider;
197 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
198 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
199 RTEXITCODE_FAILURE);
200
201 ComPtr<ICloudProfile> pCloudProfile;
202 CHECK_ERROR2_RET(hrc, pCloudProvider,
203 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
204 RTEXITCODE_FAILURE);
205
206 if (strCompartmentId.isNotEmpty())
207 {
208 CHECK_ERROR2_RET(hrc, pCloudProfile,
209 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
210 RTEXITCODE_FAILURE);
211 }
212 else
213 {
214 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
215 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->profile.pszProfileName);
216 Bstr bStrCompartmentId;
217 CHECK_ERROR2_RET(hrc, pCloudProfile,
218 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
219 RTEXITCODE_FAILURE);
220 strCompartmentId = bStrCompartmentId;
221 if (strCompartmentId.isNotEmpty())
222 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
223 else
224 return errorSyntax(USAGE_S_NEWCMD, "Parameter --compartment-id is required");
225 }
226
227 Bstr bstrProfileName;
228 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
229
230 ComObjPtr<ICloudClient> oCloudClient;
231 CHECK_ERROR2_RET(hrc, pCloudProfile,
232 CreateCloudClient(oCloudClient.asOutParam()),
233 RTEXITCODE_FAILURE);
234
235 ComPtr<IStringArray> pVMNamesHolder;
236 ComPtr<IStringArray> pVMIdsHolder;
237 com::SafeArray<BSTR> arrayVMNames;
238 com::SafeArray<BSTR> arrayVMIds;
239 ComPtr<IProgress> pProgress;
240
241 RTPrintf("Reply is in the form \'instance name\' = \'instance id\'\n");
242
243 CHECK_ERROR2_RET(hrc, oCloudClient,
244 ListInstances(ComSafeArrayAsInParam(machineStates),
245 pVMNamesHolder.asOutParam(),
246 pVMIdsHolder.asOutParam(),
247 pProgress.asOutParam()),
248 RTEXITCODE_FAILURE);
249 showProgress(pProgress);
250 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list instances"), RTEXITCODE_FAILURE);
251
252 CHECK_ERROR2_RET(hrc,
253 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
254 RTEXITCODE_FAILURE);
255 CHECK_ERROR2_RET(hrc,
256 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
257 RTEXITCODE_FAILURE);
258
259 RTPrintf("The list of the instances for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
260 bstrProfileName.raw(), strCompartmentId.c_str());
261 size_t cIds = arrayVMIds.size();
262 size_t cNames = arrayVMNames.size();
263 for (size_t k = 0; k < cNames; k++)
264 {
265 Bstr value;
266 if (k < cIds)
267 value = arrayVMIds[k];
268 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
269 }
270
271 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
272}
273
274
275/**
276 * List all available cloud images for the specified cloud provider.
277 *
278 * @returns RTEXITCODE
279 * @param a is the list of passed arguments
280 * @param iFirst is the position of the first unparsed argument in the arguments list
281 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
282 * arguments which have been already parsed before
283 */
284static RTEXITCODE listCloudImages(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
285{
286 static const RTGETOPTDEF s_aOptions[] =
287 {
288 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
289 { "--state", 's', RTGETOPT_REQ_STRING },
290 { "help", 1001, RTGETOPT_REQ_NOTHING },
291 { "--help", 1002, RTGETOPT_REQ_NOTHING }
292 };
293 RTGETOPTSTATE GetState;
294 RTGETOPTUNION ValueUnion;
295 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
296 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
297 if (a->argc == iFirst)
298 {
299 RTPrintf("Empty command parameter list, show help.\n");
300 printHelp(g_pStdOut);
301 return RTEXITCODE_SUCCESS;
302 }
303
304 Utf8Str strCompartmentId;
305 com::SafeArray<CloudImageState_T> imageStates;
306
307 int c;
308 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
309 {
310 switch (c)
311 {
312 case 'c':
313 strCompartmentId = ValueUnion.psz;
314 break;
315
316 case 's':
317 {
318 const char * const pszState = ValueUnion.psz;
319
320 if (RTStrICmp(pszState, "available") == 0)
321 imageStates.push_back(CloudImageState_Available);
322 else if (RTStrICmp(pszState, "deleted") == 0)
323 imageStates.push_back(CloudImageState_Deleted);
324 else if (RTStrICmp(pszState, "disabled") == 0)
325 imageStates.push_back(CloudImageState_Disabled);
326 else if (RTStrICmp(pszState, "exporting") == 0)
327 imageStates.push_back(CloudImageState_Exporting);
328 else if (RTStrICmp(pszState, "importing") == 0)
329 imageStates.push_back(CloudImageState_Importing);
330 else if (RTStrICmp(pszState, "provisioning") == 0)
331 imageStates.push_back(CloudImageState_Provisioning);
332 else
333 return errorArgument("Unknown cloud image state \"%s\"", pszState);
334 break;
335 }
336 case 1001:
337 case 1002:
338 printHelp(g_pStdOut);
339 return RTEXITCODE_SUCCESS;
340 case VINF_GETOPT_NOT_OPTION:
341 return errorUnknownSubcommand(ValueUnion.psz);
342
343 default:
344 return errorGetOpt(c, &ValueUnion);
345 }
346 }
347
348
349 HRESULT hrc = S_OK;
350
351 /* Delayed check. It allows us to print help information.*/
352 hrc = checkAndSetCommonOptions(a, pCommonOpts);
353 if (FAILED(hrc))
354 return RTEXITCODE_FAILURE;
355
356 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
357
358 ComPtr<ICloudProviderManager> pCloudProviderManager;
359 CHECK_ERROR2_RET(hrc, pVirtualBox,
360 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
361 RTEXITCODE_FAILURE);
362
363 ComPtr<ICloudProvider> pCloudProvider;
364 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
365 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
366 RTEXITCODE_FAILURE);
367
368 ComPtr<ICloudProfile> pCloudProfile;
369 CHECK_ERROR2_RET(hrc, pCloudProvider,
370 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
371 RTEXITCODE_FAILURE);
372
373 if (strCompartmentId.isNotEmpty())
374 {
375 CHECK_ERROR2_RET(hrc, pCloudProfile,
376 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),\
377 RTEXITCODE_FAILURE);
378 }
379 else
380 {
381 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
382 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->profile.pszProfileName);
383 Bstr bStrCompartmentId;
384 CHECK_ERROR2_RET(hrc, pCloudProfile,
385 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
386 RTEXITCODE_FAILURE);
387 strCompartmentId = bStrCompartmentId;
388 if (strCompartmentId.isNotEmpty())
389 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
390 else
391 return errorSyntax(USAGE_S_NEWCMD, "Parameter --compartment-id is required");
392 }
393
394 Bstr bstrProfileName;
395 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
396
397 ComObjPtr<ICloudClient> oCloudClient;
398 CHECK_ERROR2_RET(hrc, pCloudProfile,
399 CreateCloudClient(oCloudClient.asOutParam()),
400 RTEXITCODE_FAILURE);
401
402 ComPtr<IStringArray> pVMNamesHolder;
403 ComPtr<IStringArray> pVMIdsHolder;
404 com::SafeArray<BSTR> arrayVMNames;
405 com::SafeArray<BSTR> arrayVMIds;
406 ComPtr<IProgress> pProgress;
407
408 RTPrintf("Reply is in the form \'image name\' = \'image id\'\n");
409 CHECK_ERROR2_RET(hrc, oCloudClient,
410 ListImages(ComSafeArrayAsInParam(imageStates),
411 pVMNamesHolder.asOutParam(),
412 pVMIdsHolder.asOutParam(),
413 pProgress.asOutParam()),
414 RTEXITCODE_FAILURE);
415 showProgress(pProgress);
416 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list images"), RTEXITCODE_FAILURE);
417
418 CHECK_ERROR2_RET(hrc,
419 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
420 RTEXITCODE_FAILURE);
421 CHECK_ERROR2_RET(hrc,
422 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
423 RTEXITCODE_FAILURE);
424
425 RTPrintf("The list of the images for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
426 bstrProfileName.raw(), strCompartmentId.c_str());
427 size_t cNames = arrayVMNames.size();
428 size_t cIds = arrayVMIds.size();
429 for (size_t k = 0; k < cNames; k++)
430 {
431 Bstr value;
432 if (k < cIds)
433 value = arrayVMIds[k];
434 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
435 }
436
437 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
438}
439
440/**
441 * General function which handles the "list" commands
442 *
443 * @returns RTEXITCODE
444 * @param a is the list of passed arguments
445 * @param iFirst is the position of the first unparsed argument in the arguments list
446 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
447 * arguments which have been already parsed before
448 */
449static RTEXITCODE handleCloudLists(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
450{
451 if (a->argc == iFirst)
452 {
453 RTPrintf("Empty command parameter list, show help.\n");
454 printHelp(g_pStdOut);
455 return RTEXITCODE_SUCCESS;
456 }
457
458 static const RTGETOPTDEF s_aOptions[] =
459 {
460 { "images", 1000, RTGETOPT_REQ_NOTHING },
461 { "instances", 1001, RTGETOPT_REQ_NOTHING },
462 { "networks", 1002, RTGETOPT_REQ_NOTHING },
463 { "subnets", 1003, RTGETOPT_REQ_NOTHING },
464 { "vcns", 1004, RTGETOPT_REQ_NOTHING },
465 { "objects", 1005, RTGETOPT_REQ_NOTHING },
466 { "help", 1006, RTGETOPT_REQ_NOTHING },
467 { "--help", 1007, RTGETOPT_REQ_NOTHING }
468 };
469
470 RTGETOPTSTATE GetState;
471 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
472 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
473
474 int c;
475 RTGETOPTUNION ValueUnion;
476 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
477 {
478 switch (c)
479 {
480 case 1000:
481 setCurrentSubcommand(HELP_SCOPE_CLOUDLIST_IMAGES);
482 return listCloudImages(a, GetState.iNext, pCommonOpts);
483 case 1001:
484 setCurrentSubcommand(HELP_SCOPE_CLOUDLIST_INSTANCES);
485 return listCloudInstances(a, GetState.iNext, pCommonOpts);
486 case 1006:
487 case 1007:
488 printHelp(g_pStdOut);
489 return RTEXITCODE_SUCCESS;
490 case VINF_GETOPT_NOT_OPTION:
491 return errorUnknownSubcommand(ValueUnion.psz);
492
493 default:
494 return errorGetOpt(c, &ValueUnion);
495 }
496 }
497
498 return errorNoSubcommand();
499}
500
501static RTEXITCODE createCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
502{
503 HRESULT hrc = S_OK;
504
505 static const RTGETOPTDEF s_aOptions[] =
506 {
507 { "--image-id", 'i', RTGETOPT_REQ_STRING },
508 { "--boot-volume-id", 'v', RTGETOPT_REQ_STRING },
509 { "--display-name", 'n', RTGETOPT_REQ_STRING },
510 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
511 { "--shape", 's', RTGETOPT_REQ_STRING },
512 { "--domain-name", 'd', RTGETOPT_REQ_STRING },
513 { "--boot-disk-size", 'b', RTGETOPT_REQ_STRING },
514 { "--publicip", 'p', RTGETOPT_REQ_STRING },
515 { "--subnet", 't', RTGETOPT_REQ_STRING },
516 { "--privateip", 'P', RTGETOPT_REQ_STRING },
517 { "--launch", 'l', RTGETOPT_REQ_STRING },
518 { "--public-ssh-key", 'k', RTGETOPT_REQ_STRING },
519 { "help", 1001, RTGETOPT_REQ_NOTHING },
520 { "--help", 1002, RTGETOPT_REQ_NOTHING }
521 };
522 RTGETOPTSTATE GetState;
523 RTGETOPTUNION ValueUnion;
524 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
525 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
526 if (a->argc == iFirst)
527 {
528 RTPrintf("Empty command parameter list, show help.\n");
529 printHelp(g_pStdOut);
530 return RTEXITCODE_SUCCESS;
531 }
532
533 ComPtr<IAppliance> pAppliance;
534 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
535 ULONG vsdNum = 1;
536 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(1, &vsdNum), RTEXITCODE_FAILURE);
537 com::SafeIfaceArray<IVirtualSystemDescription> virtualSystemDescriptions;
538 CHECK_ERROR2_RET(hrc, pAppliance,
539 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(virtualSystemDescriptions)),
540 RTEXITCODE_FAILURE);
541 ComPtr<IVirtualSystemDescription> pVSD = virtualSystemDescriptions[0];
542
543 Utf8Str strDisplayName, strImageId, strBootVolumeId, strPublicSSHKey;
544 int c;
545 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
546 {
547 switch (c)
548 {
549 case 'i':
550 strImageId = ValueUnion.psz;
551 pVSD->AddDescription(VirtualSystemDescriptionType_CloudImageId,
552 Bstr(ValueUnion.psz).raw(), NULL);
553 break;
554
555 case 'v':
556 strBootVolumeId = ValueUnion.psz;
557 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootVolumeId,
558 Bstr(ValueUnion.psz).raw(), NULL);
559 break;
560 case 'n':
561 strDisplayName = ValueUnion.psz;
562 pVSD->AddDescription(VirtualSystemDescriptionType_Name,
563 Bstr(ValueUnion.psz).raw(), NULL);
564 break;
565 case 'm':
566 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCILaunchMode,
567 Bstr(ValueUnion.psz).raw(), NULL);
568 break;
569 case 's':
570 pVSD->AddDescription(VirtualSystemDescriptionType_CloudInstanceShape,
571 Bstr(ValueUnion.psz).raw(), NULL);
572 break;
573 case 'd':
574 pVSD->AddDescription(VirtualSystemDescriptionType_CloudDomain,
575 Bstr(ValueUnion.psz).raw(), NULL);
576 break;
577 case 'b':
578 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootDiskSize,
579 Bstr(ValueUnion.psz).raw(), NULL);
580 break;
581 case 'p':
582 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicIP,
583 Bstr(ValueUnion.psz).raw(), NULL);
584 break;
585 case 'P':
586 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPrivateIP,
587 Bstr(ValueUnion.psz).raw(), NULL);
588 break;
589 case 't':
590 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCISubnet,
591 Bstr(ValueUnion.psz).raw(), NULL);
592 break;
593 case 'l':
594 {
595 Utf8Str strLaunch(ValueUnion.psz);
596 if (strLaunch.isNotEmpty() && (strLaunch.equalsIgnoreCase("true") || strLaunch.equalsIgnoreCase("false")))
597 pVSD->AddDescription(VirtualSystemDescriptionType_CloudLaunchInstance,
598 Bstr(ValueUnion.psz).raw(), NULL);
599 break;
600 }
601 case 'k':
602 strPublicSSHKey = ValueUnion.psz;
603 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicSSHKey,
604 Bstr(ValueUnion.psz).raw(), NULL);
605 break;
606 case 1001:
607 case 1002:
608 printHelp(g_pStdOut);
609 return RTEXITCODE_SUCCESS;
610 case VINF_GETOPT_NOT_OPTION:
611 return errorUnknownSubcommand(ValueUnion.psz);
612 default:
613 return errorGetOpt(c, &ValueUnion);
614 }
615 }
616
617 /* Delayed check. It allows us to print help information.*/
618 hrc = checkAndSetCommonOptions(a, pCommonOpts);
619 if (FAILED(hrc))
620 return RTEXITCODE_FAILURE;
621
622 if (strPublicSSHKey.isEmpty())
623 RTPrintf("Warning!!! Public SSH key doesn't present in the passed arguments...\n");
624
625 if (strImageId.isNotEmpty() && strBootVolumeId.isNotEmpty())
626 return errorArgument("Parameters --image-id and --boot-volume-id are mutually exclusive. "
627 "Only one of them must be presented.");
628
629 if (strImageId.isEmpty() && strBootVolumeId.isEmpty())
630 return errorArgument("Missing parameter --image-id or --boot-volume-id. One of them must be presented.");
631
632 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
633
634 pVSD->AddDescription(VirtualSystemDescriptionType_CloudProfileName,
635 Bstr(pCommonOpts->profile.pszProfileName).raw(),
636 NULL);
637
638 ComObjPtr<ICloudClient> oCloudClient;
639 CHECK_ERROR2_RET(hrc, pCloudProfile,
640 CreateCloudClient(oCloudClient.asOutParam()),
641 RTEXITCODE_FAILURE);
642
643 ComPtr<IStringArray> infoArray;
644 com::SafeArray<BSTR> pStrInfoArray;
645 ComPtr<IProgress> pProgress;
646
647#if 0
648 /*
649 * OCI API returns an error during an instance creation if the image isn't available
650 * or in the inappropriate state. So the check can be omitted.
651 */
652 RTPrintf("Checking the cloud image with id \'%s\'...\n", strImageId.c_str());
653 CHECK_ERROR2_RET(hrc, oCloudClient,
654 GetImageInfo(Bstr(strImageId).raw(),
655 infoArray.asOutParam(),
656 pProgress.asOutParam()),
657 RTEXITCODE_FAILURE);
658
659 hrc = showProgress(pProgress);
660 CHECK_PROGRESS_ERROR_RET(pProgress, ("Checking the cloud image failed"), RTEXITCODE_FAILURE);
661
662 pProgress.setNull();
663#endif
664
665 if (strImageId.isNotEmpty())
666 RTPrintf("Creating cloud instance with name \'%s\' from the image \'%s\'...\n",
667 strDisplayName.c_str(), strImageId.c_str());
668 else
669 RTPrintf("Creating cloud instance with name \'%s\' from the boot volume \'%s\'...\n",
670 strDisplayName.c_str(), strBootVolumeId.c_str());
671
672 CHECK_ERROR2_RET(hrc, oCloudClient, LaunchVM(pVSD, pProgress.asOutParam()), RTEXITCODE_FAILURE);
673
674 hrc = showProgress(pProgress);
675 CHECK_PROGRESS_ERROR_RET(pProgress, ("Creating cloud instance failed"), RTEXITCODE_FAILURE);
676
677 if (SUCCEEDED(hrc))
678 RTPrintf("Cloud instance was created successfully\n");
679
680 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
681}
682
683static RTEXITCODE updateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
684{
685 RT_NOREF(a);
686 RT_NOREF(iFirst);
687 RT_NOREF(pCommonOpts);
688 return RTEXITCODE_SUCCESS;
689}
690
691static RTEXITCODE showCloudInstanceInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
692{
693 HRESULT hrc = S_OK;
694
695 static const RTGETOPTDEF s_aOptions[] =
696 {
697 { "--id", 'i', RTGETOPT_REQ_STRING },
698 { "help", 1001, RTGETOPT_REQ_NOTHING },
699 { "--help", 1002, RTGETOPT_REQ_NOTHING }
700 };
701 RTGETOPTSTATE GetState;
702 RTGETOPTUNION ValueUnion;
703 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
704 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
705 if (a->argc == iFirst)
706 {
707 RTPrintf("Empty command parameter list, show help.\n");
708 printHelp(g_pStdOut);
709 return RTEXITCODE_SUCCESS;
710 }
711
712 Utf8Str strInstanceId;
713
714 int c;
715 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
716 {
717 switch (c)
718 {
719 case 'i':
720 {
721 if (strInstanceId.isNotEmpty())
722 return errorArgument("Duplicate parameter: --id");
723
724 strInstanceId = ValueUnion.psz;
725 if (strInstanceId.isEmpty())
726 return errorArgument("Empty parameter: --id");
727
728 break;
729 }
730 case 1001:
731 case 1002:
732 printHelp(g_pStdOut);
733 return RTEXITCODE_SUCCESS;
734 case VINF_GETOPT_NOT_OPTION:
735 return errorUnknownSubcommand(ValueUnion.psz);
736
737 default:
738 return errorGetOpt(c, &ValueUnion);
739 }
740 }
741
742 /* Delayed check. It allows us to print help information.*/
743 hrc = checkAndSetCommonOptions(a, pCommonOpts);
744 if (FAILED(hrc))
745 return RTEXITCODE_FAILURE;
746
747 if (strInstanceId.isEmpty())
748 return errorArgument("Missing parameter: --id");
749
750 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
751
752 ComObjPtr<ICloudClient> oCloudClient;
753 CHECK_ERROR2_RET(hrc, pCloudProfile,
754 CreateCloudClient(oCloudClient.asOutParam()),
755 RTEXITCODE_FAILURE);
756 RTPrintf("Getting information about cloud instance with id %s...\n", strInstanceId.c_str());
757 RTPrintf("Reply is in the form \'setting name\' = \'value\'\n");
758
759 ComPtr<IAppliance> pAppliance;
760 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
761
762 com::SafeIfaceArray<IVirtualSystemDescription> vsdArray;
763 ULONG requestedVSDnums = 1;
764 ULONG newVSDnums = 0;
765 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(requestedVSDnums, &newVSDnums), RTEXITCODE_FAILURE);
766 if (requestedVSDnums != newVSDnums)
767 return RTEXITCODE_FAILURE;
768
769 CHECK_ERROR2_RET(hrc, pAppliance, COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(vsdArray)), RTEXITCODE_FAILURE);
770 ComPtr<IVirtualSystemDescription> instanceDescription = vsdArray[0];
771
772 ComPtr<IProgress> progress;
773 CHECK_ERROR2_RET(hrc, oCloudClient,
774 GetInstanceInfo(Bstr(strInstanceId).raw(), instanceDescription, progress.asOutParam()),
775 RTEXITCODE_FAILURE);
776
777 hrc = showProgress(progress);
778 CHECK_PROGRESS_ERROR_RET(progress, ("Getting information about cloud instance failed"), RTEXITCODE_FAILURE);
779
780 RTPrintf("Cloud instance info (provider '%s'):\n",
781 pCommonOpts->provider.pszProviderName);
782
783 struct vsdHReadable {
784 VirtualSystemDescriptionType_T vsdType;
785 Utf8Str strFound;
786 Utf8Str strNotFound;
787 };
788
789 const size_t vsdHReadableArraySize = 12;//the number of items in the vsdHReadableArray
790 vsdHReadable vsdHReadableArray[vsdHReadableArraySize] = {
791 {VirtualSystemDescriptionType_CloudDomain, "Availability domain = %ls\n", "Availability domain wasn't found\n"},
792 {VirtualSystemDescriptionType_Name, "Instance displayed name = %ls\n", "Instance displayed name wasn't found\n"},
793 {VirtualSystemDescriptionType_CloudInstanceState, "Instance state = %ls\n", "Instance state wasn't found\n"},
794 {VirtualSystemDescriptionType_CloudInstanceId, "Instance Id = %ls\n", "Instance Id wasn't found\n"},
795 {VirtualSystemDescriptionType_CloudInstanceDisplayName, "Instance name = %ls\n", "Instance name wasn't found\n"},
796 {VirtualSystemDescriptionType_CloudImageId, "Bootable image Id = %ls\n",
797 "Image Id whom the instance is booted up wasn't found\n"},
798 {VirtualSystemDescriptionType_CloudInstanceShape, "Shape of the instance = %ls\n",
799 "The shape of the instance wasn't found\n"},
800 {VirtualSystemDescriptionType_OS, "Type of guest OS = %ls\n", "Type of guest OS wasn't found\n"},
801 {VirtualSystemDescriptionType_Memory, "RAM = %ls MB\n", "Value for RAM wasn't found\n"},
802 {VirtualSystemDescriptionType_CPU, "CPUs = %ls\n", "Numbers of CPUs weren't found\n"},
803 {VirtualSystemDescriptionType_CloudPublicIP, "Instance public IP = %ls\n", "Public IP wasn't found\n"},
804 {VirtualSystemDescriptionType_Miscellaneous, "%ls\n", "Free-form tags or metadata weren't found\n"}
805 };
806
807 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
808 com::SafeArray<BSTR> aRefs;
809 com::SafeArray<BSTR> aOvfValues;
810 com::SafeArray<BSTR> aVBoxValues;
811 com::SafeArray<BSTR> aExtraConfigValues;
812
813 for (size_t i=0; i<vsdHReadableArraySize ; ++i)
814 {
815 hrc = instanceDescription->GetDescriptionByType(vsdHReadableArray[i].vsdType,
816 ComSafeArrayAsOutParam(retTypes),
817 ComSafeArrayAsOutParam(aRefs),
818 ComSafeArrayAsOutParam(aOvfValues),
819 ComSafeArrayAsOutParam(aVBoxValues),
820 ComSafeArrayAsOutParam(aExtraConfigValues));
821 if (FAILED(hrc) || aVBoxValues.size() == 0)
822 LogRel((vsdHReadableArray[i].strNotFound.c_str()));
823 else
824 {
825 LogRel(("Size is %d", aVBoxValues.size()));
826 for (size_t j = 0; j<aVBoxValues.size(); ++j)
827 {
828 RTPrintf(vsdHReadableArray[i].strFound.c_str(), aVBoxValues[j]);
829 }
830 }
831
832 retTypes.setNull();
833 aRefs.setNull();
834 aOvfValues.setNull();
835 aVBoxValues.setNull();
836 aExtraConfigValues.setNull();
837 }
838
839 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
840}
841
842static RTEXITCODE startCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
843{
844 HRESULT hrc = S_OK;
845
846 static const RTGETOPTDEF s_aOptions[] =
847 {
848 { "--id", 'i', RTGETOPT_REQ_STRING },
849 { "help", 1001, RTGETOPT_REQ_NOTHING },
850 { "--help", 1002, RTGETOPT_REQ_NOTHING }
851 };
852 RTGETOPTSTATE GetState;
853 RTGETOPTUNION ValueUnion;
854 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
855 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
856 if (a->argc == iFirst)
857 {
858 RTPrintf("Empty command parameter list, show help.\n");
859 printHelp(g_pStdOut);
860 return RTEXITCODE_SUCCESS;
861 }
862
863 Utf8Str strInstanceId;
864
865 int c;
866 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
867 {
868 switch (c)
869 {
870 case 'i':
871 {
872 if (strInstanceId.isNotEmpty())
873 return errorArgument("Duplicate parameter: --id");
874
875 strInstanceId = ValueUnion.psz;
876 if (strInstanceId.isEmpty())
877 return errorArgument("Empty parameter: --id");
878
879 break;
880 }
881 case 1001:
882 case 1002:
883 printHelp(g_pStdOut);
884 return RTEXITCODE_SUCCESS;
885 case VINF_GETOPT_NOT_OPTION:
886 return errorUnknownSubcommand(ValueUnion.psz);
887
888 default:
889 return errorGetOpt(c, &ValueUnion);
890 }
891 }
892
893 /* Delayed check. It allows us to print help information.*/
894 hrc = checkAndSetCommonOptions(a, pCommonOpts);
895 if (FAILED(hrc))
896 return RTEXITCODE_FAILURE;
897
898 if (strInstanceId.isEmpty())
899 return errorArgument("Missing parameter: --id");
900
901 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
902
903 ComObjPtr<ICloudClient> oCloudClient;
904 CHECK_ERROR2_RET(hrc, pCloudProfile,
905 CreateCloudClient(oCloudClient.asOutParam()),
906 RTEXITCODE_FAILURE);
907 RTPrintf("Starting cloud instance with id %s...\n", strInstanceId.c_str());
908
909 ComPtr<IProgress> progress;
910 CHECK_ERROR2_RET(hrc, oCloudClient,
911 StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
912 RTEXITCODE_FAILURE);
913 hrc = showProgress(progress);
914 CHECK_PROGRESS_ERROR_RET(progress, ("Starting the cloud instance failed"), RTEXITCODE_FAILURE);
915
916 if (SUCCEEDED(hrc))
917 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n",
918 strInstanceId.c_str(),
919 pCommonOpts->provider.pszProviderName,
920 pCommonOpts->profile.pszProfileName);
921
922 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
923}
924
925static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
926{
927 HRESULT hrc = S_OK;
928
929 static const RTGETOPTDEF s_aOptions[] =
930 {
931 { "--id", 'i', RTGETOPT_REQ_STRING },
932 { "help", 1001, RTGETOPT_REQ_NOTHING },
933 { "--help", 1002, RTGETOPT_REQ_NOTHING }
934 };
935 RTGETOPTSTATE GetState;
936 RTGETOPTUNION ValueUnion;
937 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
938 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
939 if (a->argc == iFirst)
940 {
941 RTPrintf("Empty command parameter list, show help.\n");
942 printHelp(g_pStdOut);
943 return RTEXITCODE_SUCCESS;
944 }
945
946 Utf8Str strInstanceId;
947
948 int c;
949 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
950 {
951 switch (c)
952 {
953 case 'i':
954 {
955 if (strInstanceId.isNotEmpty())
956 return errorArgument("Duplicate parameter: --id");
957
958 strInstanceId = ValueUnion.psz;
959 if (strInstanceId.isEmpty())
960 return errorArgument("Empty parameter: --id");
961
962 break;
963 }
964 case 1001:
965 case 1002:
966 printHelp(g_pStdOut);
967 return RTEXITCODE_SUCCESS;
968 case VINF_GETOPT_NOT_OPTION:
969 return errorUnknownSubcommand(ValueUnion.psz);
970
971 default:
972 return errorGetOpt(c, &ValueUnion);
973 }
974 }
975
976 /* Delayed check. It allows us to print help information.*/
977 hrc = checkAndSetCommonOptions(a, pCommonOpts);
978 if (FAILED(hrc))
979 return RTEXITCODE_FAILURE;
980
981 if (strInstanceId.isEmpty())
982 return errorArgument("Missing parameter: --id");
983
984 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
985
986 ComObjPtr<ICloudClient> oCloudClient;
987 CHECK_ERROR2_RET(hrc, pCloudProfile,
988 CreateCloudClient(oCloudClient.asOutParam()),
989 RTEXITCODE_FAILURE);
990 RTPrintf("Pausing cloud instance with id %s...\n", strInstanceId.c_str());
991
992 ComPtr<IProgress> progress;
993 CHECK_ERROR2_RET(hrc, oCloudClient,
994 PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
995 RTEXITCODE_FAILURE);
996 hrc = showProgress(progress);
997 CHECK_PROGRESS_ERROR_RET(progress, ("Pause the cloud instance failed"), RTEXITCODE_FAILURE);
998
999 if (SUCCEEDED(hrc))
1000 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n",
1001 strInstanceId.c_str(),
1002 pCommonOpts->provider.pszProviderName,
1003 pCommonOpts->profile.pszProfileName);
1004
1005 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1006}
1007
1008static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1009{
1010 HRESULT hrc = S_OK;
1011
1012 static const RTGETOPTDEF s_aOptions[] =
1013 {
1014 { "--id", 'i', RTGETOPT_REQ_STRING },
1015 { "help", 1001, RTGETOPT_REQ_NOTHING },
1016 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1017 };
1018 RTGETOPTSTATE GetState;
1019 RTGETOPTUNION ValueUnion;
1020 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1021 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1022 if (a->argc == iFirst)
1023 {
1024 RTPrintf("Empty command parameter list, show help.\n");
1025 printHelp(g_pStdOut);
1026 return RTEXITCODE_SUCCESS;
1027 }
1028
1029 Utf8Str strInstanceId;
1030
1031 int c;
1032 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1033 {
1034 switch (c)
1035 {
1036 case 'i':
1037 {
1038 if (strInstanceId.isNotEmpty())
1039 return errorArgument("Duplicate parameter: --id");
1040
1041 strInstanceId = ValueUnion.psz;
1042 if (strInstanceId.isEmpty())
1043 return errorArgument("Empty parameter: --id");
1044
1045 break;
1046 }
1047 case 1001:
1048 case 1002:
1049 printHelp(g_pStdOut);
1050 return RTEXITCODE_SUCCESS;
1051 case VINF_GETOPT_NOT_OPTION:
1052 return errorUnknownSubcommand(ValueUnion.psz);
1053
1054 default:
1055 return errorGetOpt(c, &ValueUnion);
1056 }
1057 }
1058
1059 /* Delayed check. It allows us to print help information.*/
1060 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1061 if (FAILED(hrc))
1062 return RTEXITCODE_FAILURE;
1063
1064 if (strInstanceId.isEmpty())
1065 return errorArgument("Missing parameter: --id");
1066
1067
1068 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1069
1070 ComObjPtr<ICloudClient> oCloudClient;
1071 CHECK_ERROR2_RET(hrc, pCloudProfile,
1072 CreateCloudClient(oCloudClient.asOutParam()),
1073 RTEXITCODE_FAILURE);
1074 RTPrintf("Terminating cloud instance with id %s...\n", strInstanceId.c_str());
1075
1076 ComPtr<IProgress> progress;
1077 CHECK_ERROR2_RET(hrc, oCloudClient,
1078 TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1079 RTEXITCODE_FAILURE);
1080 hrc = showProgress(progress);
1081 CHECK_PROGRESS_ERROR_RET(progress, ("Termination the cloud instance failed"), RTEXITCODE_FAILURE);
1082
1083 if (SUCCEEDED(hrc))
1084 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n",
1085 strInstanceId.c_str(),
1086 pCommonOpts->provider.pszProviderName,
1087 pCommonOpts->profile.pszProfileName);
1088
1089 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1090}
1091
1092static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1093{
1094 if (a->argc == iFirst)
1095 {
1096 RTPrintf("Empty command parameter list, show help.\n");
1097 printHelp(g_pStdOut);
1098 return RTEXITCODE_SUCCESS;
1099 }
1100
1101 static const RTGETOPTDEF s_aOptions[] =
1102 {
1103 { "create", 1000, RTGETOPT_REQ_NOTHING },
1104 { "start", 1001, RTGETOPT_REQ_NOTHING },
1105 { "pause", 1002, RTGETOPT_REQ_NOTHING },
1106 { "info", 1003, RTGETOPT_REQ_NOTHING },
1107 { "update", 1004, RTGETOPT_REQ_NOTHING },
1108 { "terminate", 1005, RTGETOPT_REQ_NOTHING },
1109 { "help", 1006, RTGETOPT_REQ_NOTHING },
1110 { "--help", 1007, RTGETOPT_REQ_NOTHING }
1111 };
1112
1113 RTGETOPTSTATE GetState;
1114 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1115 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1116
1117 int c;
1118 RTGETOPTUNION ValueUnion;
1119 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1120 {
1121 switch (c)
1122 {
1123 /* Sub-commands: */
1124 case 1000:
1125 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_CREATE);
1126 return createCloudInstance(a, GetState.iNext, pCommonOpts);
1127 case 1001:
1128 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_START);
1129 return startCloudInstance(a, GetState.iNext, pCommonOpts);
1130 case 1002:
1131 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_PAUSE);
1132 return pauseCloudInstance(a, GetState.iNext, pCommonOpts);
1133 case 1003:
1134 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_INFO);
1135 return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts);
1136 case 1004:
1137// setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_UPDATE);
1138 return updateCloudInstance(a, GetState.iNext, pCommonOpts);
1139 case 1005:
1140 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_TERMINATE);
1141 return terminateCloudInstance(a, GetState.iNext, pCommonOpts);
1142 case 1006:
1143 case 1007:
1144 printHelp(g_pStdOut);
1145 return RTEXITCODE_SUCCESS;
1146 case VINF_GETOPT_NOT_OPTION:
1147 return errorUnknownSubcommand(ValueUnion.psz);
1148
1149 default:
1150 return errorGetOpt(c, &ValueUnion);
1151 }
1152 }
1153
1154 return errorNoSubcommand();
1155}
1156
1157
1158static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1159{
1160 HRESULT hrc = S_OK;
1161
1162 static const RTGETOPTDEF s_aOptions[] =
1163 {
1164 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1165 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1166 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
1167 { "--instance-id", 'i', RTGETOPT_REQ_STRING },
1168 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1169 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1170 { "help", 1001, RTGETOPT_REQ_NOTHING },
1171 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1172 };
1173 RTGETOPTSTATE GetState;
1174 RTGETOPTUNION ValueUnion;
1175 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1176 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1177 if (a->argc == iFirst)
1178 {
1179 RTPrintf("Empty command parameter list, show help.\n");
1180 printHelp(g_pStdOut);
1181 return RTEXITCODE_SUCCESS;
1182 }
1183
1184 Utf8Str strCompartmentId;
1185 Utf8Str strInstanceId;
1186 Utf8Str strDisplayName;
1187 Utf8Str strBucketName;
1188 Utf8Str strObjectName;
1189 com::SafeArray<BSTR> parameters;
1190
1191 int c;
1192 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1193 {
1194 switch (c)
1195 {
1196 case 'c':
1197 strCompartmentId=ValueUnion.psz;
1198 Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1199 break;
1200 case 'i':
1201 strInstanceId=ValueUnion.psz;
1202 Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1203 break;
1204 case 'd':
1205 strDisplayName=ValueUnion.psz;
1206 Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1207 break;
1208 case 'o':
1209 strObjectName=ValueUnion.psz;
1210 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1211 break;
1212 case 'b':
1213 strBucketName=ValueUnion.psz;
1214 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1215 break;
1216 case 'm':
1217 strBucketName=ValueUnion.psz;
1218 Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1219 break;
1220 case 1001:
1221 case 1002:
1222 printHelp(g_pStdOut);
1223 return RTEXITCODE_SUCCESS;
1224 case VINF_GETOPT_NOT_OPTION:
1225 return errorUnknownSubcommand(ValueUnion.psz);
1226 default:
1227 return errorGetOpt(c, &ValueUnion);
1228 }
1229 }
1230
1231 /* Delayed check. It allows us to print help information.*/
1232 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1233 if (FAILED(hrc))
1234 return RTEXITCODE_FAILURE;
1235
1236 if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty())
1237 return errorArgument("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one.");
1238
1239 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1240
1241 ComObjPtr<ICloudClient> oCloudClient;
1242 CHECK_ERROR2_RET(hrc, pCloudProfile,
1243 CreateCloudClient(oCloudClient.asOutParam()),
1244 RTEXITCODE_FAILURE);
1245 if (strInstanceId.isNotEmpty())
1246 RTPrintf("Creating cloud image with name \'%s\' from the instance \'%s\'...\n",
1247 strDisplayName.c_str(), strInstanceId.c_str());
1248 else
1249 RTPrintf("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n",
1250 strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str());
1251
1252 ComPtr<IProgress> progress;
1253 CHECK_ERROR2_RET(hrc, oCloudClient,
1254 CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1255 RTEXITCODE_FAILURE);
1256 hrc = showProgress(progress);
1257 CHECK_PROGRESS_ERROR_RET(progress, ("Creating cloud image failed"), RTEXITCODE_FAILURE);
1258
1259 if (SUCCEEDED(hrc))
1260 RTPrintf("Cloud image was created successfully\n");
1261
1262 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1263}
1264
1265
1266static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1267{
1268 HRESULT hrc = S_OK;
1269
1270 static const RTGETOPTDEF s_aOptions[] =
1271 {
1272 { "--id", 'i', RTGETOPT_REQ_STRING },
1273 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1274 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1275 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1276 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1277 { "help", 1001, RTGETOPT_REQ_NOTHING },
1278 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1279 };
1280 RTGETOPTSTATE GetState;
1281 RTGETOPTUNION ValueUnion;
1282 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1283 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1284 if (a->argc == iFirst)
1285 {
1286 RTPrintf("Empty command parameter list, show help.\n");
1287 printHelp(g_pStdOut);
1288 return RTEXITCODE_SUCCESS;
1289 }
1290
1291 Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */
1292 Utf8Str strBucketName;
1293 Utf8Str strObjectName;
1294 Utf8Str strDisplayName;
1295 Utf8Str strLaunchMode;
1296 com::SafeArray<BSTR> parameters;
1297
1298 int c;
1299 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1300 {
1301 switch (c)
1302 {
1303 case 'b': /* --bucket-name */
1304 {
1305 if (strBucketName.isNotEmpty())
1306 return errorArgument("Duplicate parameter: --bucket-name");
1307
1308 strBucketName = ValueUnion.psz;
1309 if (strBucketName.isEmpty())
1310 return errorArgument("Empty parameter: --bucket-name");
1311
1312 break;
1313 }
1314
1315 case 'o': /* --object-name */
1316 {
1317 if (strObjectName.isNotEmpty())
1318 return errorArgument("Duplicate parameter: --object-name");
1319
1320 strObjectName = ValueUnion.psz;
1321 if (strObjectName.isEmpty())
1322 return errorArgument("Empty parameter: --object-name");
1323
1324 break;
1325 }
1326
1327 case 'i': /* --id */
1328 {
1329 if (strImageId.isNotEmpty())
1330 return errorArgument("Duplicate parameter: --id");
1331
1332 strImageId = ValueUnion.psz;
1333 if (strImageId.isEmpty())
1334 return errorArgument("Empty parameter: --id");
1335
1336 break;
1337 }
1338
1339 case 'd': /* --display-name */
1340 {
1341 if (strDisplayName.isNotEmpty())
1342 return errorArgument("Duplicate parameter: --display-name");
1343
1344 strDisplayName = ValueUnion.psz;
1345 if (strDisplayName.isEmpty())
1346 return errorArgument("Empty parameter: --display-name");
1347
1348 break;
1349 }
1350
1351 case 'm': /* --launch-mode */
1352 {
1353 if (strLaunchMode.isNotEmpty())
1354 return errorArgument("Duplicate parameter: --launch-mode");
1355
1356 strLaunchMode = ValueUnion.psz;
1357 if (strLaunchMode.isEmpty())
1358 return errorArgument("Empty parameter: --launch-mode");
1359
1360 break;
1361 }
1362
1363 case 1001:
1364 case 1002:
1365 printHelp(g_pStdOut);
1366 return RTEXITCODE_SUCCESS;
1367
1368 case VINF_GETOPT_NOT_OPTION:
1369 return errorUnknownSubcommand(ValueUnion.psz);
1370
1371 default:
1372 return errorGetOpt(c, &ValueUnion);
1373 }
1374 }
1375
1376 /* Delayed check. It allows us to print help information.*/
1377 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1378 if (FAILED(hrc))
1379 return RTEXITCODE_FAILURE;
1380
1381 if (strImageId.isNotEmpty())
1382 BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw());
1383 else
1384 return errorArgument("Missing parameter: --id");
1385
1386 if (strBucketName.isNotEmpty())
1387 BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw());
1388 else
1389 return errorArgument("Missing parameter: --bucket-name");
1390
1391 if (strObjectName.isNotEmpty())
1392 BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw());
1393
1394 if (strDisplayName.isNotEmpty())
1395 BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw());
1396
1397 if (strLaunchMode.isNotEmpty())
1398 BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw());
1399
1400
1401 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1402
1403 ComObjPtr<ICloudClient> oCloudClient;
1404 CHECK_ERROR2_RET(hrc, pCloudProfile,
1405 CreateCloudClient(oCloudClient.asOutParam()),
1406 RTEXITCODE_FAILURE);
1407
1408 if (strObjectName.isNotEmpty())
1409 RTPrintf("Exporting image \'%s\' to the Cloud with name \'%s\'...\n",
1410 strImageId.c_str(), strObjectName.c_str());
1411 else
1412 RTPrintf("Exporting image \'%s\' to the Cloud with default name\n",
1413 strImageId.c_str());
1414
1415 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1416 SafeIfaceArray<IMedium> aImageList;
1417 CHECK_ERROR2_RET(hrc, pVirtualBox,
1418 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)),
1419 RTEXITCODE_FAILURE);
1420
1421 ComPtr<IMedium> pImage;
1422 size_t cImages = aImageList.size();
1423 bool fFound = false;
1424 for (size_t i = 0; i < cImages; ++i)
1425 {
1426 pImage = aImageList[i];
1427 Bstr bstrImageId;
1428 hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam());
1429 if (FAILED(hrc))
1430 continue;
1431
1432 com::Guid imageId(bstrImageId);
1433
1434 if (!imageId.isValid() || imageId.isZero())
1435 continue;
1436
1437 if (!strImageId.compare(imageId.toString()))
1438 {
1439 fFound = true;
1440 RTPrintf("Image %s was found\n", strImageId.c_str());
1441 break;
1442 }
1443 }
1444
1445 if (!fFound)
1446 {
1447 RTPrintf("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n");
1448 return RTEXITCODE_FAILURE;
1449 }
1450
1451 ComPtr<IProgress> progress;
1452 CHECK_ERROR2_RET(hrc, oCloudClient,
1453 ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1454 RTEXITCODE_FAILURE);
1455 hrc = showProgress(progress);
1456 CHECK_PROGRESS_ERROR_RET(progress, ("Export the image to the Cloud failed"), RTEXITCODE_FAILURE);
1457
1458 if (SUCCEEDED(hrc))
1459 RTPrintf("Export the image to the Cloud was successfull\n");
1460
1461 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1462}
1463
1464static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1465{
1466 HRESULT hrc = S_OK;
1467
1468 static const RTGETOPTDEF s_aOptions[] =
1469 {
1470 { "--id", 'i', RTGETOPT_REQ_STRING },
1471 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1472 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1473 { "help", 1001, RTGETOPT_REQ_NOTHING },
1474 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1475 };
1476 RTGETOPTSTATE GetState;
1477 RTGETOPTUNION ValueUnion;
1478 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1479 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1480 if (a->argc == iFirst)
1481 {
1482 RTPrintf("Empty command parameter list, show help.\n");
1483 printHelp(g_pStdOut);
1484 return RTEXITCODE_SUCCESS;
1485 }
1486
1487 Utf8Str strImageId;
1488 Utf8Str strCompartmentId;
1489 Utf8Str strBucketName;
1490 Utf8Str strObjectName;
1491 Utf8Str strDisplayName;
1492 com::SafeArray<BSTR> parameters;
1493
1494 int c;
1495 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1496 {
1497 switch (c)
1498 {
1499 case 'i':
1500 strImageId=ValueUnion.psz;
1501 break;
1502 case 'b':
1503 strBucketName=ValueUnion.psz;
1504 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1505 break;
1506 case 'o':
1507 strObjectName=ValueUnion.psz;
1508 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1509 break;
1510 case 1001:
1511 case 1002:
1512 printHelp(g_pStdOut);
1513 return RTEXITCODE_SUCCESS;
1514 case VINF_GETOPT_NOT_OPTION:
1515 return errorUnknownSubcommand(ValueUnion.psz);
1516 default:
1517 return errorGetOpt(c, &ValueUnion);
1518 }
1519 }
1520
1521 /* Delayed check. It allows us to print help information.*/
1522 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1523 if (FAILED(hrc))
1524 return RTEXITCODE_FAILURE;
1525
1526 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1527
1528 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1529 ComObjPtr<ICloudClient> oCloudClient;
1530 CHECK_ERROR2_RET(hrc, pCloudProfile,
1531 CreateCloudClient(oCloudClient.asOutParam()),
1532 RTEXITCODE_FAILURE);
1533 RTPrintf("Creating an object \'%s\' from the cloud image \'%s\'...\n", strObjectName.c_str(), strImageId.c_str());
1534
1535 ComPtr<IProgress> progress;
1536 CHECK_ERROR2_RET(hrc, oCloudClient,
1537 ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1538 RTEXITCODE_FAILURE);
1539 hrc = showProgress(progress);
1540 CHECK_PROGRESS_ERROR_RET(progress, ("Cloud image import failed"), RTEXITCODE_FAILURE);
1541
1542 if (SUCCEEDED(hrc))
1543 {
1544 RTPrintf("Cloud image was imported successfully. Find the downloaded object with the name %s "
1545 "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n",
1546 strObjectName.c_str());
1547 }
1548
1549 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1550}
1551
1552static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1553{
1554 HRESULT hrc = S_OK;
1555
1556 static const RTGETOPTDEF s_aOptions[] =
1557 {
1558 { "--id", 'i', RTGETOPT_REQ_STRING },
1559 { "help", 1001, RTGETOPT_REQ_NOTHING },
1560 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1561 };
1562 RTGETOPTSTATE GetState;
1563 RTGETOPTUNION ValueUnion;
1564 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1565 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1566 if (a->argc == iFirst)
1567 {
1568 RTPrintf("Empty command parameter list, show help.\n");
1569 printHelp(g_pStdOut);
1570 return RTEXITCODE_SUCCESS;
1571 }
1572
1573 Utf8Str strImageId;
1574
1575 int c;
1576 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1577 {
1578 switch (c)
1579 {
1580 case 'i':
1581 strImageId = ValueUnion.psz;
1582 break;
1583 case 1001:
1584 case 1002:
1585 printHelp(g_pStdOut);
1586 return RTEXITCODE_SUCCESS;
1587 case VINF_GETOPT_NOT_OPTION:
1588 return errorUnknownSubcommand(ValueUnion.psz);
1589 default:
1590 return errorGetOpt(c, &ValueUnion);
1591 }
1592 }
1593
1594 /* Delayed check. It allows us to print help information.*/
1595 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1596 if (FAILED(hrc))
1597 return RTEXITCODE_FAILURE;
1598
1599 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1600
1601 ComObjPtr<ICloudClient> oCloudClient;
1602 CHECK_ERROR2_RET(hrc, pCloudProfile,
1603 CreateCloudClient(oCloudClient.asOutParam()),
1604 RTEXITCODE_FAILURE);
1605 RTPrintf("Getting information about the cloud image with id \'%s\'...\n", strImageId.c_str());
1606
1607 ComPtr<IStringArray> infoArray;
1608 com::SafeArray<BSTR> pStrInfoArray;
1609 ComPtr<IProgress> pProgress;
1610
1611 RTPrintf("Reply is in the form \'image property\' = \'value\'\n");
1612 CHECK_ERROR2_RET(hrc, oCloudClient,
1613 GetImageInfo(Bstr(strImageId).raw(),
1614 infoArray.asOutParam(),
1615 pProgress.asOutParam()),
1616 RTEXITCODE_FAILURE);
1617
1618 hrc = showProgress(pProgress);
1619 CHECK_PROGRESS_ERROR_RET(pProgress, ("Getting information about the cloud image failed"), RTEXITCODE_FAILURE);
1620
1621 CHECK_ERROR2_RET(hrc,
1622 infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)),
1623 RTEXITCODE_FAILURE);
1624
1625 RTPrintf("General information about the image:\n");
1626 size_t cParamNames = pStrInfoArray.size();
1627 for (size_t k = 0; k < cParamNames; k++)
1628 {
1629 Utf8Str data(pStrInfoArray[k]);
1630 RTPrintf("\t%s\n", data.c_str());
1631 }
1632
1633 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1634}
1635
1636static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1637{
1638 RT_NOREF(a);
1639 RT_NOREF(iFirst);
1640 RT_NOREF(pCommonOpts);
1641 return RTEXITCODE_SUCCESS;
1642}
1643
1644static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1645{
1646 HRESULT hrc = S_OK;
1647
1648 static const RTGETOPTDEF s_aOptions[] =
1649 {
1650 { "--id", 'i', RTGETOPT_REQ_STRING },
1651 { "help", 1001, RTGETOPT_REQ_NOTHING },
1652 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1653 };
1654 RTGETOPTSTATE GetState;
1655 RTGETOPTUNION ValueUnion;
1656 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1657 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1658 if (a->argc == iFirst)
1659 {
1660 RTPrintf("Empty command parameter list, show help.\n");
1661 printHelp(g_pStdOut);
1662 return RTEXITCODE_SUCCESS;
1663 }
1664
1665 Utf8Str strImageId;
1666
1667 int c;
1668 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1669 {
1670 switch (c)
1671 {
1672 case 'i':
1673 {
1674 if (strImageId.isNotEmpty())
1675 return errorArgument("Duplicate parameter: --id");
1676
1677 strImageId = ValueUnion.psz;
1678 if (strImageId.isEmpty())
1679 return errorArgument("Empty parameter: --id");
1680
1681 break;
1682 }
1683
1684 case 1001:
1685 case 1002:
1686 printHelp(g_pStdOut);
1687 return RTEXITCODE_SUCCESS;
1688 case VINF_GETOPT_NOT_OPTION:
1689 return errorUnknownSubcommand(ValueUnion.psz);
1690
1691 default:
1692 return errorGetOpt(c, &ValueUnion);
1693 }
1694 }
1695
1696 /* Delayed check. It allows us to print help information.*/
1697 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1698 if (FAILED(hrc))
1699 return RTEXITCODE_FAILURE;
1700
1701 if (strImageId.isEmpty())
1702 return errorArgument("Missing parameter: --id");
1703
1704
1705 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1706
1707 ComObjPtr<ICloudClient> oCloudClient;
1708 CHECK_ERROR2_RET(hrc, pCloudProfile,
1709 CreateCloudClient(oCloudClient.asOutParam()),
1710 RTEXITCODE_FAILURE);
1711 RTPrintf("Deleting cloud image with id %s...\n", strImageId.c_str());
1712
1713 ComPtr<IProgress> progress;
1714 CHECK_ERROR2_RET(hrc, oCloudClient,
1715 DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()),
1716 RTEXITCODE_FAILURE);
1717 hrc = showProgress(progress);
1718 CHECK_PROGRESS_ERROR_RET(progress, ("Deleting cloud image failed"), RTEXITCODE_FAILURE);
1719
1720 if (SUCCEEDED(hrc))
1721 RTPrintf("Cloud image with was deleted successfully\n");
1722
1723 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1724}
1725
1726static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1727{
1728 if (a->argc == iFirst)
1729 {
1730 RTPrintf("Empty command parameter list, show help.\n");
1731 printHelp(g_pStdOut);
1732 return RTEXITCODE_SUCCESS;
1733 }
1734
1735 static const RTGETOPTDEF s_aOptions[] =
1736 {
1737 { "create", 1000, RTGETOPT_REQ_NOTHING },
1738 { "export", 1001, RTGETOPT_REQ_NOTHING },
1739 { "import", 1002, RTGETOPT_REQ_NOTHING },
1740 { "info", 1003, RTGETOPT_REQ_NOTHING },
1741 { "update", 1004, RTGETOPT_REQ_NOTHING },
1742 { "delete", 1005, RTGETOPT_REQ_NOTHING },
1743 { "help", 1006, RTGETOPT_REQ_NOTHING },
1744 { "--help", 1007, RTGETOPT_REQ_NOTHING }
1745 };
1746
1747 RTGETOPTSTATE GetState;
1748 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1749 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1750
1751 int c;
1752 RTGETOPTUNION ValueUnion;
1753 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1754 {
1755 switch (c)
1756 {
1757 /* Sub-commands: */
1758 case 1000:
1759 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_CREATE);
1760 return createCloudImage(a, GetState.iNext, pCommonOpts);
1761 case 1001:
1762 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_EXPORT);
1763 return exportCloudImage(a, GetState.iNext, pCommonOpts);
1764 case 1002:
1765 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_IMPORT);
1766 return importCloudImage(a, GetState.iNext, pCommonOpts);
1767 case 1003:
1768 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_INFO);
1769 return showCloudImageInfo(a, GetState.iNext, pCommonOpts);
1770 case 1004:
1771// setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_UPDATE);
1772 return updateCloudImage(a, GetState.iNext, pCommonOpts);
1773 case 1005:
1774 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_DELETE);
1775 return deleteCloudImage(a, GetState.iNext, pCommonOpts);
1776 case 1006:
1777 case 1007:
1778 printHelp(g_pStdOut);
1779 return RTEXITCODE_SUCCESS;
1780 case VINF_GETOPT_NOT_OPTION:
1781 return errorUnknownSubcommand(ValueUnion.psz);
1782
1783 default:
1784 return errorGetOpt(c, &ValueUnion);
1785 }
1786 }
1787
1788 return errorNoSubcommand();
1789}
1790
1791#ifdef VBOX_WITH_CLOUD_NET
1792struct CloudNetworkOptions
1793{
1794 BOOL fEnable;
1795 BOOL fDisable;
1796 Bstr strNetworkId;
1797 Bstr strNetworkName;
1798};
1799typedef struct CloudNetworkOptions CLOUDNETOPT;
1800typedef CLOUDNETOPT *PCLOUDNETOPT;
1801
1802static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr<ICloudNetwork> cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts)
1803{
1804 HRESULT hrc = S_OK;
1805
1806 Bstr strProvider = pCommonOpts->provider.pszProviderName;
1807 Bstr strProfile = pCommonOpts->profile.pszProfileName;
1808
1809 if (options.fEnable)
1810 {
1811 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
1812 }
1813 if (options.fDisable)
1814 {
1815 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
1816 }
1817 if (options.strNetworkId.isNotEmpty())
1818 {
1819 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE);
1820 }
1821 if (strProvider.isNotEmpty())
1822 {
1823 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE);
1824 }
1825 if (strProfile.isNotEmpty())
1826 {
1827 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE);
1828 }
1829
1830 return RTEXITCODE_SUCCESS;
1831}
1832
1833
1834static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1835{
1836 HRESULT hrc = S_OK;
1837 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1838 if (FAILED(hrc))
1839 return RTEXITCODE_FAILURE;
1840
1841 /* Required parameters, the rest is handled in update */
1842 static const RTGETOPTDEF s_aOptions[] =
1843 {
1844 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
1845 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1846 { "--network-id", 'i', RTGETOPT_REQ_STRING },
1847 { "--name", 'n', RTGETOPT_REQ_STRING },
1848 };
1849
1850 RTGETOPTSTATE GetState;
1851 RTGETOPTUNION ValueUnion;
1852 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1853 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1854
1855 CLOUDNETOPT options;
1856 options.fEnable = FALSE;
1857 options.fDisable = FALSE;
1858
1859 int c;
1860 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1861 {
1862 switch (c)
1863 {
1864 case 'd':
1865 options.fDisable = TRUE;
1866 break;
1867 case 'e':
1868 options.fEnable = TRUE;
1869 break;
1870 case 'i':
1871 options.strNetworkId=ValueUnion.psz;
1872 break;
1873 case 'n':
1874 options.strNetworkName=ValueUnion.psz;
1875 break;
1876 case VINF_GETOPT_NOT_OPTION:
1877 return errorUnknownSubcommand(ValueUnion.psz);
1878 default:
1879 return errorGetOpt(c, &ValueUnion);
1880 }
1881 }
1882
1883 if (options.strNetworkName.isEmpty())
1884 return errorArgument("Missing --name parameter");
1885 if (options.strNetworkId.isEmpty())
1886 return errorArgument("Missing --network-id parameter");
1887
1888 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1889
1890 ComPtr<ICloudNetwork> cloudNetwork;
1891 CHECK_ERROR2_RET(hrc, pVirtualBox,
1892 CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
1893 RTEXITCODE_FAILURE);
1894
1895 /* Fill out the created network */
1896 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
1897 if (RT_SUCCESS(rc))
1898 RTPrintf("Cloud network was created successfully\n");
1899
1900 return rc;
1901}
1902
1903
1904static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1905{
1906 RT_NOREF(pCommonOpts);
1907 HRESULT hrc = S_OK;
1908 static const RTGETOPTDEF s_aOptions[] =
1909 {
1910 { "--name", 'n', RTGETOPT_REQ_STRING },
1911 };
1912 RTGETOPTSTATE GetState;
1913 RTGETOPTUNION ValueUnion;
1914 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1915 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1916
1917 Bstr strNetworkName;
1918
1919 int c;
1920 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1921 {
1922 switch (c)
1923 {
1924 case 'n':
1925 strNetworkName=ValueUnion.psz;
1926 break;
1927 case VINF_GETOPT_NOT_OPTION:
1928 return errorUnknownSubcommand(ValueUnion.psz);
1929 default:
1930 return errorGetOpt(c, &ValueUnion);
1931 }
1932 }
1933
1934 if (strNetworkName.isEmpty())
1935 return errorArgument("Missing --name parameter");
1936
1937 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1938 ComPtr<ICloudNetwork> cloudNetwork;
1939 CHECK_ERROR2_RET(hrc, pVirtualBox,
1940 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
1941 RTEXITCODE_FAILURE);
1942
1943 RTPrintf("Name: %ls\n", strNetworkName.raw());
1944 BOOL fEnabled = FALSE;
1945 cloudNetwork->COMGETTER(Enabled)(&fEnabled);
1946 RTPrintf("State: %s\n", fEnabled ? "Enabled" : "Disabled");
1947 Bstr Provider;
1948 cloudNetwork->COMGETTER(Provider)(Provider.asOutParam());
1949 RTPrintf("CloudProvider: %ls\n", Provider.raw());
1950 Bstr Profile;
1951 cloudNetwork->COMGETTER(Profile)(Profile.asOutParam());
1952 RTPrintf("CloudProfile: %ls\n", Profile.raw());
1953 Bstr NetworkId;
1954 cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam());
1955 RTPrintf("CloudNetworkId: %ls\n", NetworkId.raw());
1956 Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw());
1957 RTPrintf("VBoxNetworkName: %ls\n\n", netName.raw());
1958
1959 return RTEXITCODE_SUCCESS;
1960}
1961
1962
1963static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1964{
1965 HRESULT hrc = S_OK;
1966
1967 static const RTGETOPTDEF s_aOptions[] =
1968 {
1969 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
1970 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1971 { "--network-id", 'i', RTGETOPT_REQ_STRING },
1972 { "--name", 'n', RTGETOPT_REQ_STRING },
1973 };
1974
1975 RTGETOPTSTATE GetState;
1976 RTGETOPTUNION ValueUnion;
1977 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1978 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1979
1980 CLOUDNETOPT options;
1981 options.fEnable = FALSE;
1982 options.fDisable = FALSE;
1983
1984 int c;
1985 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1986 {
1987 switch (c)
1988 {
1989 case 'd':
1990 options.fDisable = TRUE;
1991 break;
1992 case 'e':
1993 options.fEnable = TRUE;
1994 break;
1995 case 'i':
1996 options.strNetworkId=ValueUnion.psz;
1997 break;
1998 case 'n':
1999 options.strNetworkName=ValueUnion.psz;
2000 break;
2001 case VINF_GETOPT_NOT_OPTION:
2002 return errorUnknownSubcommand(ValueUnion.psz);
2003 default:
2004 return errorGetOpt(c, &ValueUnion);
2005 }
2006 }
2007
2008 if (options.strNetworkName.isEmpty())
2009 return errorArgument("Missing --name parameter");
2010
2011 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2012 ComPtr<ICloudNetwork> cloudNetwork;
2013 CHECK_ERROR2_RET(hrc, pVirtualBox,
2014 FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2015 RTEXITCODE_FAILURE);
2016
2017 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2018 if (RT_SUCCESS(rc))
2019 RTPrintf("Cloud network %ls was updated successfully\n", options.strNetworkName.raw());
2020
2021 return rc;
2022}
2023
2024
2025static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2026{
2027 RT_NOREF(pCommonOpts);
2028 HRESULT hrc = S_OK;
2029 static const RTGETOPTDEF s_aOptions[] =
2030 {
2031 { "--name", 'n', RTGETOPT_REQ_STRING },
2032 };
2033 RTGETOPTSTATE GetState;
2034 RTGETOPTUNION ValueUnion;
2035 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2036 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2037
2038 Bstr strNetworkName;
2039
2040 int c;
2041 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2042 {
2043 switch (c)
2044 {
2045 case 'n':
2046 strNetworkName=ValueUnion.psz;
2047 break;
2048 case VINF_GETOPT_NOT_OPTION:
2049 return errorUnknownSubcommand(ValueUnion.psz);
2050 default:
2051 return errorGetOpt(c, &ValueUnion);
2052 }
2053 }
2054
2055 if (strNetworkName.isEmpty())
2056 return errorArgument("Missing --name parameter");
2057
2058 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2059 ComPtr<ICloudNetwork> cloudNetwork;
2060 CHECK_ERROR2_RET(hrc, pVirtualBox,
2061 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2062 RTEXITCODE_FAILURE);
2063
2064 CHECK_ERROR2_RET(hrc, pVirtualBox,
2065 RemoveCloudNetwork(cloudNetwork),
2066 RTEXITCODE_FAILURE);
2067
2068 if (SUCCEEDED(hrc))
2069 RTPrintf("Cloud network %ls was deleted successfully\n", strNetworkName.raw());
2070
2071 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2072}
2073
2074
2075static bool errorOccured(HRESULT hrc, const char *pszFormat, ...)
2076{
2077 if (FAILED(hrc))
2078 {
2079 va_list va;
2080 va_start(va, pszFormat);
2081 Utf8Str strError(pszFormat, va);
2082 va_end(va);
2083 RTStrmPrintf(g_pStdErr, "%s (rc=%x)\n", strError.c_str(), hrc);
2084 RTStrmFlush(g_pStdErr);
2085 return true;
2086 }
2087 return false;
2088}
2089
2090
2091static int composeTemplatePath(const char *pcszTemplate, Bstr& strFullPath)
2092{
2093 com::Utf8Str strTemplatePath;
2094 int rc = RTPathAppPrivateNoArchCxx(strTemplatePath);
2095 if (RT_SUCCESS(rc))
2096 rc = RTPathAppendCxx(strTemplatePath, "UnattendedTemplates");
2097 if (RT_SUCCESS(rc))
2098 rc = RTPathAppendCxx(strTemplatePath, pcszTemplate);
2099 if (RT_FAILURE(rc))
2100 {
2101 RTStrmPrintf(g_pStdErr, "Failed to compose path to the unattended installer script templates (%Rrc)", rc);
2102 RTStrmFlush(g_pStdErr);
2103 }
2104 else
2105 strFullPath = strTemplatePath;
2106
2107 return rc;
2108}
2109
2110/**
2111 * @returns COM status code.
2112 * @retval S_OK if url needs proxy.
2113 * @retval S_FALSE if noproxy for the URL.
2114 */
2115static HRESULT getSystemProxyForUrl(const com::Utf8Str &strUrl, Bstr &strProxy)
2116{
2117 /** @todo r=bird: LogRel is pointless here. */
2118#ifndef VBOX_WITH_PROXY_INFO
2119 RT_NOREF(strUrl, strProxy);
2120 LogRel(("CLOUD-NET: Proxy support is disabled. Using direct connection.\n"));
2121 return S_FALSE;
2122#else /* VBOX_WITH_PROXY_INFO */
2123 HRESULT hrc = E_FAIL;
2124 RTHTTP hHttp;
2125 int rc = RTHttpCreate(&hHttp);
2126 if (RT_SUCCESS(rc))
2127 {
2128 rc = RTHttpUseSystemProxySettings(hHttp);
2129 if (RT_SUCCESS(rc))
2130 {
2131 RTHTTPPROXYINFO proxy;
2132 rc = RTHttpQueryProxyInfoForUrl(hHttp, strUrl.c_str(), &proxy);
2133 if (RT_SUCCESS(rc))
2134 {
2135 const char *pcszProxyScheme = "";
2136 switch (proxy.enmProxyType)
2137 {
2138 case RTHTTPPROXYTYPE_NOPROXY:
2139 pcszProxyScheme = NULL;
2140 hrc = S_FALSE;
2141 break;
2142 case RTHTTPPROXYTYPE_HTTP:
2143 pcszProxyScheme = "http://";
2144 break;
2145 case RTHTTPPROXYTYPE_HTTPS:
2146 pcszProxyScheme = "https://";
2147 break;
2148 case RTHTTPPROXYTYPE_SOCKS4:
2149 pcszProxyScheme = "socks4://";
2150 break;
2151 case RTHTTPPROXYTYPE_SOCKS5:
2152 pcszProxyScheme = "socks://";
2153 break;
2154 case RTHTTPPROXYTYPE_INVALID:
2155 case RTHTTPPROXYTYPE_UNKNOWN:
2156 case RTHTTPPROXYTYPE_END:
2157 case RTHTTPPROXYTYPE_32BIT_HACK:
2158 break;
2159 }
2160 if (pcszProxyScheme && *pcszProxyScheme != '\0')
2161 {
2162 if (proxy.pszProxyUsername || proxy.pszProxyPassword)
2163 LogRel(("CLOUD-NET: Warning! Code doesn't yet handle proxy user or password. Sorry.\n"));
2164 if (proxy.uProxyPort != UINT32_MAX)
2165 strProxy.printf("%s%s:%d", pcszProxyScheme, proxy.pszProxyHost, proxy.uProxyPort);
2166 else
2167 strProxy.printf("%s%s", pcszProxyScheme, proxy.pszProxyHost);
2168 hrc = S_OK;
2169 }
2170 else if (pcszProxyScheme)
2171 {
2172 LogRel(("CLOUD-NET: Unknown proxy type %d. Using direct connection.\n", proxy.enmProxyType));
2173 AssertFailed();
2174 }
2175 RTHttpFreeProxyInfo(&proxy);
2176 }
2177 else
2178 LogRel(("CLOUD-NET: Failed to get proxy for %s (rc=%Rrc)\n", strUrl.c_str(), rc));
2179 }
2180 else
2181 LogRel(("CLOUD-NET: Failed to use system proxy (rc=%Rrc)\n", rc));
2182 RTHttpDestroy(hHttp);
2183 }
2184 else
2185 LogRel(("CLOUD-NET: Failed to create HTTP context (rc=%Rrc)\n", rc));
2186 return hrc;
2187#endif /* VBOX_WITH_PROXY_INFO */
2188}
2189
2190static HRESULT createLocalGatewayImage(ComPtr<IVirtualBox> virtualBox, const Bstr& aGatewayIso, const Bstr& aGuestAdditionsIso, const Bstr& aProxy)
2191{
2192 /* Check if the image already exists. */
2193 HRESULT hrc;
2194
2195 Bstr strGatewayVM = "lgw";
2196 Bstr strUser = "vbox";
2197 Bstr strPassword = "vbox";
2198
2199 Bstr strInstallerScript;
2200 Bstr strPostInstallScript;
2201
2202 if (RT_FAILURE(composeTemplatePath("lgw_ks.cfg", strInstallerScript)))
2203 return E_FAIL;
2204 if (RT_FAILURE(composeTemplatePath("lgw_postinstall.sh", strPostInstallScript)))
2205 return E_FAIL;
2206
2207 ComPtr<ISystemProperties> systemProperties;
2208 ProxyMode_T enmProxyMode;
2209 Bstr strProxy;
2210 ComPtr<IMedium> hd;
2211 Bstr defaultMachineFolder;
2212 Bstr guestAdditionsISO;
2213 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
2214 if (errorOccured(hrc, "Failed to obtain system properties."))
2215 return hrc;
2216 if (aProxy.isNotEmpty())
2217 strProxy = aProxy;
2218 else
2219 {
2220 hrc = systemProperties->COMGETTER(ProxyMode)(&enmProxyMode);
2221 if (errorOccured(hrc, "Failed to obtain proxy mode."))
2222 return hrc;
2223 switch (enmProxyMode)
2224 {
2225 case ProxyMode_NoProxy:
2226 strProxy.setNull();
2227 break;
2228 case ProxyMode_Manual:
2229 hrc = systemProperties->COMGETTER(ProxyURL)(strProxy.asOutParam());
2230 if (errorOccured(hrc, "Failed to obtain proxy URL."))
2231 return hrc;
2232 break;
2233 case ProxyMode_System:
2234 hrc = getSystemProxyForUrl("https://dl.fedoraproject.org", strProxy);
2235 if (FAILED(hrc))
2236 errorOccured(hrc, "Failed to get system proxy for https://dl.fedoraproject.org. Will use direct connection.");
2237 break;
2238 default: /* To get rid of ProxyMode_32BitHack 'warning' */
2239 AssertFailed();
2240 break;
2241 }
2242
2243 }
2244 hrc = systemProperties->COMGETTER(DefaultMachineFolder)(defaultMachineFolder.asOutParam());
2245 if (errorOccured(hrc, "Failed to obtain default machine folder."))
2246 return hrc;
2247 if (aGuestAdditionsIso.isEmpty())
2248 {
2249 hrc = systemProperties->COMGETTER(DefaultAdditionsISO)(guestAdditionsISO.asOutParam());
2250 if (errorOccured(hrc, "Failed to obtain default guest additions ISO path."))
2251 return hrc;
2252 if (guestAdditionsISO.isEmpty())
2253 {
2254 errorOccured(E_INVALIDARG, "The default guest additions ISO path is empty nor it is provided as --guest-additions-iso parameter. Cannot proceed without it.");
2255 return E_INVALIDARG;
2256 }
2257 }
2258 else
2259 guestAdditionsISO = aGuestAdditionsIso;
2260
2261 BstrFmt strGatewayImage("%ls\\gateways\\lgw.vdi", defaultMachineFolder.raw());
2262 hrc = virtualBox->OpenMedium(strGatewayImage.raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE, hd.asOutParam());
2263 /* If the image is already in place, there is nothing for us to do. */
2264 if (SUCCEEDED(hrc))
2265 {
2266 RTPrintf("Local gateway image already exists, skipping image preparation step.\n");
2267 return hrc;
2268 }
2269
2270 RTPrintf("Preparing unattended install of temporary local gateway machine from %ls...\n", aGatewayIso.raw());
2271 /* The image does not exist, let's try to open the provided ISO file. */
2272 ComPtr<IMedium> iso;
2273 hrc = virtualBox->OpenMedium(aGatewayIso.raw(), DeviceType_DVD, AccessMode_ReadOnly, FALSE, iso.asOutParam());
2274 if (errorOccured(hrc, "Failed to open %ls.", aGatewayIso.raw()))
2275 return hrc;
2276
2277 ComPtr<IMachine> machine;
2278 SafeArray<IN_BSTR> groups;
2279 groups.push_back(Bstr("/gateways").mutableRaw());
2280 hrc = virtualBox->CreateMachine(NULL, strGatewayVM.raw(), ComSafeArrayAsInParam(groups), Bstr("Oracle_64").raw(), Bstr("").raw(), machine.asOutParam());
2281 if (errorOccured(hrc, "Failed to create '%ls'.", strGatewayVM.raw()))
2282 return hrc;
2283 /* Initial configuration */
2284 hrc = machine->ApplyDefaults(NULL);
2285 if (errorOccured(hrc, "Failed to apply defaults to '%ls'.", strGatewayVM.raw()))
2286 return hrc;
2287
2288 hrc = machine->COMSETTER(CPUCount)(2);
2289 if (errorOccured(hrc, "Failed to adjust CPU count for '%ls'.", strGatewayVM.raw()))
2290 return hrc;
2291
2292 hrc = machine->COMSETTER(MemorySize)(512/*MB*/);
2293 if (errorOccured(hrc, "Failed to adjust memory size for '%ls'.", strGatewayVM.raw()))
2294 return hrc;
2295
2296 /* No need for audio -- disable it. */
2297 ComPtr<IAudioAdapter> audioAdapter;
2298 hrc = machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam());
2299 if (errorOccured(hrc, "Failed to set attachment type for the second network adapter."))
2300 return hrc;
2301
2302 hrc = audioAdapter->COMSETTER(Enabled)(FALSE);
2303 if (errorOccured(hrc, "Failed to disable the audio adapter."))
2304 return hrc;
2305 audioAdapter.setNull();
2306
2307 hrc = virtualBox->RegisterMachine(machine);
2308 if (errorOccured(hrc, "Failed to register '%ls'.", strGatewayVM.raw()))
2309 return hrc;
2310
2311 hrc = virtualBox->CreateMedium(Bstr("VDI").raw(), strGatewayImage.raw(), AccessMode_ReadWrite, DeviceType_HardDisk, hd.asOutParam());
2312 if (errorOccured(hrc, "Failed to create %ls.", strGatewayImage.raw()))
2313 return hrc;
2314
2315 ComPtr<IProgress> progress;
2316 com::SafeArray<MediumVariant_T> mediumVariant;
2317 mediumVariant.push_back(MediumVariant_Standard);
2318
2319 /* Kick off the creation of a dynamic growing disk image with the given capacity. */
2320 hrc = hd->CreateBaseStorage(8ll * 1000 * 1000 * 1000 /* 8GB */,
2321 ComSafeArrayAsInParam(mediumVariant),
2322 progress.asOutParam());
2323 if (errorOccured(hrc, "Failed to create base storage for local gateway image."))
2324 return hrc;
2325
2326 hrc = showProgress(progress);
2327 CHECK_PROGRESS_ERROR_RET(progress, ("Failed to create base storage for local gateway image."), hrc);
2328
2329 ComPtr<ISession> session;
2330 hrc = session.createInprocObject(CLSID_Session);
2331 hrc = machine->LockMachine(session, LockType_Write);
2332 if (errorOccured(hrc, "Failed to lock '%ls' for modifications.", strGatewayVM.raw()))
2333 return hrc;
2334
2335 ComPtr<IMachine> sessionMachine;
2336 hrc = session->COMGETTER(Machine)(sessionMachine.asOutParam());
2337 if (errorOccured(hrc, "Failed to obtain a mutable machine."))
2338 return hrc;
2339
2340 hrc = sessionMachine->AttachDevice(Bstr("SATA").raw(), 0, 0, DeviceType_HardDisk, hd);
2341 if (errorOccured(hrc, "Failed to attach HD to '%ls'.", strGatewayVM.raw()))
2342 return hrc;
2343
2344 hrc = sessionMachine->AttachDevice(Bstr("IDE").raw(), 0, 0, DeviceType_DVD, iso);
2345 if (errorOccured(hrc, "Failed to attach ISO to '%ls'.", strGatewayVM.raw()))
2346 return hrc;
2347
2348 /* Save settings */
2349 hrc = sessionMachine->SaveSettings();
2350 if (errorOccured(hrc, "Failed to save '%ls' settings.", strGatewayVM.raw()))
2351 return hrc;
2352 session->UnlockMachine();
2353
2354 /* Prepare unattended install */
2355 ComPtr<IUnattended> unattended;
2356 hrc = virtualBox->CreateUnattendedInstaller(unattended.asOutParam());
2357 if (errorOccured(hrc, "Failed to create unattended installer."))
2358 return hrc;
2359
2360 hrc = unattended->COMSETTER(Machine)(machine);
2361 if (errorOccured(hrc, "Failed to set machine for the unattended installer."))
2362 return hrc;
2363
2364 hrc = unattended->COMSETTER(IsoPath)(aGatewayIso.raw());
2365 if (errorOccured(hrc, "Failed to set machine for the unattended installer."))
2366 return hrc;
2367
2368 hrc = unattended->COMSETTER(User)(strUser.raw());
2369 if (errorOccured(hrc, "Failed to set user for the unattended installer."))
2370 return hrc;
2371
2372 hrc = unattended->COMSETTER(Password)(strPassword.raw());
2373 if (errorOccured(hrc, "Failed to set password for the unattended installer."))
2374 return hrc;
2375
2376 hrc = unattended->COMSETTER(FullUserName)(strUser.raw());
2377 if (errorOccured(hrc, "Failed to set full user name for the unattended installer."))
2378 return hrc;
2379
2380 hrc = unattended->COMSETTER(InstallGuestAdditions)(TRUE);
2381 if (errorOccured(hrc, "Failed to enable guest addtions for the unattended installer."))
2382 return hrc;
2383
2384 hrc = unattended->COMSETTER(AdditionsIsoPath)(guestAdditionsISO.raw());
2385 if (errorOccured(hrc, "Failed to set guest addtions ISO path for the unattended installer."))
2386 return hrc;
2387
2388 hrc = unattended->COMSETTER(ScriptTemplatePath)(strInstallerScript.raw());
2389 if (errorOccured(hrc, "Failed to set script template for the unattended installer."))
2390 return hrc;
2391
2392 hrc = unattended->COMSETTER(PostInstallScriptTemplatePath)(strPostInstallScript.raw());
2393 if (errorOccured(hrc, "Failed to set post install script template for the unattended installer."))
2394 return hrc;
2395
2396 if (strProxy.isNotEmpty())
2397 {
2398 hrc = unattended->COMSETTER(Proxy)(strProxy.raw());
2399 if (errorOccured(hrc, "Failed to set post install script template for the unattended installer."))
2400 return hrc;
2401 }
2402
2403 hrc = unattended->Prepare();
2404 if (errorOccured(hrc, "Failed to prepare unattended installation."))
2405 return hrc;
2406
2407 hrc = unattended->ConstructMedia();
2408 if (errorOccured(hrc, "Failed to construct media for unattended installation."))
2409 return hrc;
2410
2411 hrc = unattended->ReconfigureVM();
2412 if (errorOccured(hrc, "Failed to reconfigure %ls for unattended installation.", strGatewayVM.raw()))
2413 return hrc;
2414
2415#define SHOW_ATTR(a_Attr, a_szText, a_Type, a_szFmt) do { \
2416 a_Type Value; \
2417 HRESULT hrc2 = unattended->COMGETTER(a_Attr)(&Value); \
2418 if (SUCCEEDED(hrc2)) \
2419 RTPrintf(" %32s = " a_szFmt "\n", a_szText, Value); \
2420 else \
2421 RTPrintf(" %32s = failed: %Rhrc\n", a_szText, hrc2); \
2422 } while (0)
2423#define SHOW_STR_ATTR(a_Attr, a_szText) do { \
2424 Bstr bstrString; \
2425 HRESULT hrc2 = unattended->COMGETTER(a_Attr)(bstrString.asOutParam()); \
2426 if (SUCCEEDED(hrc2)) \
2427 RTPrintf(" %32s = %ls\n", a_szText, bstrString.raw()); \
2428 else \
2429 RTPrintf(" %32s = failed: %Rhrc\n", a_szText, hrc2); \
2430 } while (0)
2431
2432 SHOW_STR_ATTR(IsoPath, "isoPath");
2433 SHOW_STR_ATTR(User, "user");
2434 SHOW_STR_ATTR(Password, "password");
2435 SHOW_STR_ATTR(FullUserName, "fullUserName");
2436 SHOW_STR_ATTR(ProductKey, "productKey");
2437 SHOW_STR_ATTR(AdditionsIsoPath, "additionsIsoPath");
2438 SHOW_ATTR( InstallGuestAdditions, "installGuestAdditions", BOOL, "%RTbool");
2439 SHOW_STR_ATTR(ValidationKitIsoPath, "validationKitIsoPath");
2440 SHOW_ATTR( InstallTestExecService, "installTestExecService", BOOL, "%RTbool");
2441 SHOW_STR_ATTR(Locale, "locale");
2442 SHOW_STR_ATTR(Country, "country");
2443 SHOW_STR_ATTR(TimeZone, "timeZone");
2444 SHOW_STR_ATTR(Proxy, "proxy");
2445 SHOW_STR_ATTR(Hostname, "hostname");
2446 SHOW_STR_ATTR(PackageSelectionAdjustments, "packageSelectionAdjustments");
2447 SHOW_STR_ATTR(AuxiliaryBasePath, "auxiliaryBasePath");
2448 SHOW_ATTR( ImageIndex, "imageIndex", ULONG, "%u");
2449 SHOW_STR_ATTR(ScriptTemplatePath, "scriptTemplatePath");
2450 SHOW_STR_ATTR(PostInstallScriptTemplatePath, "postInstallScriptTemplatePath");
2451 SHOW_STR_ATTR(PostInstallCommand, "postInstallCommand");
2452 SHOW_STR_ATTR(ExtraInstallKernelParameters, "extraInstallKernelParameters");
2453 SHOW_STR_ATTR(Language, "language");
2454 SHOW_STR_ATTR(DetectedOSTypeId, "detectedOSTypeId");
2455 SHOW_STR_ATTR(DetectedOSVersion, "detectedOSVersion");
2456 SHOW_STR_ATTR(DetectedOSFlavor, "detectedOSFlavor");
2457 SHOW_STR_ATTR(DetectedOSLanguages, "detectedOSLanguages");
2458 SHOW_STR_ATTR(DetectedOSHints, "detectedOSHints");
2459
2460#undef SHOW_STR_ATTR
2461#undef SHOW_ATTR
2462
2463 /* 'unattended' is no longer needed. */
2464 unattended.setNull();
2465
2466 RTPrintf("Performing unattended install of temporary local gateway...\n");
2467
2468 hrc = machine->LaunchVMProcess(session, Bstr("gui").raw(), ComSafeArrayNullInParam(), progress.asOutParam());
2469 if (errorOccured(hrc, "Failed to launch '%ls'.", strGatewayVM.raw()))
2470 return hrc;
2471
2472 hrc = progress->WaitForCompletion(-1);
2473 if (errorOccured(hrc, "Failed to launch '%ls'.", strGatewayVM.raw()))
2474 return hrc;
2475
2476 unsigned i = 0;
2477 const char progressChars[] = { '|', '/', '-', '\\'};
2478 MachineState_T machineState;
2479 uint64_t u64Started = RTTimeMilliTS();
2480 do
2481 {
2482 RTThreadSleep(1000); /* One second */
2483 hrc = machine->COMGETTER(State)(&machineState);
2484 if (errorOccured(hrc, "Failed to get machine state."))
2485 break;
2486 RTPrintf("\r%c", progressChars[i++ % sizeof(progressChars)]);
2487 if (machineState == MachineState_Aborted)
2488 {
2489 errorOccured(E_ABORT, "Temporary local gateway VM has aborted.");
2490 return E_ABORT;
2491 }
2492 }
2493 while (machineState != MachineState_PoweredOff && RTTimeMilliTS() - u64Started < 40 * 60 * 1000);
2494
2495 if (machineState != MachineState_PoweredOff)
2496 {
2497 errorOccured(E_ABORT, "Timed out (40min) while waiting for unattended install to finish.");
2498 return E_ABORT;
2499 }
2500 /* Machine will still be immutable for a short while after powering off, let's wait a little. */
2501 RTThreadSleep(5000); /* Five seconds */
2502
2503 RTPrintf("\rDone.\n");
2504
2505 hrc = machine->LockMachine(session, LockType_Write);
2506 if (errorOccured(hrc, "Failed to lock '%ls' for modifications.", strGatewayVM.raw()))
2507 return hrc;
2508
2509 RTPrintf("Detaching local gateway image...\n");
2510 hrc = session->COMGETTER(Machine)(sessionMachine.asOutParam());
2511 if (errorOccured(hrc, "Failed to obtain a mutable machine."))
2512 return hrc;
2513
2514 hrc = sessionMachine->DetachDevice(Bstr("SATA").raw(), 0, 0);
2515 if (errorOccured(hrc, "Failed to detach HD to '%ls'.", strGatewayVM.raw()))
2516 return hrc;
2517
2518 /* Remove the image from the media registry. */
2519 hd->Close();
2520
2521 /* Save settings */
2522 hrc = sessionMachine->SaveSettings();
2523 if (errorOccured(hrc, "Failed to save '%ls' settings.", strGatewayVM.raw()))
2524 return hrc;
2525 session->UnlockMachine();
2526
2527#if 0
2528 /** @todo Unregistering the temporary VM makes the image mutable again. Find out the way around it! */
2529 RTPrintf("Unregistering temporary local gateway machine...\n");
2530 SafeIfaceArray<IMedium> media;
2531 hrc = machine->Unregister(CleanupMode_DetachAllReturnNone, ComSafeArrayAsOutParam(media));
2532 if (errorOccured(hrc, "Failed to unregister '%ls'.", strGatewayVM.raw()))
2533 return hrc;
2534 hrc = machine->DeleteConfig(ComSafeArrayAsInParam(media), progress.asOutParam());
2535 if (errorOccured(hrc, "Failed to delete config for '%ls'.", strGatewayVM.raw()))
2536 return hrc;
2537 hrc = progress->WaitForCompletion(-1);
2538 if (errorOccured(hrc, "Failed to delete config for '%ls'.", strGatewayVM.raw()))
2539 return hrc;
2540#endif
2541
2542 RTPrintf("Making local gateway image immutable...\n");
2543 hrc = virtualBox->OpenMedium(strGatewayImage.raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE, hd.asOutParam());
2544 if (errorOccured(hrc, "Failed to open '%ls'.", strGatewayImage.raw()))
2545 return hrc;
2546 hd->COMSETTER(Type)(MediumType_Immutable);
2547 if (errorOccured(hrc, "Failed to make '%ls' immutable.", strGatewayImage.raw()))
2548 return hrc;
2549
2550 return S_OK;
2551}
2552
2553
2554static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2555{
2556 RT_NOREF(pCommonOpts);
2557 HRESULT hrc = S_OK;
2558 static const RTGETOPTDEF s_aOptions[] =
2559 {
2560 { "--gateway-os-name", 'n', RTGETOPT_REQ_STRING },
2561 { "--gateway-os-version", 'v', RTGETOPT_REQ_STRING },
2562 { "--gateway-shape", 's', RTGETOPT_REQ_STRING },
2563 { "--tunnel-network-name", 't', RTGETOPT_REQ_STRING },
2564 { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING },
2565 { "--guest-additions-iso", 'a', RTGETOPT_REQ_STRING },
2566 { "--local-gateway-iso", 'l', RTGETOPT_REQ_STRING },
2567 { "--proxy", 'p', RTGETOPT_REQ_STRING }
2568 };
2569 RTGETOPTSTATE GetState;
2570 RTGETOPTUNION ValueUnion;
2571 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2572 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2573
2574 Bstr strGatewayOsName;
2575 Bstr strGatewayOsVersion;
2576 Bstr strGatewayShape;
2577 Bstr strTunnelNetworkName;
2578 Bstr strTunnelNetworkRange;
2579 Bstr strLocalGatewayIso;
2580 Bstr strGuestAdditionsIso;
2581 Bstr strProxy;
2582
2583 int c;
2584 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2585 {
2586 switch (c)
2587 {
2588 case 'n':
2589 strGatewayOsName=ValueUnion.psz;
2590 break;
2591 case 'v':
2592 strGatewayOsVersion=ValueUnion.psz;
2593 break;
2594 case 's':
2595 strGatewayShape=ValueUnion.psz;
2596 break;
2597 case 't':
2598 strTunnelNetworkName=ValueUnion.psz;
2599 break;
2600 case 'r':
2601 strTunnelNetworkRange=ValueUnion.psz;
2602 break;
2603 case 'l':
2604 strLocalGatewayIso=ValueUnion.psz;
2605 break;
2606 case 'a':
2607 strGuestAdditionsIso=ValueUnion.psz;
2608 break;
2609 case 'p':
2610 strProxy=ValueUnion.psz;
2611 break;
2612 case VINF_GETOPT_NOT_OPTION:
2613 return errorUnknownSubcommand(ValueUnion.psz);
2614 default:
2615 return errorGetOpt(c, &ValueUnion);
2616 }
2617 }
2618
2619 /* Delayed check. It allows us to print help information.*/
2620 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2621 if (FAILED(hrc))
2622 return RTEXITCODE_FAILURE;
2623
2624 if (strLocalGatewayIso.isEmpty())
2625 return errorArgument("Missing --local-gateway-iso parameter");
2626
2627 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2628
2629 hrc = createLocalGatewayImage(pVirtualBox, strLocalGatewayIso, strGuestAdditionsIso, strProxy);
2630 if (FAILED(hrc))
2631 return RTEXITCODE_FAILURE;
2632
2633 RTPrintf("Setting up tunnel network in the cloud...\n");
2634
2635 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2636
2637 ComObjPtr<ICloudClient> oCloudClient;
2638 CHECK_ERROR2_RET(hrc, pCloudProfile,
2639 CreateCloudClient(oCloudClient.asOutParam()),
2640 RTEXITCODE_FAILURE);
2641
2642 ComPtr<ICloudNetworkEnvironmentInfo> cloudNetworkEnv;
2643 ComPtr<IProgress> progress;
2644 CHECK_ERROR2_RET(hrc, oCloudClient,
2645 SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(),
2646 strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(),
2647 cloudNetworkEnv.asOutParam(), progress.asOutParam()),
2648 RTEXITCODE_FAILURE);
2649
2650 hrc = showProgress(progress);
2651 CHECK_PROGRESS_ERROR_RET(progress, ("Setting up cloud network environment failed"), RTEXITCODE_FAILURE);
2652
2653 Bstr tunnelNetworkId;
2654 hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam());
2655 RTPrintf("Cloud network environment was set up successfully. Tunnel network id is: %ls\n", tunnelNetworkId.raw());
2656
2657 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2658}
2659
2660
2661static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2662{
2663 if (a->argc < 1)
2664 return errorNoSubcommand();
2665
2666 static const RTGETOPTDEF s_aOptions[] =
2667 {
2668 { "create", 1000, RTGETOPT_REQ_NOTHING },
2669 { "info", 1001, RTGETOPT_REQ_NOTHING },
2670 { "update", 1002, RTGETOPT_REQ_NOTHING },
2671 { "delete", 1003, RTGETOPT_REQ_NOTHING },
2672 { "setup", 1004, RTGETOPT_REQ_NOTHING }
2673 };
2674
2675 RTGETOPTSTATE GetState;
2676 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2677 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2678
2679 int c;
2680 RTGETOPTUNION ValueUnion;
2681 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2682 {
2683 switch (c)
2684 {
2685 /* Sub-commands: */
2686 case 1000:
2687 return createCloudNetwork(a, GetState.iNext, pCommonOpts);
2688 case 1001:
2689 return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts);
2690 case 1002:
2691 return updateCloudNetwork(a, GetState.iNext, pCommonOpts);
2692 case 1003:
2693 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
2694 case 1004:
2695 return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts);
2696 case VINF_GETOPT_NOT_OPTION:
2697 return errorUnknownSubcommand(ValueUnion.psz);
2698
2699 default:
2700 return errorGetOpt(c, &ValueUnion);
2701 }
2702 }
2703
2704 return errorNoSubcommand();
2705}
2706#endif /* VBOX_WITH_CLOUD_NET */
2707
2708
2709RTEXITCODE handleCloud(HandlerArg *a)
2710{
2711 if (a->argc < 1)
2712 return errorNoSubcommand();
2713
2714 static const RTGETOPTDEF s_aOptions[] =
2715 {
2716 /* common options */
2717 { "--provider", 'v', RTGETOPT_REQ_STRING },
2718 { "--profile", 'f', RTGETOPT_REQ_STRING },
2719 { "list", 1000, RTGETOPT_REQ_NOTHING },
2720 { "image", 1001, RTGETOPT_REQ_NOTHING },
2721 { "instance", 1002, RTGETOPT_REQ_NOTHING },
2722 { "network", 1003, RTGETOPT_REQ_NOTHING },
2723 { "volume", 1004, RTGETOPT_REQ_NOTHING },
2724 { "object", 1005, RTGETOPT_REQ_NOTHING }
2725 };
2726
2727 RTGETOPTSTATE GetState;
2728 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
2729 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2730
2731 CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} };
2732 int c;
2733 RTGETOPTUNION ValueUnion;
2734 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2735 {
2736 switch (c)
2737 {
2738 case 'v': // --provider
2739 commonOpts.provider.pszProviderName = ValueUnion.psz;
2740 break;
2741 case 'f': // --profile
2742 commonOpts.profile.pszProfileName = ValueUnion.psz;
2743 break;
2744 /* Sub-commands: */
2745 case 1000:
2746 return handleCloudLists(a, GetState.iNext, &commonOpts);
2747 case 1001:
2748 return handleCloudImage(a, GetState.iNext, &commonOpts);
2749 case 1002:
2750 return handleCloudInstance(a, GetState.iNext, &commonOpts);
2751#ifdef VBOX_WITH_CLOUD_NET
2752 case 1003:
2753 return handleCloudNetwork(a, GetState.iNext, &commonOpts);
2754#endif /* VBOX_WITH_CLOUD_NET */
2755 case VINF_GETOPT_NOT_OPTION:
2756 return errorUnknownSubcommand(ValueUnion.psz);
2757
2758 default:
2759 return errorGetOpt(c, &ValueUnion);
2760 }
2761 }
2762
2763 return errorNoSubcommand();
2764}
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