VirtualBox

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

Last change on this file since 83432 was 83279, checked in by vboxsync, 5 years ago

added displaying help information for the cloud commands. The information is shown if there are not all needed parameters in the CLI or the one argument "help" was passed.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 77.8 KB
Line 
1/* $Id: VBoxManageCloud.cpp 83279 2020-03-13 11:47:05Z 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/uuid.h>
31#include <iprt/file.h>
32#include <VBox/log.h>
33
34#include "VBoxManage.h"
35
36#include <list>
37
38using namespace com;//at least for Bstr
39
40/**
41 * Common Cloud options.
42 */
43typedef struct
44{
45 struct {
46 const char *pszProviderName;
47 ComPtr<ICloudProvider> pCloudProvider;
48 }provider;
49 struct {
50 const char *pszProfileName;
51 ComPtr<ICloudProfile> pCloudProfile;
52 }profile;
53
54} CLOUDCOMMONOPT;
55typedef CLOUDCOMMONOPT *PCLOUDCOMMONOPT;
56
57static HRESULT checkAndSetCommonOptions(HandlerArg *a, PCLOUDCOMMONOPT pCommonOpts)
58{
59 HRESULT hrc = S_OK;
60
61 Bstr bstrProvider(pCommonOpts->provider.pszProviderName);
62 Bstr bstrProfile(pCommonOpts->profile.pszProfileName);
63
64 /* check for required options */
65 if (bstrProvider.isEmpty())
66 {
67 errorSyntax(USAGE_S_NEWCMD, "Parameter --provider is required");
68 return E_FAIL;
69 }
70 if (bstrProfile.isEmpty())
71 {
72 errorSyntax(USAGE_S_NEWCMD, "Parameter --profile is required");
73 return E_FAIL;
74 }
75
76 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
77 ComPtr<ICloudProviderManager> pCloudProviderManager;
78 CHECK_ERROR2_RET(hrc, pVirtualBox,
79 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
80 RTEXITCODE_FAILURE);
81
82 ComPtr<ICloudProvider> pCloudProvider;
83 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
84 GetProviderByShortName(bstrProvider.raw(), pCloudProvider.asOutParam()),
85 RTEXITCODE_FAILURE);
86 pCommonOpts->provider.pCloudProvider = pCloudProvider;
87
88 ComPtr<ICloudProfile> pCloudProfile;
89 CHECK_ERROR2_RET(hrc, pCloudProvider,
90 GetProfileByName(bstrProfile.raw(), pCloudProfile.asOutParam()),
91 RTEXITCODE_FAILURE);
92 pCommonOpts->profile.pCloudProfile = pCloudProfile;
93
94 return hrc;
95}
96
97
98/**
99 * List all available cloud instances for the specified cloud provider.
100 * Available cloud instance is one which state whether "running" or "stopped".
101 *
102 * @returns RTEXITCODE
103 * @param a is the list of passed arguments
104 * @param iFirst is the position of the first unparsed argument in the arguments list
105 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
106 * arguments which have been already parsed before
107 */
108static RTEXITCODE listCloudInstances(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
109{
110 static const RTGETOPTDEF s_aOptions[] =
111 {
112 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
113 { "--state", 's', RTGETOPT_REQ_STRING },
114 { "help", 1001, RTGETOPT_REQ_NOTHING },
115 { "--help", 1002, RTGETOPT_REQ_NOTHING }
116 };
117 RTGETOPTSTATE GetState;
118 RTGETOPTUNION ValueUnion;
119 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
120 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
121 if (a->argc == iFirst)
122 {
123 RTPrintf("Empty command parameter list, show help.\n");
124 printHelp(g_pStdOut);
125 return RTEXITCODE_SUCCESS;
126 }
127
128 Utf8Str strCompartmentId;
129 com::SafeArray<CloudMachineState_T> machineStates;
130
131 int c;
132 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
133 {
134 switch (c)
135 {
136 case 'c':
137 strCompartmentId = ValueUnion.psz;
138 break;
139
140 case 's':
141 {
142 const char * const pszState = ValueUnion.psz;
143
144 if (RTStrICmp(pszState, "creatingimage") == 0)
145 machineStates.push_back(CloudMachineState_CreatingImage);
146 else if (RTStrICmp(pszState, "paused") == 0) /* XXX */
147 machineStates.push_back(CloudMachineState_Stopped);
148 else if (RTStrICmp(pszState, "provisioning") == 0)
149 machineStates.push_back(CloudMachineState_Provisioning);
150 else if (RTStrICmp(pszState, "running") == 0)
151 machineStates.push_back(CloudMachineState_Running);
152 else if (RTStrICmp(pszState, "starting") == 0)
153 machineStates.push_back(CloudMachineState_Starting);
154 else if (RTStrICmp(pszState, "stopped") == 0)
155 machineStates.push_back(CloudMachineState_Stopped);
156 else if (RTStrICmp(pszState, "stopping") == 0)
157 machineStates.push_back(CloudMachineState_Stopping);
158 else if (RTStrICmp(pszState, "terminated") == 0)
159 machineStates.push_back(CloudMachineState_Terminated);
160 else if (RTStrICmp(pszState, "terminating") == 0)
161 machineStates.push_back(CloudMachineState_Terminating);
162 else
163 return errorArgument("Unknown cloud instance state \"%s\"", pszState);
164 break;
165 }
166 case 1001:
167 case 1002:
168 printHelp(g_pStdOut);
169 return RTEXITCODE_SUCCESS;
170 case VINF_GETOPT_NOT_OPTION:
171 return errorUnknownSubcommand(ValueUnion.psz);
172
173 default:
174 return errorGetOpt(c, &ValueUnion);
175 }
176 }
177
178 HRESULT hrc = S_OK;
179
180 /* Delayed check. It allows us to print help information.*/
181 hrc = checkAndSetCommonOptions(a, pCommonOpts);
182 if (FAILED(hrc))
183 return RTEXITCODE_FAILURE;
184
185 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
186
187 ComPtr<ICloudProviderManager> pCloudProviderManager;
188 CHECK_ERROR2_RET(hrc, pVirtualBox,
189 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
190 RTEXITCODE_FAILURE);
191
192 ComPtr<ICloudProvider> pCloudProvider;
193 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
194 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
195 RTEXITCODE_FAILURE);
196
197 ComPtr<ICloudProfile> pCloudProfile;
198 CHECK_ERROR2_RET(hrc, pCloudProvider,
199 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
200 RTEXITCODE_FAILURE);
201
202 if (strCompartmentId.isNotEmpty())
203 {
204 CHECK_ERROR2_RET(hrc, pCloudProfile,
205 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
206 RTEXITCODE_FAILURE);
207 }
208 else
209 {
210 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
211 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->profile.pszProfileName);
212 Bstr bStrCompartmentId;
213 CHECK_ERROR2_RET(hrc, pCloudProfile,
214 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
215 RTEXITCODE_FAILURE);
216 strCompartmentId = bStrCompartmentId;
217 if (strCompartmentId.isNotEmpty())
218 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
219 else
220 return errorSyntax(USAGE_S_NEWCMD, "Parameter --compartment-id is required");
221 }
222
223 Bstr bstrProfileName;
224 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
225
226 ComObjPtr<ICloudClient> oCloudClient;
227 CHECK_ERROR2_RET(hrc, pCloudProfile,
228 CreateCloudClient(oCloudClient.asOutParam()),
229 RTEXITCODE_FAILURE);
230
231 ComPtr<IStringArray> pVMNamesHolder;
232 ComPtr<IStringArray> pVMIdsHolder;
233 com::SafeArray<BSTR> arrayVMNames;
234 com::SafeArray<BSTR> arrayVMIds;
235 ComPtr<IProgress> pProgress;
236
237 RTPrintf("Reply is in the form \'instance name\' = \'instance id\'\n");
238
239 CHECK_ERROR2_RET(hrc, oCloudClient,
240 ListInstances(ComSafeArrayAsInParam(machineStates),
241 pVMNamesHolder.asOutParam(),
242 pVMIdsHolder.asOutParam(),
243 pProgress.asOutParam()),
244 RTEXITCODE_FAILURE);
245 showProgress(pProgress);
246 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list instances"), RTEXITCODE_FAILURE);
247
248 CHECK_ERROR2_RET(hrc,
249 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
250 RTEXITCODE_FAILURE);
251 CHECK_ERROR2_RET(hrc,
252 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
253 RTEXITCODE_FAILURE);
254
255 RTPrintf("The list of the instances for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
256 bstrProfileName.raw(), strCompartmentId.c_str());
257 size_t cIds = arrayVMIds.size();
258 size_t cNames = arrayVMNames.size();
259 for (size_t k = 0; k < cNames; k++)
260 {
261 Bstr value;
262 if (k < cIds)
263 value = arrayVMIds[k];
264 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
265 }
266
267 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
268}
269
270
271/**
272 * List all available cloud images for the specified cloud provider.
273 *
274 * @returns RTEXITCODE
275 * @param a is the list of passed arguments
276 * @param iFirst is the position of the first unparsed argument in the arguments list
277 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
278 * arguments which have been already parsed before
279 */
280static RTEXITCODE listCloudImages(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
281{
282 static const RTGETOPTDEF s_aOptions[] =
283 {
284 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
285 { "--state", 's', RTGETOPT_REQ_STRING },
286 { "help", 1001, RTGETOPT_REQ_NOTHING },
287 { "--help", 1002, RTGETOPT_REQ_NOTHING }
288 };
289 RTGETOPTSTATE GetState;
290 RTGETOPTUNION ValueUnion;
291 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
292 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
293 if (a->argc == iFirst)
294 {
295 RTPrintf("Empty command parameter list, show help.\n");
296 printHelp(g_pStdOut);
297 return RTEXITCODE_SUCCESS;
298 }
299
300 Utf8Str strCompartmentId;
301 com::SafeArray<CloudImageState_T> imageStates;
302
303 int c;
304 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
305 {
306 switch (c)
307 {
308 case 'c':
309 strCompartmentId = ValueUnion.psz;
310 break;
311
312 case 's':
313 {
314 const char * const pszState = ValueUnion.psz;
315
316 if (RTStrICmp(pszState, "available") == 0)
317 imageStates.push_back(CloudImageState_Available);
318 else if (RTStrICmp(pszState, "deleted") == 0)
319 imageStates.push_back(CloudImageState_Deleted);
320 else if (RTStrICmp(pszState, "disabled") == 0)
321 imageStates.push_back(CloudImageState_Disabled);
322 else if (RTStrICmp(pszState, "exporting") == 0)
323 imageStates.push_back(CloudImageState_Exporting);
324 else if (RTStrICmp(pszState, "importing") == 0)
325 imageStates.push_back(CloudImageState_Importing);
326 else if (RTStrICmp(pszState, "provisioning") == 0)
327 imageStates.push_back(CloudImageState_Provisioning);
328 else
329 return errorArgument("Unknown cloud image state \"%s\"", pszState);
330 break;
331 }
332 case 1001:
333 case 1002:
334 printHelp(g_pStdOut);
335 return RTEXITCODE_SUCCESS;
336 case VINF_GETOPT_NOT_OPTION:
337 return errorUnknownSubcommand(ValueUnion.psz);
338
339 default:
340 return errorGetOpt(c, &ValueUnion);
341 }
342 }
343
344
345 HRESULT hrc = S_OK;
346
347 /* Delayed check. It allows us to print help information.*/
348 hrc = checkAndSetCommonOptions(a, pCommonOpts);
349 if (FAILED(hrc))
350 return RTEXITCODE_FAILURE;
351
352 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
353
354 ComPtr<ICloudProviderManager> pCloudProviderManager;
355 CHECK_ERROR2_RET(hrc, pVirtualBox,
356 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
357 RTEXITCODE_FAILURE);
358
359 ComPtr<ICloudProvider> pCloudProvider;
360 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
361 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
362 RTEXITCODE_FAILURE);
363
364 ComPtr<ICloudProfile> pCloudProfile;
365 CHECK_ERROR2_RET(hrc, pCloudProvider,
366 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
367 RTEXITCODE_FAILURE);
368
369 if (strCompartmentId.isNotEmpty())
370 {
371 CHECK_ERROR2_RET(hrc, pCloudProfile,
372 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),\
373 RTEXITCODE_FAILURE);
374 }
375 else
376 {
377 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
378 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->profile.pszProfileName);
379 Bstr bStrCompartmentId;
380 CHECK_ERROR2_RET(hrc, pCloudProfile,
381 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
382 RTEXITCODE_FAILURE);
383 strCompartmentId = bStrCompartmentId;
384 if (strCompartmentId.isNotEmpty())
385 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
386 else
387 return errorSyntax(USAGE_S_NEWCMD, "Parameter --compartment-id is required");
388 }
389
390 Bstr bstrProfileName;
391 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
392
393 ComObjPtr<ICloudClient> oCloudClient;
394 CHECK_ERROR2_RET(hrc, pCloudProfile,
395 CreateCloudClient(oCloudClient.asOutParam()),
396 RTEXITCODE_FAILURE);
397
398 ComPtr<IStringArray> pVMNamesHolder;
399 ComPtr<IStringArray> pVMIdsHolder;
400 com::SafeArray<BSTR> arrayVMNames;
401 com::SafeArray<BSTR> arrayVMIds;
402 ComPtr<IProgress> pProgress;
403
404 RTPrintf("Reply is in the form \'image name\' = \'image id\'\n");
405 CHECK_ERROR2_RET(hrc, oCloudClient,
406 ListImages(ComSafeArrayAsInParam(imageStates),
407 pVMNamesHolder.asOutParam(),
408 pVMIdsHolder.asOutParam(),
409 pProgress.asOutParam()),
410 RTEXITCODE_FAILURE);
411 showProgress(pProgress);
412 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list images"), RTEXITCODE_FAILURE);
413
414 CHECK_ERROR2_RET(hrc,
415 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
416 RTEXITCODE_FAILURE);
417 CHECK_ERROR2_RET(hrc,
418 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
419 RTEXITCODE_FAILURE);
420
421 RTPrintf("The list of the images for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
422 bstrProfileName.raw(), strCompartmentId.c_str());
423 size_t cNames = arrayVMNames.size();
424 size_t cIds = arrayVMIds.size();
425 for (size_t k = 0; k < cNames; k++)
426 {
427 Bstr value;
428 if (k < cIds)
429 value = arrayVMIds[k];
430 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
431 }
432
433 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
434}
435
436/**
437 * General function which handles the "list" commands
438 *
439 * @returns RTEXITCODE
440 * @param a is the list of passed arguments
441 * @param iFirst is the position of the first unparsed argument in the arguments list
442 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
443 * arguments which have been already parsed before
444 */
445static RTEXITCODE handleCloudLists(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
446{
447 setCurrentCommand(HELP_CMD_CLOUDLIST);
448 setCurrentSubcommand(HELP_SCOPE_CLOUDLIST);
449 if (a->argc == iFirst)
450 {
451 RTPrintf("Empty command parameter list, show help.\n");
452 printHelp(g_pStdOut);
453 return RTEXITCODE_SUCCESS;
454 }
455
456 static const RTGETOPTDEF s_aOptions[] =
457 {
458 { "images", 1000, RTGETOPT_REQ_NOTHING },
459 { "instances", 1001, RTGETOPT_REQ_NOTHING },
460 { "networks", 1002, RTGETOPT_REQ_NOTHING },
461 { "subnets", 1003, RTGETOPT_REQ_NOTHING },
462 { "vcns", 1004, RTGETOPT_REQ_NOTHING },
463 { "objects", 1005, RTGETOPT_REQ_NOTHING },
464 { "help", 1006, RTGETOPT_REQ_NOTHING },
465 { "--help", 1007, RTGETOPT_REQ_NOTHING }
466 };
467
468// Bstr bstrProvider(pCommonOpts->provider.pszProviderName);
469// Bstr bstrProfile(pCommonOpts->profile.pszProfileName);
470//
471// /* check for required options */
472// if (bstrProvider.isEmpty())
473// return errorSyntax(USAGE_S_NEWCMD, "Parameter --provider is required");
474// if (bstrProfile.isEmpty())
475// return errorSyntax(USAGE_S_NEWCMD, "Parameter --profile is required");
476
477 RTGETOPTSTATE GetState;
478 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
479 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
480
481 int c;
482 RTGETOPTUNION ValueUnion;
483 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
484 {
485 switch (c)
486 {
487 case 1000:
488 setCurrentSubcommand(HELP_SCOPE_CLOUDLIST_IMAGES);
489 return listCloudImages(a, GetState.iNext, pCommonOpts);
490 case 1001:
491 setCurrentSubcommand(HELP_SCOPE_CLOUDLIST_INSTANCES);
492 return listCloudInstances(a, GetState.iNext, pCommonOpts);
493 case 1006:
494 case 1007:
495 printHelp(g_pStdOut);
496 return RTEXITCODE_SUCCESS;
497 case VINF_GETOPT_NOT_OPTION:
498 return errorUnknownSubcommand(ValueUnion.psz);
499
500 default:
501 return errorGetOpt(c, &ValueUnion);
502 }
503 }
504
505 return errorNoSubcommand();
506}
507
508static RTEXITCODE createCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
509{
510 HRESULT hrc = S_OK;
511
512 static const RTGETOPTDEF s_aOptions[] =
513 {
514 { "--image-id", 'i', RTGETOPT_REQ_STRING },
515 { "--boot-volume-id", 'v', RTGETOPT_REQ_STRING },
516 { "--display-name", 'n', RTGETOPT_REQ_STRING },
517 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
518 { "--shape", 's', RTGETOPT_REQ_STRING },
519 { "--domain-name", 'd', RTGETOPT_REQ_STRING },
520 { "--boot-disk-size", 'b', RTGETOPT_REQ_STRING },
521 { "--publicip", 'p', RTGETOPT_REQ_STRING },
522 { "--subnet", 't', RTGETOPT_REQ_STRING },
523 { "--privateip", 'P', RTGETOPT_REQ_STRING },
524 { "--launch", 'l', RTGETOPT_REQ_STRING },
525 { "--public-ssh-key", 'k', RTGETOPT_REQ_STRING },
526 { "help", 1001, RTGETOPT_REQ_NOTHING },
527 { "--help", 1002, RTGETOPT_REQ_NOTHING }
528 };
529 RTGETOPTSTATE GetState;
530 RTGETOPTUNION ValueUnion;
531 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
532 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
533 if (a->argc == iFirst)
534 {
535 RTPrintf("Empty command parameter list, show help.\n");
536 printHelp(g_pStdOut);
537 return RTEXITCODE_SUCCESS;
538 }
539
540 ComPtr<IAppliance> pAppliance;
541 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
542 ULONG vsdNum = 1;
543 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(1, &vsdNum), RTEXITCODE_FAILURE);
544 com::SafeIfaceArray<IVirtualSystemDescription> virtualSystemDescriptions;
545 CHECK_ERROR2_RET(hrc, pAppliance,
546 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(virtualSystemDescriptions)),
547 RTEXITCODE_FAILURE);
548 ComPtr<IVirtualSystemDescription> pVSD = virtualSystemDescriptions[0];
549
550 Utf8Str strDisplayName, strImageId, strBootVolumeId, strPublicSSHKey;
551 int c;
552 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
553 {
554 switch (c)
555 {
556 case 'i':
557 strImageId = ValueUnion.psz;
558 pVSD->AddDescription(VirtualSystemDescriptionType_CloudImageId,
559 Bstr(ValueUnion.psz).raw(), NULL);
560 break;
561
562 case 'v':
563 strBootVolumeId = ValueUnion.psz;
564 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootVolumeId,
565 Bstr(ValueUnion.psz).raw(), NULL);
566 break;
567 case 'n':
568 strDisplayName = ValueUnion.psz;
569 pVSD->AddDescription(VirtualSystemDescriptionType_Name,
570 Bstr(ValueUnion.psz).raw(), NULL);
571 break;
572 case 'm':
573 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCILaunchMode,
574 Bstr(ValueUnion.psz).raw(), NULL);
575 break;
576 case 's':
577 pVSD->AddDescription(VirtualSystemDescriptionType_CloudInstanceShape,
578 Bstr(ValueUnion.psz).raw(), NULL);
579 break;
580 case 'd':
581 pVSD->AddDescription(VirtualSystemDescriptionType_CloudDomain,
582 Bstr(ValueUnion.psz).raw(), NULL);
583 break;
584 case 'b':
585 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootDiskSize,
586 Bstr(ValueUnion.psz).raw(), NULL);
587 break;
588 case 'p':
589 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicIP,
590 Bstr(ValueUnion.psz).raw(), NULL);
591 break;
592 case 'P':
593 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPrivateIP,
594 Bstr(ValueUnion.psz).raw(), NULL);
595 break;
596 case 't':
597 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCISubnet,
598 Bstr(ValueUnion.psz).raw(), NULL);
599 break;
600 case 'l':
601 {
602 Utf8Str strLaunch(ValueUnion.psz);
603 if (strLaunch.isNotEmpty() && (strLaunch.equalsIgnoreCase("true") || strLaunch.equalsIgnoreCase("false")))
604 pVSD->AddDescription(VirtualSystemDescriptionType_CloudLaunchInstance,
605 Bstr(ValueUnion.psz).raw(), NULL);
606 break;
607 }
608 case 'k':
609 strPublicSSHKey = ValueUnion.psz;
610 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicSSHKey,
611 Bstr(ValueUnion.psz).raw(), NULL);
612 break;
613 case 1001:
614 case 1002:
615 printHelp(g_pStdOut);
616 return RTEXITCODE_SUCCESS;
617 case VINF_GETOPT_NOT_OPTION:
618 return errorUnknownSubcommand(ValueUnion.psz);
619 default:
620 return errorGetOpt(c, &ValueUnion);
621 }
622 }
623
624 /* Delayed check. It allows us to print help information.*/
625 hrc = checkAndSetCommonOptions(a, pCommonOpts);
626 if (FAILED(hrc))
627 return RTEXITCODE_FAILURE;
628
629 if (strPublicSSHKey.isEmpty())
630 RTPrintf("Warning!!! Public SSH key doesn't present in the passed arguments...\n");
631
632 if (strImageId.isNotEmpty() && strBootVolumeId.isNotEmpty())
633 return errorArgument("Parameters --image-id and --boot-volume-id are mutually exclusive. "
634 "Only one of them must be presented.");
635
636 if (strImageId.isEmpty() && strBootVolumeId.isEmpty())
637 return errorArgument("Missing parameter --image-id or --boot-volume-id. One of them must be presented.");
638
639 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
640
641 pVSD->AddDescription(VirtualSystemDescriptionType_CloudProfileName,
642 Bstr(pCommonOpts->profile.pszProfileName).raw(),
643 NULL);
644
645 ComObjPtr<ICloudClient> oCloudClient;
646 CHECK_ERROR2_RET(hrc, pCloudProfile,
647 CreateCloudClient(oCloudClient.asOutParam()),
648 RTEXITCODE_FAILURE);
649
650 ComPtr<IStringArray> infoArray;
651 com::SafeArray<BSTR> pStrInfoArray;
652 ComPtr<IProgress> pProgress;
653
654#if 0
655 /*
656 * OCI API returns an error during an instance creation if the image isn't available
657 * or in the inappropriate state. So the check can be omitted.
658 */
659 RTPrintf("Checking the cloud image with id \'%s\'...\n", strImageId.c_str());
660 CHECK_ERROR2_RET(hrc, oCloudClient,
661 GetImageInfo(Bstr(strImageId).raw(),
662 infoArray.asOutParam(),
663 pProgress.asOutParam()),
664 RTEXITCODE_FAILURE);
665
666 hrc = showProgress(pProgress);
667 CHECK_PROGRESS_ERROR_RET(pProgress, ("Checking the cloud image failed"), RTEXITCODE_FAILURE);
668
669 pProgress.setNull();
670#endif
671
672 if (strImageId.isNotEmpty())
673 RTPrintf("Creating cloud instance with name \'%s\' from the image \'%s\'...\n",
674 strDisplayName.c_str(), strImageId.c_str());
675 else
676 RTPrintf("Creating cloud instance with name \'%s\' from the boot volume \'%s\'...\n",
677 strDisplayName.c_str(), strBootVolumeId.c_str());
678
679 CHECK_ERROR2_RET(hrc, oCloudClient, LaunchVM(pVSD, pProgress.asOutParam()), RTEXITCODE_FAILURE);
680
681 hrc = showProgress(pProgress);
682 CHECK_PROGRESS_ERROR_RET(pProgress, ("Creating cloud instance failed"), RTEXITCODE_FAILURE);
683
684 if (SUCCEEDED(hrc))
685 RTPrintf("Cloud instance was created successfully\n");
686
687 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
688}
689
690static RTEXITCODE updateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
691{
692 RT_NOREF(a);
693 RT_NOREF(iFirst);
694 RT_NOREF(pCommonOpts);
695 return RTEXITCODE_SUCCESS;
696}
697
698static RTEXITCODE showCloudInstanceInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
699{
700 HRESULT hrc = S_OK;
701
702 static const RTGETOPTDEF s_aOptions[] =
703 {
704 { "--id", 'i', RTGETOPT_REQ_STRING },
705 { "help", 1001, RTGETOPT_REQ_NOTHING },
706 { "--help", 1002, RTGETOPT_REQ_NOTHING }
707 };
708 RTGETOPTSTATE GetState;
709 RTGETOPTUNION ValueUnion;
710 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
711 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
712 if (a->argc == iFirst)
713 {
714 RTPrintf("Empty command parameter list, show help.\n");
715 printHelp(g_pStdOut);
716 return RTEXITCODE_SUCCESS;
717 }
718
719 Utf8Str strInstanceId;
720
721 int c;
722 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
723 {
724 switch (c)
725 {
726 case 'i':
727 {
728 if (strInstanceId.isNotEmpty())
729 return errorArgument("Duplicate parameter: --id");
730
731 strInstanceId = ValueUnion.psz;
732 if (strInstanceId.isEmpty())
733 return errorArgument("Empty parameter: --id");
734
735 break;
736 }
737 case 1001:
738 case 1002:
739 printHelp(g_pStdOut);
740 return RTEXITCODE_SUCCESS;
741 case VINF_GETOPT_NOT_OPTION:
742 return errorUnknownSubcommand(ValueUnion.psz);
743
744 default:
745 return errorGetOpt(c, &ValueUnion);
746 }
747 }
748
749 /* Delayed check. It allows us to print help information.*/
750 hrc = checkAndSetCommonOptions(a, pCommonOpts);
751 if (FAILED(hrc))
752 return RTEXITCODE_FAILURE;
753
754 if (strInstanceId.isEmpty())
755 return errorArgument("Missing parameter: --id");
756
757 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
758
759 ComObjPtr<ICloudClient> oCloudClient;
760 CHECK_ERROR2_RET(hrc, pCloudProfile,
761 CreateCloudClient(oCloudClient.asOutParam()),
762 RTEXITCODE_FAILURE);
763 RTPrintf("Getting information about cloud instance with id %s...\n", strInstanceId.c_str());
764 RTPrintf("Reply is in the form \'setting name\' = \'value\'\n");
765
766 ComPtr<IAppliance> pAppliance;
767 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
768
769 com::SafeIfaceArray<IVirtualSystemDescription> vsdArray;
770 ULONG requestedVSDnums = 1;
771 ULONG newVSDnums = 0;
772 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(requestedVSDnums, &newVSDnums), RTEXITCODE_FAILURE);
773 if (requestedVSDnums != newVSDnums)
774 return RTEXITCODE_FAILURE;
775
776 CHECK_ERROR2_RET(hrc, pAppliance, COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(vsdArray)), RTEXITCODE_FAILURE);
777 ComPtr<IVirtualSystemDescription> instanceDescription = vsdArray[0];
778
779 ComPtr<IProgress> progress;
780 CHECK_ERROR2_RET(hrc, oCloudClient,
781 GetInstanceInfo(Bstr(strInstanceId).raw(), instanceDescription, progress.asOutParam()),
782 RTEXITCODE_FAILURE);
783
784 hrc = showProgress(progress);
785 CHECK_PROGRESS_ERROR_RET(progress, ("Getting information about cloud instance failed"), RTEXITCODE_FAILURE);
786
787 RTPrintf("Cloud instance info (provider '%s'):\n",
788 pCommonOpts->provider.pszProviderName);
789
790 struct vsdHReadable {
791 VirtualSystemDescriptionType_T vsdType;
792 Utf8Str strFound;
793 Utf8Str strNotFound;
794 };
795
796 const size_t vsdHReadableArraySize = 12;//the number of items in the vsdHReadableArray
797 vsdHReadable vsdHReadableArray[vsdHReadableArraySize] = {
798 {VirtualSystemDescriptionType_CloudDomain, "Availability domain = %ls\n", "Availability domain wasn't found\n"},
799 {VirtualSystemDescriptionType_Name, "Instance displayed name = %ls\n", "Instance displayed name wasn't found\n"},
800 {VirtualSystemDescriptionType_CloudInstanceState, "Instance state = %ls\n", "Instance state wasn't found\n"},
801 {VirtualSystemDescriptionType_CloudInstanceId, "Instance Id = %ls\n", "Instance Id wasn't found\n"},
802 {VirtualSystemDescriptionType_CloudInstanceDisplayName, "Instance name = %ls\n", "Instance name wasn't found\n"},
803 {VirtualSystemDescriptionType_CloudImageId, "Bootable image Id = %ls\n",
804 "Image Id whom the instance is booted up wasn't found\n"},
805 {VirtualSystemDescriptionType_CloudInstanceShape, "Shape of the instance = %ls\n",
806 "The shape of the instance wasn't found\n"},
807 {VirtualSystemDescriptionType_OS, "Type of guest OS = %ls\n", "Type of guest OS wasn't found\n"},
808 {VirtualSystemDescriptionType_Memory, "RAM = %ls MB\n", "Value for RAM wasn't found\n"},
809 {VirtualSystemDescriptionType_CPU, "CPUs = %ls\n", "Numbers of CPUs weren't found\n"},
810 {VirtualSystemDescriptionType_CloudPublicIP, "Instance public IP = %ls\n", "Public IP wasn't found\n"},
811 {VirtualSystemDescriptionType_Miscellaneous, "%ls\n", "Free-form tags or metadata weren't found\n"}
812 };
813
814 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
815 com::SafeArray<BSTR> aRefs;
816 com::SafeArray<BSTR> aOvfValues;
817 com::SafeArray<BSTR> aVBoxValues;
818 com::SafeArray<BSTR> aExtraConfigValues;
819
820 for (size_t i=0; i<vsdHReadableArraySize ; ++i)
821 {
822 hrc = instanceDescription->GetDescriptionByType(vsdHReadableArray[i].vsdType,
823 ComSafeArrayAsOutParam(retTypes),
824 ComSafeArrayAsOutParam(aRefs),
825 ComSafeArrayAsOutParam(aOvfValues),
826 ComSafeArrayAsOutParam(aVBoxValues),
827 ComSafeArrayAsOutParam(aExtraConfigValues));
828 if (FAILED(hrc) || aVBoxValues.size() == 0)
829 LogRel((vsdHReadableArray[i].strNotFound.c_str()));
830 else
831 {
832 LogRel(("Size is %d", aVBoxValues.size()));
833 for (size_t j = 0; j<aVBoxValues.size(); ++j)
834 {
835 RTPrintf(vsdHReadableArray[i].strFound.c_str(), aVBoxValues[j]);
836 }
837 }
838
839 retTypes.setNull();
840 aRefs.setNull();
841 aOvfValues.setNull();
842 aVBoxValues.setNull();
843 aExtraConfigValues.setNull();
844 }
845
846 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
847}
848
849static RTEXITCODE startCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
850{
851 HRESULT hrc = S_OK;
852
853 static const RTGETOPTDEF s_aOptions[] =
854 {
855 { "--id", 'i', RTGETOPT_REQ_STRING },
856 { "help", 1001, RTGETOPT_REQ_NOTHING },
857 { "--help", 1002, RTGETOPT_REQ_NOTHING }
858 };
859 RTGETOPTSTATE GetState;
860 RTGETOPTUNION ValueUnion;
861 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
862 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
863 if (a->argc == iFirst)
864 {
865 RTPrintf("Empty command parameter list, show help.\n");
866 printHelp(g_pStdOut);
867 return RTEXITCODE_SUCCESS;
868 }
869
870 Utf8Str strInstanceId;
871
872 int c;
873 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
874 {
875 switch (c)
876 {
877 case 'i':
878 {
879 if (strInstanceId.isNotEmpty())
880 return errorArgument("Duplicate parameter: --id");
881
882 strInstanceId = ValueUnion.psz;
883 if (strInstanceId.isEmpty())
884 return errorArgument("Empty parameter: --id");
885
886 break;
887 }
888 case 1001:
889 case 1002:
890 printHelp(g_pStdOut);
891 return RTEXITCODE_SUCCESS;
892 case VINF_GETOPT_NOT_OPTION:
893 return errorUnknownSubcommand(ValueUnion.psz);
894
895 default:
896 return errorGetOpt(c, &ValueUnion);
897 }
898 }
899
900 /* Delayed check. It allows us to print help information.*/
901 hrc = checkAndSetCommonOptions(a, pCommonOpts);
902 if (FAILED(hrc))
903 return RTEXITCODE_FAILURE;
904
905 if (strInstanceId.isEmpty())
906 return errorArgument("Missing parameter: --id");
907
908 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
909
910 ComObjPtr<ICloudClient> oCloudClient;
911 CHECK_ERROR2_RET(hrc, pCloudProfile,
912 CreateCloudClient(oCloudClient.asOutParam()),
913 RTEXITCODE_FAILURE);
914 RTPrintf("Starting cloud instance with id %s...\n", strInstanceId.c_str());
915
916 ComPtr<IProgress> progress;
917 CHECK_ERROR2_RET(hrc, oCloudClient,
918 StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
919 RTEXITCODE_FAILURE);
920 hrc = showProgress(progress);
921 CHECK_PROGRESS_ERROR_RET(progress, ("Starting the cloud instance failed"), RTEXITCODE_FAILURE);
922
923 if (SUCCEEDED(hrc))
924 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n",
925 strInstanceId.c_str(),
926 pCommonOpts->provider.pszProviderName,
927 pCommonOpts->profile.pszProfileName);
928
929 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
930}
931
932static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
933{
934 HRESULT hrc = S_OK;
935
936 static const RTGETOPTDEF s_aOptions[] =
937 {
938 { "--id", 'i', RTGETOPT_REQ_STRING },
939 { "help", 1001, RTGETOPT_REQ_NOTHING },
940 { "--help", 1002, RTGETOPT_REQ_NOTHING }
941 };
942 RTGETOPTSTATE GetState;
943 RTGETOPTUNION ValueUnion;
944 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
945 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
946 if (a->argc == iFirst)
947 {
948 RTPrintf("Empty command parameter list, show help.\n");
949 printHelp(g_pStdOut);
950 return RTEXITCODE_SUCCESS;
951 }
952
953 Utf8Str strInstanceId;
954
955 int c;
956 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
957 {
958 switch (c)
959 {
960 case 'i':
961 {
962 if (strInstanceId.isNotEmpty())
963 return errorArgument("Duplicate parameter: --id");
964
965 strInstanceId = ValueUnion.psz;
966 if (strInstanceId.isEmpty())
967 return errorArgument("Empty parameter: --id");
968
969 break;
970 }
971 case 1001:
972 case 1002:
973 printHelp(g_pStdOut);
974 return RTEXITCODE_SUCCESS;
975 case VINF_GETOPT_NOT_OPTION:
976 return errorUnknownSubcommand(ValueUnion.psz);
977
978 default:
979 return errorGetOpt(c, &ValueUnion);
980 }
981 }
982
983 /* Delayed check. It allows us to print help information.*/
984 hrc = checkAndSetCommonOptions(a, pCommonOpts);
985 if (FAILED(hrc))
986 return RTEXITCODE_FAILURE;
987
988 if (strInstanceId.isEmpty())
989 return errorArgument("Missing parameter: --id");
990
991 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
992
993 ComObjPtr<ICloudClient> oCloudClient;
994 CHECK_ERROR2_RET(hrc, pCloudProfile,
995 CreateCloudClient(oCloudClient.asOutParam()),
996 RTEXITCODE_FAILURE);
997 RTPrintf("Pausing cloud instance with id %s...\n", strInstanceId.c_str());
998
999 ComPtr<IProgress> progress;
1000 CHECK_ERROR2_RET(hrc, oCloudClient,
1001 PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1002 RTEXITCODE_FAILURE);
1003 hrc = showProgress(progress);
1004 CHECK_PROGRESS_ERROR_RET(progress, ("Pause the cloud instance failed"), RTEXITCODE_FAILURE);
1005
1006 if (SUCCEEDED(hrc))
1007 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n",
1008 strInstanceId.c_str(),
1009 pCommonOpts->provider.pszProviderName,
1010 pCommonOpts->profile.pszProfileName);
1011
1012 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1013}
1014
1015static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1016{
1017 HRESULT hrc = S_OK;
1018
1019 static const RTGETOPTDEF s_aOptions[] =
1020 {
1021 { "--id", 'i', RTGETOPT_REQ_STRING },
1022 { "help", 1001, RTGETOPT_REQ_NOTHING },
1023 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1024 };
1025 RTGETOPTSTATE GetState;
1026 RTGETOPTUNION ValueUnion;
1027 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1028 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1029 if (a->argc == iFirst)
1030 {
1031 RTPrintf("Empty command parameter list, show help.\n");
1032 printHelp(g_pStdOut);
1033 return RTEXITCODE_SUCCESS;
1034 }
1035
1036 Utf8Str strInstanceId;
1037
1038 int c;
1039 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1040 {
1041 switch (c)
1042 {
1043 case 'i':
1044 {
1045 if (strInstanceId.isNotEmpty())
1046 return errorArgument("Duplicate parameter: --id");
1047
1048 strInstanceId = ValueUnion.psz;
1049 if (strInstanceId.isEmpty())
1050 return errorArgument("Empty parameter: --id");
1051
1052 break;
1053 }
1054 case 1001:
1055 case 1002:
1056 printHelp(g_pStdOut);
1057 return RTEXITCODE_SUCCESS;
1058 case VINF_GETOPT_NOT_OPTION:
1059 return errorUnknownSubcommand(ValueUnion.psz);
1060
1061 default:
1062 return errorGetOpt(c, &ValueUnion);
1063 }
1064 }
1065
1066 /* Delayed check. It allows us to print help information.*/
1067 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1068 if (FAILED(hrc))
1069 return RTEXITCODE_FAILURE;
1070
1071 if (strInstanceId.isEmpty())
1072 return errorArgument("Missing parameter: --id");
1073
1074
1075 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1076
1077 ComObjPtr<ICloudClient> oCloudClient;
1078 CHECK_ERROR2_RET(hrc, pCloudProfile,
1079 CreateCloudClient(oCloudClient.asOutParam()),
1080 RTEXITCODE_FAILURE);
1081 RTPrintf("Terminating cloud instance with id %s...\n", strInstanceId.c_str());
1082
1083 ComPtr<IProgress> progress;
1084 CHECK_ERROR2_RET(hrc, oCloudClient,
1085 TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1086 RTEXITCODE_FAILURE);
1087 hrc = showProgress(progress);
1088 CHECK_PROGRESS_ERROR_RET(progress, ("Termination the cloud instance failed"), RTEXITCODE_FAILURE);
1089
1090 if (SUCCEEDED(hrc))
1091 RTPrintf("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n",
1092 strInstanceId.c_str(),
1093 pCommonOpts->provider.pszProviderName,
1094 pCommonOpts->profile.pszProfileName);
1095
1096 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1097}
1098
1099static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1100{
1101 setCurrentCommand(HELP_CMD_CLOUDINSTANCE);
1102 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE);
1103 if (a->argc == iFirst)
1104 {
1105 RTPrintf("Empty command parameter list, show help.\n");
1106 printHelp(g_pStdOut);
1107 return RTEXITCODE_SUCCESS;
1108 }
1109
1110 static const RTGETOPTDEF s_aOptions[] =
1111 {
1112 { "create", 1000, RTGETOPT_REQ_NOTHING },
1113 { "start", 1001, RTGETOPT_REQ_NOTHING },
1114 { "pause", 1002, RTGETOPT_REQ_NOTHING },
1115 { "info", 1003, RTGETOPT_REQ_NOTHING },
1116 { "update", 1004, RTGETOPT_REQ_NOTHING },
1117 { "terminate", 1005, RTGETOPT_REQ_NOTHING },
1118 { "help", 1006, RTGETOPT_REQ_NOTHING },
1119 { "--help", 1007, RTGETOPT_REQ_NOTHING }
1120 };
1121
1122 RTGETOPTSTATE GetState;
1123 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1124 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1125
1126 int c;
1127 RTGETOPTUNION ValueUnion;
1128 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1129 {
1130 switch (c)
1131 {
1132 /* Sub-commands: */
1133 case 1000:
1134 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_CREATE);
1135 return createCloudInstance(a, GetState.iNext, pCommonOpts);
1136 case 1001:
1137 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_START);
1138 return startCloudInstance(a, GetState.iNext, pCommonOpts);
1139 case 1002:
1140 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_PAUSE);
1141 return pauseCloudInstance(a, GetState.iNext, pCommonOpts);
1142 case 1003:
1143 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_INFO);
1144 return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts);
1145 case 1004:
1146// setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_UPDATE);
1147 return updateCloudInstance(a, GetState.iNext, pCommonOpts);
1148 case 1005:
1149 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_TERMINATE);
1150 return terminateCloudInstance(a, GetState.iNext, pCommonOpts);
1151 case 1006:
1152 case 1007:
1153 printHelp(g_pStdOut);
1154 return RTEXITCODE_SUCCESS;
1155 case VINF_GETOPT_NOT_OPTION:
1156 return errorUnknownSubcommand(ValueUnion.psz);
1157
1158 default:
1159 return errorGetOpt(c, &ValueUnion);
1160 }
1161 }
1162
1163 return errorNoSubcommand();
1164}
1165
1166
1167static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1168{
1169 HRESULT hrc = S_OK;
1170
1171 static const RTGETOPTDEF s_aOptions[] =
1172 {
1173 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1174 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1175 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
1176 { "--instance-id", 'i', RTGETOPT_REQ_STRING },
1177 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1178 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1179 { "help", 1001, RTGETOPT_REQ_NOTHING },
1180 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1181 };
1182 RTGETOPTSTATE GetState;
1183 RTGETOPTUNION ValueUnion;
1184 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1185 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1186 if (a->argc == iFirst)
1187 {
1188 RTPrintf("Empty command parameter list, show help.\n");
1189 printHelp(g_pStdOut);
1190 return RTEXITCODE_SUCCESS;
1191 }
1192
1193 Utf8Str strCompartmentId;
1194 Utf8Str strInstanceId;
1195 Utf8Str strDisplayName;
1196 Utf8Str strBucketName;
1197 Utf8Str strObjectName;
1198 com::SafeArray<BSTR> parameters;
1199
1200 int c;
1201 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1202 {
1203 switch (c)
1204 {
1205 case 'c':
1206 strCompartmentId=ValueUnion.psz;
1207 Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1208 break;
1209 case 'i':
1210 strInstanceId=ValueUnion.psz;
1211 Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1212 break;
1213 case 'd':
1214 strDisplayName=ValueUnion.psz;
1215 Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1216 break;
1217 case 'o':
1218 strObjectName=ValueUnion.psz;
1219 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1220 break;
1221 case 'b':
1222 strBucketName=ValueUnion.psz;
1223 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1224 break;
1225 case 'm':
1226 strBucketName=ValueUnion.psz;
1227 Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1228 break;
1229 case 1001:
1230 case 1002:
1231 printHelp(g_pStdOut);
1232 return RTEXITCODE_SUCCESS;
1233 case VINF_GETOPT_NOT_OPTION:
1234 return errorUnknownSubcommand(ValueUnion.psz);
1235 default:
1236 return errorGetOpt(c, &ValueUnion);
1237 }
1238 }
1239
1240 /* Delayed check. It allows us to print help information.*/
1241 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1242 if (FAILED(hrc))
1243 return RTEXITCODE_FAILURE;
1244
1245 if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty())
1246 return errorArgument("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one.");
1247
1248 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1249
1250 ComObjPtr<ICloudClient> oCloudClient;
1251 CHECK_ERROR2_RET(hrc, pCloudProfile,
1252 CreateCloudClient(oCloudClient.asOutParam()),
1253 RTEXITCODE_FAILURE);
1254 if (strInstanceId.isNotEmpty())
1255 RTPrintf("Creating cloud image with name \'%s\' from the instance \'%s\'...\n",
1256 strDisplayName.c_str(), strInstanceId.c_str());
1257 else
1258 RTPrintf("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n",
1259 strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str());
1260
1261 ComPtr<IProgress> progress;
1262 CHECK_ERROR2_RET(hrc, oCloudClient,
1263 CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1264 RTEXITCODE_FAILURE);
1265 hrc = showProgress(progress);
1266 CHECK_PROGRESS_ERROR_RET(progress, ("Creating cloud image failed"), RTEXITCODE_FAILURE);
1267
1268 if (SUCCEEDED(hrc))
1269 RTPrintf("Cloud image was created successfully\n");
1270
1271 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1272}
1273
1274
1275static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1276{
1277 HRESULT hrc = S_OK;
1278
1279 static const RTGETOPTDEF s_aOptions[] =
1280 {
1281 { "--id", 'i', RTGETOPT_REQ_STRING },
1282 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1283 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1284 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1285 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1286 { "help", 1001, RTGETOPT_REQ_NOTHING },
1287 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1288 };
1289 RTGETOPTSTATE GetState;
1290 RTGETOPTUNION ValueUnion;
1291 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1292 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1293 if (a->argc == iFirst)
1294 {
1295 RTPrintf("Empty command parameter list, show help.\n");
1296 printHelp(g_pStdOut);
1297 return RTEXITCODE_SUCCESS;
1298 }
1299
1300 Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */
1301 Utf8Str strBucketName;
1302 Utf8Str strObjectName;
1303 Utf8Str strDisplayName;
1304 Utf8Str strLaunchMode;
1305 com::SafeArray<BSTR> parameters;
1306
1307 int c;
1308 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1309 {
1310 switch (c)
1311 {
1312 case 'b': /* --bucket-name */
1313 {
1314 if (strBucketName.isNotEmpty())
1315 return errorArgument("Duplicate parameter: --bucket-name");
1316
1317 strBucketName = ValueUnion.psz;
1318 if (strBucketName.isEmpty())
1319 return errorArgument("Empty parameter: --bucket-name");
1320
1321 break;
1322 }
1323
1324 case 'o': /* --object-name */
1325 {
1326 if (strObjectName.isNotEmpty())
1327 return errorArgument("Duplicate parameter: --object-name");
1328
1329 strObjectName = ValueUnion.psz;
1330 if (strObjectName.isEmpty())
1331 return errorArgument("Empty parameter: --object-name");
1332
1333 break;
1334 }
1335
1336 case 'i': /* --id */
1337 {
1338 if (strImageId.isNotEmpty())
1339 return errorArgument("Duplicate parameter: --id");
1340
1341 strImageId = ValueUnion.psz;
1342 if (strImageId.isEmpty())
1343 return errorArgument("Empty parameter: --id");
1344
1345 break;
1346 }
1347
1348 case 'd': /* --display-name */
1349 {
1350 if (strDisplayName.isNotEmpty())
1351 return errorArgument("Duplicate parameter: --display-name");
1352
1353 strDisplayName = ValueUnion.psz;
1354 if (strDisplayName.isEmpty())
1355 return errorArgument("Empty parameter: --display-name");
1356
1357 break;
1358 }
1359
1360 case 'm': /* --launch-mode */
1361 {
1362 if (strLaunchMode.isNotEmpty())
1363 return errorArgument("Duplicate parameter: --launch-mode");
1364
1365 strLaunchMode = ValueUnion.psz;
1366 if (strLaunchMode.isEmpty())
1367 return errorArgument("Empty parameter: --launch-mode");
1368
1369 break;
1370 }
1371
1372 case 1001:
1373 case 1002:
1374 printHelp(g_pStdOut);
1375 return RTEXITCODE_SUCCESS;
1376
1377 case VINF_GETOPT_NOT_OPTION:
1378 return errorUnknownSubcommand(ValueUnion.psz);
1379
1380 default:
1381 return errorGetOpt(c, &ValueUnion);
1382 }
1383 }
1384
1385 /* Delayed check. It allows us to print help information.*/
1386 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1387 if (FAILED(hrc))
1388 return RTEXITCODE_FAILURE;
1389
1390 if (strImageId.isNotEmpty())
1391 BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw());
1392 else
1393 return errorArgument("Missing parameter: --id");
1394
1395 if (strBucketName.isNotEmpty())
1396 BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw());
1397 else
1398 return errorArgument("Missing parameter: --bucket-name");
1399
1400 if (strObjectName.isNotEmpty())
1401 BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw());
1402
1403 if (strDisplayName.isNotEmpty())
1404 BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw());
1405
1406 if (strLaunchMode.isNotEmpty())
1407 BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw());
1408
1409
1410 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1411
1412 ComObjPtr<ICloudClient> oCloudClient;
1413 CHECK_ERROR2_RET(hrc, pCloudProfile,
1414 CreateCloudClient(oCloudClient.asOutParam()),
1415 RTEXITCODE_FAILURE);
1416
1417 if (strObjectName.isNotEmpty())
1418 RTPrintf("Exporting image \'%s\' to the Cloud with name \'%s\'...\n",
1419 strImageId.c_str(), strObjectName.c_str());
1420 else
1421 RTPrintf("Exporting image \'%s\' to the Cloud with default name\n",
1422 strImageId.c_str());
1423
1424 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1425 SafeIfaceArray<IMedium> aImageList;
1426 CHECK_ERROR2_RET(hrc, pVirtualBox,
1427 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)),
1428 RTEXITCODE_FAILURE);
1429
1430 ComPtr<IMedium> pImage;
1431 size_t cImages = aImageList.size();
1432 bool fFound = false;
1433 for (size_t i = 0; i < cImages; ++i)
1434 {
1435 pImage = aImageList[i];
1436 Bstr bstrImageId;
1437 hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam());
1438 if (FAILED(hrc))
1439 continue;
1440
1441 com::Guid imageId(bstrImageId);
1442
1443 if (!imageId.isValid() || imageId.isZero())
1444 continue;
1445
1446 if (!strImageId.compare(imageId.toString()))
1447 {
1448 fFound = true;
1449 RTPrintf("Image %s was found\n", strImageId.c_str());
1450 break;
1451 }
1452 }
1453
1454 if (!fFound)
1455 {
1456 RTPrintf("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n");
1457 return RTEXITCODE_FAILURE;
1458 }
1459
1460 ComPtr<IProgress> progress;
1461 CHECK_ERROR2_RET(hrc, oCloudClient,
1462 ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1463 RTEXITCODE_FAILURE);
1464 hrc = showProgress(progress);
1465 CHECK_PROGRESS_ERROR_RET(progress, ("Export the image to the Cloud failed"), RTEXITCODE_FAILURE);
1466
1467 if (SUCCEEDED(hrc))
1468 RTPrintf("Export the image to the Cloud was successfull\n");
1469
1470 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1471}
1472
1473static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1474{
1475 HRESULT hrc = S_OK;
1476
1477 static const RTGETOPTDEF s_aOptions[] =
1478 {
1479 { "--id", 'i', RTGETOPT_REQ_STRING },
1480 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1481 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1482 { "help", 1001, RTGETOPT_REQ_NOTHING },
1483 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1484 };
1485 RTGETOPTSTATE GetState;
1486 RTGETOPTUNION ValueUnion;
1487 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1488 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1489 if (a->argc == iFirst)
1490 {
1491 RTPrintf("Empty command parameter list, show help.\n");
1492 printHelp(g_pStdOut);
1493 return RTEXITCODE_SUCCESS;
1494 }
1495
1496 Utf8Str strImageId;
1497 Utf8Str strCompartmentId;
1498 Utf8Str strBucketName;
1499 Utf8Str strObjectName;
1500 Utf8Str strDisplayName;
1501 com::SafeArray<BSTR> parameters;
1502
1503 int c;
1504 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1505 {
1506 switch (c)
1507 {
1508 case 'i':
1509 strImageId=ValueUnion.psz;
1510 break;
1511 case 'b':
1512 strBucketName=ValueUnion.psz;
1513 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1514 break;
1515 case 'o':
1516 strObjectName=ValueUnion.psz;
1517 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1518 break;
1519 case 1001:
1520 case 1002:
1521 printHelp(g_pStdOut);
1522 return RTEXITCODE_SUCCESS;
1523 case VINF_GETOPT_NOT_OPTION:
1524 return errorUnknownSubcommand(ValueUnion.psz);
1525 default:
1526 return errorGetOpt(c, &ValueUnion);
1527 }
1528 }
1529
1530 /* Delayed check. It allows us to print help information.*/
1531 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1532 if (FAILED(hrc))
1533 return RTEXITCODE_FAILURE;
1534
1535 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1536
1537 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1538 ComObjPtr<ICloudClient> oCloudClient;
1539 CHECK_ERROR2_RET(hrc, pCloudProfile,
1540 CreateCloudClient(oCloudClient.asOutParam()),
1541 RTEXITCODE_FAILURE);
1542 RTPrintf("Creating an object \'%s\' from the cloud image \'%s\'...\n", strObjectName.c_str(), strImageId.c_str());
1543
1544 ComPtr<IProgress> progress;
1545 CHECK_ERROR2_RET(hrc, oCloudClient,
1546 ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1547 RTEXITCODE_FAILURE);
1548 hrc = showProgress(progress);
1549 CHECK_PROGRESS_ERROR_RET(progress, ("Cloud image import failed"), RTEXITCODE_FAILURE);
1550
1551 if (SUCCEEDED(hrc))
1552 {
1553 RTPrintf("Cloud image was imported successfully. Find the downloaded object with the name %s "
1554 "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n",
1555 strObjectName.c_str());
1556 }
1557
1558 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1559}
1560
1561static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1562{
1563 HRESULT hrc = S_OK;
1564
1565 static const RTGETOPTDEF s_aOptions[] =
1566 {
1567 { "--id", 'i', RTGETOPT_REQ_STRING },
1568 { "help", 1001, RTGETOPT_REQ_NOTHING },
1569 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1570 };
1571 RTGETOPTSTATE GetState;
1572 RTGETOPTUNION ValueUnion;
1573 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1574 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1575 if (a->argc == iFirst)
1576 {
1577 RTPrintf("Empty command parameter list, show help.\n");
1578 printHelp(g_pStdOut);
1579 return RTEXITCODE_SUCCESS;
1580 }
1581
1582 Utf8Str strImageId;
1583
1584 int c;
1585 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1586 {
1587 switch (c)
1588 {
1589 case 'i':
1590 strImageId = ValueUnion.psz;
1591 break;
1592 case 1001:
1593 case 1002:
1594 printHelp(g_pStdOut);
1595 return RTEXITCODE_SUCCESS;
1596 case VINF_GETOPT_NOT_OPTION:
1597 return errorUnknownSubcommand(ValueUnion.psz);
1598 default:
1599 return errorGetOpt(c, &ValueUnion);
1600 }
1601 }
1602
1603 /* Delayed check. It allows us to print help information.*/
1604 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1605 if (FAILED(hrc))
1606 return RTEXITCODE_FAILURE;
1607
1608 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1609
1610 ComObjPtr<ICloudClient> oCloudClient;
1611 CHECK_ERROR2_RET(hrc, pCloudProfile,
1612 CreateCloudClient(oCloudClient.asOutParam()),
1613 RTEXITCODE_FAILURE);
1614 RTPrintf("Getting information about the cloud image with id \'%s\'...\n", strImageId.c_str());
1615
1616 ComPtr<IStringArray> infoArray;
1617 com::SafeArray<BSTR> pStrInfoArray;
1618 ComPtr<IProgress> pProgress;
1619
1620 RTPrintf("Reply is in the form \'image property\' = \'value\'\n");
1621 CHECK_ERROR2_RET(hrc, oCloudClient,
1622 GetImageInfo(Bstr(strImageId).raw(),
1623 infoArray.asOutParam(),
1624 pProgress.asOutParam()),
1625 RTEXITCODE_FAILURE);
1626
1627 hrc = showProgress(pProgress);
1628 CHECK_PROGRESS_ERROR_RET(pProgress, ("Getting information about the cloud image failed"), RTEXITCODE_FAILURE);
1629
1630 CHECK_ERROR2_RET(hrc,
1631 infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)),
1632 RTEXITCODE_FAILURE);
1633
1634 RTPrintf("General information about the image:\n");
1635 size_t cParamNames = pStrInfoArray.size();
1636 for (size_t k = 0; k < cParamNames; k++)
1637 {
1638 Utf8Str data(pStrInfoArray[k]);
1639 RTPrintf("\t%s\n", data.c_str());
1640 }
1641
1642 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1643}
1644
1645static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1646{
1647 RT_NOREF(a);
1648 RT_NOREF(iFirst);
1649 RT_NOREF(pCommonOpts);
1650 return RTEXITCODE_SUCCESS;
1651}
1652
1653static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1654{
1655 HRESULT hrc = S_OK;
1656
1657 static const RTGETOPTDEF s_aOptions[] =
1658 {
1659 { "--id", 'i', RTGETOPT_REQ_STRING },
1660 { "help", 1001, RTGETOPT_REQ_NOTHING },
1661 { "--help", 1002, RTGETOPT_REQ_NOTHING }
1662 };
1663 RTGETOPTSTATE GetState;
1664 RTGETOPTUNION ValueUnion;
1665 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1666 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1667 if (a->argc == iFirst)
1668 {
1669 RTPrintf("Empty command parameter list, show help.\n");
1670 printHelp(g_pStdOut);
1671 return RTEXITCODE_SUCCESS;
1672 }
1673
1674 Utf8Str strImageId;
1675
1676 int c;
1677 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1678 {
1679 switch (c)
1680 {
1681 case 'i':
1682 {
1683 if (strImageId.isNotEmpty())
1684 return errorArgument("Duplicate parameter: --id");
1685
1686 strImageId = ValueUnion.psz;
1687 if (strImageId.isEmpty())
1688 return errorArgument("Empty parameter: --id");
1689
1690 break;
1691 }
1692
1693 case 1001:
1694 case 1002:
1695 printHelp(g_pStdOut);
1696 return RTEXITCODE_SUCCESS;
1697 case VINF_GETOPT_NOT_OPTION:
1698 return errorUnknownSubcommand(ValueUnion.psz);
1699
1700 default:
1701 return errorGetOpt(c, &ValueUnion);
1702 }
1703 }
1704
1705 /* Delayed check. It allows us to print help information.*/
1706 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1707 if (FAILED(hrc))
1708 return RTEXITCODE_FAILURE;
1709
1710 if (strImageId.isEmpty())
1711 return errorArgument("Missing parameter: --id");
1712
1713
1714 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1715
1716 ComObjPtr<ICloudClient> oCloudClient;
1717 CHECK_ERROR2_RET(hrc, pCloudProfile,
1718 CreateCloudClient(oCloudClient.asOutParam()),
1719 RTEXITCODE_FAILURE);
1720 RTPrintf("Deleting cloud image with id %s...\n", strImageId.c_str());
1721
1722 ComPtr<IProgress> progress;
1723 CHECK_ERROR2_RET(hrc, oCloudClient,
1724 DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()),
1725 RTEXITCODE_FAILURE);
1726 hrc = showProgress(progress);
1727 CHECK_PROGRESS_ERROR_RET(progress, ("Deleting cloud image failed"), RTEXITCODE_FAILURE);
1728
1729 if (SUCCEEDED(hrc))
1730 RTPrintf("Cloud image with was deleted successfully\n");
1731
1732 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1733}
1734
1735static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1736{
1737 setCurrentCommand(HELP_CMD_CLOUDIMAGE);
1738 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE);
1739 if (a->argc == iFirst)
1740 {
1741 RTPrintf("Empty command parameter list, show help.\n");
1742 printHelp(g_pStdOut);
1743 return RTEXITCODE_SUCCESS;
1744 }
1745
1746 static const RTGETOPTDEF s_aOptions[] =
1747 {
1748 { "create", 1000, RTGETOPT_REQ_NOTHING },
1749 { "export", 1001, RTGETOPT_REQ_NOTHING },
1750 { "import", 1002, RTGETOPT_REQ_NOTHING },
1751 { "info", 1003, RTGETOPT_REQ_NOTHING },
1752 { "update", 1004, RTGETOPT_REQ_NOTHING },
1753 { "delete", 1005, RTGETOPT_REQ_NOTHING },
1754 { "help", 1006, RTGETOPT_REQ_NOTHING },
1755 { "--help", 1007, RTGETOPT_REQ_NOTHING }
1756 };
1757
1758 RTGETOPTSTATE GetState;
1759 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1760 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1761
1762 int c;
1763 RTGETOPTUNION ValueUnion;
1764 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1765 {
1766 switch (c)
1767 {
1768 /* Sub-commands: */
1769 case 1000:
1770 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_CREATE);
1771 return createCloudImage(a, GetState.iNext, pCommonOpts);
1772 case 1001:
1773 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_EXPORT);
1774 return exportCloudImage(a, GetState.iNext, pCommonOpts);
1775 case 1002:
1776 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_IMPORT);
1777 return importCloudImage(a, GetState.iNext, pCommonOpts);
1778 case 1003:
1779 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_INFO);
1780 return showCloudImageInfo(a, GetState.iNext, pCommonOpts);
1781 case 1004:
1782// setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_UPDATE);
1783 return updateCloudImage(a, GetState.iNext, pCommonOpts);
1784 case 1005:
1785 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_DELETE);
1786 return deleteCloudImage(a, GetState.iNext, pCommonOpts);
1787 case 1006:
1788 case 1007:
1789 printHelp(g_pStdOut);
1790 return RTEXITCODE_SUCCESS;
1791 case VINF_GETOPT_NOT_OPTION:
1792 return errorUnknownSubcommand(ValueUnion.psz);
1793
1794 default:
1795 return errorGetOpt(c, &ValueUnion);
1796 }
1797 }
1798
1799 return errorNoSubcommand();
1800}
1801
1802#ifdef VBOX_WITH_CLOUD_NET
1803struct CloudNetworkOptions
1804{
1805 BOOL fEnable;
1806 BOOL fDisable;
1807 Bstr strNetworkId;
1808 Bstr strNetworkName;
1809};
1810typedef struct CloudNetworkOptions CLOUDNETOPT;
1811typedef CLOUDNETOPT *PCLOUDNETOPT;
1812
1813static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr<ICloudNetwork> cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts)
1814{
1815 HRESULT hrc = S_OK;
1816
1817 Bstr strProvider = pCommonOpts->provider.pszProviderName;
1818 Bstr strProfile = pCommonOpts->profile.pszProfileName;
1819
1820 if (options.fEnable)
1821 {
1822 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
1823 }
1824 if (options.fDisable)
1825 {
1826 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
1827 }
1828 if (options.strNetworkId.isNotEmpty())
1829 {
1830 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE);
1831 }
1832 if (strProvider.isNotEmpty())
1833 {
1834 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE);
1835 }
1836 if (strProfile.isNotEmpty())
1837 {
1838 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE);
1839 }
1840
1841 return RTEXITCODE_SUCCESS;
1842}
1843
1844
1845static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1846{
1847 HRESULT hrc = S_OK;
1848 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1849 if (FAILED(hrc))
1850 return RTEXITCODE_FAILURE;
1851
1852 /* Required parameters, the rest is handled in update */
1853 static const RTGETOPTDEF s_aOptions[] =
1854 {
1855 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
1856 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1857 { "--network-id", 'i', RTGETOPT_REQ_STRING },
1858 { "--name", 'n', RTGETOPT_REQ_STRING },
1859 };
1860
1861 RTGETOPTSTATE GetState;
1862 RTGETOPTUNION ValueUnion;
1863 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1864 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1865
1866 CLOUDNETOPT options;
1867 options.fEnable = FALSE;
1868 options.fDisable = FALSE;
1869
1870 int c;
1871 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1872 {
1873 switch (c)
1874 {
1875 case 'd':
1876 options.fDisable = TRUE;
1877 break;
1878 case 'e':
1879 options.fEnable = TRUE;
1880 break;
1881 case 'i':
1882 options.strNetworkId=ValueUnion.psz;
1883 break;
1884 case 'n':
1885 options.strNetworkName=ValueUnion.psz;
1886 break;
1887 case VINF_GETOPT_NOT_OPTION:
1888 return errorUnknownSubcommand(ValueUnion.psz);
1889 default:
1890 return errorGetOpt(c, &ValueUnion);
1891 }
1892 }
1893
1894 if (options.strNetworkName.isEmpty())
1895 return errorArgument("Missing --name parameter");
1896 if (options.strNetworkId.isEmpty())
1897 return errorArgument("Missing --network-id parameter");
1898
1899 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1900
1901 ComPtr<ICloudNetwork> cloudNetwork;
1902 CHECK_ERROR2_RET(hrc, pVirtualBox,
1903 CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
1904 RTEXITCODE_FAILURE);
1905
1906 /* Fill out the created network */
1907 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
1908 if (RT_SUCCESS(rc))
1909 RTPrintf("Cloud network was created successfully\n");
1910
1911 return rc;
1912}
1913
1914
1915static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1916{
1917 RT_NOREF(pCommonOpts);
1918 HRESULT hrc = S_OK;
1919 static const RTGETOPTDEF s_aOptions[] =
1920 {
1921 { "--name", 'n', RTGETOPT_REQ_STRING },
1922 };
1923 RTGETOPTSTATE GetState;
1924 RTGETOPTUNION ValueUnion;
1925 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1926 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1927
1928 Bstr strNetworkName;
1929
1930 int c;
1931 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1932 {
1933 switch (c)
1934 {
1935 case 'n':
1936 strNetworkName=ValueUnion.psz;
1937 break;
1938 case VINF_GETOPT_NOT_OPTION:
1939 return errorUnknownSubcommand(ValueUnion.psz);
1940 default:
1941 return errorGetOpt(c, &ValueUnion);
1942 }
1943 }
1944
1945 if (strNetworkName.isEmpty())
1946 return errorArgument("Missing --name parameter");
1947
1948 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1949 ComPtr<ICloudNetwork> cloudNetwork;
1950 CHECK_ERROR2_RET(hrc, pVirtualBox,
1951 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
1952 RTEXITCODE_FAILURE);
1953
1954 RTPrintf("Name: %ls\n", strNetworkName.raw());
1955 BOOL fEnabled = FALSE;
1956 cloudNetwork->COMGETTER(Enabled)(&fEnabled);
1957 RTPrintf("State: %s\n", fEnabled ? "Enabled" : "Disabled");
1958 Bstr Provider;
1959 cloudNetwork->COMGETTER(Provider)(Provider.asOutParam());
1960 RTPrintf("CloudProvider: %ls\n", Provider.raw());
1961 Bstr Profile;
1962 cloudNetwork->COMGETTER(Profile)(Profile.asOutParam());
1963 RTPrintf("CloudProfile: %ls\n", Profile.raw());
1964 Bstr NetworkId;
1965 cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam());
1966 RTPrintf("CloudNetworkId: %ls\n", NetworkId.raw());
1967 Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw());
1968 RTPrintf("VBoxNetworkName: %ls\n\n", netName.raw());
1969
1970 return RTEXITCODE_SUCCESS;
1971}
1972
1973
1974static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1975{
1976 HRESULT hrc = S_OK;
1977
1978 static const RTGETOPTDEF s_aOptions[] =
1979 {
1980 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
1981 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1982 { "--network-id", 'i', RTGETOPT_REQ_STRING },
1983 { "--name", 'n', RTGETOPT_REQ_STRING },
1984 };
1985
1986 RTGETOPTSTATE GetState;
1987 RTGETOPTUNION ValueUnion;
1988 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1989 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1990
1991 CLOUDNETOPT options;
1992 options.fEnable = FALSE;
1993 options.fDisable = FALSE;
1994
1995 int c;
1996 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1997 {
1998 switch (c)
1999 {
2000 case 'd':
2001 options.fDisable = TRUE;
2002 break;
2003 case 'e':
2004 options.fEnable = TRUE;
2005 break;
2006 case 'i':
2007 options.strNetworkId=ValueUnion.psz;
2008 break;
2009 case 'n':
2010 options.strNetworkName=ValueUnion.psz;
2011 break;
2012 case VINF_GETOPT_NOT_OPTION:
2013 return errorUnknownSubcommand(ValueUnion.psz);
2014 default:
2015 return errorGetOpt(c, &ValueUnion);
2016 }
2017 }
2018
2019 if (options.strNetworkName.isEmpty())
2020 return errorArgument("Missing --name parameter");
2021
2022 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2023 ComPtr<ICloudNetwork> cloudNetwork;
2024 CHECK_ERROR2_RET(hrc, pVirtualBox,
2025 FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2026 RTEXITCODE_FAILURE);
2027
2028 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2029 if (RT_SUCCESS(rc))
2030 RTPrintf("Cloud network %ls was updated successfully\n", options.strNetworkName.raw());
2031
2032 return rc;
2033}
2034
2035
2036static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2037{
2038 RT_NOREF(pCommonOpts);
2039 HRESULT hrc = S_OK;
2040 static const RTGETOPTDEF s_aOptions[] =
2041 {
2042 { "--name", 'n', RTGETOPT_REQ_STRING },
2043 };
2044 RTGETOPTSTATE GetState;
2045 RTGETOPTUNION ValueUnion;
2046 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2047 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2048
2049 Bstr strNetworkName;
2050
2051 int c;
2052 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2053 {
2054 switch (c)
2055 {
2056 case 'n':
2057 strNetworkName=ValueUnion.psz;
2058 break;
2059 case VINF_GETOPT_NOT_OPTION:
2060 return errorUnknownSubcommand(ValueUnion.psz);
2061 default:
2062 return errorGetOpt(c, &ValueUnion);
2063 }
2064 }
2065
2066 if (strNetworkName.isEmpty())
2067 return errorArgument("Missing --name parameter");
2068
2069 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2070 ComPtr<ICloudNetwork> cloudNetwork;
2071 CHECK_ERROR2_RET(hrc, pVirtualBox,
2072 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2073 RTEXITCODE_FAILURE);
2074
2075 CHECK_ERROR2_RET(hrc, pVirtualBox,
2076 RemoveCloudNetwork(cloudNetwork),
2077 RTEXITCODE_FAILURE);
2078
2079 if (SUCCEEDED(hrc))
2080 RTPrintf("Cloud network %ls was deleted successfully\n", strNetworkName.raw());
2081
2082 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2083}
2084
2085
2086static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2087{
2088 if (a->argc < 1)
2089 return errorNoSubcommand();
2090
2091 static const RTGETOPTDEF s_aOptions[] =
2092 {
2093 { "create", 1000, RTGETOPT_REQ_NOTHING },
2094 { "info", 1001, RTGETOPT_REQ_NOTHING },
2095 { "update", 1002, RTGETOPT_REQ_NOTHING },
2096 { "delete", 1003, RTGETOPT_REQ_NOTHING }
2097 };
2098
2099 RTGETOPTSTATE GetState;
2100 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2101 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2102
2103 int c;
2104 RTGETOPTUNION ValueUnion;
2105 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2106 {
2107 switch (c)
2108 {
2109 /* Sub-commands: */
2110 case 1000:
2111 return createCloudNetwork(a, GetState.iNext, pCommonOpts);
2112 case 1001:
2113 return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts);
2114 case 1002:
2115 return updateCloudNetwork(a, GetState.iNext, pCommonOpts);
2116 case 1003:
2117 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
2118 case VINF_GETOPT_NOT_OPTION:
2119 return errorUnknownSubcommand(ValueUnion.psz);
2120
2121 default:
2122 return errorGetOpt(c, &ValueUnion);
2123 }
2124 }
2125
2126 return errorNoSubcommand();
2127}
2128#endif /* VBOX_WITH_CLOUD_NET */
2129
2130
2131RTEXITCODE handleCloud(HandlerArg *a)
2132{
2133 if (a->argc < 1)
2134 return errorNoSubcommand();
2135
2136 static const RTGETOPTDEF s_aOptions[] =
2137 {
2138 /* common options */
2139 { "--provider", 'v', RTGETOPT_REQ_STRING },
2140 { "--profile", 'f', RTGETOPT_REQ_STRING },
2141 { "list", 1000, RTGETOPT_REQ_NOTHING },
2142 { "image", 1001, RTGETOPT_REQ_NOTHING },
2143 { "instance", 1002, RTGETOPT_REQ_NOTHING },
2144 { "network", 1003, RTGETOPT_REQ_NOTHING },
2145 { "volume", 1004, RTGETOPT_REQ_NOTHING },
2146 { "object", 1005, RTGETOPT_REQ_NOTHING }
2147 };
2148
2149 RTGETOPTSTATE GetState;
2150 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
2151 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2152
2153 CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} };
2154 int c;
2155 RTGETOPTUNION ValueUnion;
2156 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2157 {
2158 switch (c)
2159 {
2160 case 'v': // --provider
2161 commonOpts.provider.pszProviderName = ValueUnion.psz;
2162 break;
2163 case 'f': // --profile
2164 commonOpts.profile.pszProfileName = ValueUnion.psz;
2165 break;
2166 /* Sub-commands: */
2167 case 1000:
2168 return handleCloudLists(a, GetState.iNext, &commonOpts);
2169 case 1001:
2170 return handleCloudImage(a, GetState.iNext, &commonOpts);
2171 case 1002:
2172 return handleCloudInstance(a, GetState.iNext, &commonOpts);
2173#ifdef VBOX_WITH_CLOUD_NET
2174 case 1003:
2175 return handleCloudNetwork(a, GetState.iNext, &commonOpts);
2176#endif /* VBOX_WITH_CLOUD_NET */
2177 case VINF_GETOPT_NOT_OPTION:
2178 return errorUnknownSubcommand(ValueUnion.psz);
2179
2180 default:
2181 return errorGetOpt(c, &ValueUnion);
2182 }
2183 }
2184
2185 return errorNoSubcommand();
2186}
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