VirtualBox

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

Last change on this file since 89519 was 87278, checked in by vboxsync, 4 years ago

bugref:9907. Added support for cloud-init script.

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