VirtualBox

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

Last change on this file since 85550 was 85359, checked in by vboxsync, 4 years ago

OCI: (bugref:9469) Enable cloud network feature in OSE, LogRel messages and copyright fixes.

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