VirtualBox

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

Last change on this file since 102100 was 102100, checked in by vboxsync, 6 months ago

scm fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.8 KB
Line 
1/* $Id: VBoxManageCloud.cpp 102100 2023-11-15 12:03:41Z vboxsync $ */
2/** @file
3 * VBoxManageCloud - The cloud related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include <VBox/com/com.h>
29#include <VBox/com/string.h>
30#include <VBox/com/Guid.h>
31#include <VBox/com/array.h>
32#include <VBox/com/ErrorInfo.h>
33#include <VBox/com/errorprint.h>
34#include <VBox/com/VirtualBox.h>
35
36#include <iprt/ctype.h>
37#include <iprt/getopt.h>
38#include <iprt/stream.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/uuid.h>
42#include <iprt/file.h>
43#include <iprt/http.h>
44#include <VBox/log.h>
45
46#include <iprt/cpp/path.h>
47
48#include "VBoxManage.h"
49
50#include <list>
51#include <vector>
52
53using namespace com;//at least for Bstr
54
55DECLARE_TRANSLATION_CONTEXT(Cloud);
56DECLARE_TRANSLATION_CONTEXT(CloudMachine);
57
58/**
59 * Common Cloud options.
60 */
61typedef struct
62{
63 struct {
64 const char *pszProviderName;
65 ComPtr<ICloudProvider> pCloudProvider;
66 }provider;
67 struct {
68 const char *pszProfileName;
69 ComPtr<ICloudProfile> pCloudProfile;
70 }profile;
71
72} CLOUDCOMMONOPT;
73typedef CLOUDCOMMONOPT *PCLOUDCOMMONOPT;
74
75static HRESULT checkAndSetCommonOptions(HandlerArg *a, PCLOUDCOMMONOPT pCommonOpts)
76{
77 HRESULT hrc = S_OK;
78
79 Bstr bstrProvider(pCommonOpts->provider.pszProviderName);
80 Bstr bstrProfile(pCommonOpts->profile.pszProfileName);
81
82 /* check for required options */
83 if (bstrProvider.isEmpty())
84 {
85 errorSyntax(Cloud::tr("Parameter --provider is required"));
86 return E_FAIL;
87 }
88 if (bstrProfile.isEmpty())
89 {
90 errorSyntax(Cloud::tr("Parameter --profile is required"));
91 return E_FAIL;
92 }
93
94 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
95 ComPtr<ICloudProviderManager> pCloudProviderManager;
96 CHECK_ERROR2_RET(hrc, pVirtualBox,
97 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
98 RTEXITCODE_FAILURE);
99
100 ComPtr<ICloudProvider> pCloudProvider;
101 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
102 GetProviderByShortName(bstrProvider.raw(), pCloudProvider.asOutParam()),
103 RTEXITCODE_FAILURE);
104 pCommonOpts->provider.pCloudProvider = pCloudProvider;
105
106 ComPtr<ICloudProfile> pCloudProfile;
107 CHECK_ERROR2_RET(hrc, pCloudProvider,
108 GetProfileByName(bstrProfile.raw(), pCloudProfile.asOutParam()),
109 RTEXITCODE_FAILURE);
110 pCommonOpts->profile.pCloudProfile = pCloudProfile;
111
112 return hrc;
113}
114
115
116/**
117 * List all available cloud instances for the specified cloud provider.
118 * Available cloud instance is one which state whether "running" or "stopped".
119 *
120 * @returns RTEXITCODE
121 * @param a is the list of passed arguments
122 * @param iFirst is the position of the first unparsed argument in the arguments list
123 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
124 * arguments which have been already parsed before
125 */
126static RTEXITCODE listCloudInstances(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
127{
128 static const RTGETOPTDEF s_aOptions[] =
129 {
130 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
131 { "--state", 's', RTGETOPT_REQ_STRING },
132 { "help", 'h', RTGETOPT_REQ_NOTHING },
133 { "--help", 'h', RTGETOPT_REQ_NOTHING }
134 };
135 RTGETOPTSTATE GetState;
136 RTGETOPTUNION ValueUnion;
137 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
138 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
139
140 Utf8Str strCompartmentId;
141 com::SafeArray<CloudMachineState_T> machineStates;
142
143 int c;
144 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
145 {
146 switch (c)
147 {
148 case 'c':
149 strCompartmentId = ValueUnion.psz;
150 break;
151
152 case 's':
153 {
154 const char * const pszState = ValueUnion.psz;
155
156 if (RTStrICmp(pszState, "creatingimage") == 0)
157 machineStates.push_back(CloudMachineState_CreatingImage);
158 else if (RTStrICmp(pszState, "paused") == 0) /* XXX */
159 machineStates.push_back(CloudMachineState_Stopped);
160 else if (RTStrICmp(pszState, "provisioning") == 0)
161 machineStates.push_back(CloudMachineState_Provisioning);
162 else if (RTStrICmp(pszState, "running") == 0)
163 machineStates.push_back(CloudMachineState_Running);
164 else if (RTStrICmp(pszState, "starting") == 0)
165 machineStates.push_back(CloudMachineState_Starting);
166 else if (RTStrICmp(pszState, "stopped") == 0)
167 machineStates.push_back(CloudMachineState_Stopped);
168 else if (RTStrICmp(pszState, "stopping") == 0)
169 machineStates.push_back(CloudMachineState_Stopping);
170 else if (RTStrICmp(pszState, "terminated") == 0)
171 machineStates.push_back(CloudMachineState_Terminated);
172 else if (RTStrICmp(pszState, "terminating") == 0)
173 machineStates.push_back(CloudMachineState_Terminating);
174 else
175 return errorArgument(Cloud::tr("Unknown cloud instance state \"%s\""), pszState);
176 break;
177 }
178 case 'h':
179 printHelp(g_pStdOut);
180 return RTEXITCODE_SUCCESS;
181 case VINF_GETOPT_NOT_OPTION:
182 return errorUnknownSubcommand(ValueUnion.psz);
183
184 default:
185 return errorGetOpt(c, &ValueUnion);
186 }
187 }
188
189 HRESULT hrc = S_OK;
190
191 /* Delayed check. It allows us to print help information.*/
192 hrc = checkAndSetCommonOptions(a, pCommonOpts);
193 if (FAILED(hrc))
194 return RTEXITCODE_FAILURE;
195
196 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
197
198 ComPtr<ICloudProviderManager> pCloudProviderManager;
199 CHECK_ERROR2_RET(hrc, pVirtualBox,
200 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
201 RTEXITCODE_FAILURE);
202
203 ComPtr<ICloudProvider> pCloudProvider;
204 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
205 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
206 RTEXITCODE_FAILURE);
207
208 ComPtr<ICloudProfile> pCloudProfile;
209 CHECK_ERROR2_RET(hrc, pCloudProvider,
210 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
211 RTEXITCODE_FAILURE);
212
213 if (strCompartmentId.isNotEmpty())
214 {
215 CHECK_ERROR2_RET(hrc, pCloudProfile,
216 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
217 RTEXITCODE_FAILURE);
218 }
219 else
220 {
221 RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n"
222 "Trying to get the compartment from the passed cloud profile \'%s\'\n"),
223 pCommonOpts->profile.pszProfileName);
224 Bstr bStrCompartmentId;
225 CHECK_ERROR2_RET(hrc, pCloudProfile,
226 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
227 RTEXITCODE_FAILURE);
228 strCompartmentId = bStrCompartmentId;
229 if (strCompartmentId.isNotEmpty())
230 RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str());
231 else
232 return errorSyntax(Cloud::tr("Parameter --compartment-id is required"));
233 }
234
235 Bstr bstrProfileName;
236 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
237
238 ComObjPtr<ICloudClient> oCloudClient;
239 CHECK_ERROR2_RET(hrc, pCloudProfile,
240 CreateCloudClient(oCloudClient.asOutParam()),
241 RTEXITCODE_FAILURE);
242
243 ComPtr<IStringArray> pVMNamesHolder;
244 ComPtr<IStringArray> pVMIdsHolder;
245 com::SafeArray<BSTR> arrayVMNames;
246 com::SafeArray<BSTR> arrayVMIds;
247 ComPtr<IProgress> pProgress;
248
249 RTPrintf(Cloud::tr("Reply is in the form \'instance name\' = \'instance id\'\n"));
250
251 CHECK_ERROR2_RET(hrc, oCloudClient,
252 ListInstances(ComSafeArrayAsInParam(machineStates),
253 pVMNamesHolder.asOutParam(),
254 pVMIdsHolder.asOutParam(),
255 pProgress.asOutParam()),
256 RTEXITCODE_FAILURE);
257 showProgress(pProgress);
258 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list instances")), RTEXITCODE_FAILURE);
259
260 CHECK_ERROR2_RET(hrc,
261 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
262 RTEXITCODE_FAILURE);
263 CHECK_ERROR2_RET(hrc,
264 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
265 RTEXITCODE_FAILURE);
266
267 RTPrintf(Cloud::tr("The list of the instances for the cloud profile \'%ls\'\nand compartment \'%s\':\n"),
268 bstrProfileName.raw(), strCompartmentId.c_str());
269 size_t cIds = arrayVMIds.size();
270 size_t cNames = arrayVMNames.size();
271 for (size_t k = 0; k < cNames; k++)
272 {
273 Bstr value;
274 if (k < cIds)
275 value = arrayVMIds[k];
276 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
277 }
278
279 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
280}
281
282
283/**
284 * List all available cloud images for the specified cloud provider.
285 *
286 * @returns RTEXITCODE
287 * @param a is the list of passed arguments
288 * @param iFirst is the position of the first unparsed argument in the arguments list
289 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
290 * arguments which have been already parsed before
291 */
292static RTEXITCODE listCloudImages(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
293{
294 static const RTGETOPTDEF s_aOptions[] =
295 {
296 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
297 { "--state", 's', RTGETOPT_REQ_STRING },
298 { "help", 'h', RTGETOPT_REQ_NOTHING },
299 { "--help", 'h', RTGETOPT_REQ_NOTHING }
300 };
301 RTGETOPTSTATE GetState;
302 RTGETOPTUNION ValueUnion;
303 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
304 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
305
306 Utf8Str strCompartmentId;
307 com::SafeArray<CloudImageState_T> imageStates;
308
309 int c;
310 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
311 {
312 switch (c)
313 {
314 case 'c':
315 strCompartmentId = ValueUnion.psz;
316 break;
317
318 case 's':
319 {
320 const char * const pszState = ValueUnion.psz;
321
322 if (RTStrICmp(pszState, "available") == 0)
323 imageStates.push_back(CloudImageState_Available);
324 else if (RTStrICmp(pszState, "deleted") == 0)
325 imageStates.push_back(CloudImageState_Deleted);
326 else if (RTStrICmp(pszState, "disabled") == 0)
327 imageStates.push_back(CloudImageState_Disabled);
328 else if (RTStrICmp(pszState, "exporting") == 0)
329 imageStates.push_back(CloudImageState_Exporting);
330 else if (RTStrICmp(pszState, "importing") == 0)
331 imageStates.push_back(CloudImageState_Importing);
332 else if (RTStrICmp(pszState, "provisioning") == 0)
333 imageStates.push_back(CloudImageState_Provisioning);
334 else
335 return errorArgument(Cloud::tr("Unknown cloud image state \"%s\""), pszState);
336 break;
337 }
338 case 'h':
339 printHelp(g_pStdOut);
340 return RTEXITCODE_SUCCESS;
341 case VINF_GETOPT_NOT_OPTION:
342 return errorUnknownSubcommand(ValueUnion.psz);
343
344 default:
345 return errorGetOpt(c, &ValueUnion);
346 }
347 }
348
349
350 HRESULT hrc = S_OK;
351
352 /* Delayed check. It allows us to print help information.*/
353 hrc = checkAndSetCommonOptions(a, pCommonOpts);
354 if (FAILED(hrc))
355 return RTEXITCODE_FAILURE;
356
357 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
358
359 ComPtr<ICloudProviderManager> pCloudProviderManager;
360 CHECK_ERROR2_RET(hrc, pVirtualBox,
361 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
362 RTEXITCODE_FAILURE);
363
364 ComPtr<ICloudProvider> pCloudProvider;
365 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
366 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
367 RTEXITCODE_FAILURE);
368
369 ComPtr<ICloudProfile> pCloudProfile;
370 CHECK_ERROR2_RET(hrc, pCloudProvider,
371 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
372 RTEXITCODE_FAILURE);
373
374 if (strCompartmentId.isNotEmpty())
375 {
376 CHECK_ERROR2_RET(hrc, pCloudProfile,
377 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
378 RTEXITCODE_FAILURE);
379 }
380 else
381 {
382 RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n"
383 "Trying to get the compartment from the passed cloud profile \'%s\'\n"),
384 pCommonOpts->profile.pszProfileName);
385 Bstr bStrCompartmentId;
386 CHECK_ERROR2_RET(hrc, pCloudProfile,
387 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
388 RTEXITCODE_FAILURE);
389 strCompartmentId = bStrCompartmentId;
390 if (strCompartmentId.isNotEmpty())
391 RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str());
392 else
393 return errorSyntax(Cloud::tr("Parameter --compartment-id is required"));
394 }
395
396 Bstr bstrProfileName;
397 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
398
399 ComObjPtr<ICloudClient> oCloudClient;
400 CHECK_ERROR2_RET(hrc, pCloudProfile,
401 CreateCloudClient(oCloudClient.asOutParam()),
402 RTEXITCODE_FAILURE);
403
404 ComPtr<IStringArray> pVMNamesHolder;
405 ComPtr<IStringArray> pVMIdsHolder;
406 com::SafeArray<BSTR> arrayVMNames;
407 com::SafeArray<BSTR> arrayVMIds;
408 ComPtr<IProgress> pProgress;
409
410 RTPrintf(Cloud::tr("Reply is in the form \'image name\' = \'image id\'\n"));
411 CHECK_ERROR2_RET(hrc, oCloudClient,
412 ListImages(ComSafeArrayAsInParam(imageStates),
413 pVMNamesHolder.asOutParam(),
414 pVMIdsHolder.asOutParam(),
415 pProgress.asOutParam()),
416 RTEXITCODE_FAILURE);
417 showProgress(pProgress);
418 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list images")), RTEXITCODE_FAILURE);
419
420 CHECK_ERROR2_RET(hrc,
421 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
422 RTEXITCODE_FAILURE);
423 CHECK_ERROR2_RET(hrc,
424 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
425 RTEXITCODE_FAILURE);
426
427 RTPrintf(Cloud::tr("The list of the images for the cloud profile \'%ls\'\nand compartment \'%s\':\n"),
428 bstrProfileName.raw(), strCompartmentId.c_str());
429 size_t cNames = arrayVMNames.size();
430 size_t cIds = arrayVMIds.size();
431 for (size_t k = 0; k < cNames; k++)
432 {
433 Bstr value;
434 if (k < cIds)
435 value = arrayVMIds[k];
436 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
437 }
438
439 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
440}
441
442
443/**
444 * List all available cloud vnic attachments for the specified cloud provider.
445 *
446 * @returns RTEXITCODE
447 * @param a is the list of passed arguments
448 * @param iFirst is the position of the first unparsed argument in the arguments list
449 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
450 * arguments which have been already parsed before
451 */
452static RTEXITCODE listCloudVnicAttachments(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
453{
454 static const RTGETOPTDEF s_aOptions[] =
455 {
456 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
457 { "--filter", 'f', RTGETOPT_REQ_STRING },/*instanceId=<id>, vnicId=<id>, domainName=<name>*/
458 { "help", 'h', RTGETOPT_REQ_NOTHING },
459 { "--help", 'h', RTGETOPT_REQ_NOTHING }
460 };
461 RTGETOPTSTATE GetState;
462 RTGETOPTUNION ValueUnion;
463 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
464 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
465
466 com::SafeArray<BSTR> parameters;
467 Utf8Str strCompartmentId;
468 Utf8Str filterList;
469 HRESULT hrc = S_OK;
470
471 int c;
472 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
473 {
474 switch (c)
475 {
476 case 'c':
477 strCompartmentId = ValueUnion.psz;
478 Bstr(Utf8Str("compartmentId=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
479 break;
480
481 case 'f':
482 filterList.append(ValueUnion.psz).append(",");
483 Bstr(Utf8Str(ValueUnion.psz)).detachTo(parameters.appendedRaw());
484 break;
485 case 'h':
486 printHelp(g_pStdOut);
487 return RTEXITCODE_SUCCESS;
488 case VINF_GETOPT_NOT_OPTION:
489 return errorUnknownSubcommand(ValueUnion.psz);
490
491 default:
492 return errorGetOpt(c, &ValueUnion);
493 }
494 }
495
496 RTPrintf(Cloud::tr("Filters: \'%s\' \n"), filterList.c_str());
497
498 /* Delayed check. It allows us to print help information.*/
499 hrc = checkAndSetCommonOptions(a, pCommonOpts);
500 if (FAILED(hrc))
501 return RTEXITCODE_FAILURE;
502
503 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
504
505 ComPtr<ICloudProviderManager> pCloudProviderManager;
506 CHECK_ERROR2_RET(hrc, pVirtualBox,
507 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
508 RTEXITCODE_FAILURE);
509
510 ComPtr<ICloudProvider> pCloudProvider;
511 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
512 GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()),
513 RTEXITCODE_FAILURE);
514
515 ComPtr<ICloudProfile> pCloudProfile;
516 CHECK_ERROR2_RET(hrc, pCloudProvider,
517 GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()),
518 RTEXITCODE_FAILURE);
519
520 if (strCompartmentId.isNotEmpty())
521 {
522 CHECK_ERROR2_RET(hrc, pCloudProfile,
523 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
524 RTEXITCODE_FAILURE);
525 }
526 else
527 {
528 RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n"
529 "Trying to get the compartment from the passed cloud profile \'%s\'\n"), pCommonOpts->profile.pszProfileName);
530 Bstr bStrCompartmentId;
531 CHECK_ERROR2_RET(hrc, pCloudProfile,
532 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
533 RTEXITCODE_FAILURE);
534 strCompartmentId = bStrCompartmentId;
535 if (strCompartmentId.isNotEmpty())
536 RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str());
537 else
538 return errorArgument(Cloud::tr("Parameter --compartment-id is required."));
539 }
540
541 Bstr bstrProfileName;
542 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
543
544 ComObjPtr<ICloudClient> oCloudClient;
545 CHECK_ERROR2_RET(hrc, pCloudProfile,
546 CreateCloudClient(oCloudClient.asOutParam()),
547 RTEXITCODE_FAILURE);
548
549 ComPtr<IStringArray> pVnicAttachmentIdsHolder;
550 ComPtr<IStringArray> pVnicIdsHolder;
551 com::SafeArray<BSTR> arrayVnicAttachmentIds;
552 com::SafeArray<BSTR> arrayVnicIds;
553 ComPtr<IProgress> pProgress;
554
555 RTPrintf(Cloud::tr("Reply is in the form \'Vnic attachment <id>\': \n\t \'Vnic <id>\'\n"));
556 CHECK_ERROR2_RET(hrc, oCloudClient,
557 ListVnicAttachments(ComSafeArrayAsInParam(parameters),
558 pVnicAttachmentIdsHolder.asOutParam(),
559 pVnicIdsHolder.asOutParam(),
560 pProgress.asOutParam()),
561 RTEXITCODE_FAILURE);
562 showProgress(pProgress);
563 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list Vnic attachments")), RTEXITCODE_FAILURE);
564
565 CHECK_ERROR2_RET(hrc,
566 pVnicAttachmentIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVnicAttachmentIds)),
567 RTEXITCODE_FAILURE);
568 CHECK_ERROR2_RET(hrc,
569 pVnicIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVnicIds)),
570 RTEXITCODE_FAILURE);
571
572 RTPrintf(Cloud::tr("The list of the Vnic attachments:\n"));
573 size_t cVnicAttchIds = arrayVnicAttachmentIds.size();
574 size_t cVnicIds = arrayVnicIds.size();
575
576 if (cVnicAttchIds == 0)
577 RTPrintf(Cloud::tr("\tEmpty\n"));
578 else
579 {
580 Bstr value;
581 for (size_t k = 0; k < cVnicAttchIds; k++)
582 {
583 if (k < cVnicIds)
584 value = arrayVnicIds[k];
585 RTPrintf(Cloud::tr("Vnic attachment id [%ls]:\n\t Vnic id - %ls\n"), arrayVnicAttachmentIds[k], value.raw());
586 }
587 }
588
589 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
590}
591
592
593/**
594 * General function which handles the "list" commands
595 *
596 * @returns RTEXITCODE
597 * @param a is the list of passed arguments
598 * @param iFirst is the position of the first unparsed argument in the arguments list
599 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
600 * arguments which have been already parsed before
601 */
602static RTEXITCODE handleCloudLists(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
603{
604 enum
605 {
606 kCloudListIota = 1000,
607 kCloudList_Images,
608 kCloudList_Instances,
609 kCloudList_Machines,
610 kCloudList_Networks,
611 kCloudList_Objects,
612 kCloudList_Subnets,
613 kCloudList_Vcns,
614 kCloudList_VnicAttachments,
615 };
616
617 static const RTGETOPTDEF s_aOptions[] =
618 {
619 { "images", kCloudList_Images, RTGETOPT_REQ_NOTHING },
620 { "instances", kCloudList_Instances, RTGETOPT_REQ_NOTHING },
621 { "machines", kCloudList_Machines, RTGETOPT_REQ_NOTHING },
622 { "networks", kCloudList_Networks, RTGETOPT_REQ_NOTHING },
623 { "objects", kCloudList_Objects, RTGETOPT_REQ_NOTHING },
624 { "subnets", kCloudList_Subnets, RTGETOPT_REQ_NOTHING },
625 { "vcns", kCloudList_Vcns, RTGETOPT_REQ_NOTHING },
626 { "vms", kCloudList_Machines, RTGETOPT_REQ_NOTHING },
627 { "vnicattachments", kCloudList_VnicAttachments, RTGETOPT_REQ_NOTHING },
628
629 { "help", 'h', RTGETOPT_REQ_NOTHING },
630 { "-?", 'h', RTGETOPT_REQ_NOTHING },
631 { "-help", 'h', RTGETOPT_REQ_NOTHING },
632 { "--help", 'h', RTGETOPT_REQ_NOTHING },
633 };
634
635 if (a->argc == iFirst)
636 {
637 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
638 printHelp(g_pStdOut);
639 return RTEXITCODE_SUCCESS;
640 }
641
642 RTGETOPTSTATE GetState;
643 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
644 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
645
646 int c;
647 RTGETOPTUNION ValueUnion;
648 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
649 {
650 switch (c)
651 {
652 case kCloudList_Images:
653 setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_IMAGES);
654 return listCloudImages(a, GetState.iNext, pCommonOpts);
655
656 case kCloudList_Instances:
657 setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_INSTANCES);
658 return listCloudInstances(a, GetState.iNext, pCommonOpts);
659 case kCloudList_Machines:
660 return listCloudMachines(a, GetState.iNext,
661 pCommonOpts->provider.pszProviderName,
662 pCommonOpts->profile.pszProfileName);
663
664 case kCloudList_VnicAttachments:
665 setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_VNICATTACHMENTS);
666 return listCloudVnicAttachments(a, GetState.iNext, pCommonOpts);
667
668 case 'h':
669 printHelp(g_pStdOut);
670 return RTEXITCODE_SUCCESS;
671
672 case VINF_GETOPT_NOT_OPTION:
673 return errorUnknownSubcommand(ValueUnion.psz);
674
675 default:
676 return errorGetOpt(c, &ValueUnion);
677 }
678 }
679
680 return errorNoSubcommand();
681}
682
683
684static RTEXITCODE createCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
685{
686 HRESULT hrc = S_OK;
687
688 enum
689 {
690 kInstanceIota = 1000,
691 kInstance_ShapeCpu,
692 kInstance_ShapeMemory,
693 };
694
695 static const RTGETOPTDEF s_aOptions[] =
696 {
697 { "--image-id", 'i', RTGETOPT_REQ_STRING },
698 { "--boot-volume-id", 'v', RTGETOPT_REQ_STRING },
699 { "--display-name", 'n', RTGETOPT_REQ_STRING },
700 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
701 { "--shape", 's', RTGETOPT_REQ_STRING },
702 { "--shape-cpus", kInstance_ShapeCpu, RTGETOPT_REQ_UINT32 },
703 { "--shape-memory", kInstance_ShapeMemory, RTGETOPT_REQ_UINT32 },
704 { "--domain-name", 'd', RTGETOPT_REQ_STRING },
705 { "--boot-disk-size", 'b', RTGETOPT_REQ_STRING },
706 { "--publicip", 'p', RTGETOPT_REQ_STRING },
707 { "--subnet", 't', RTGETOPT_REQ_STRING },
708 { "--privateip", 'P', RTGETOPT_REQ_STRING },
709 { "--launch", 'l', RTGETOPT_REQ_STRING },
710 { "--public-ssh-key", 'k', RTGETOPT_REQ_STRING },
711 { "--cloud-init-script-path", 'c', RTGETOPT_REQ_STRING },
712 { "help", 'h', RTGETOPT_REQ_NOTHING },
713 { "--help", 'h', RTGETOPT_REQ_NOTHING }
714 };
715 RTGETOPTSTATE GetState;
716 RTGETOPTUNION ValueUnion;
717 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
718 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
719 if (a->argc == iFirst)
720 {
721 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
722 printHelp(g_pStdOut);
723 return RTEXITCODE_SUCCESS;
724 }
725
726 ComPtr<IAppliance> pAppliance;
727 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
728 ULONG vsdNum = 1;
729 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(1, &vsdNum), RTEXITCODE_FAILURE);
730 com::SafeIfaceArray<IVirtualSystemDescription> virtualSystemDescriptions;
731 CHECK_ERROR2_RET(hrc, pAppliance,
732 COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(virtualSystemDescriptions)),
733 RTEXITCODE_FAILURE);
734 ComPtr<IVirtualSystemDescription> pVSD = virtualSystemDescriptions[0];
735
736 Utf8Str strDisplayName, strImageId, strBootVolumeId, strPublicSSHKey;
737 int c;
738 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
739 {
740 switch (c)
741 {
742 case 'i':
743 strImageId = ValueUnion.psz;
744 pVSD->AddDescription(VirtualSystemDescriptionType_CloudImageId,
745 Bstr(ValueUnion.psz).raw(), NULL);
746 break;
747
748 case 'v':
749 strBootVolumeId = ValueUnion.psz;
750 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootVolumeId,
751 Bstr(ValueUnion.psz).raw(), NULL);
752 break;
753 case 'n':
754 strDisplayName = ValueUnion.psz;
755 pVSD->AddDescription(VirtualSystemDescriptionType_Name,
756 Bstr(ValueUnion.psz).raw(), NULL);
757 break;
758 case 'm':
759 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCILaunchMode,
760 Bstr(ValueUnion.psz).raw(), NULL);
761 break;
762
763 case 's':
764 pVSD->AddDescription(VirtualSystemDescriptionType_CloudInstanceShape,
765 Bstr(ValueUnion.psz).raw(), NULL);
766 break;
767
768 case kInstance_ShapeCpu:
769 pVSD->AddDescription(VirtualSystemDescriptionType_CloudShapeCpus,
770 BstrFmt("%RI32", ValueUnion.u32).raw(), NULL);
771 break;
772
773 case kInstance_ShapeMemory:
774 pVSD->AddDescription(VirtualSystemDescriptionType_CloudShapeMemory,
775 BstrFmt("%RI32", ValueUnion.u32).raw(), NULL);
776 break;
777
778 case 'd':
779 pVSD->AddDescription(VirtualSystemDescriptionType_CloudDomain,
780 Bstr(ValueUnion.psz).raw(), NULL);
781 break;
782 case 'b':
783 pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootDiskSize,
784 Bstr(ValueUnion.psz).raw(), NULL);
785 break;
786 case 'p':
787 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicIP,
788 Bstr(ValueUnion.psz).raw(), NULL);
789 break;
790 case 'P':
791 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPrivateIP,
792 Bstr(ValueUnion.psz).raw(), NULL);
793 break;
794 case 't':
795 pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCISubnet,
796 Bstr(ValueUnion.psz).raw(), NULL);
797 break;
798 case 'l':
799 {
800 Utf8Str strLaunch(ValueUnion.psz);
801 if (strLaunch.isNotEmpty() && (strLaunch.equalsIgnoreCase("true") || strLaunch.equalsIgnoreCase("false")))
802 pVSD->AddDescription(VirtualSystemDescriptionType_CloudLaunchInstance,
803 Bstr(ValueUnion.psz).raw(), NULL);
804 break;
805 }
806 case 'k':
807 strPublicSSHKey = ValueUnion.psz;
808 pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicSSHKey,
809 Bstr(ValueUnion.psz).raw(), NULL);
810 break;
811 case 'c':
812 pVSD->AddDescription(VirtualSystemDescriptionType_CloudInitScriptPath,
813 Bstr(ValueUnion.psz).raw(), NULL);
814 break;
815 case 'h':
816 printHelp(g_pStdOut);
817 return RTEXITCODE_SUCCESS;
818 case VINF_GETOPT_NOT_OPTION:
819 return errorUnknownSubcommand(ValueUnion.psz);
820 default:
821 return errorGetOpt(c, &ValueUnion);
822 }
823 }
824
825 /* Delayed check. It allows us to print help information.*/
826 hrc = checkAndSetCommonOptions(a, pCommonOpts);
827 if (FAILED(hrc))
828 return RTEXITCODE_FAILURE;
829
830 if (strPublicSSHKey.isEmpty())
831 RTPrintf(Cloud::tr("Warning!!! Public SSH key doesn't present in the passed arguments...\n"));
832
833 if (strImageId.isNotEmpty() && strBootVolumeId.isNotEmpty())
834 return errorArgument(Cloud::tr("Parameters --image-id and --boot-volume-id are mutually exclusive. "
835 "Only one of them must be presented."));
836
837 if (strImageId.isEmpty() && strBootVolumeId.isEmpty())
838 return errorArgument(Cloud::tr("Missing parameter --image-id or --boot-volume-id. One of them must be presented."));
839
840 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
841
842 pVSD->AddDescription(VirtualSystemDescriptionType_CloudProfileName,
843 Bstr(pCommonOpts->profile.pszProfileName).raw(),
844 NULL);
845
846 ComObjPtr<ICloudClient> oCloudClient;
847 CHECK_ERROR2_RET(hrc, pCloudProfile,
848 CreateCloudClient(oCloudClient.asOutParam()),
849 RTEXITCODE_FAILURE);
850
851 ComPtr<IStringArray> infoArray;
852 com::SafeArray<BSTR> pStrInfoArray;
853 ComPtr<IProgress> pProgress;
854
855#if 0
856 /*
857 * OCI API returns an error during an instance creation if the image isn't available
858 * or in the inappropriate state. So the check can be omitted.
859 */
860 RTPrintf(Cloud::tr("Checking the cloud image with id \'%s\'...\n"), strImageId.c_str());
861 CHECK_ERROR2_RET(hrc, oCloudClient,
862 GetImageInfo(Bstr(strImageId).raw(),
863 infoArray.asOutParam(),
864 pProgress.asOutParam()),
865 RTEXITCODE_FAILURE);
866
867 hrc = showProgress(pProgress);
868 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Checking the cloud image failed")), RTEXITCODE_FAILURE);
869
870 pProgress.setNull();
871#endif
872
873 if (strImageId.isNotEmpty())
874 RTPrintf(Cloud::tr("Creating cloud instance with name \'%s\' from the image \'%s\'...\n"),
875 strDisplayName.c_str(), strImageId.c_str());
876 else
877 RTPrintf(Cloud::tr("Creating cloud instance with name \'%s\' from the boot volume \'%s\'...\n"),
878 strDisplayName.c_str(), strBootVolumeId.c_str());
879
880 CHECK_ERROR2_RET(hrc, oCloudClient, LaunchVM(pVSD, pProgress.asOutParam()), RTEXITCODE_FAILURE);
881
882 hrc = showProgress(pProgress);
883 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Creating cloud instance failed")), RTEXITCODE_FAILURE);
884
885 if (SUCCEEDED(hrc))
886 RTPrintf(Cloud::tr("Cloud instance was created successfully\n"));
887
888 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
889}
890
891
892static RTEXITCODE cloneCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
893{
894 HRESULT hrc = S_OK;
895
896 enum
897 {
898 kInstanceIota = 1000,
899 kInstance_ShapeCpu,
900 kInstance_ShapeMemory,
901 };
902
903 static const RTGETOPTDEF s_aOptions[] =
904 {
905 { "--id", 'i', RTGETOPT_REQ_STRING },
906 { "--clone-name", 'n', RTGETOPT_REQ_STRING },
907
908 { "help", 'h', RTGETOPT_REQ_NOTHING },
909 { "--help", 'h', RTGETOPT_REQ_NOTHING }
910 };
911 RTGETOPTSTATE GetState;
912 RTGETOPTUNION ValueUnion;
913 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
914 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
915 if (a->argc == iFirst)
916 {
917 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
918 printHelp(g_pStdOut);
919 return RTEXITCODE_SUCCESS;
920 }
921
922 Utf8Str strCloneName, strInstanceId;
923 int c;
924 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
925 {
926 switch (c)
927 {
928 case 'i':
929 strInstanceId = ValueUnion.psz;
930
931 break;
932 case 'n':
933 strCloneName = ValueUnion.psz;
934 break;
935 case 'h':
936 printHelp(g_pStdOut);
937 return RTEXITCODE_SUCCESS;
938 case VINF_GETOPT_NOT_OPTION:
939 return errorUnknownSubcommand(ValueUnion.psz);
940 default:
941 return errorGetOpt(c, &ValueUnion);
942 }
943 }
944
945 /* Delayed check. It allows us to print help information.*/
946 hrc = checkAndSetCommonOptions(a, pCommonOpts);
947 if (FAILED(hrc))
948 return RTEXITCODE_FAILURE;
949
950 if (strInstanceId.isEmpty())
951 return errorArgument(Cloud::tr("Missing parameter --id."));
952
953// if (strCloneName.isEmpty())
954// return errorArgument(Cloud::tr("Missing parameter --clone-name."));
955
956 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
957
958 ComObjPtr<ICloudClient> oCloudClient;
959 CHECK_ERROR2_RET(hrc, pCloudProfile,
960 CreateCloudClient(oCloudClient.asOutParam()),
961 RTEXITCODE_FAILURE);
962
963 ComPtr<IProgress> pProgress;
964 ComPtr<ICloudMachine> pClonedMachine;
965
966 RTPrintf(Cloud::tr("Cloning cloud instance with Id \'%s\'...\n"), strInstanceId.c_str());
967
968 CHECK_ERROR2_RET(hrc, oCloudClient, CloneInstance(Bstr(strInstanceId).raw(),
969 Bstr(strCloneName).raw(),
970 pClonedMachine.asOutParam(),
971 pProgress.asOutParam()), RTEXITCODE_FAILURE);
972
973 hrc = showProgress(pProgress);
974 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Cloning cloud instance failed")), RTEXITCODE_FAILURE);
975
976 Bstr strAttr;
977 pClonedMachine->COMGETTER(Id)(strAttr.asOutParam());
978 RTPrintf(Cloud::tr("Cloned instance UUID in VirtualBox: %ls\n"), strAttr.raw());
979 strAttr.setNull();
980 pClonedMachine->COMGETTER(Name)(strAttr.asOutParam());
981 RTPrintf(Cloud::tr("Cloned instance name: %ls\n"), strAttr.raw());
982
983 if (SUCCEEDED(hrc))
984 RTPrintf(Cloud::tr("Cloud instance was cloned successfully\n"));
985
986 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
987}
988
989static RTEXITCODE updateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
990{
991 RT_NOREF(a);
992 RT_NOREF(iFirst);
993 RT_NOREF(pCommonOpts);
994 return RTEXITCODE_SUCCESS;
995}
996
997static RTEXITCODE showCloudInstanceInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
998{
999 HRESULT hrc = S_OK;
1000
1001 static const RTGETOPTDEF s_aOptions[] =
1002 {
1003 { "--id", 'i', RTGETOPT_REQ_STRING },
1004 { "help", 'h', RTGETOPT_REQ_NOTHING },
1005 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1006 };
1007 RTGETOPTSTATE GetState;
1008 RTGETOPTUNION ValueUnion;
1009 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1010 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1011 if (a->argc == iFirst)
1012 {
1013 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1014 printHelp(g_pStdOut);
1015 return RTEXITCODE_SUCCESS;
1016 }
1017
1018 Utf8Str strInstanceId;
1019
1020 int c;
1021 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1022 {
1023 switch (c)
1024 {
1025 case 'i':
1026 {
1027 if (strInstanceId.isNotEmpty())
1028 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1029
1030 strInstanceId = ValueUnion.psz;
1031 if (strInstanceId.isEmpty())
1032 return errorArgument(Cloud::tr("Empty parameter: --id"));
1033
1034 break;
1035 }
1036 case 'h':
1037 printHelp(g_pStdOut);
1038 return RTEXITCODE_SUCCESS;
1039 case VINF_GETOPT_NOT_OPTION:
1040 return errorUnknownSubcommand(ValueUnion.psz);
1041
1042 default:
1043 return errorGetOpt(c, &ValueUnion);
1044 }
1045 }
1046
1047 /* Delayed check. It allows us to print help information.*/
1048 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1049 if (FAILED(hrc))
1050 return RTEXITCODE_FAILURE;
1051
1052 if (strInstanceId.isEmpty())
1053 return errorArgument(Cloud::tr("Missing parameter: --id"));
1054
1055 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1056
1057 ComObjPtr<ICloudClient> oCloudClient;
1058 CHECK_ERROR2_RET(hrc, pCloudProfile,
1059 CreateCloudClient(oCloudClient.asOutParam()),
1060 RTEXITCODE_FAILURE);
1061 RTPrintf(Cloud::tr("Getting information about cloud instance with id %s...\n"), strInstanceId.c_str());
1062 RTPrintf(Cloud::tr("Reply is in the form \'setting name\' = \'value\'\n"));
1063
1064 ComPtr<IAppliance> pAppliance;
1065 CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE);
1066
1067 com::SafeIfaceArray<IVirtualSystemDescription> vsdArray;
1068 ULONG requestedVSDnums = 1;
1069 ULONG newVSDnums = 0;
1070 CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(requestedVSDnums, &newVSDnums), RTEXITCODE_FAILURE);
1071 if (requestedVSDnums != newVSDnums)
1072 return RTEXITCODE_FAILURE;
1073
1074 CHECK_ERROR2_RET(hrc, pAppliance, COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(vsdArray)), RTEXITCODE_FAILURE);
1075 ComPtr<IVirtualSystemDescription> instanceDescription = vsdArray[0];
1076
1077 ComPtr<IProgress> progress;
1078 CHECK_ERROR2_RET(hrc, oCloudClient,
1079 GetInstanceInfo(Bstr(strInstanceId).raw(), instanceDescription, progress.asOutParam()),
1080 RTEXITCODE_FAILURE);
1081
1082 hrc = showProgress(progress);
1083 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Getting information about cloud instance failed")), RTEXITCODE_FAILURE);
1084
1085 RTPrintf(Cloud::tr("Cloud instance info (provider '%s'):\n"),
1086 pCommonOpts->provider.pszProviderName);
1087
1088 struct vsdHReadable {
1089 VirtualSystemDescriptionType_T vsdType;
1090 Utf8Str strFound;
1091 Utf8Str strNotFound;
1092 };
1093
1094 const size_t vsdHReadableArraySize = 15;//the number of items in the vsdHReadableArray
1095 vsdHReadable vsdHReadableArray[vsdHReadableArraySize] = {
1096 {VirtualSystemDescriptionType_CloudDomain, Cloud::tr("Availability domain = %ls\n"), Cloud::tr("Availability domain wasn't found\n")},
1097 {VirtualSystemDescriptionType_Name, Cloud::tr("Instance displayed name = %ls\n"), Cloud::tr("Instance displayed name wasn't found\n")},
1098 {VirtualSystemDescriptionType_CloudInstanceState, Cloud::tr("Instance state = %ls\n"), Cloud::tr("Instance state wasn't found\n")},
1099 {VirtualSystemDescriptionType_CloudInstanceId, Cloud::tr("Instance Id = %ls\n"), Cloud::tr("Instance Id wasn't found\n")},
1100 {VirtualSystemDescriptionType_CloudInstanceDisplayName, Cloud::tr("Instance name = %ls\n"), Cloud::tr("Instance name wasn't found\n")},
1101 {VirtualSystemDescriptionType_CloudImageId, Cloud::tr("Bootable image Id = %ls\n"),
1102 Cloud::tr("Image Id whom the instance is booted up wasn't found\n")},
1103 {VirtualSystemDescriptionType_CloudInstanceShape, Cloud::tr("Shape of the instance = %ls\n"),
1104 Cloud::tr("The shape of the instance wasn't found\n")},
1105 {VirtualSystemDescriptionType_OS, Cloud::tr("Type of guest OS = %ls\n"), Cloud::tr("Type of guest OS wasn't found\n")},
1106 {VirtualSystemDescriptionType_Memory, Cloud::tr("RAM = %ls MB\n"), Cloud::tr("Value for RAM wasn't found\n")},
1107 {VirtualSystemDescriptionType_CPU, Cloud::tr("CPUs = %ls\n"), Cloud::tr("Numbers of CPUs weren't found\n")},
1108 {VirtualSystemDescriptionType_CloudPublicIP, Cloud::tr("Instance public IP = %ls\n"), Cloud::tr("Public IP wasn't found\n")},
1109 {VirtualSystemDescriptionType_Miscellaneous, "%ls\n", Cloud::tr("Miscellanious wasn't found\n")},
1110 {VirtualSystemDescriptionType_CloudInstanceFreeFormTags, "%ls\n", Cloud::tr("Free-form tags weren't found\n")},
1111 {VirtualSystemDescriptionType_CloudInstanceMetadata, "%ls\n", Cloud::tr("Metadata was't found\n")},
1112 {VirtualSystemDescriptionType_CloudInitScriptPath, "Cloud-init script: \n\t%ls\n", Cloud::tr("Cloud-init script wasn't found\n")}
1113 };
1114
1115 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
1116 com::SafeArray<BSTR> aRefs;
1117 com::SafeArray<BSTR> aOvfValues;
1118 com::SafeArray<BSTR> aVBoxValues;
1119 com::SafeArray<BSTR> aExtraConfigValues;
1120
1121 for (size_t i=0; i<vsdHReadableArraySize ; ++i)
1122 {
1123 hrc = instanceDescription->GetDescriptionByType(vsdHReadableArray[i].vsdType,
1124 ComSafeArrayAsOutParam(retTypes),
1125 ComSafeArrayAsOutParam(aRefs),
1126 ComSafeArrayAsOutParam(aOvfValues),
1127 ComSafeArrayAsOutParam(aVBoxValues),
1128 ComSafeArrayAsOutParam(aExtraConfigValues));
1129 if (FAILED(hrc) || aVBoxValues.size() == 0)
1130 LogRel((vsdHReadableArray[i].strNotFound.c_str()));
1131 else
1132 {
1133 LogRel(("Size is %d", aVBoxValues.size()));
1134 for (size_t j = 0; j<aVBoxValues.size(); ++j)
1135 {
1136 RTPrintf(vsdHReadableArray[i].strFound.c_str(), aVBoxValues[j]);
1137 }
1138 }
1139
1140 retTypes.setNull();
1141 aRefs.setNull();
1142 aOvfValues.setNull();
1143 aVBoxValues.setNull();
1144 aExtraConfigValues.setNull();
1145 }
1146
1147 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1148}
1149
1150
1151static RTEXITCODE cloudInstanceMetricList(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1152{
1153 HRESULT hrc = S_OK;
1154
1155 static const RTGETOPTDEF s_aOptions[] =
1156 {
1157 { "--id", 'i', RTGETOPT_REQ_STRING },
1158 { "help", 'h', RTGETOPT_REQ_NOTHING },
1159 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1160 };
1161 RTGETOPTSTATE GetState;
1162 RTGETOPTUNION ValueUnion;
1163 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1164 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1165 if (a->argc == iFirst)
1166 {
1167 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1168 printHelp(g_pStdOut);
1169 return RTEXITCODE_SUCCESS;
1170 }
1171
1172 Utf8Str strInstanceId;
1173
1174 int c;
1175 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1176 {
1177 switch (c)
1178 {
1179 case 'i':
1180 {
1181 if (strInstanceId.isNotEmpty())
1182 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1183
1184 strInstanceId = ValueUnion.psz;
1185 if (strInstanceId.isEmpty())
1186 return errorArgument(Cloud::tr("Empty parameter: --id"));
1187
1188 break;
1189 }
1190 case 'h':
1191 printHelp(g_pStdOut);
1192 return RTEXITCODE_SUCCESS;
1193 case VINF_GETOPT_NOT_OPTION:
1194 return errorUnknownSubcommand(ValueUnion.psz);
1195
1196 default:
1197 return errorGetOpt(c, &ValueUnion);
1198 }
1199 }
1200
1201 /* Delayed check. It allows us to print help information.*/
1202 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1203 if (FAILED(hrc))
1204 return RTEXITCODE_FAILURE;
1205
1206 if (strInstanceId.isEmpty())
1207 return errorArgument(Cloud::tr("Missing parameter: --id"));
1208
1209 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1210
1211 ComObjPtr<ICloudClient> oCloudClient;
1212 CHECK_ERROR2_RET(hrc, pCloudProfile,
1213 CreateCloudClient(oCloudClient.asOutParam()),
1214 RTEXITCODE_FAILURE);
1215 RTPrintf(Cloud::tr("Getting list of metric names for the cloud instance with id %s\n"), strInstanceId.c_str());
1216 RTPrintf(Cloud::tr("Reply is the list, each metric name is placed on a separate line as \' - <metric name>\'\n"));
1217
1218 ComPtr<IProgress> progress;
1219
1220 CHECK_ERROR2_RET(hrc, oCloudClient, ReadCloudMachineList(progress.asOutParam()), RTEXITCODE_FAILURE);
1221
1222 /* First step*/
1223 RTPrintf(Cloud::tr("First, reading the cloud machines list...\n"));
1224 hrc = showProgress(progress);
1225 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reading the cloud machines list failed")), RTEXITCODE_FAILURE);
1226
1227 com::SafeIfaceArray<ICloudMachine> aMachines;
1228 CHECK_ERROR2_RET(hrc, oCloudClient,
1229 COMGETTER(CloudMachineList)(ComSafeArrayAsOutParam(aMachines)),
1230 RTEXITCODE_FAILURE);
1231
1232 const size_t cMachines = aMachines.size();
1233 if (cMachines == 0)
1234 return RTEXITCODE_SUCCESS;
1235
1236 std::vector<ComPtr<ICloudMachine> > vMachines(cMachines);
1237 std::vector<com::Bstr> vBstrCloudIds(cMachines);
1238 std::vector<com::Bstr> vBstrIds(cMachines);
1239
1240 com::Bstr bstrFoundMachineVBoxId;
1241
1242 for (size_t i = 0; i < cMachines; ++i)
1243 {
1244 vMachines[i] = aMachines[i];
1245
1246 CHECK_ERROR2_RET(hrc, vMachines[i],
1247 COMGETTER(CloudId)(vBstrCloudIds[i].asOutParam()),
1248 RTEXITCODE_FAILURE);
1249
1250 Utf8Str strCurrMachineCloudId(vBstrCloudIds[i]);
1251 if (strCurrMachineCloudId.equals(strInstanceId))
1252 {
1253 CHECK_ERROR2_RET(hrc, vMachines[i],
1254 COMGETTER(Id)(vBstrIds[i].asOutParam()),
1255 RTEXITCODE_FAILURE);
1256 bstrFoundMachineVBoxId = vBstrIds[i];
1257 break;
1258 }
1259 }
1260
1261 if (bstrFoundMachineVBoxId.isEmpty())
1262 {
1263 RTPrintf("The passed cloud instance Id \'%s\' WASN'T found among the cloud machines "
1264 "of user \'%s\' registered with VirtualBox\n",
1265 strInstanceId.c_str(), pCommonOpts->profile.pszProfileName);
1266 return RTEXITCODE_FAILURE;
1267 }
1268
1269 /* Second step*/
1270 RTPrintf(Cloud::tr("Second, refresh information about cloud instance ...\n"));
1271 ComPtr<ICloudMachine> pMachine;
1272 CHECK_ERROR2_RET(hrc, oCloudClient,
1273 GetCloudMachine(bstrFoundMachineVBoxId.raw(), pMachine.asOutParam()), RTEXITCODE_FAILURE);
1274
1275 ComPtr<IProgress> pRefreshProgress;
1276 CHECK_ERROR2_RET(hrc, pMachine, Refresh(pRefreshProgress.asOutParam()), RTEXITCODE_FAILURE);
1277
1278 hrc = showProgress(pRefreshProgress);
1279 CHECK_PROGRESS_ERROR_RET(pRefreshProgress, (Cloud::tr("Refreshing information about cloud instance failed")), RTEXITCODE_FAILURE);
1280
1281 /* Third step*/
1282 RTPrintf(Cloud::tr("Third, getting information about cloud instance metric names...\n"));
1283 ComPtr<IProgress> progress2;
1284 ComPtr<IStringArray> returnMetricNames;
1285 CHECK_ERROR2_RET(hrc, pMachine, ListMetricNames(returnMetricNames.asOutParam(), progress2.asOutParam()), RTEXITCODE_FAILURE);
1286
1287 hrc = showProgress(progress2);
1288 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Getting information about cloud instance metrics failed")), RTEXITCODE_FAILURE);
1289
1290 com::SafeArray<BSTR> metricNamesArray;
1291 CHECK_ERROR2_RET(hrc,
1292 returnMetricNames, COMGETTER(Values)(ComSafeArrayAsOutParam(metricNamesArray)),
1293 RTEXITCODE_FAILURE);
1294
1295 RTPrintf(Cloud::tr("Available metric names:\n"));
1296 size_t cMetricNamesArraySize = metricNamesArray.size();
1297
1298 if (cMetricNamesArraySize == 0)
1299 {
1300 RTPrintf(Cloud::tr("\tThe list of metric names is empty. It may mean that an appropriate service wasn't run on the instance.\n"));
1301 return RTEXITCODE_FAILURE;
1302 }
1303 else
1304 {
1305 Bstr value;
1306 for (size_t k = 0; k < cMetricNamesArraySize; ++k)
1307 {
1308 value = metricNamesArray[k];
1309 MetricType_T aMetricType;
1310 CHECK_ERROR2_RET(hrc, oCloudClient, GetMetricTypeByName(value.raw(), &aMetricType), RTEXITCODE_FAILURE);
1311
1312 if (SUCCEEDED(hrc))
1313 {
1314 switch (aMetricType)
1315 {
1316 case MetricType_CpuUtilization:
1317 case MetricType_MemoryUtilization:
1318 case MetricType_DiskBytesRead:
1319 case MetricType_DiskBytesWritten:
1320 case MetricType_NetworksBytesIn:
1321 case MetricType_NetworksBytesOut:
1322 RTPrintf(Cloud::tr(" - %ls\n"), value.raw());
1323 break;
1324 case MetricType_Invalid:
1325 default:
1326 break;
1327 }
1328 }
1329 }
1330 }
1331
1332 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1333}
1334
1335
1336static RTEXITCODE cloudInstanceMetricData(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1337{
1338 HRESULT hrc = S_OK;
1339
1340 static const RTGETOPTDEF s_aOptions[] =
1341 {
1342 { "--id", 'i', RTGETOPT_REQ_STRING },
1343 { "--metric-name", 'n', RTGETOPT_REQ_STRING },
1344 { "--metric-points",'p', RTGETOPT_REQ_STRING },
1345 { "help", 'h', RTGETOPT_REQ_NOTHING },
1346 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1347 };
1348 RTGETOPTSTATE GetState;
1349 RTGETOPTUNION ValueUnion;
1350 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1351 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1352 if (a->argc == iFirst)
1353 {
1354 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1355 printHelp(g_pStdOut);
1356 return RTEXITCODE_SUCCESS;
1357 }
1358
1359 Utf8Str strInstanceId;
1360 Utf8Str strMetricName;
1361 Utf8Str strMetricPoints;
1362
1363 int c;
1364 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1365 {
1366 switch (c)
1367 {
1368 case 'i':
1369 {
1370 if (strInstanceId.isNotEmpty())
1371 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1372
1373 strInstanceId = ValueUnion.psz;
1374 if (strInstanceId.isEmpty())
1375 return errorArgument(Cloud::tr("Empty parameter: --id"));
1376
1377 break;
1378 }
1379 case 'n':
1380 {
1381 if (strMetricName.isNotEmpty())
1382 return errorArgument(Cloud::tr("Duplicate parameter: --metric-name"));
1383
1384 strMetricName = ValueUnion.psz;
1385 if (strMetricName.isEmpty())
1386 return errorArgument(Cloud::tr("Empty parameter: --metric-name"));
1387
1388 break;
1389 }
1390 case 'p':
1391 {
1392 if (strMetricPoints.isNotEmpty())
1393 return errorArgument(Cloud::tr("Duplicate parameter: --metric-points"));
1394
1395 strMetricPoints = ValueUnion.psz;
1396 if (strMetricPoints.isEmpty())
1397 return errorArgument(Cloud::tr("Empty parameter: --metric-points"));
1398
1399 break;
1400 }
1401 case 'h':
1402 printHelp(g_pStdOut);
1403 return RTEXITCODE_SUCCESS;
1404 case VINF_GETOPT_NOT_OPTION:
1405 return errorUnknownSubcommand(ValueUnion.psz);
1406
1407 default:
1408 return errorGetOpt(c, &ValueUnion);
1409 }
1410 }
1411
1412 /* Delayed check. It allows us to print help information.*/
1413 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1414 if (FAILED(hrc))
1415 return RTEXITCODE_FAILURE;
1416
1417 if (strInstanceId.isEmpty())
1418 return errorArgument(Cloud::tr("Missing parameter: --id"));
1419 if (strMetricName.isEmpty())
1420 return errorArgument(Cloud::tr("Missing parameter: --metric-name"));
1421
1422 unsigned long metricPoins;
1423 strMetricPoints.isEmpty() ? metricPoins = 1 : metricPoins = RTStrToUInt32(strMetricPoints.c_str());
1424
1425 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1426
1427 ComObjPtr<ICloudClient> oCloudClient;
1428 CHECK_ERROR2_RET(hrc, pCloudProfile,
1429 CreateCloudClient(oCloudClient.asOutParam()),
1430 RTEXITCODE_FAILURE);
1431 RTPrintf(Cloud::tr("Getting %s metric for the cloud instance with id %s...\n"), strMetricName.c_str(), strInstanceId.c_str());
1432 RTPrintf(Cloud::tr("Reply is in the form \'%s[Rfc2822 time format]\' = \'value\'\n"), strMetricName.c_str());
1433
1434 /* Check the requested metric type */
1435 MetricType_T aMetricType;
1436 CHECK_ERROR2_RET(hrc, oCloudClient, GetMetricTypeByName(com::Bstr(strMetricName.c_str()).raw(), &aMetricType), RTEXITCODE_FAILURE);
1437
1438 /* First step*/
1439 RTPrintf(Cloud::tr("First, reading the cloud machines list...\n"));
1440 ComPtr<IProgress> progress;
1441 CHECK_ERROR2_RET(hrc, oCloudClient, ReadCloudMachineList(progress.asOutParam()), RTEXITCODE_FAILURE);
1442
1443 hrc = showProgress(progress);
1444 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reading the cloud machines list failed")), RTEXITCODE_FAILURE);
1445
1446 com::SafeIfaceArray<ICloudMachine> aMachines;
1447 CHECK_ERROR2_RET(hrc, oCloudClient,
1448 COMGETTER(CloudMachineList)(ComSafeArrayAsOutParam(aMachines)),
1449 RTEXITCODE_FAILURE);
1450
1451 const size_t cMachines = aMachines.size();
1452 if (cMachines == 0)
1453 return RTEXITCODE_SUCCESS;
1454
1455 std::vector<ComPtr<ICloudMachine> > vMachines(cMachines);
1456 std::vector<com::Bstr> vBstrCloudIds(cMachines);
1457 std::vector<com::Bstr> vBstrIds(cMachines);
1458
1459 com::Bstr bstrFoundMachineVBoxId;
1460
1461 for (size_t i = 0; i < cMachines; ++i)
1462 {
1463 vMachines[i] = aMachines[i];
1464
1465 CHECK_ERROR2_RET(hrc, vMachines[i],
1466 COMGETTER(CloudId)(vBstrCloudIds[i].asOutParam()),
1467 RTEXITCODE_FAILURE);
1468
1469 Utf8Str strCurrMachineCloudId(vBstrCloudIds[i]);
1470 if (strCurrMachineCloudId.equals(strInstanceId))
1471 {
1472 CHECK_ERROR2_RET(hrc, vMachines[i],
1473 COMGETTER(Id)(vBstrIds[i].asOutParam()),
1474 RTEXITCODE_FAILURE);
1475 bstrFoundMachineVBoxId = vBstrIds[i];
1476 break;
1477 }
1478 }
1479
1480 if (bstrFoundMachineVBoxId.isEmpty())
1481 {
1482 RTPrintf("The passed cloud instance Id \'%s\' WASN'T found among the cloud machines "
1483 "of user \'%s\' registered with VirtualBox\n",
1484 strInstanceId.c_str(), pCommonOpts->profile.pszProfileName);
1485 return RTEXITCODE_FAILURE;
1486 }
1487
1488 /* Second step*/
1489 RTPrintf(Cloud::tr("Second, refresh information about cloud instance ...\n"));
1490 ComPtr<ICloudMachine> pMachine;
1491 CHECK_ERROR2_RET(hrc, oCloudClient,
1492 GetCloudMachine(bstrFoundMachineVBoxId.raw(), pMachine.asOutParam()), RTEXITCODE_FAILURE);
1493
1494 ComPtr<IProgress> pRefreshProgress;
1495 CHECK_ERROR2_RET(hrc, pMachine, Refresh(pRefreshProgress.asOutParam()), RTEXITCODE_FAILURE);
1496
1497 hrc = showProgress(pRefreshProgress);
1498 CHECK_PROGRESS_ERROR_RET(pRefreshProgress, (Cloud::tr("Refreshing information about cloud instance failed")), RTEXITCODE_FAILURE);
1499
1500 /* Third step*/
1501 RTPrintf(Cloud::tr("Third, request metric data from cloud instance ...\n"));
1502 ComPtr<IProgress> progress2;
1503 ComPtr<IStringArray> returnDataValues;
1504 ComPtr<IStringArray> returnDataTimestamps;
1505 ComPtr<IStringArray> returnMeasureUnits;
1506
1507 CHECK_ERROR2_RET(hrc, pMachine, EnumerateMetricData(aMetricType,
1508 metricPoins,
1509 returnDataValues.asOutParam(),
1510 returnDataTimestamps.asOutParam(),
1511 returnMeasureUnits.asOutParam(),
1512 progress2.asOutParam()), RTEXITCODE_FAILURE);
1513
1514 hrc = showProgress(progress2);
1515 CHECK_PROGRESS_ERROR_RET(progress2, (Cloud::tr("Getting metric data failed")), RTEXITCODE_FAILURE);
1516
1517 com::SafeArray<BSTR> dataValueArray;
1518 CHECK_ERROR2_RET(hrc,
1519 returnDataValues, COMGETTER(Values)(ComSafeArrayAsOutParam(dataValueArray)),
1520 RTEXITCODE_FAILURE);
1521
1522 com::SafeArray<BSTR> dataTimestampArray;
1523 CHECK_ERROR2_RET(hrc,
1524 returnDataTimestamps, COMGETTER(Values)(ComSafeArrayAsOutParam(dataTimestampArray)),
1525 RTEXITCODE_FAILURE);
1526
1527 com::SafeArray<BSTR> measureUnitArray;
1528 CHECK_ERROR2_RET(hrc,
1529 returnMeasureUnits, COMGETTER(Values)(ComSafeArrayAsOutParam(measureUnitArray)),
1530 RTEXITCODE_FAILURE);
1531
1532 size_t cDataValueArraySize = dataValueArray.size();
1533 Bstr unit = cDataValueArraySize == 0 ? Bstr("unknown units") : measureUnitArray[0];
1534 RTPrintf(Cloud::tr("The %s metric values (in %ls):\n"), strMetricName.c_str(), unit.raw());
1535
1536 if (cDataValueArraySize == 0)
1537 RTPrintf(Cloud::tr("\tThe list of metric data is empty. It may mean that an appropriate service wasn't run on the instance.\n"));
1538 else
1539 {
1540 Bstr value;
1541 for (size_t k = 0; k < cDataValueArraySize; ++k)
1542 {
1543 value = dataValueArray[k];
1544 Utf8Str strTimestamp(dataTimestampArray[k]);
1545 RTPrintf(Cloud::tr("%d: %s[%s] = %ls\n"), k, strMetricName.c_str(), strTimestamp.c_str(), value.raw());
1546 }
1547 }
1548
1549 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1550}
1551
1552
1553static RTEXITCODE startCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1554{
1555 HRESULT hrc = S_OK;
1556
1557 static const RTGETOPTDEF s_aOptions[] =
1558 {
1559 { "--id", 'i', RTGETOPT_REQ_STRING },
1560 { "help", 'h', RTGETOPT_REQ_NOTHING },
1561 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1562 };
1563 RTGETOPTSTATE GetState;
1564 RTGETOPTUNION ValueUnion;
1565 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1566 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1567 if (a->argc == iFirst)
1568 {
1569 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1570 printHelp(g_pStdOut);
1571 return RTEXITCODE_SUCCESS;
1572 }
1573
1574 Utf8Str strInstanceId;
1575
1576 int c;
1577 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1578 {
1579 switch (c)
1580 {
1581 case 'i':
1582 {
1583 if (strInstanceId.isNotEmpty())
1584 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1585
1586 strInstanceId = ValueUnion.psz;
1587 if (strInstanceId.isEmpty())
1588 return errorArgument(Cloud::tr("Empty parameter: --id"));
1589
1590 break;
1591 }
1592 case 'h':
1593 printHelp(g_pStdOut);
1594 return RTEXITCODE_SUCCESS;
1595 case VINF_GETOPT_NOT_OPTION:
1596 return errorUnknownSubcommand(ValueUnion.psz);
1597
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 if (strInstanceId.isEmpty())
1609 return errorArgument(Cloud::tr("Missing parameter: --id"));
1610
1611 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1612
1613 ComObjPtr<ICloudClient> oCloudClient;
1614 CHECK_ERROR2_RET(hrc, pCloudProfile,
1615 CreateCloudClient(oCloudClient.asOutParam()),
1616 RTEXITCODE_FAILURE);
1617 RTPrintf(Cloud::tr("Starting cloud instance with id %s...\n"), strInstanceId.c_str());
1618
1619 ComPtr<IProgress> progress;
1620 CHECK_ERROR2_RET(hrc, oCloudClient,
1621 StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1622 RTEXITCODE_FAILURE);
1623 hrc = showProgress(progress);
1624 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Starting the cloud instance failed")), RTEXITCODE_FAILURE);
1625
1626 if (SUCCEEDED(hrc))
1627 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n"),
1628 strInstanceId.c_str(),
1629 pCommonOpts->provider.pszProviderName,
1630 pCommonOpts->profile.pszProfileName);
1631
1632 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1633}
1634
1635static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1636{
1637 HRESULT hrc = S_OK;
1638
1639 static const RTGETOPTDEF s_aOptions[] =
1640 {
1641 { "--id", 'i', RTGETOPT_REQ_STRING },
1642 { "help", 'h', RTGETOPT_REQ_NOTHING },
1643 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1644 };
1645 RTGETOPTSTATE GetState;
1646 RTGETOPTUNION ValueUnion;
1647 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1648 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1649 if (a->argc == iFirst)
1650 {
1651 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1652 printHelp(g_pStdOut);
1653 return RTEXITCODE_SUCCESS;
1654 }
1655
1656 Utf8Str strInstanceId;
1657
1658 int c;
1659 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1660 {
1661 switch (c)
1662 {
1663 case 'i':
1664 {
1665 if (strInstanceId.isNotEmpty())
1666 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1667
1668 strInstanceId = ValueUnion.psz;
1669 if (strInstanceId.isEmpty())
1670 return errorArgument(Cloud::tr("Empty parameter: --id"));
1671
1672 break;
1673 }
1674 case 'h':
1675 printHelp(g_pStdOut);
1676 return RTEXITCODE_SUCCESS;
1677 case VINF_GETOPT_NOT_OPTION:
1678 return errorUnknownSubcommand(ValueUnion.psz);
1679
1680 default:
1681 return errorGetOpt(c, &ValueUnion);
1682 }
1683 }
1684
1685 /* Delayed check. It allows us to print help information.*/
1686 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1687 if (FAILED(hrc))
1688 return RTEXITCODE_FAILURE;
1689
1690 if (strInstanceId.isEmpty())
1691 return errorArgument(Cloud::tr("Missing parameter: --id"));
1692
1693 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1694
1695 ComObjPtr<ICloudClient> oCloudClient;
1696 CHECK_ERROR2_RET(hrc, pCloudProfile,
1697 CreateCloudClient(oCloudClient.asOutParam()),
1698 RTEXITCODE_FAILURE);
1699 RTPrintf(Cloud::tr("Pausing cloud instance with id %s...\n"), strInstanceId.c_str());
1700
1701 ComPtr<IProgress> progress;
1702 CHECK_ERROR2_RET(hrc, oCloudClient,
1703 PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1704 RTEXITCODE_FAILURE);
1705 hrc = showProgress(progress);
1706 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Pause the cloud instance failed")), RTEXITCODE_FAILURE);
1707
1708 if (SUCCEEDED(hrc))
1709 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n"),
1710 strInstanceId.c_str(),
1711 pCommonOpts->provider.pszProviderName,
1712 pCommonOpts->profile.pszProfileName);
1713
1714 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1715}
1716
1717static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1718{
1719 HRESULT hrc = S_OK;
1720
1721 static const RTGETOPTDEF s_aOptions[] =
1722 {
1723 { "--id", 'i', RTGETOPT_REQ_STRING },
1724 { "help", 'h', RTGETOPT_REQ_NOTHING },
1725 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1726 };
1727 RTGETOPTSTATE GetState;
1728 RTGETOPTUNION ValueUnion;
1729 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1730 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1731 if (a->argc == iFirst)
1732 {
1733 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1734 printHelp(g_pStdOut);
1735 return RTEXITCODE_SUCCESS;
1736 }
1737
1738 Utf8Str strInstanceId;
1739
1740 int c;
1741 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1742 {
1743 switch (c)
1744 {
1745 case 'i':
1746 {
1747 if (strInstanceId.isNotEmpty())
1748 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1749
1750 strInstanceId = ValueUnion.psz;
1751 if (strInstanceId.isEmpty())
1752 return errorArgument(Cloud::tr("Empty parameter: --id"));
1753
1754 break;
1755 }
1756 case 'h':
1757 printHelp(g_pStdOut);
1758 return RTEXITCODE_SUCCESS;
1759 case VINF_GETOPT_NOT_OPTION:
1760 return errorUnknownSubcommand(ValueUnion.psz);
1761
1762 default:
1763 return errorGetOpt(c, &ValueUnion);
1764 }
1765 }
1766
1767 /* Delayed check. It allows us to print help information.*/
1768 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1769 if (FAILED(hrc))
1770 return RTEXITCODE_FAILURE;
1771
1772 if (strInstanceId.isEmpty())
1773 return errorArgument(Cloud::tr("Missing parameter: --id"));
1774
1775
1776 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1777
1778 ComObjPtr<ICloudClient> oCloudClient;
1779 CHECK_ERROR2_RET(hrc, pCloudProfile,
1780 CreateCloudClient(oCloudClient.asOutParam()),
1781 RTEXITCODE_FAILURE);
1782 RTPrintf(Cloud::tr("Terminating cloud instance with id %s...\n"), strInstanceId.c_str());
1783
1784 ComPtr<IProgress> progress;
1785 CHECK_ERROR2_RET(hrc, oCloudClient,
1786 TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1787 RTEXITCODE_FAILURE);
1788 hrc = showProgress(progress);
1789 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Termination the cloud instance failed")), RTEXITCODE_FAILURE);
1790
1791 if (SUCCEEDED(hrc))
1792 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n"),
1793 strInstanceId.c_str(),
1794 pCommonOpts->provider.pszProviderName,
1795 pCommonOpts->profile.pszProfileName);
1796
1797 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1798}
1799
1800static RTEXITCODE resetCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1801{
1802 HRESULT hrc = S_OK;
1803
1804 static const RTGETOPTDEF s_aOptions[] =
1805 {
1806 { "--id", 'i', RTGETOPT_REQ_STRING },
1807 { "help", 'h', RTGETOPT_REQ_NOTHING },
1808 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1809 };
1810 RTGETOPTSTATE GetState;
1811 RTGETOPTUNION ValueUnion;
1812 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1813 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1814 if (a->argc == iFirst)
1815 {
1816 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1817 printHelp(g_pStdOut);
1818 return RTEXITCODE_SUCCESS;
1819 }
1820
1821 Utf8Str strInstanceId;
1822
1823 int c;
1824 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1825 {
1826 switch (c)
1827 {
1828 case 'i':
1829 {
1830 if (strInstanceId.isNotEmpty())
1831 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1832
1833 strInstanceId = ValueUnion.psz;
1834 if (strInstanceId.isEmpty())
1835 return errorArgument(Cloud::tr("Empty parameter: --id"));
1836
1837 break;
1838 }
1839 case 'h':
1840 printHelp(g_pStdOut);
1841 return RTEXITCODE_SUCCESS;
1842 case VINF_GETOPT_NOT_OPTION:
1843 return errorUnknownSubcommand(ValueUnion.psz);
1844
1845 default:
1846 return errorGetOpt(c, &ValueUnion);
1847 }
1848 }
1849
1850 /* Delayed check. It allows us to print help information.*/
1851 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1852 if (FAILED(hrc))
1853 return RTEXITCODE_FAILURE;
1854
1855 if (strInstanceId.isEmpty())
1856 return errorArgument(Cloud::tr("Missing parameter: --id"));
1857
1858 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1859
1860 ComObjPtr<ICloudClient> oCloudClient;
1861 CHECK_ERROR2_RET(hrc, pCloudProfile,
1862 CreateCloudClient(oCloudClient.asOutParam()),
1863 RTEXITCODE_FAILURE);
1864 RTPrintf(Cloud::tr("Reset cloud instance with id %s...\n"), strInstanceId.c_str());
1865
1866 ComPtr<IProgress> progress;
1867 CHECK_ERROR2_RET(hrc, oCloudClient,
1868 ResetInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1869 RTEXITCODE_FAILURE);
1870 hrc = showProgress(progress);
1871 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reset the cloud instance failed")), RTEXITCODE_FAILURE);
1872
1873 if (SUCCEEDED(hrc))
1874 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was reset\n"),
1875 strInstanceId.c_str(),
1876 pCommonOpts->provider.pszProviderName,
1877 pCommonOpts->profile.pszProfileName);
1878
1879 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1880}
1881
1882static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1883{
1884 enum
1885 {
1886 kCloudInstanceIota = 1000,
1887 kCloudInstance_Create,
1888 kCloudInstance_Info,
1889 kCloudInstance_Pause,
1890 kCloudInstance_Start,
1891 kCloudInstance_Terminate,
1892 kCloudInstance_Update,
1893 kCloudInstance_Reset,
1894 kCloudInstance_Clone,
1895 kCloudInstance_MetricList,
1896 kCloudInstance_MetricData,
1897 };
1898
1899 static const RTGETOPTDEF s_aOptions[] =
1900 {
1901 { "create", kCloudInstance_Create, RTGETOPT_REQ_NOTHING },
1902 { "info", kCloudInstance_Info, RTGETOPT_REQ_NOTHING },
1903 { "pause", kCloudInstance_Pause, RTGETOPT_REQ_NOTHING },
1904 { "start", kCloudInstance_Start, RTGETOPT_REQ_NOTHING },
1905 { "terminate", kCloudInstance_Terminate, RTGETOPT_REQ_NOTHING },
1906 { "update", kCloudInstance_Update, RTGETOPT_REQ_NOTHING },
1907 { "reset", kCloudInstance_Reset, RTGETOPT_REQ_NOTHING },
1908 { "clone", kCloudInstance_Clone, RTGETOPT_REQ_NOTHING },
1909 { "metriclist", kCloudInstance_MetricList,RTGETOPT_REQ_NOTHING },
1910 { "metricdata", kCloudInstance_MetricData,RTGETOPT_REQ_NOTHING },
1911
1912 { "help", 'h', RTGETOPT_REQ_NOTHING },
1913 { "-?", 'h', RTGETOPT_REQ_NOTHING },
1914 { "-help", 'h', RTGETOPT_REQ_NOTHING },
1915 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1916 };
1917
1918 if (a->argc == iFirst)
1919 {
1920 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1921 printHelp(g_pStdOut);
1922 return RTEXITCODE_SUCCESS;
1923 }
1924
1925 RTGETOPTSTATE GetState;
1926 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1927 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1928
1929 int c;
1930 RTGETOPTUNION ValueUnion;
1931 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1932 {
1933 switch (c)
1934 {
1935 /* Sub-commands: */
1936 case kCloudInstance_Create:
1937 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_CREATE);
1938 return createCloudInstance(a, GetState.iNext, pCommonOpts);
1939
1940 case kCloudInstance_Start:
1941 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_START);
1942 return startCloudInstance(a, GetState.iNext, pCommonOpts);
1943
1944 case kCloudInstance_Pause:
1945 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_PAUSE);
1946 return pauseCloudInstance(a, GetState.iNext, pCommonOpts);
1947
1948 case kCloudInstance_Info:
1949 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_INFO);
1950 return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts);
1951
1952 case kCloudInstance_Update:
1953// setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_UPDATE);
1954 return updateCloudInstance(a, GetState.iNext, pCommonOpts);
1955
1956 case kCloudInstance_Terminate:
1957 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_TERMINATE);
1958 return terminateCloudInstance(a, GetState.iNext, pCommonOpts);
1959
1960 case kCloudInstance_Reset:
1961 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_RESET);
1962 return resetCloudInstance(a, GetState.iNext, pCommonOpts);
1963
1964 case kCloudInstance_Clone:
1965 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_CLONE);
1966 return cloneCloudInstance(a, GetState.iNext, pCommonOpts);
1967
1968 case kCloudInstance_MetricData:
1969 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_METRICDATA);
1970 return cloudInstanceMetricData(a, GetState.iNext, pCommonOpts);
1971
1972 case kCloudInstance_MetricList:
1973 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_METRICLIST);
1974 return cloudInstanceMetricList(a, GetState.iNext, pCommonOpts);
1975
1976 case 'h':
1977 printHelp(g_pStdOut);
1978 return RTEXITCODE_SUCCESS;
1979
1980 case VINF_GETOPT_NOT_OPTION:
1981 return errorUnknownSubcommand(ValueUnion.psz);
1982
1983 default:
1984 return errorGetOpt(c, &ValueUnion);
1985 }
1986 }
1987
1988 return errorNoSubcommand();
1989}
1990
1991
1992static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1993{
1994 HRESULT hrc = S_OK;
1995
1996 static const RTGETOPTDEF s_aOptions[] =
1997 {
1998 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1999 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
2000 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
2001 { "--instance-id", 'i', RTGETOPT_REQ_STRING },
2002 { "--display-name", 'd', RTGETOPT_REQ_STRING },
2003 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
2004 { "help", 'h', RTGETOPT_REQ_NOTHING },
2005 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2006 };
2007 RTGETOPTSTATE GetState;
2008 RTGETOPTUNION ValueUnion;
2009 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2010 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2011 if (a->argc == iFirst)
2012 {
2013 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2014 printHelp(g_pStdOut);
2015 return RTEXITCODE_SUCCESS;
2016 }
2017
2018 Utf8Str strCompartmentId;
2019 Utf8Str strInstanceId;
2020 Utf8Str strDisplayName;
2021 Utf8Str strBucketName;
2022 Utf8Str strObjectName;
2023 com::SafeArray<BSTR> parameters;
2024
2025 int c;
2026 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2027 {
2028 switch (c)
2029 {
2030 case 'c':
2031 strCompartmentId=ValueUnion.psz;
2032 Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2033 break;
2034 case 'i':
2035 strInstanceId=ValueUnion.psz;
2036 Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2037 break;
2038 case 'd':
2039 strDisplayName=ValueUnion.psz;
2040 Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2041 break;
2042 case 'o':
2043 strObjectName=ValueUnion.psz;
2044 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2045 break;
2046 case 'b':
2047 strBucketName=ValueUnion.psz;
2048 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2049 break;
2050 case 'm':
2051 strBucketName=ValueUnion.psz;
2052 Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2053 break;
2054 case 'h':
2055 printHelp(g_pStdOut);
2056 return RTEXITCODE_SUCCESS;
2057 case VINF_GETOPT_NOT_OPTION:
2058 return errorUnknownSubcommand(ValueUnion.psz);
2059 default:
2060 return errorGetOpt(c, &ValueUnion);
2061 }
2062 }
2063
2064 /* Delayed check. It allows us to print help information.*/
2065 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2066 if (FAILED(hrc))
2067 return RTEXITCODE_FAILURE;
2068
2069 if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty())
2070 return errorArgument(Cloud::tr("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one."));
2071
2072 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2073
2074 ComObjPtr<ICloudClient> oCloudClient;
2075 CHECK_ERROR2_RET(hrc, pCloudProfile,
2076 CreateCloudClient(oCloudClient.asOutParam()),
2077 RTEXITCODE_FAILURE);
2078 if (strInstanceId.isNotEmpty())
2079 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the instance \'%s\'...\n"),
2080 strDisplayName.c_str(), strInstanceId.c_str());
2081 else
2082 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n"),
2083 strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str());
2084
2085 ComPtr<IProgress> progress;
2086 CHECK_ERROR2_RET(hrc, oCloudClient,
2087 CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2088 RTEXITCODE_FAILURE);
2089 hrc = showProgress(progress);
2090 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Creating cloud image failed")), RTEXITCODE_FAILURE);
2091
2092 if (SUCCEEDED(hrc))
2093 RTPrintf(Cloud::tr("Cloud image was created successfully\n"));
2094
2095 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2096}
2097
2098
2099static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2100{
2101 HRESULT hrc = S_OK;
2102
2103 static const RTGETOPTDEF s_aOptions[] =
2104 {
2105 { "--id", 'i', RTGETOPT_REQ_STRING },
2106 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
2107 { "--object-name", 'o', RTGETOPT_REQ_STRING },
2108 { "--display-name", 'd', RTGETOPT_REQ_STRING },
2109 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
2110 { "help", 'h', RTGETOPT_REQ_NOTHING },
2111 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2112 };
2113 RTGETOPTSTATE GetState;
2114 RTGETOPTUNION ValueUnion;
2115 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2116 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2117 if (a->argc == iFirst)
2118 {
2119 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2120 printHelp(g_pStdOut);
2121 return RTEXITCODE_SUCCESS;
2122 }
2123
2124 Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */
2125 Utf8Str strBucketName;
2126 Utf8Str strObjectName;
2127 Utf8Str strDisplayName;
2128 Utf8Str strLaunchMode;
2129 com::SafeArray<BSTR> parameters;
2130
2131 int c;
2132 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2133 {
2134 switch (c)
2135 {
2136 case 'b': /* --bucket-name */
2137 {
2138 if (strBucketName.isNotEmpty())
2139 return errorArgument(Cloud::tr("Duplicate parameter: --bucket-name"));
2140
2141 strBucketName = ValueUnion.psz;
2142 if (strBucketName.isEmpty())
2143 return errorArgument(Cloud::tr("Empty parameter: --bucket-name"));
2144
2145 break;
2146 }
2147
2148 case 'o': /* --object-name */
2149 {
2150 if (strObjectName.isNotEmpty())
2151 return errorArgument(Cloud::tr("Duplicate parameter: --object-name"));
2152
2153 strObjectName = ValueUnion.psz;
2154 if (strObjectName.isEmpty())
2155 return errorArgument(Cloud::tr("Empty parameter: --object-name"));
2156
2157 break;
2158 }
2159
2160 case 'i': /* --id */
2161 {
2162 if (strImageId.isNotEmpty())
2163 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
2164
2165 strImageId = ValueUnion.psz;
2166 if (strImageId.isEmpty())
2167 return errorArgument(Cloud::tr("Empty parameter: --id"));
2168
2169 break;
2170 }
2171
2172 case 'd': /* --display-name */
2173 {
2174 if (strDisplayName.isNotEmpty())
2175 return errorArgument(Cloud::tr("Duplicate parameter: --display-name"));
2176
2177 strDisplayName = ValueUnion.psz;
2178 if (strDisplayName.isEmpty())
2179 return errorArgument(Cloud::tr("Empty parameter: --display-name"));
2180
2181 break;
2182 }
2183
2184 case 'm': /* --launch-mode */
2185 {
2186 if (strLaunchMode.isNotEmpty())
2187 return errorArgument(Cloud::tr("Duplicate parameter: --launch-mode"));
2188
2189 strLaunchMode = ValueUnion.psz;
2190 if (strLaunchMode.isEmpty())
2191 return errorArgument(Cloud::tr("Empty parameter: --launch-mode"));
2192
2193 break;
2194 }
2195
2196 case 'h':
2197 printHelp(g_pStdOut);
2198 return RTEXITCODE_SUCCESS;
2199
2200 case VINF_GETOPT_NOT_OPTION:
2201 return errorUnknownSubcommand(ValueUnion.psz);
2202
2203 default:
2204 return errorGetOpt(c, &ValueUnion);
2205 }
2206 }
2207
2208 /* Delayed check. It allows us to print help information.*/
2209 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2210 if (FAILED(hrc))
2211 return RTEXITCODE_FAILURE;
2212
2213 if (strImageId.isNotEmpty())
2214 BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw());
2215 else
2216 return errorArgument(Cloud::tr("Missing parameter: --id"));
2217
2218 if (strBucketName.isNotEmpty())
2219 BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw());
2220 else
2221 return errorArgument(Cloud::tr("Missing parameter: --bucket-name"));
2222
2223 if (strObjectName.isNotEmpty())
2224 BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw());
2225
2226 if (strDisplayName.isNotEmpty())
2227 BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw());
2228
2229 if (strLaunchMode.isNotEmpty())
2230 BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw());
2231
2232
2233 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2234
2235 ComObjPtr<ICloudClient> oCloudClient;
2236 CHECK_ERROR2_RET(hrc, pCloudProfile,
2237 CreateCloudClient(oCloudClient.asOutParam()),
2238 RTEXITCODE_FAILURE);
2239
2240 if (strObjectName.isNotEmpty())
2241 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with name \'%s\'...\n"),
2242 strImageId.c_str(), strObjectName.c_str());
2243 else
2244 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with default name\n"),
2245 strImageId.c_str());
2246
2247 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2248 SafeIfaceArray<IMedium> aImageList;
2249 CHECK_ERROR2_RET(hrc, pVirtualBox,
2250 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)),
2251 RTEXITCODE_FAILURE);
2252
2253 ComPtr<IMedium> pImage;
2254 size_t cImages = aImageList.size();
2255 bool fFound = false;
2256 for (size_t i = 0; i < cImages; ++i)
2257 {
2258 pImage = aImageList[i];
2259 Bstr bstrImageId;
2260 hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam());
2261 if (FAILED(hrc))
2262 continue;
2263
2264 com::Guid imageId(bstrImageId);
2265
2266 if (!imageId.isValid() || imageId.isZero())
2267 continue;
2268
2269 if (!strImageId.compare(imageId.toString()))
2270 {
2271 fFound = true;
2272 RTPrintf(Cloud::tr("Image %s was found\n"), strImageId.c_str());
2273 break;
2274 }
2275 }
2276
2277 if (!fFound)
2278 {
2279 RTPrintf(Cloud::tr("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n"));
2280 return RTEXITCODE_FAILURE;
2281 }
2282
2283 ComPtr<IProgress> progress;
2284 CHECK_ERROR2_RET(hrc, oCloudClient,
2285 ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2286 RTEXITCODE_FAILURE);
2287 hrc = showProgress(progress);
2288 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Export the image to the Cloud failed")), RTEXITCODE_FAILURE);
2289
2290 if (SUCCEEDED(hrc))
2291 RTPrintf(Cloud::tr("Export the image to the Cloud was successfull\n"));
2292
2293 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2294}
2295
2296static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2297{
2298 HRESULT hrc = S_OK;
2299
2300 static const RTGETOPTDEF s_aOptions[] =
2301 {
2302 { "--id", 'i', RTGETOPT_REQ_STRING },
2303 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
2304 { "--object-name", 'o', RTGETOPT_REQ_STRING },
2305 { "help", 'h', RTGETOPT_REQ_NOTHING },
2306 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2307 };
2308 RTGETOPTSTATE GetState;
2309 RTGETOPTUNION ValueUnion;
2310 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2311 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2312 if (a->argc == iFirst)
2313 {
2314 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2315 printHelp(g_pStdOut);
2316 return RTEXITCODE_SUCCESS;
2317 }
2318
2319 Utf8Str strImageId;
2320 Utf8Str strCompartmentId;
2321 Utf8Str strBucketName;
2322 Utf8Str strObjectName;
2323 Utf8Str strDisplayName;
2324 com::SafeArray<BSTR> parameters;
2325
2326 int c;
2327 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2328 {
2329 switch (c)
2330 {
2331 case 'i':
2332 strImageId=ValueUnion.psz;
2333 break;
2334 case 'b':
2335 strBucketName=ValueUnion.psz;
2336 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2337 break;
2338 case 'o':
2339 strObjectName=ValueUnion.psz;
2340 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2341 break;
2342 case 'h':
2343 printHelp(g_pStdOut);
2344 return RTEXITCODE_SUCCESS;
2345 case VINF_GETOPT_NOT_OPTION:
2346 return errorUnknownSubcommand(ValueUnion.psz);
2347 default:
2348 return errorGetOpt(c, &ValueUnion);
2349 }
2350 }
2351
2352 /* Delayed check. It allows us to print help information.*/
2353 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2354 if (FAILED(hrc))
2355 return RTEXITCODE_FAILURE;
2356
2357 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2358
2359 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2360 ComObjPtr<ICloudClient> oCloudClient;
2361 CHECK_ERROR2_RET(hrc, pCloudProfile,
2362 CreateCloudClient(oCloudClient.asOutParam()),
2363 RTEXITCODE_FAILURE);
2364 RTPrintf(Cloud::tr("Creating an object \'%s\' from the cloud image \'%s\'...\n"), strObjectName.c_str(), strImageId.c_str());
2365
2366 ComPtr<IProgress> progress;
2367 CHECK_ERROR2_RET(hrc, oCloudClient,
2368 ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2369 RTEXITCODE_FAILURE);
2370 hrc = showProgress(progress);
2371 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Cloud image import failed")), RTEXITCODE_FAILURE);
2372
2373 if (SUCCEEDED(hrc))
2374 {
2375 RTPrintf(Cloud::tr("Cloud image was imported successfully. Find the downloaded object with the name %s "
2376 "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n"),
2377 strObjectName.c_str());
2378 }
2379
2380 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2381}
2382
2383static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2384{
2385 HRESULT hrc = S_OK;
2386
2387 static const RTGETOPTDEF s_aOptions[] =
2388 {
2389 { "--id", 'i', RTGETOPT_REQ_STRING },
2390 { "help", 'h', RTGETOPT_REQ_NOTHING },
2391 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2392 };
2393 RTGETOPTSTATE GetState;
2394 RTGETOPTUNION ValueUnion;
2395 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2396 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2397 if (a->argc == iFirst)
2398 {
2399 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2400 printHelp(g_pStdOut);
2401 return RTEXITCODE_SUCCESS;
2402 }
2403
2404 Utf8Str strImageId;
2405
2406 int c;
2407 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2408 {
2409 switch (c)
2410 {
2411 case 'i':
2412 strImageId = ValueUnion.psz;
2413 break;
2414 case 'h':
2415 printHelp(g_pStdOut);
2416 return RTEXITCODE_SUCCESS;
2417 case VINF_GETOPT_NOT_OPTION:
2418 return errorUnknownSubcommand(ValueUnion.psz);
2419 default:
2420 return errorGetOpt(c, &ValueUnion);
2421 }
2422 }
2423
2424 /* Delayed check. It allows us to print help information.*/
2425 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2426 if (FAILED(hrc))
2427 return RTEXITCODE_FAILURE;
2428
2429 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2430
2431 ComObjPtr<ICloudClient> oCloudClient;
2432 CHECK_ERROR2_RET(hrc, pCloudProfile,
2433 CreateCloudClient(oCloudClient.asOutParam()),
2434 RTEXITCODE_FAILURE);
2435 RTPrintf(Cloud::tr("Getting information about the cloud image with id \'%s\'...\n"), strImageId.c_str());
2436
2437 ComPtr<IStringArray> infoArray;
2438 com::SafeArray<BSTR> pStrInfoArray;
2439 ComPtr<IProgress> pProgress;
2440
2441 RTPrintf(Cloud::tr("Reply is in the form \'image property\' = \'value\'\n"));
2442 CHECK_ERROR2_RET(hrc, oCloudClient,
2443 GetImageInfo(Bstr(strImageId).raw(),
2444 infoArray.asOutParam(),
2445 pProgress.asOutParam()),
2446 RTEXITCODE_FAILURE);
2447
2448 hrc = showProgress(pProgress);
2449 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Getting information about the cloud image failed")), RTEXITCODE_FAILURE);
2450
2451 CHECK_ERROR2_RET(hrc,
2452 infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)),
2453 RTEXITCODE_FAILURE);
2454
2455 RTPrintf(Cloud::tr("General information about the image:\n"));
2456 size_t cParamNames = pStrInfoArray.size();
2457 for (size_t k = 0; k < cParamNames; k++)
2458 {
2459 Utf8Str data(pStrInfoArray[k]);
2460 RTPrintf("\t%s\n", data.c_str());
2461 }
2462
2463 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2464}
2465
2466static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2467{
2468 RT_NOREF(a);
2469 RT_NOREF(iFirst);
2470 RT_NOREF(pCommonOpts);
2471 return RTEXITCODE_SUCCESS;
2472}
2473
2474static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2475{
2476 HRESULT hrc = S_OK;
2477
2478 static const RTGETOPTDEF s_aOptions[] =
2479 {
2480 { "--id", 'i', RTGETOPT_REQ_STRING },
2481 { "help", 'h', RTGETOPT_REQ_NOTHING },
2482 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2483 };
2484 RTGETOPTSTATE GetState;
2485 RTGETOPTUNION ValueUnion;
2486 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2487 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2488 if (a->argc == iFirst)
2489 {
2490 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2491 printHelp(g_pStdOut);
2492 return RTEXITCODE_SUCCESS;
2493 }
2494
2495 Utf8Str strImageId;
2496
2497 int c;
2498 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2499 {
2500 switch (c)
2501 {
2502 case 'i':
2503 {
2504 if (strImageId.isNotEmpty())
2505 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
2506
2507 strImageId = ValueUnion.psz;
2508 if (strImageId.isEmpty())
2509 return errorArgument(Cloud::tr("Empty parameter: --id"));
2510
2511 break;
2512 }
2513
2514 case 'h':
2515 printHelp(g_pStdOut);
2516 return RTEXITCODE_SUCCESS;
2517 case VINF_GETOPT_NOT_OPTION:
2518 return errorUnknownSubcommand(ValueUnion.psz);
2519
2520 default:
2521 return errorGetOpt(c, &ValueUnion);
2522 }
2523 }
2524
2525 /* Delayed check. It allows us to print help information.*/
2526 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2527 if (FAILED(hrc))
2528 return RTEXITCODE_FAILURE;
2529
2530 if (strImageId.isEmpty())
2531 return errorArgument(Cloud::tr("Missing parameter: --id"));
2532
2533
2534 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2535
2536 ComObjPtr<ICloudClient> oCloudClient;
2537 CHECK_ERROR2_RET(hrc, pCloudProfile,
2538 CreateCloudClient(oCloudClient.asOutParam()),
2539 RTEXITCODE_FAILURE);
2540 RTPrintf(Cloud::tr("Deleting cloud image with id %s...\n"), strImageId.c_str());
2541
2542 ComPtr<IProgress> progress;
2543 CHECK_ERROR2_RET(hrc, oCloudClient,
2544 DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()),
2545 RTEXITCODE_FAILURE);
2546 hrc = showProgress(progress);
2547 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Deleting cloud image failed")), RTEXITCODE_FAILURE);
2548
2549 if (SUCCEEDED(hrc))
2550 RTPrintf(Cloud::tr("Cloud image was deleted successfully\n"));
2551
2552 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2553}
2554
2555static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2556{
2557 enum
2558 {
2559 kCloudImageIota = 1000,
2560 kCloudImage_Create,
2561 kCloudImage_Delete,
2562 kCloudImage_Export,
2563 kCloudImage_Import,
2564 kCloudImage_Info,
2565 kCloudImage_Update,
2566 };
2567
2568 static const RTGETOPTDEF s_aOptions[] =
2569 {
2570 { "create", kCloudImage_Create, RTGETOPT_REQ_NOTHING },
2571 { "delete", kCloudImage_Delete, RTGETOPT_REQ_NOTHING },
2572 { "export", kCloudImage_Export, RTGETOPT_REQ_NOTHING },
2573 { "import", kCloudImage_Import, RTGETOPT_REQ_NOTHING },
2574 { "info", kCloudImage_Info, RTGETOPT_REQ_NOTHING },
2575 { "update", kCloudImage_Update, RTGETOPT_REQ_NOTHING },
2576
2577 { "help", 'h', RTGETOPT_REQ_NOTHING },
2578 { "-?", 'h', RTGETOPT_REQ_NOTHING },
2579 { "-help", 'h', RTGETOPT_REQ_NOTHING },
2580 { "--help", 'h', RTGETOPT_REQ_NOTHING },
2581 };
2582
2583 if (a->argc == iFirst)
2584 {
2585 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2586 printHelp(g_pStdOut);
2587 return RTEXITCODE_SUCCESS;
2588 }
2589
2590 RTGETOPTSTATE GetState;
2591 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2592 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2593
2594 int c;
2595 RTGETOPTUNION ValueUnion;
2596 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2597 {
2598 switch (c)
2599 {
2600 /* Sub-commands: */
2601 case kCloudImage_Create:
2602 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_CREATE);
2603 return createCloudImage(a, GetState.iNext, pCommonOpts);
2604
2605 case kCloudImage_Export:
2606 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_EXPORT);
2607 return exportCloudImage(a, GetState.iNext, pCommonOpts);
2608
2609 case kCloudImage_Import:
2610 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_IMPORT);
2611 return importCloudImage(a, GetState.iNext, pCommonOpts);
2612
2613 case kCloudImage_Info:
2614 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_INFO);
2615 return showCloudImageInfo(a, GetState.iNext, pCommonOpts);
2616
2617 case kCloudImage_Update:
2618// setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_UPDATE);
2619 return updateCloudImage(a, GetState.iNext, pCommonOpts);
2620
2621 case kCloudImage_Delete:
2622 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_DELETE);
2623 return deleteCloudImage(a, GetState.iNext, pCommonOpts);
2624
2625 case 'h':
2626 printHelp(g_pStdOut);
2627 return RTEXITCODE_SUCCESS;
2628
2629 case VINF_GETOPT_NOT_OPTION:
2630 return errorUnknownSubcommand(ValueUnion.psz);
2631
2632 default:
2633 return errorGetOpt(c, &ValueUnion);
2634 }
2635 }
2636
2637 return errorNoSubcommand();
2638}
2639
2640#ifdef VBOX_WITH_CLOUD_NET
2641struct CloudNetworkOptions
2642{
2643 BOOL fEnable;
2644 BOOL fDisable;
2645 Bstr strNetworkId;
2646 Bstr strNetworkName;
2647};
2648typedef struct CloudNetworkOptions CLOUDNETOPT;
2649typedef CLOUDNETOPT *PCLOUDNETOPT;
2650
2651static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr<ICloudNetwork> cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts)
2652{
2653 HRESULT hrc = S_OK;
2654
2655 Bstr strProvider = pCommonOpts->provider.pszProviderName;
2656 Bstr strProfile = pCommonOpts->profile.pszProfileName;
2657
2658 if (options.fEnable)
2659 {
2660 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
2661 }
2662 if (options.fDisable)
2663 {
2664 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
2665 }
2666 if (options.strNetworkId.isNotEmpty())
2667 {
2668 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE);
2669 }
2670 if (strProvider.isNotEmpty())
2671 {
2672 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE);
2673 }
2674 if (strProfile.isNotEmpty())
2675 {
2676 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE);
2677 }
2678
2679 return RTEXITCODE_SUCCESS;
2680}
2681
2682
2683static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2684{
2685 HRESULT hrc = S_OK;
2686 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2687 if (FAILED(hrc))
2688 return RTEXITCODE_FAILURE;
2689
2690 /* Required parameters, the rest is handled in update */
2691 static const RTGETOPTDEF s_aOptions[] =
2692 {
2693 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2694 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2695 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2696 { "--name", 'n', RTGETOPT_REQ_STRING },
2697 };
2698
2699 RTGETOPTSTATE GetState;
2700 RTGETOPTUNION ValueUnion;
2701 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2702 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2703
2704 CLOUDNETOPT options;
2705 options.fEnable = FALSE;
2706 options.fDisable = FALSE;
2707
2708 int c;
2709 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2710 {
2711 switch (c)
2712 {
2713 case 'd':
2714 options.fDisable = TRUE;
2715 break;
2716 case 'e':
2717 options.fEnable = TRUE;
2718 break;
2719 case 'i':
2720 options.strNetworkId=ValueUnion.psz;
2721 break;
2722 case 'n':
2723 options.strNetworkName=ValueUnion.psz;
2724 break;
2725 case VINF_GETOPT_NOT_OPTION:
2726 return errorUnknownSubcommand(ValueUnion.psz);
2727 default:
2728 return errorGetOpt(c, &ValueUnion);
2729 }
2730 }
2731
2732 if (options.strNetworkName.isEmpty())
2733 return errorArgument(Cloud::tr("Missing --name parameter"));
2734 if (options.strNetworkId.isEmpty())
2735 return errorArgument(Cloud::tr("Missing --network-id parameter"));
2736
2737 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2738
2739 ComPtr<ICloudNetwork> cloudNetwork;
2740 CHECK_ERROR2_RET(hrc, pVirtualBox,
2741 CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2742 RTEXITCODE_FAILURE);
2743
2744 /* Fill out the created network */
2745 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2746 if (RT_SUCCESS(rc))
2747 RTPrintf(Cloud::tr("Cloud network was created successfully\n"));
2748
2749 return rc;
2750}
2751
2752
2753static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2754{
2755 RT_NOREF(pCommonOpts);
2756 HRESULT hrc = S_OK;
2757 static const RTGETOPTDEF s_aOptions[] =
2758 {
2759 { "--name", 'n', RTGETOPT_REQ_STRING },
2760 };
2761 RTGETOPTSTATE GetState;
2762 RTGETOPTUNION ValueUnion;
2763 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2764 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2765
2766 Bstr strNetworkName;
2767
2768 int c;
2769 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2770 {
2771 switch (c)
2772 {
2773 case 'n':
2774 strNetworkName=ValueUnion.psz;
2775 break;
2776 case VINF_GETOPT_NOT_OPTION:
2777 return errorUnknownSubcommand(ValueUnion.psz);
2778 default:
2779 return errorGetOpt(c, &ValueUnion);
2780 }
2781 }
2782
2783 if (strNetworkName.isEmpty())
2784 return errorArgument(Cloud::tr("Missing --name parameter"));
2785
2786 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2787 ComPtr<ICloudNetwork> cloudNetwork;
2788 CHECK_ERROR2_RET(hrc, pVirtualBox,
2789 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2790 RTEXITCODE_FAILURE);
2791
2792 RTPrintf(Cloud::tr("Name: %ls\n"), strNetworkName.raw());
2793 BOOL fEnabled = FALSE;
2794 cloudNetwork->COMGETTER(Enabled)(&fEnabled);
2795 RTPrintf(Cloud::tr("State: %s\n"), fEnabled ? Cloud::tr("Enabled") : Cloud::tr("Disabled"));
2796 Bstr Provider;
2797 cloudNetwork->COMGETTER(Provider)(Provider.asOutParam());
2798 RTPrintf(Cloud::tr("CloudProvider: %ls\n"), Provider.raw());
2799 Bstr Profile;
2800 cloudNetwork->COMGETTER(Profile)(Profile.asOutParam());
2801 RTPrintf(Cloud::tr("CloudProfile: %ls\n"), Profile.raw());
2802 Bstr NetworkId;
2803 cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam());
2804 RTPrintf(Cloud::tr("CloudNetworkId: %ls\n"), NetworkId.raw());
2805 Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw());
2806 RTPrintf(Cloud::tr("VBoxNetworkName: %ls\n\n"), netName.raw());
2807
2808 return RTEXITCODE_SUCCESS;
2809}
2810
2811
2812static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2813{
2814 HRESULT hrc = S_OK;
2815
2816 static const RTGETOPTDEF s_aOptions[] =
2817 {
2818 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2819 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2820 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2821 { "--name", 'n', RTGETOPT_REQ_STRING },
2822 };
2823
2824 RTGETOPTSTATE GetState;
2825 RTGETOPTUNION ValueUnion;
2826 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2827 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2828
2829 CLOUDNETOPT options;
2830 options.fEnable = FALSE;
2831 options.fDisable = FALSE;
2832
2833 int c;
2834 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2835 {
2836 switch (c)
2837 {
2838 case 'd':
2839 options.fDisable = TRUE;
2840 break;
2841 case 'e':
2842 options.fEnable = TRUE;
2843 break;
2844 case 'i':
2845 options.strNetworkId=ValueUnion.psz;
2846 break;
2847 case 'n':
2848 options.strNetworkName=ValueUnion.psz;
2849 break;
2850 case VINF_GETOPT_NOT_OPTION:
2851 return errorUnknownSubcommand(ValueUnion.psz);
2852 default:
2853 return errorGetOpt(c, &ValueUnion);
2854 }
2855 }
2856
2857 if (options.strNetworkName.isEmpty())
2858 return errorArgument(Cloud::tr("Missing --name parameter"));
2859
2860 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2861 ComPtr<ICloudNetwork> cloudNetwork;
2862 CHECK_ERROR2_RET(hrc, pVirtualBox,
2863 FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2864 RTEXITCODE_FAILURE);
2865
2866 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2867 if (RT_SUCCESS(rc))
2868 RTPrintf(Cloud::tr("Cloud network %ls was updated successfully\n"), options.strNetworkName.raw());
2869
2870 return rc;
2871}
2872
2873
2874static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2875{
2876 RT_NOREF(pCommonOpts);
2877 HRESULT hrc = S_OK;
2878 static const RTGETOPTDEF s_aOptions[] =
2879 {
2880 { "--name", 'n', RTGETOPT_REQ_STRING },
2881 };
2882 RTGETOPTSTATE GetState;
2883 RTGETOPTUNION ValueUnion;
2884 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2885 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2886
2887 Bstr strNetworkName;
2888
2889 int c;
2890 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2891 {
2892 switch (c)
2893 {
2894 case 'n':
2895 strNetworkName=ValueUnion.psz;
2896 break;
2897 case VINF_GETOPT_NOT_OPTION:
2898 return errorUnknownSubcommand(ValueUnion.psz);
2899 default:
2900 return errorGetOpt(c, &ValueUnion);
2901 }
2902 }
2903
2904 if (strNetworkName.isEmpty())
2905 return errorArgument(Cloud::tr("Missing --name parameter"));
2906
2907 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2908 ComPtr<ICloudNetwork> cloudNetwork;
2909 CHECK_ERROR2_RET(hrc, pVirtualBox,
2910 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2911 RTEXITCODE_FAILURE);
2912
2913 CHECK_ERROR2_RET(hrc, pVirtualBox,
2914 RemoveCloudNetwork(cloudNetwork),
2915 RTEXITCODE_FAILURE);
2916
2917 if (SUCCEEDED(hrc))
2918 RTPrintf(Cloud::tr("Cloud network %ls was deleted successfully\n"), strNetworkName.raw());
2919
2920 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2921}
2922
2923
2924static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2925{
2926 RT_NOREF(pCommonOpts);
2927 HRESULT hrc = S_OK;
2928 static const RTGETOPTDEF s_aOptions[] =
2929 {
2930 { "--gateway-os-name", 'n', RTGETOPT_REQ_STRING },
2931 { "--gateway-os-version", 'v', RTGETOPT_REQ_STRING },
2932 { "--gateway-shape", 's', RTGETOPT_REQ_STRING },
2933 { "--tunnel-network-name", 't', RTGETOPT_REQ_STRING },
2934 { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING },
2935 { "--compartment-id", 'c', RTGETOPT_REQ_STRING }
2936 };
2937 RTGETOPTSTATE GetState;
2938 RTGETOPTUNION ValueUnion;
2939 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2940 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2941
2942 Bstr strGatewayOsName;
2943 Bstr strGatewayOsVersion;
2944 Bstr strGatewayShape;
2945 Bstr strTunnelNetworkName;
2946 Bstr strTunnelNetworkRange;
2947 Bstr strCompartmentId;
2948
2949 int c;
2950 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2951 {
2952 switch (c)
2953 {
2954 case 'n':
2955 strGatewayOsName=ValueUnion.psz;
2956 break;
2957 case 'v':
2958 strGatewayOsVersion=ValueUnion.psz;
2959 break;
2960 case 's':
2961 strGatewayShape=ValueUnion.psz;
2962 break;
2963 case 't':
2964 strTunnelNetworkName=ValueUnion.psz;
2965 break;
2966 case 'r':
2967 strTunnelNetworkRange=ValueUnion.psz;
2968 break;
2969 case 'c':
2970 strCompartmentId=ValueUnion.psz;
2971 break;
2972 case VINF_GETOPT_NOT_OPTION:
2973 return errorUnknownSubcommand(ValueUnion.psz);
2974 default:
2975 return errorGetOpt(c, &ValueUnion);
2976 }
2977 }
2978
2979 /* Delayed check. It allows us to print help information.*/
2980 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2981 if (FAILED(hrc))
2982 return RTEXITCODE_FAILURE;
2983
2984 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2985
2986 RTPrintf(Cloud::tr("Setting up tunnel network in the cloud...\n"));
2987
2988 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2989
2990 /* Use user-specified profile instead of default one. */
2991 if (strCompartmentId.isNotEmpty())
2992 {
2993 CHECK_ERROR2_RET(hrc, pCloudProfile,
2994 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
2995 RTEXITCODE_FAILURE);
2996 }
2997
2998 ComObjPtr<ICloudClient> oCloudClient;
2999 CHECK_ERROR2_RET(hrc, pCloudProfile,
3000 CreateCloudClient(oCloudClient.asOutParam()),
3001 RTEXITCODE_FAILURE);
3002
3003 ComPtr<ICloudNetworkEnvironmentInfo> cloudNetworkEnv;
3004 ComPtr<IProgress> progress;
3005 CHECK_ERROR2_RET(hrc, oCloudClient,
3006 SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(),
3007 strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(),
3008 cloudNetworkEnv.asOutParam(), progress.asOutParam()),
3009 RTEXITCODE_FAILURE);
3010
3011 hrc = showProgress(progress);
3012 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Setting up cloud network environment failed")), RTEXITCODE_FAILURE);
3013
3014 Bstr tunnelNetworkId;
3015 hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam());
3016 RTPrintf(Cloud::tr("Cloud network environment was set up successfully. Tunnel network id is: %ls\n"), tunnelNetworkId.raw());
3017
3018 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
3019}
3020
3021
3022static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
3023{
3024 enum
3025 {
3026 kCloudNetworkIota = 1000,
3027 kCloudNetwork_Create,
3028 kCloudNetwork_Delete,
3029 kCloudNetwork_Info,
3030 kCloudNetwork_Setup,
3031 kCloudNetwork_Update,
3032 };
3033
3034 static const RTGETOPTDEF s_aOptions[] =
3035 {
3036 { "create", kCloudNetwork_Create, RTGETOPT_REQ_NOTHING },
3037 { "delete", kCloudNetwork_Delete, RTGETOPT_REQ_NOTHING },
3038 { "info", kCloudNetwork_Info, RTGETOPT_REQ_NOTHING },
3039 { "setup", kCloudNetwork_Setup, RTGETOPT_REQ_NOTHING },
3040 { "update", kCloudNetwork_Update, RTGETOPT_REQ_NOTHING },
3041 };
3042
3043 if (a->argc < 1)
3044 return errorNoSubcommand();
3045
3046 RTGETOPTSTATE GetState;
3047 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
3048 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
3049
3050 int c;
3051 RTGETOPTUNION ValueUnion;
3052 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
3053 {
3054 switch (c)
3055 {
3056 /* Sub-commands: */
3057 case kCloudNetwork_Create:
3058 return createCloudNetwork(a, GetState.iNext, pCommonOpts);
3059
3060 case kCloudNetwork_Info:
3061 return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts);
3062
3063 case kCloudNetwork_Update:
3064 return updateCloudNetwork(a, GetState.iNext, pCommonOpts);
3065
3066 case kCloudNetwork_Delete:
3067 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
3068
3069 case kCloudNetwork_Setup:
3070 return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts);
3071
3072 case VINF_GETOPT_NOT_OPTION:
3073 return errorUnknownSubcommand(ValueUnion.psz);
3074
3075 default:
3076 return errorGetOpt(c, &ValueUnion);
3077 }
3078 }
3079
3080 return errorNoSubcommand();
3081}
3082#endif /* VBOX_WITH_CLOUD_NET */
3083
3084
3085RTEXITCODE handleCloud(HandlerArg *a)
3086{
3087 enum
3088 {
3089 kCloudIota = 1000,
3090 kCloud_Image,
3091 kCloud_Instance,
3092 kCloud_List,
3093 kCloud_Machine,
3094 kCloud_Network,
3095 kCloud_Object,
3096 kCloud_ShowVMInfo,
3097 kCloud_Volume,
3098 };
3099
3100 static const RTGETOPTDEF s_aOptions[] =
3101 {
3102 /* common options */
3103 { "--provider", 'v', RTGETOPT_REQ_STRING },
3104 { "--profile", 'f', RTGETOPT_REQ_STRING },
3105
3106 { "image", kCloud_Image, RTGETOPT_REQ_NOTHING },
3107 { "instance", kCloud_Instance, RTGETOPT_REQ_NOTHING },
3108 { "list", kCloud_List, RTGETOPT_REQ_NOTHING },
3109 { "machine", kCloud_Machine, RTGETOPT_REQ_NOTHING },
3110 { "network", kCloud_Network, RTGETOPT_REQ_NOTHING },
3111 { "object", kCloud_Object, RTGETOPT_REQ_NOTHING },
3112 { "showvminfo", kCloud_ShowVMInfo, RTGETOPT_REQ_NOTHING },
3113 { "volume", kCloud_Volume, RTGETOPT_REQ_NOTHING },
3114 };
3115
3116 if (a->argc < 1)
3117 return errorNoSubcommand();
3118
3119 RTGETOPTSTATE GetState;
3120 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
3121 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
3122
3123 CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} };
3124 int c;
3125 RTGETOPTUNION ValueUnion;
3126 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
3127 {
3128 switch (c)
3129 {
3130 case 'v': // --provider
3131 commonOpts.provider.pszProviderName = ValueUnion.psz;
3132 break;
3133
3134 case 'f': // --profile
3135 commonOpts.profile.pszProfileName = ValueUnion.psz;
3136 break;
3137
3138 /* Sub-commands: */
3139 case kCloud_List:
3140 return handleCloudLists(a, GetState.iNext, &commonOpts);
3141
3142 case kCloud_Image:
3143 return handleCloudImage(a, GetState.iNext, &commonOpts);
3144
3145 case kCloud_Instance:
3146 return handleCloudInstance(a, GetState.iNext, &commonOpts);
3147
3148#ifdef VBOX_WITH_CLOUD_NET
3149 case kCloud_Network:
3150 return handleCloudNetwork(a, GetState.iNext, &commonOpts);
3151#endif /* VBOX_WITH_CLOUD_NET */
3152
3153 /* "cloud machine ..." handling is in VBoxManageCloudMachine.cpp */
3154 case kCloud_Machine:
3155 return handleCloudMachine(a, GetState.iNext,
3156 commonOpts.provider.pszProviderName,
3157 commonOpts.profile.pszProfileName);
3158
3159 /* ... including aliases that mimic the local vm commands */
3160 case kCloud_ShowVMInfo:
3161 return handleCloudShowVMInfo(a, GetState.iNext,
3162 commonOpts.provider.pszProviderName,
3163 commonOpts.profile.pszProfileName);
3164
3165 case VINF_GETOPT_NOT_OPTION:
3166 return errorUnknownSubcommand(ValueUnion.psz);
3167
3168 default:
3169 return errorGetOpt(c, &ValueUnion);
3170 }
3171 }
3172
3173 return errorNoSubcommand();
3174}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use