VirtualBox

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

Last change on this file since 86708 was 86703, checked in by vboxsync, 4 years ago

the cloud commands "list instances\images" support default settings from OCI config.

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