VirtualBox

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

Last change on this file was 102637, checked in by vboxsync, 5 months ago

Removed excessive code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 115.2 KB
Line 
1/* $Id: VBoxManageCloud.cpp 102637 2023-12-18 15:56:11Z 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 RTPrintf(Cloud::tr(" - %ls\n"), value.raw());
1314 }
1315 }
1316
1317 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1318}
1319
1320
1321static RTEXITCODE cloudInstanceMetricData(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1322{
1323 HRESULT hrc = S_OK;
1324
1325 static const RTGETOPTDEF s_aOptions[] =
1326 {
1327 { "--id", 'i', RTGETOPT_REQ_STRING },
1328 { "--metric-name", 'n', RTGETOPT_REQ_STRING },
1329 { "--metric-points",'p', RTGETOPT_REQ_STRING },
1330 { "help", 'h', RTGETOPT_REQ_NOTHING },
1331 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1332 };
1333 RTGETOPTSTATE GetState;
1334 RTGETOPTUNION ValueUnion;
1335 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1336 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1337 if (a->argc == iFirst)
1338 {
1339 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1340 printHelp(g_pStdOut);
1341 return RTEXITCODE_SUCCESS;
1342 }
1343
1344 Utf8Str strInstanceId;
1345 Utf8Str strMetricName;
1346 Utf8Str strMetricPoints;
1347
1348 int c;
1349 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1350 {
1351 switch (c)
1352 {
1353 case 'i':
1354 {
1355 if (strInstanceId.isNotEmpty())
1356 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1357
1358 strInstanceId = ValueUnion.psz;
1359 if (strInstanceId.isEmpty())
1360 return errorArgument(Cloud::tr("Empty parameter: --id"));
1361
1362 break;
1363 }
1364 case 'n':
1365 {
1366 if (strMetricName.isNotEmpty())
1367 return errorArgument(Cloud::tr("Duplicate parameter: --metric-name"));
1368
1369 strMetricName = ValueUnion.psz;
1370 if (strMetricName.isEmpty())
1371 return errorArgument(Cloud::tr("Empty parameter: --metric-name"));
1372
1373 break;
1374 }
1375 case 'p':
1376 {
1377 if (strMetricPoints.isNotEmpty())
1378 return errorArgument(Cloud::tr("Duplicate parameter: --metric-points"));
1379
1380 strMetricPoints = ValueUnion.psz;
1381 if (strMetricPoints.isEmpty())
1382 return errorArgument(Cloud::tr("Empty parameter: --metric-points"));
1383
1384 break;
1385 }
1386 case 'h':
1387 printHelp(g_pStdOut);
1388 return RTEXITCODE_SUCCESS;
1389 case VINF_GETOPT_NOT_OPTION:
1390 return errorUnknownSubcommand(ValueUnion.psz);
1391
1392 default:
1393 return errorGetOpt(c, &ValueUnion);
1394 }
1395 }
1396
1397 /* Delayed check. It allows us to print help information.*/
1398 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1399 if (FAILED(hrc))
1400 return RTEXITCODE_FAILURE;
1401
1402 if (strInstanceId.isEmpty())
1403 return errorArgument(Cloud::tr("Missing parameter: --id"));
1404 if (strMetricName.isEmpty())
1405 return errorArgument(Cloud::tr("Missing parameter: --metric-name"));
1406
1407 unsigned long metricPoins;
1408 strMetricPoints.isEmpty() ? metricPoins = 1 : metricPoins = RTStrToUInt32(strMetricPoints.c_str());
1409
1410 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1411
1412 ComObjPtr<ICloudClient> oCloudClient;
1413 CHECK_ERROR2_RET(hrc, pCloudProfile,
1414 CreateCloudClient(oCloudClient.asOutParam()),
1415 RTEXITCODE_FAILURE);
1416 RTPrintf(Cloud::tr("Getting %s metric for the cloud instance with id %s...\n"), strMetricName.c_str(), strInstanceId.c_str());
1417 RTPrintf(Cloud::tr("Reply is in the form \'%s[Rfc2822 time format]\' = \'value\'\n"), strMetricName.c_str());
1418
1419 /* Check the requested metric type */
1420 MetricType_T aMetricType;
1421 CHECK_ERROR2_RET(hrc, oCloudClient, GetMetricTypeByName(com::Bstr(strMetricName.c_str()).raw(), &aMetricType), RTEXITCODE_FAILURE);
1422
1423 /* First step*/
1424 RTPrintf(Cloud::tr("First, reading the cloud machines list...\n"));
1425 ComPtr<IProgress> progress;
1426 CHECK_ERROR2_RET(hrc, oCloudClient, ReadCloudMachineList(progress.asOutParam()), RTEXITCODE_FAILURE);
1427
1428 hrc = showProgress(progress);
1429 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reading the cloud machines list failed")), RTEXITCODE_FAILURE);
1430
1431 com::SafeIfaceArray<ICloudMachine> aMachines;
1432 CHECK_ERROR2_RET(hrc, oCloudClient,
1433 COMGETTER(CloudMachineList)(ComSafeArrayAsOutParam(aMachines)),
1434 RTEXITCODE_FAILURE);
1435
1436 const size_t cMachines = aMachines.size();
1437 if (cMachines == 0)
1438 return RTEXITCODE_SUCCESS;
1439
1440 std::vector<ComPtr<ICloudMachine> > vMachines(cMachines);
1441 std::vector<com::Bstr> vBstrCloudIds(cMachines);
1442 std::vector<com::Bstr> vBstrIds(cMachines);
1443
1444 com::Bstr bstrFoundMachineVBoxId;
1445
1446 for (size_t i = 0; i < cMachines; ++i)
1447 {
1448 vMachines[i] = aMachines[i];
1449
1450 CHECK_ERROR2_RET(hrc, vMachines[i],
1451 COMGETTER(CloudId)(vBstrCloudIds[i].asOutParam()),
1452 RTEXITCODE_FAILURE);
1453
1454 Utf8Str strCurrMachineCloudId(vBstrCloudIds[i]);
1455 if (strCurrMachineCloudId.equals(strInstanceId))
1456 {
1457 CHECK_ERROR2_RET(hrc, vMachines[i],
1458 COMGETTER(Id)(vBstrIds[i].asOutParam()),
1459 RTEXITCODE_FAILURE);
1460 bstrFoundMachineVBoxId = vBstrIds[i];
1461 break;
1462 }
1463 }
1464
1465 if (bstrFoundMachineVBoxId.isEmpty())
1466 {
1467 RTPrintf("The passed cloud instance Id \'%s\' WASN'T found among the cloud machines "
1468 "of user \'%s\' registered with VirtualBox\n",
1469 strInstanceId.c_str(), pCommonOpts->profile.pszProfileName);
1470 return RTEXITCODE_FAILURE;
1471 }
1472
1473 /* Second step*/
1474 RTPrintf(Cloud::tr("Second, refresh information about cloud instance ...\n"));
1475 ComPtr<ICloudMachine> pMachine;
1476 CHECK_ERROR2_RET(hrc, oCloudClient,
1477 GetCloudMachine(bstrFoundMachineVBoxId.raw(), pMachine.asOutParam()), RTEXITCODE_FAILURE);
1478
1479 ComPtr<IProgress> pRefreshProgress;
1480 CHECK_ERROR2_RET(hrc, pMachine, Refresh(pRefreshProgress.asOutParam()), RTEXITCODE_FAILURE);
1481
1482 hrc = showProgress(pRefreshProgress);
1483 CHECK_PROGRESS_ERROR_RET(pRefreshProgress, (Cloud::tr("Refreshing information about cloud instance failed")), RTEXITCODE_FAILURE);
1484
1485 /* Third step*/
1486 RTPrintf(Cloud::tr("Third, request metric data from cloud instance ...\n"));
1487 ComPtr<IProgress> progress2;
1488 ComPtr<IStringArray> returnDataValues;
1489 ComPtr<IStringArray> returnDataTimestamps;
1490 ComPtr<IStringArray> returnMeasureUnits;
1491
1492 CHECK_ERROR2_RET(hrc, pMachine, EnumerateMetricData(aMetricType,
1493 metricPoins,
1494 returnDataValues.asOutParam(),
1495 returnDataTimestamps.asOutParam(),
1496 returnMeasureUnits.asOutParam(),
1497 progress2.asOutParam()), RTEXITCODE_FAILURE);
1498
1499 hrc = showProgress(progress2);
1500 CHECK_PROGRESS_ERROR_RET(progress2, (Cloud::tr("Getting metric data failed")), RTEXITCODE_FAILURE);
1501
1502 com::SafeArray<BSTR> dataValueArray;
1503 CHECK_ERROR2_RET(hrc,
1504 returnDataValues, COMGETTER(Values)(ComSafeArrayAsOutParam(dataValueArray)),
1505 RTEXITCODE_FAILURE);
1506
1507 com::SafeArray<BSTR> dataTimestampArray;
1508 CHECK_ERROR2_RET(hrc,
1509 returnDataTimestamps, COMGETTER(Values)(ComSafeArrayAsOutParam(dataTimestampArray)),
1510 RTEXITCODE_FAILURE);
1511
1512 com::SafeArray<BSTR> measureUnitArray;
1513 CHECK_ERROR2_RET(hrc,
1514 returnMeasureUnits, COMGETTER(Values)(ComSafeArrayAsOutParam(measureUnitArray)),
1515 RTEXITCODE_FAILURE);
1516
1517 size_t cDataValueArraySize = dataValueArray.size();
1518 Bstr unit = cDataValueArraySize == 0 ? Bstr("unknown units") : measureUnitArray[0];
1519 RTPrintf(Cloud::tr("The %s metric values (in %ls):\n"), strMetricName.c_str(), unit.raw());
1520
1521 if (cDataValueArraySize == 0)
1522 RTPrintf(Cloud::tr("\tThe list of metric data is empty. It may mean that an appropriate service wasn't run on the instance.\n"));
1523 else
1524 {
1525 Bstr value;
1526 for (size_t k = 0; k < cDataValueArraySize; ++k)
1527 {
1528 value = dataValueArray[k];
1529 Utf8Str strTimestamp(dataTimestampArray[k]);
1530 RTPrintf(Cloud::tr("%d: %s[%s] = %ls\n"), k, strMetricName.c_str(), strTimestamp.c_str(), value.raw());
1531 }
1532 }
1533
1534 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1535}
1536
1537
1538static RTEXITCODE startCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1539{
1540 HRESULT hrc = S_OK;
1541
1542 static const RTGETOPTDEF s_aOptions[] =
1543 {
1544 { "--id", 'i', RTGETOPT_REQ_STRING },
1545 { "help", 'h', RTGETOPT_REQ_NOTHING },
1546 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1547 };
1548 RTGETOPTSTATE GetState;
1549 RTGETOPTUNION ValueUnion;
1550 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1551 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1552 if (a->argc == iFirst)
1553 {
1554 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1555 printHelp(g_pStdOut);
1556 return RTEXITCODE_SUCCESS;
1557 }
1558
1559 Utf8Str strInstanceId;
1560
1561 int c;
1562 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1563 {
1564 switch (c)
1565 {
1566 case 'i':
1567 {
1568 if (strInstanceId.isNotEmpty())
1569 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1570
1571 strInstanceId = ValueUnion.psz;
1572 if (strInstanceId.isEmpty())
1573 return errorArgument(Cloud::tr("Empty parameter: --id"));
1574
1575 break;
1576 }
1577 case 'h':
1578 printHelp(g_pStdOut);
1579 return RTEXITCODE_SUCCESS;
1580 case VINF_GETOPT_NOT_OPTION:
1581 return errorUnknownSubcommand(ValueUnion.psz);
1582
1583 default:
1584 return errorGetOpt(c, &ValueUnion);
1585 }
1586 }
1587
1588 /* Delayed check. It allows us to print help information.*/
1589 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1590 if (FAILED(hrc))
1591 return RTEXITCODE_FAILURE;
1592
1593 if (strInstanceId.isEmpty())
1594 return errorArgument(Cloud::tr("Missing parameter: --id"));
1595
1596 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1597
1598 ComObjPtr<ICloudClient> oCloudClient;
1599 CHECK_ERROR2_RET(hrc, pCloudProfile,
1600 CreateCloudClient(oCloudClient.asOutParam()),
1601 RTEXITCODE_FAILURE);
1602 RTPrintf(Cloud::tr("Starting cloud instance with id %s...\n"), strInstanceId.c_str());
1603
1604 ComPtr<IProgress> progress;
1605 CHECK_ERROR2_RET(hrc, oCloudClient,
1606 StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1607 RTEXITCODE_FAILURE);
1608 hrc = showProgress(progress);
1609 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Starting the cloud instance failed")), RTEXITCODE_FAILURE);
1610
1611 if (SUCCEEDED(hrc))
1612 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n"),
1613 strInstanceId.c_str(),
1614 pCommonOpts->provider.pszProviderName,
1615 pCommonOpts->profile.pszProfileName);
1616
1617 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1618}
1619
1620static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1621{
1622 HRESULT hrc = S_OK;
1623
1624 static const RTGETOPTDEF s_aOptions[] =
1625 {
1626 { "--id", 'i', RTGETOPT_REQ_STRING },
1627 { "help", 'h', RTGETOPT_REQ_NOTHING },
1628 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1629 };
1630 RTGETOPTSTATE GetState;
1631 RTGETOPTUNION ValueUnion;
1632 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1633 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1634 if (a->argc == iFirst)
1635 {
1636 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1637 printHelp(g_pStdOut);
1638 return RTEXITCODE_SUCCESS;
1639 }
1640
1641 Utf8Str strInstanceId;
1642
1643 int c;
1644 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1645 {
1646 switch (c)
1647 {
1648 case 'i':
1649 {
1650 if (strInstanceId.isNotEmpty())
1651 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1652
1653 strInstanceId = ValueUnion.psz;
1654 if (strInstanceId.isEmpty())
1655 return errorArgument(Cloud::tr("Empty parameter: --id"));
1656
1657 break;
1658 }
1659 case 'h':
1660 printHelp(g_pStdOut);
1661 return RTEXITCODE_SUCCESS;
1662 case VINF_GETOPT_NOT_OPTION:
1663 return errorUnknownSubcommand(ValueUnion.psz);
1664
1665 default:
1666 return errorGetOpt(c, &ValueUnion);
1667 }
1668 }
1669
1670 /* Delayed check. It allows us to print help information.*/
1671 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1672 if (FAILED(hrc))
1673 return RTEXITCODE_FAILURE;
1674
1675 if (strInstanceId.isEmpty())
1676 return errorArgument(Cloud::tr("Missing parameter: --id"));
1677
1678 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1679
1680 ComObjPtr<ICloudClient> oCloudClient;
1681 CHECK_ERROR2_RET(hrc, pCloudProfile,
1682 CreateCloudClient(oCloudClient.asOutParam()),
1683 RTEXITCODE_FAILURE);
1684 RTPrintf(Cloud::tr("Pausing cloud instance with id %s...\n"), strInstanceId.c_str());
1685
1686 ComPtr<IProgress> progress;
1687 CHECK_ERROR2_RET(hrc, oCloudClient,
1688 PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1689 RTEXITCODE_FAILURE);
1690 hrc = showProgress(progress);
1691 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Pause the cloud instance failed")), RTEXITCODE_FAILURE);
1692
1693 if (SUCCEEDED(hrc))
1694 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n"),
1695 strInstanceId.c_str(),
1696 pCommonOpts->provider.pszProviderName,
1697 pCommonOpts->profile.pszProfileName);
1698
1699 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1700}
1701
1702static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1703{
1704 HRESULT hrc = S_OK;
1705
1706 static const RTGETOPTDEF s_aOptions[] =
1707 {
1708 { "--id", 'i', RTGETOPT_REQ_STRING },
1709 { "help", 'h', RTGETOPT_REQ_NOTHING },
1710 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1711 };
1712 RTGETOPTSTATE GetState;
1713 RTGETOPTUNION ValueUnion;
1714 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1715 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1716 if (a->argc == iFirst)
1717 {
1718 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1719 printHelp(g_pStdOut);
1720 return RTEXITCODE_SUCCESS;
1721 }
1722
1723 Utf8Str strInstanceId;
1724
1725 int c;
1726 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1727 {
1728 switch (c)
1729 {
1730 case 'i':
1731 {
1732 if (strInstanceId.isNotEmpty())
1733 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1734
1735 strInstanceId = ValueUnion.psz;
1736 if (strInstanceId.isEmpty())
1737 return errorArgument(Cloud::tr("Empty parameter: --id"));
1738
1739 break;
1740 }
1741 case 'h':
1742 printHelp(g_pStdOut);
1743 return RTEXITCODE_SUCCESS;
1744 case VINF_GETOPT_NOT_OPTION:
1745 return errorUnknownSubcommand(ValueUnion.psz);
1746
1747 default:
1748 return errorGetOpt(c, &ValueUnion);
1749 }
1750 }
1751
1752 /* Delayed check. It allows us to print help information.*/
1753 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1754 if (FAILED(hrc))
1755 return RTEXITCODE_FAILURE;
1756
1757 if (strInstanceId.isEmpty())
1758 return errorArgument(Cloud::tr("Missing parameter: --id"));
1759
1760
1761 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1762
1763 ComObjPtr<ICloudClient> oCloudClient;
1764 CHECK_ERROR2_RET(hrc, pCloudProfile,
1765 CreateCloudClient(oCloudClient.asOutParam()),
1766 RTEXITCODE_FAILURE);
1767 RTPrintf(Cloud::tr("Terminating cloud instance with id %s...\n"), strInstanceId.c_str());
1768
1769 ComPtr<IProgress> progress;
1770 CHECK_ERROR2_RET(hrc, oCloudClient,
1771 TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1772 RTEXITCODE_FAILURE);
1773 hrc = showProgress(progress);
1774 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Termination the cloud instance failed")), RTEXITCODE_FAILURE);
1775
1776 if (SUCCEEDED(hrc))
1777 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n"),
1778 strInstanceId.c_str(),
1779 pCommonOpts->provider.pszProviderName,
1780 pCommonOpts->profile.pszProfileName);
1781
1782 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1783}
1784
1785static RTEXITCODE resetCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1786{
1787 HRESULT hrc = S_OK;
1788
1789 static const RTGETOPTDEF s_aOptions[] =
1790 {
1791 { "--id", 'i', RTGETOPT_REQ_STRING },
1792 { "help", 'h', RTGETOPT_REQ_NOTHING },
1793 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1794 };
1795 RTGETOPTSTATE GetState;
1796 RTGETOPTUNION ValueUnion;
1797 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1798 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1799 if (a->argc == iFirst)
1800 {
1801 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1802 printHelp(g_pStdOut);
1803 return RTEXITCODE_SUCCESS;
1804 }
1805
1806 Utf8Str strInstanceId;
1807
1808 int c;
1809 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1810 {
1811 switch (c)
1812 {
1813 case 'i':
1814 {
1815 if (strInstanceId.isNotEmpty())
1816 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1817
1818 strInstanceId = ValueUnion.psz;
1819 if (strInstanceId.isEmpty())
1820 return errorArgument(Cloud::tr("Empty parameter: --id"));
1821
1822 break;
1823 }
1824 case 'h':
1825 printHelp(g_pStdOut);
1826 return RTEXITCODE_SUCCESS;
1827 case VINF_GETOPT_NOT_OPTION:
1828 return errorUnknownSubcommand(ValueUnion.psz);
1829
1830 default:
1831 return errorGetOpt(c, &ValueUnion);
1832 }
1833 }
1834
1835 /* Delayed check. It allows us to print help information.*/
1836 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1837 if (FAILED(hrc))
1838 return RTEXITCODE_FAILURE;
1839
1840 if (strInstanceId.isEmpty())
1841 return errorArgument(Cloud::tr("Missing parameter: --id"));
1842
1843 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1844
1845 ComObjPtr<ICloudClient> oCloudClient;
1846 CHECK_ERROR2_RET(hrc, pCloudProfile,
1847 CreateCloudClient(oCloudClient.asOutParam()),
1848 RTEXITCODE_FAILURE);
1849 RTPrintf(Cloud::tr("Reset cloud instance with id %s...\n"), strInstanceId.c_str());
1850
1851 ComPtr<IProgress> progress;
1852 CHECK_ERROR2_RET(hrc, oCloudClient,
1853 ResetInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1854 RTEXITCODE_FAILURE);
1855 hrc = showProgress(progress);
1856 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reset the cloud instance failed")), RTEXITCODE_FAILURE);
1857
1858 if (SUCCEEDED(hrc))
1859 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was reset\n"),
1860 strInstanceId.c_str(),
1861 pCommonOpts->provider.pszProviderName,
1862 pCommonOpts->profile.pszProfileName);
1863
1864 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1865}
1866
1867static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1868{
1869 enum
1870 {
1871 kCloudInstanceIota = 1000,
1872 kCloudInstance_Create,
1873 kCloudInstance_Info,
1874 kCloudInstance_Pause,
1875 kCloudInstance_Start,
1876 kCloudInstance_Terminate,
1877 kCloudInstance_Update,
1878 kCloudInstance_Reset,
1879 kCloudInstance_Clone,
1880 kCloudInstance_MetricList,
1881 kCloudInstance_MetricData,
1882 };
1883
1884 static const RTGETOPTDEF s_aOptions[] =
1885 {
1886 { "create", kCloudInstance_Create, RTGETOPT_REQ_NOTHING },
1887 { "info", kCloudInstance_Info, RTGETOPT_REQ_NOTHING },
1888 { "pause", kCloudInstance_Pause, RTGETOPT_REQ_NOTHING },
1889 { "start", kCloudInstance_Start, RTGETOPT_REQ_NOTHING },
1890 { "terminate", kCloudInstance_Terminate, RTGETOPT_REQ_NOTHING },
1891 { "update", kCloudInstance_Update, RTGETOPT_REQ_NOTHING },
1892 { "reset", kCloudInstance_Reset, RTGETOPT_REQ_NOTHING },
1893 { "clone", kCloudInstance_Clone, RTGETOPT_REQ_NOTHING },
1894 { "metriclist", kCloudInstance_MetricList,RTGETOPT_REQ_NOTHING },
1895 { "metricdata", kCloudInstance_MetricData,RTGETOPT_REQ_NOTHING },
1896
1897 { "help", 'h', RTGETOPT_REQ_NOTHING },
1898 { "-?", 'h', RTGETOPT_REQ_NOTHING },
1899 { "-help", 'h', RTGETOPT_REQ_NOTHING },
1900 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1901 };
1902
1903 if (a->argc == iFirst)
1904 {
1905 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1906 printHelp(g_pStdOut);
1907 return RTEXITCODE_SUCCESS;
1908 }
1909
1910 RTGETOPTSTATE GetState;
1911 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1912 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1913
1914 int c;
1915 RTGETOPTUNION ValueUnion;
1916 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1917 {
1918 switch (c)
1919 {
1920 /* Sub-commands: */
1921 case kCloudInstance_Create:
1922 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_CREATE);
1923 return createCloudInstance(a, GetState.iNext, pCommonOpts);
1924
1925 case kCloudInstance_Start:
1926 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_START);
1927 return startCloudInstance(a, GetState.iNext, pCommonOpts);
1928
1929 case kCloudInstance_Pause:
1930 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_PAUSE);
1931 return pauseCloudInstance(a, GetState.iNext, pCommonOpts);
1932
1933 case kCloudInstance_Info:
1934 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_INFO);
1935 return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts);
1936
1937 case kCloudInstance_Update:
1938// setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_UPDATE);
1939 return updateCloudInstance(a, GetState.iNext, pCommonOpts);
1940
1941 case kCloudInstance_Terminate:
1942 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_TERMINATE);
1943 return terminateCloudInstance(a, GetState.iNext, pCommonOpts);
1944
1945 case kCloudInstance_Reset:
1946 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_RESET);
1947 return resetCloudInstance(a, GetState.iNext, pCommonOpts);
1948
1949 case kCloudInstance_Clone:
1950 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_CLONE);
1951 return cloneCloudInstance(a, GetState.iNext, pCommonOpts);
1952
1953 case kCloudInstance_MetricData:
1954 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_METRICDATA);
1955 return cloudInstanceMetricData(a, GetState.iNext, pCommonOpts);
1956
1957 case kCloudInstance_MetricList:
1958 setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_METRICLIST);
1959 return cloudInstanceMetricList(a, GetState.iNext, pCommonOpts);
1960
1961 case 'h':
1962 printHelp(g_pStdOut);
1963 return RTEXITCODE_SUCCESS;
1964
1965 case VINF_GETOPT_NOT_OPTION:
1966 return errorUnknownSubcommand(ValueUnion.psz);
1967
1968 default:
1969 return errorGetOpt(c, &ValueUnion);
1970 }
1971 }
1972
1973 return errorNoSubcommand();
1974}
1975
1976
1977static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1978{
1979 HRESULT hrc = S_OK;
1980
1981 static const RTGETOPTDEF s_aOptions[] =
1982 {
1983 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1984 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1985 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
1986 { "--instance-id", 'i', RTGETOPT_REQ_STRING },
1987 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1988 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1989 { "help", 'h', RTGETOPT_REQ_NOTHING },
1990 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1991 };
1992 RTGETOPTSTATE GetState;
1993 RTGETOPTUNION ValueUnion;
1994 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1995 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1996 if (a->argc == iFirst)
1997 {
1998 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1999 printHelp(g_pStdOut);
2000 return RTEXITCODE_SUCCESS;
2001 }
2002
2003 Utf8Str strCompartmentId;
2004 Utf8Str strInstanceId;
2005 Utf8Str strDisplayName;
2006 Utf8Str strBucketName;
2007 Utf8Str strObjectName;
2008 com::SafeArray<BSTR> parameters;
2009
2010 int c;
2011 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2012 {
2013 switch (c)
2014 {
2015 case 'c':
2016 strCompartmentId=ValueUnion.psz;
2017 Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2018 break;
2019 case 'i':
2020 strInstanceId=ValueUnion.psz;
2021 Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2022 break;
2023 case 'd':
2024 strDisplayName=ValueUnion.psz;
2025 Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2026 break;
2027 case 'o':
2028 strObjectName=ValueUnion.psz;
2029 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2030 break;
2031 case 'b':
2032 strBucketName=ValueUnion.psz;
2033 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2034 break;
2035 case 'm':
2036 strBucketName=ValueUnion.psz;
2037 Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2038 break;
2039 case 'h':
2040 printHelp(g_pStdOut);
2041 return RTEXITCODE_SUCCESS;
2042 case VINF_GETOPT_NOT_OPTION:
2043 return errorUnknownSubcommand(ValueUnion.psz);
2044 default:
2045 return errorGetOpt(c, &ValueUnion);
2046 }
2047 }
2048
2049 /* Delayed check. It allows us to print help information.*/
2050 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2051 if (FAILED(hrc))
2052 return RTEXITCODE_FAILURE;
2053
2054 if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty())
2055 return errorArgument(Cloud::tr("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one."));
2056
2057 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2058
2059 ComObjPtr<ICloudClient> oCloudClient;
2060 CHECK_ERROR2_RET(hrc, pCloudProfile,
2061 CreateCloudClient(oCloudClient.asOutParam()),
2062 RTEXITCODE_FAILURE);
2063 if (strInstanceId.isNotEmpty())
2064 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the instance \'%s\'...\n"),
2065 strDisplayName.c_str(), strInstanceId.c_str());
2066 else
2067 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n"),
2068 strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str());
2069
2070 ComPtr<IProgress> progress;
2071 CHECK_ERROR2_RET(hrc, oCloudClient,
2072 CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2073 RTEXITCODE_FAILURE);
2074 hrc = showProgress(progress);
2075 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Creating cloud image failed")), RTEXITCODE_FAILURE);
2076
2077 if (SUCCEEDED(hrc))
2078 RTPrintf(Cloud::tr("Cloud image was created successfully\n"));
2079
2080 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2081}
2082
2083
2084static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2085{
2086 HRESULT hrc = S_OK;
2087
2088 static const RTGETOPTDEF s_aOptions[] =
2089 {
2090 { "--id", 'i', RTGETOPT_REQ_STRING },
2091 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
2092 { "--object-name", 'o', RTGETOPT_REQ_STRING },
2093 { "--display-name", 'd', RTGETOPT_REQ_STRING },
2094 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
2095 { "help", 'h', RTGETOPT_REQ_NOTHING },
2096 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2097 };
2098 RTGETOPTSTATE GetState;
2099 RTGETOPTUNION ValueUnion;
2100 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2101 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2102 if (a->argc == iFirst)
2103 {
2104 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2105 printHelp(g_pStdOut);
2106 return RTEXITCODE_SUCCESS;
2107 }
2108
2109 Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */
2110 Utf8Str strBucketName;
2111 Utf8Str strObjectName;
2112 Utf8Str strDisplayName;
2113 Utf8Str strLaunchMode;
2114 com::SafeArray<BSTR> parameters;
2115
2116 int c;
2117 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2118 {
2119 switch (c)
2120 {
2121 case 'b': /* --bucket-name */
2122 {
2123 if (strBucketName.isNotEmpty())
2124 return errorArgument(Cloud::tr("Duplicate parameter: --bucket-name"));
2125
2126 strBucketName = ValueUnion.psz;
2127 if (strBucketName.isEmpty())
2128 return errorArgument(Cloud::tr("Empty parameter: --bucket-name"));
2129
2130 break;
2131 }
2132
2133 case 'o': /* --object-name */
2134 {
2135 if (strObjectName.isNotEmpty())
2136 return errorArgument(Cloud::tr("Duplicate parameter: --object-name"));
2137
2138 strObjectName = ValueUnion.psz;
2139 if (strObjectName.isEmpty())
2140 return errorArgument(Cloud::tr("Empty parameter: --object-name"));
2141
2142 break;
2143 }
2144
2145 case 'i': /* --id */
2146 {
2147 if (strImageId.isNotEmpty())
2148 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
2149
2150 strImageId = ValueUnion.psz;
2151 if (strImageId.isEmpty())
2152 return errorArgument(Cloud::tr("Empty parameter: --id"));
2153
2154 break;
2155 }
2156
2157 case 'd': /* --display-name */
2158 {
2159 if (strDisplayName.isNotEmpty())
2160 return errorArgument(Cloud::tr("Duplicate parameter: --display-name"));
2161
2162 strDisplayName = ValueUnion.psz;
2163 if (strDisplayName.isEmpty())
2164 return errorArgument(Cloud::tr("Empty parameter: --display-name"));
2165
2166 break;
2167 }
2168
2169 case 'm': /* --launch-mode */
2170 {
2171 if (strLaunchMode.isNotEmpty())
2172 return errorArgument(Cloud::tr("Duplicate parameter: --launch-mode"));
2173
2174 strLaunchMode = ValueUnion.psz;
2175 if (strLaunchMode.isEmpty())
2176 return errorArgument(Cloud::tr("Empty parameter: --launch-mode"));
2177
2178 break;
2179 }
2180
2181 case 'h':
2182 printHelp(g_pStdOut);
2183 return RTEXITCODE_SUCCESS;
2184
2185 case VINF_GETOPT_NOT_OPTION:
2186 return errorUnknownSubcommand(ValueUnion.psz);
2187
2188 default:
2189 return errorGetOpt(c, &ValueUnion);
2190 }
2191 }
2192
2193 /* Delayed check. It allows us to print help information.*/
2194 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2195 if (FAILED(hrc))
2196 return RTEXITCODE_FAILURE;
2197
2198 if (strImageId.isNotEmpty())
2199 BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw());
2200 else
2201 return errorArgument(Cloud::tr("Missing parameter: --id"));
2202
2203 if (strBucketName.isNotEmpty())
2204 BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw());
2205 else
2206 return errorArgument(Cloud::tr("Missing parameter: --bucket-name"));
2207
2208 if (strObjectName.isNotEmpty())
2209 BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw());
2210
2211 if (strDisplayName.isNotEmpty())
2212 BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw());
2213
2214 if (strLaunchMode.isNotEmpty())
2215 BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw());
2216
2217
2218 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2219
2220 ComObjPtr<ICloudClient> oCloudClient;
2221 CHECK_ERROR2_RET(hrc, pCloudProfile,
2222 CreateCloudClient(oCloudClient.asOutParam()),
2223 RTEXITCODE_FAILURE);
2224
2225 if (strObjectName.isNotEmpty())
2226 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with name \'%s\'...\n"),
2227 strImageId.c_str(), strObjectName.c_str());
2228 else
2229 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with default name\n"),
2230 strImageId.c_str());
2231
2232 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2233 SafeIfaceArray<IMedium> aImageList;
2234 CHECK_ERROR2_RET(hrc, pVirtualBox,
2235 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)),
2236 RTEXITCODE_FAILURE);
2237
2238 ComPtr<IMedium> pImage;
2239 size_t cImages = aImageList.size();
2240 bool fFound = false;
2241 for (size_t i = 0; i < cImages; ++i)
2242 {
2243 pImage = aImageList[i];
2244 Bstr bstrImageId;
2245 hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam());
2246 if (FAILED(hrc))
2247 continue;
2248
2249 com::Guid imageId(bstrImageId);
2250
2251 if (!imageId.isValid() || imageId.isZero())
2252 continue;
2253
2254 if (!strImageId.compare(imageId.toString()))
2255 {
2256 fFound = true;
2257 RTPrintf(Cloud::tr("Image %s was found\n"), strImageId.c_str());
2258 break;
2259 }
2260 }
2261
2262 if (!fFound)
2263 {
2264 RTPrintf(Cloud::tr("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n"));
2265 return RTEXITCODE_FAILURE;
2266 }
2267
2268 ComPtr<IProgress> progress;
2269 CHECK_ERROR2_RET(hrc, oCloudClient,
2270 ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2271 RTEXITCODE_FAILURE);
2272 hrc = showProgress(progress);
2273 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Export the image to the Cloud failed")), RTEXITCODE_FAILURE);
2274
2275 if (SUCCEEDED(hrc))
2276 RTPrintf(Cloud::tr("Export the image to the Cloud was successfull\n"));
2277
2278 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2279}
2280
2281static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2282{
2283 HRESULT hrc = S_OK;
2284
2285 static const RTGETOPTDEF s_aOptions[] =
2286 {
2287 { "--id", 'i', RTGETOPT_REQ_STRING },
2288 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
2289 { "--object-name", 'o', RTGETOPT_REQ_STRING },
2290 { "help", 'h', RTGETOPT_REQ_NOTHING },
2291 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2292 };
2293 RTGETOPTSTATE GetState;
2294 RTGETOPTUNION ValueUnion;
2295 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2296 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2297 if (a->argc == iFirst)
2298 {
2299 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2300 printHelp(g_pStdOut);
2301 return RTEXITCODE_SUCCESS;
2302 }
2303
2304 Utf8Str strImageId;
2305 Utf8Str strCompartmentId;
2306 Utf8Str strBucketName;
2307 Utf8Str strObjectName;
2308 Utf8Str strDisplayName;
2309 com::SafeArray<BSTR> parameters;
2310
2311 int c;
2312 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2313 {
2314 switch (c)
2315 {
2316 case 'i':
2317 strImageId=ValueUnion.psz;
2318 break;
2319 case 'b':
2320 strBucketName=ValueUnion.psz;
2321 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2322 break;
2323 case 'o':
2324 strObjectName=ValueUnion.psz;
2325 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
2326 break;
2327 case 'h':
2328 printHelp(g_pStdOut);
2329 return RTEXITCODE_SUCCESS;
2330 case VINF_GETOPT_NOT_OPTION:
2331 return errorUnknownSubcommand(ValueUnion.psz);
2332 default:
2333 return errorGetOpt(c, &ValueUnion);
2334 }
2335 }
2336
2337 /* Delayed check. It allows us to print help information.*/
2338 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2339 if (FAILED(hrc))
2340 return RTEXITCODE_FAILURE;
2341
2342 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2343
2344 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2345 ComObjPtr<ICloudClient> oCloudClient;
2346 CHECK_ERROR2_RET(hrc, pCloudProfile,
2347 CreateCloudClient(oCloudClient.asOutParam()),
2348 RTEXITCODE_FAILURE);
2349 RTPrintf(Cloud::tr("Creating an object \'%s\' from the cloud image \'%s\'...\n"), strObjectName.c_str(), strImageId.c_str());
2350
2351 ComPtr<IProgress> progress;
2352 CHECK_ERROR2_RET(hrc, oCloudClient,
2353 ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()),
2354 RTEXITCODE_FAILURE);
2355 hrc = showProgress(progress);
2356 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Cloud image import failed")), RTEXITCODE_FAILURE);
2357
2358 if (SUCCEEDED(hrc))
2359 {
2360 RTPrintf(Cloud::tr("Cloud image was imported successfully. Find the downloaded object with the name %s "
2361 "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n"),
2362 strObjectName.c_str());
2363 }
2364
2365 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2366}
2367
2368static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2369{
2370 HRESULT hrc = S_OK;
2371
2372 static const RTGETOPTDEF s_aOptions[] =
2373 {
2374 { "--id", 'i', RTGETOPT_REQ_STRING },
2375 { "help", 'h', RTGETOPT_REQ_NOTHING },
2376 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2377 };
2378 RTGETOPTSTATE GetState;
2379 RTGETOPTUNION ValueUnion;
2380 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2381 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2382 if (a->argc == iFirst)
2383 {
2384 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2385 printHelp(g_pStdOut);
2386 return RTEXITCODE_SUCCESS;
2387 }
2388
2389 Utf8Str strImageId;
2390
2391 int c;
2392 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2393 {
2394 switch (c)
2395 {
2396 case 'i':
2397 strImageId = ValueUnion.psz;
2398 break;
2399 case 'h':
2400 printHelp(g_pStdOut);
2401 return RTEXITCODE_SUCCESS;
2402 case VINF_GETOPT_NOT_OPTION:
2403 return errorUnknownSubcommand(ValueUnion.psz);
2404 default:
2405 return errorGetOpt(c, &ValueUnion);
2406 }
2407 }
2408
2409 /* Delayed check. It allows us to print help information.*/
2410 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2411 if (FAILED(hrc))
2412 return RTEXITCODE_FAILURE;
2413
2414 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2415
2416 ComObjPtr<ICloudClient> oCloudClient;
2417 CHECK_ERROR2_RET(hrc, pCloudProfile,
2418 CreateCloudClient(oCloudClient.asOutParam()),
2419 RTEXITCODE_FAILURE);
2420 RTPrintf(Cloud::tr("Getting information about the cloud image with id \'%s\'...\n"), strImageId.c_str());
2421
2422 ComPtr<IStringArray> infoArray;
2423 com::SafeArray<BSTR> pStrInfoArray;
2424 ComPtr<IProgress> pProgress;
2425
2426 RTPrintf(Cloud::tr("Reply is in the form \'image property\' = \'value\'\n"));
2427 CHECK_ERROR2_RET(hrc, oCloudClient,
2428 GetImageInfo(Bstr(strImageId).raw(),
2429 infoArray.asOutParam(),
2430 pProgress.asOutParam()),
2431 RTEXITCODE_FAILURE);
2432
2433 hrc = showProgress(pProgress);
2434 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Getting information about the cloud image failed")), RTEXITCODE_FAILURE);
2435
2436 CHECK_ERROR2_RET(hrc,
2437 infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)),
2438 RTEXITCODE_FAILURE);
2439
2440 RTPrintf(Cloud::tr("General information about the image:\n"));
2441 size_t cParamNames = pStrInfoArray.size();
2442 for (size_t k = 0; k < cParamNames; k++)
2443 {
2444 Utf8Str data(pStrInfoArray[k]);
2445 RTPrintf("\t%s\n", data.c_str());
2446 }
2447
2448 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2449}
2450
2451static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2452{
2453 RT_NOREF(a);
2454 RT_NOREF(iFirst);
2455 RT_NOREF(pCommonOpts);
2456 return RTEXITCODE_SUCCESS;
2457}
2458
2459static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2460{
2461 HRESULT hrc = S_OK;
2462
2463 static const RTGETOPTDEF s_aOptions[] =
2464 {
2465 { "--id", 'i', RTGETOPT_REQ_STRING },
2466 { "help", 'h', RTGETOPT_REQ_NOTHING },
2467 { "--help", 'h', RTGETOPT_REQ_NOTHING }
2468 };
2469 RTGETOPTSTATE GetState;
2470 RTGETOPTUNION ValueUnion;
2471 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2472 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2473 if (a->argc == iFirst)
2474 {
2475 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2476 printHelp(g_pStdOut);
2477 return RTEXITCODE_SUCCESS;
2478 }
2479
2480 Utf8Str strImageId;
2481
2482 int c;
2483 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2484 {
2485 switch (c)
2486 {
2487 case 'i':
2488 {
2489 if (strImageId.isNotEmpty())
2490 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
2491
2492 strImageId = ValueUnion.psz;
2493 if (strImageId.isEmpty())
2494 return errorArgument(Cloud::tr("Empty parameter: --id"));
2495
2496 break;
2497 }
2498
2499 case 'h':
2500 printHelp(g_pStdOut);
2501 return RTEXITCODE_SUCCESS;
2502 case VINF_GETOPT_NOT_OPTION:
2503 return errorUnknownSubcommand(ValueUnion.psz);
2504
2505 default:
2506 return errorGetOpt(c, &ValueUnion);
2507 }
2508 }
2509
2510 /* Delayed check. It allows us to print help information.*/
2511 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2512 if (FAILED(hrc))
2513 return RTEXITCODE_FAILURE;
2514
2515 if (strImageId.isEmpty())
2516 return errorArgument(Cloud::tr("Missing parameter: --id"));
2517
2518
2519 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2520
2521 ComObjPtr<ICloudClient> oCloudClient;
2522 CHECK_ERROR2_RET(hrc, pCloudProfile,
2523 CreateCloudClient(oCloudClient.asOutParam()),
2524 RTEXITCODE_FAILURE);
2525 RTPrintf(Cloud::tr("Deleting cloud image with id %s...\n"), strImageId.c_str());
2526
2527 ComPtr<IProgress> progress;
2528 CHECK_ERROR2_RET(hrc, oCloudClient,
2529 DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()),
2530 RTEXITCODE_FAILURE);
2531 hrc = showProgress(progress);
2532 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Deleting cloud image failed")), RTEXITCODE_FAILURE);
2533
2534 if (SUCCEEDED(hrc))
2535 RTPrintf(Cloud::tr("Cloud image was deleted successfully\n"));
2536
2537 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2538}
2539
2540static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2541{
2542 enum
2543 {
2544 kCloudImageIota = 1000,
2545 kCloudImage_Create,
2546 kCloudImage_Delete,
2547 kCloudImage_Export,
2548 kCloudImage_Import,
2549 kCloudImage_Info,
2550 kCloudImage_Update,
2551 };
2552
2553 static const RTGETOPTDEF s_aOptions[] =
2554 {
2555 { "create", kCloudImage_Create, RTGETOPT_REQ_NOTHING },
2556 { "delete", kCloudImage_Delete, RTGETOPT_REQ_NOTHING },
2557 { "export", kCloudImage_Export, RTGETOPT_REQ_NOTHING },
2558 { "import", kCloudImage_Import, RTGETOPT_REQ_NOTHING },
2559 { "info", kCloudImage_Info, RTGETOPT_REQ_NOTHING },
2560 { "update", kCloudImage_Update, RTGETOPT_REQ_NOTHING },
2561
2562 { "help", 'h', RTGETOPT_REQ_NOTHING },
2563 { "-?", 'h', RTGETOPT_REQ_NOTHING },
2564 { "-help", 'h', RTGETOPT_REQ_NOTHING },
2565 { "--help", 'h', RTGETOPT_REQ_NOTHING },
2566 };
2567
2568 if (a->argc == iFirst)
2569 {
2570 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
2571 printHelp(g_pStdOut);
2572 return RTEXITCODE_SUCCESS;
2573 }
2574
2575 RTGETOPTSTATE GetState;
2576 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2577 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2578
2579 int c;
2580 RTGETOPTUNION ValueUnion;
2581 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2582 {
2583 switch (c)
2584 {
2585 /* Sub-commands: */
2586 case kCloudImage_Create:
2587 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_CREATE);
2588 return createCloudImage(a, GetState.iNext, pCommonOpts);
2589
2590 case kCloudImage_Export:
2591 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_EXPORT);
2592 return exportCloudImage(a, GetState.iNext, pCommonOpts);
2593
2594 case kCloudImage_Import:
2595 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_IMPORT);
2596 return importCloudImage(a, GetState.iNext, pCommonOpts);
2597
2598 case kCloudImage_Info:
2599 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_INFO);
2600 return showCloudImageInfo(a, GetState.iNext, pCommonOpts);
2601
2602 case kCloudImage_Update:
2603// setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_UPDATE);
2604 return updateCloudImage(a, GetState.iNext, pCommonOpts);
2605
2606 case kCloudImage_Delete:
2607 setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_DELETE);
2608 return deleteCloudImage(a, GetState.iNext, pCommonOpts);
2609
2610 case 'h':
2611 printHelp(g_pStdOut);
2612 return RTEXITCODE_SUCCESS;
2613
2614 case VINF_GETOPT_NOT_OPTION:
2615 return errorUnknownSubcommand(ValueUnion.psz);
2616
2617 default:
2618 return errorGetOpt(c, &ValueUnion);
2619 }
2620 }
2621
2622 return errorNoSubcommand();
2623}
2624
2625#ifdef VBOX_WITH_CLOUD_NET
2626struct CloudNetworkOptions
2627{
2628 BOOL fEnable;
2629 BOOL fDisable;
2630 Bstr strNetworkId;
2631 Bstr strNetworkName;
2632};
2633typedef struct CloudNetworkOptions CLOUDNETOPT;
2634typedef CLOUDNETOPT *PCLOUDNETOPT;
2635
2636static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr<ICloudNetwork> cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts)
2637{
2638 HRESULT hrc = S_OK;
2639
2640 Bstr strProvider = pCommonOpts->provider.pszProviderName;
2641 Bstr strProfile = pCommonOpts->profile.pszProfileName;
2642
2643 if (options.fEnable)
2644 {
2645 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
2646 }
2647 if (options.fDisable)
2648 {
2649 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
2650 }
2651 if (options.strNetworkId.isNotEmpty())
2652 {
2653 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE);
2654 }
2655 if (strProvider.isNotEmpty())
2656 {
2657 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE);
2658 }
2659 if (strProfile.isNotEmpty())
2660 {
2661 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE);
2662 }
2663
2664 return RTEXITCODE_SUCCESS;
2665}
2666
2667
2668static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2669{
2670 HRESULT hrc = S_OK;
2671 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2672 if (FAILED(hrc))
2673 return RTEXITCODE_FAILURE;
2674
2675 /* Required parameters, the rest is handled in update */
2676 static const RTGETOPTDEF s_aOptions[] =
2677 {
2678 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2679 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2680 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2681 { "--name", 'n', RTGETOPT_REQ_STRING },
2682 };
2683
2684 RTGETOPTSTATE GetState;
2685 RTGETOPTUNION ValueUnion;
2686 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2687 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2688
2689 CLOUDNETOPT options;
2690 options.fEnable = FALSE;
2691 options.fDisable = FALSE;
2692
2693 int c;
2694 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2695 {
2696 switch (c)
2697 {
2698 case 'd':
2699 options.fDisable = TRUE;
2700 break;
2701 case 'e':
2702 options.fEnable = TRUE;
2703 break;
2704 case 'i':
2705 options.strNetworkId=ValueUnion.psz;
2706 break;
2707 case 'n':
2708 options.strNetworkName=ValueUnion.psz;
2709 break;
2710 case VINF_GETOPT_NOT_OPTION:
2711 return errorUnknownSubcommand(ValueUnion.psz);
2712 default:
2713 return errorGetOpt(c, &ValueUnion);
2714 }
2715 }
2716
2717 if (options.strNetworkName.isEmpty())
2718 return errorArgument(Cloud::tr("Missing --name parameter"));
2719 if (options.strNetworkId.isEmpty())
2720 return errorArgument(Cloud::tr("Missing --network-id parameter"));
2721
2722 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2723
2724 ComPtr<ICloudNetwork> cloudNetwork;
2725 CHECK_ERROR2_RET(hrc, pVirtualBox,
2726 CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2727 RTEXITCODE_FAILURE);
2728
2729 /* Fill out the created network */
2730 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2731 if (RT_SUCCESS(rc))
2732 RTPrintf(Cloud::tr("Cloud network was created successfully\n"));
2733
2734 return rc;
2735}
2736
2737
2738static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2739{
2740 RT_NOREF(pCommonOpts);
2741 HRESULT hrc = S_OK;
2742 static const RTGETOPTDEF s_aOptions[] =
2743 {
2744 { "--name", 'n', RTGETOPT_REQ_STRING },
2745 };
2746 RTGETOPTSTATE GetState;
2747 RTGETOPTUNION ValueUnion;
2748 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2749 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2750
2751 Bstr strNetworkName;
2752
2753 int c;
2754 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2755 {
2756 switch (c)
2757 {
2758 case 'n':
2759 strNetworkName=ValueUnion.psz;
2760 break;
2761 case VINF_GETOPT_NOT_OPTION:
2762 return errorUnknownSubcommand(ValueUnion.psz);
2763 default:
2764 return errorGetOpt(c, &ValueUnion);
2765 }
2766 }
2767
2768 if (strNetworkName.isEmpty())
2769 return errorArgument(Cloud::tr("Missing --name parameter"));
2770
2771 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2772 ComPtr<ICloudNetwork> cloudNetwork;
2773 CHECK_ERROR2_RET(hrc, pVirtualBox,
2774 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2775 RTEXITCODE_FAILURE);
2776
2777 RTPrintf(Cloud::tr("Name: %ls\n"), strNetworkName.raw());
2778 BOOL fEnabled = FALSE;
2779 cloudNetwork->COMGETTER(Enabled)(&fEnabled);
2780 RTPrintf(Cloud::tr("State: %s\n"), fEnabled ? Cloud::tr("Enabled") : Cloud::tr("Disabled"));
2781 Bstr Provider;
2782 cloudNetwork->COMGETTER(Provider)(Provider.asOutParam());
2783 RTPrintf(Cloud::tr("CloudProvider: %ls\n"), Provider.raw());
2784 Bstr Profile;
2785 cloudNetwork->COMGETTER(Profile)(Profile.asOutParam());
2786 RTPrintf(Cloud::tr("CloudProfile: %ls\n"), Profile.raw());
2787 Bstr NetworkId;
2788 cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam());
2789 RTPrintf(Cloud::tr("CloudNetworkId: %ls\n"), NetworkId.raw());
2790 Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw());
2791 RTPrintf(Cloud::tr("VBoxNetworkName: %ls\n\n"), netName.raw());
2792
2793 return RTEXITCODE_SUCCESS;
2794}
2795
2796
2797static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2798{
2799 HRESULT hrc = S_OK;
2800
2801 static const RTGETOPTDEF s_aOptions[] =
2802 {
2803 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2804 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2805 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2806 { "--name", 'n', RTGETOPT_REQ_STRING },
2807 };
2808
2809 RTGETOPTSTATE GetState;
2810 RTGETOPTUNION ValueUnion;
2811 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2812 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2813
2814 CLOUDNETOPT options;
2815 options.fEnable = FALSE;
2816 options.fDisable = FALSE;
2817
2818 int c;
2819 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2820 {
2821 switch (c)
2822 {
2823 case 'd':
2824 options.fDisable = TRUE;
2825 break;
2826 case 'e':
2827 options.fEnable = TRUE;
2828 break;
2829 case 'i':
2830 options.strNetworkId=ValueUnion.psz;
2831 break;
2832 case 'n':
2833 options.strNetworkName=ValueUnion.psz;
2834 break;
2835 case VINF_GETOPT_NOT_OPTION:
2836 return errorUnknownSubcommand(ValueUnion.psz);
2837 default:
2838 return errorGetOpt(c, &ValueUnion);
2839 }
2840 }
2841
2842 if (options.strNetworkName.isEmpty())
2843 return errorArgument(Cloud::tr("Missing --name parameter"));
2844
2845 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2846 ComPtr<ICloudNetwork> cloudNetwork;
2847 CHECK_ERROR2_RET(hrc, pVirtualBox,
2848 FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2849 RTEXITCODE_FAILURE);
2850
2851 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2852 if (RT_SUCCESS(rc))
2853 RTPrintf(Cloud::tr("Cloud network %ls was updated successfully\n"), options.strNetworkName.raw());
2854
2855 return rc;
2856}
2857
2858
2859static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2860{
2861 RT_NOREF(pCommonOpts);
2862 HRESULT hrc = S_OK;
2863 static const RTGETOPTDEF s_aOptions[] =
2864 {
2865 { "--name", 'n', RTGETOPT_REQ_STRING },
2866 };
2867 RTGETOPTSTATE GetState;
2868 RTGETOPTUNION ValueUnion;
2869 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2870 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2871
2872 Bstr strNetworkName;
2873
2874 int c;
2875 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2876 {
2877 switch (c)
2878 {
2879 case 'n':
2880 strNetworkName=ValueUnion.psz;
2881 break;
2882 case VINF_GETOPT_NOT_OPTION:
2883 return errorUnknownSubcommand(ValueUnion.psz);
2884 default:
2885 return errorGetOpt(c, &ValueUnion);
2886 }
2887 }
2888
2889 if (strNetworkName.isEmpty())
2890 return errorArgument(Cloud::tr("Missing --name parameter"));
2891
2892 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2893 ComPtr<ICloudNetwork> cloudNetwork;
2894 CHECK_ERROR2_RET(hrc, pVirtualBox,
2895 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2896 RTEXITCODE_FAILURE);
2897
2898 CHECK_ERROR2_RET(hrc, pVirtualBox,
2899 RemoveCloudNetwork(cloudNetwork),
2900 RTEXITCODE_FAILURE);
2901
2902 if (SUCCEEDED(hrc))
2903 RTPrintf(Cloud::tr("Cloud network %ls was deleted successfully\n"), strNetworkName.raw());
2904
2905 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2906}
2907
2908
2909static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2910{
2911 RT_NOREF(pCommonOpts);
2912 HRESULT hrc = S_OK;
2913 static const RTGETOPTDEF s_aOptions[] =
2914 {
2915 { "--gateway-os-name", 'n', RTGETOPT_REQ_STRING },
2916 { "--gateway-os-version", 'v', RTGETOPT_REQ_STRING },
2917 { "--gateway-shape", 's', RTGETOPT_REQ_STRING },
2918 { "--tunnel-network-name", 't', RTGETOPT_REQ_STRING },
2919 { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING },
2920 { "--compartment-id", 'c', RTGETOPT_REQ_STRING }
2921 };
2922 RTGETOPTSTATE GetState;
2923 RTGETOPTUNION ValueUnion;
2924 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2925 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2926
2927 Bstr strGatewayOsName;
2928 Bstr strGatewayOsVersion;
2929 Bstr strGatewayShape;
2930 Bstr strTunnelNetworkName;
2931 Bstr strTunnelNetworkRange;
2932 Bstr strCompartmentId;
2933
2934 int c;
2935 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2936 {
2937 switch (c)
2938 {
2939 case 'n':
2940 strGatewayOsName=ValueUnion.psz;
2941 break;
2942 case 'v':
2943 strGatewayOsVersion=ValueUnion.psz;
2944 break;
2945 case 's':
2946 strGatewayShape=ValueUnion.psz;
2947 break;
2948 case 't':
2949 strTunnelNetworkName=ValueUnion.psz;
2950 break;
2951 case 'r':
2952 strTunnelNetworkRange=ValueUnion.psz;
2953 break;
2954 case 'c':
2955 strCompartmentId=ValueUnion.psz;
2956 break;
2957 case VINF_GETOPT_NOT_OPTION:
2958 return errorUnknownSubcommand(ValueUnion.psz);
2959 default:
2960 return errorGetOpt(c, &ValueUnion);
2961 }
2962 }
2963
2964 /* Delayed check. It allows us to print help information.*/
2965 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2966 if (FAILED(hrc))
2967 return RTEXITCODE_FAILURE;
2968
2969 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2970
2971 RTPrintf(Cloud::tr("Setting up tunnel network in the cloud...\n"));
2972
2973 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2974
2975 /* Use user-specified profile instead of default one. */
2976 if (strCompartmentId.isNotEmpty())
2977 {
2978 CHECK_ERROR2_RET(hrc, pCloudProfile,
2979 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
2980 RTEXITCODE_FAILURE);
2981 }
2982
2983 ComObjPtr<ICloudClient> oCloudClient;
2984 CHECK_ERROR2_RET(hrc, pCloudProfile,
2985 CreateCloudClient(oCloudClient.asOutParam()),
2986 RTEXITCODE_FAILURE);
2987
2988 ComPtr<ICloudNetworkEnvironmentInfo> cloudNetworkEnv;
2989 ComPtr<IProgress> progress;
2990 CHECK_ERROR2_RET(hrc, oCloudClient,
2991 SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(),
2992 strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(),
2993 cloudNetworkEnv.asOutParam(), progress.asOutParam()),
2994 RTEXITCODE_FAILURE);
2995
2996 hrc = showProgress(progress);
2997 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Setting up cloud network environment failed")), RTEXITCODE_FAILURE);
2998
2999 Bstr tunnelNetworkId;
3000 hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam());
3001 RTPrintf(Cloud::tr("Cloud network environment was set up successfully. Tunnel network id is: %ls\n"), tunnelNetworkId.raw());
3002
3003 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
3004}
3005
3006
3007static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
3008{
3009 enum
3010 {
3011 kCloudNetworkIota = 1000,
3012 kCloudNetwork_Create,
3013 kCloudNetwork_Delete,
3014 kCloudNetwork_Info,
3015 kCloudNetwork_Setup,
3016 kCloudNetwork_Update,
3017 };
3018
3019 static const RTGETOPTDEF s_aOptions[] =
3020 {
3021 { "create", kCloudNetwork_Create, RTGETOPT_REQ_NOTHING },
3022 { "delete", kCloudNetwork_Delete, RTGETOPT_REQ_NOTHING },
3023 { "info", kCloudNetwork_Info, RTGETOPT_REQ_NOTHING },
3024 { "setup", kCloudNetwork_Setup, RTGETOPT_REQ_NOTHING },
3025 { "update", kCloudNetwork_Update, RTGETOPT_REQ_NOTHING },
3026 };
3027
3028 if (a->argc < 1)
3029 return errorNoSubcommand();
3030
3031 RTGETOPTSTATE GetState;
3032 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
3033 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
3034
3035 int c;
3036 RTGETOPTUNION ValueUnion;
3037 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
3038 {
3039 switch (c)
3040 {
3041 /* Sub-commands: */
3042 case kCloudNetwork_Create:
3043 return createCloudNetwork(a, GetState.iNext, pCommonOpts);
3044
3045 case kCloudNetwork_Info:
3046 return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts);
3047
3048 case kCloudNetwork_Update:
3049 return updateCloudNetwork(a, GetState.iNext, pCommonOpts);
3050
3051 case kCloudNetwork_Delete:
3052 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
3053
3054 case kCloudNetwork_Setup:
3055 return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts);
3056
3057 case VINF_GETOPT_NOT_OPTION:
3058 return errorUnknownSubcommand(ValueUnion.psz);
3059
3060 default:
3061 return errorGetOpt(c, &ValueUnion);
3062 }
3063 }
3064
3065 return errorNoSubcommand();
3066}
3067#endif /* VBOX_WITH_CLOUD_NET */
3068
3069
3070RTEXITCODE handleCloud(HandlerArg *a)
3071{
3072 enum
3073 {
3074 kCloudIota = 1000,
3075 kCloud_Image,
3076 kCloud_Instance,
3077 kCloud_List,
3078 kCloud_Machine,
3079 kCloud_Network,
3080 kCloud_Object,
3081 kCloud_ShowVMInfo,
3082 kCloud_Volume,
3083 };
3084
3085 static const RTGETOPTDEF s_aOptions[] =
3086 {
3087 /* common options */
3088 { "--provider", 'v', RTGETOPT_REQ_STRING },
3089 { "--profile", 'f', RTGETOPT_REQ_STRING },
3090
3091 { "image", kCloud_Image, RTGETOPT_REQ_NOTHING },
3092 { "instance", kCloud_Instance, RTGETOPT_REQ_NOTHING },
3093 { "list", kCloud_List, RTGETOPT_REQ_NOTHING },
3094 { "machine", kCloud_Machine, RTGETOPT_REQ_NOTHING },
3095 { "network", kCloud_Network, RTGETOPT_REQ_NOTHING },
3096 { "object", kCloud_Object, RTGETOPT_REQ_NOTHING },
3097 { "showvminfo", kCloud_ShowVMInfo, RTGETOPT_REQ_NOTHING },
3098 { "volume", kCloud_Volume, RTGETOPT_REQ_NOTHING },
3099 };
3100
3101 if (a->argc < 1)
3102 return errorNoSubcommand();
3103
3104 RTGETOPTSTATE GetState;
3105 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
3106 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
3107
3108 CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} };
3109 int c;
3110 RTGETOPTUNION ValueUnion;
3111 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
3112 {
3113 switch (c)
3114 {
3115 case 'v': // --provider
3116 commonOpts.provider.pszProviderName = ValueUnion.psz;
3117 break;
3118
3119 case 'f': // --profile
3120 commonOpts.profile.pszProfileName = ValueUnion.psz;
3121 break;
3122
3123 /* Sub-commands: */
3124 case kCloud_List:
3125 return handleCloudLists(a, GetState.iNext, &commonOpts);
3126
3127 case kCloud_Image:
3128 return handleCloudImage(a, GetState.iNext, &commonOpts);
3129
3130 case kCloud_Instance:
3131 return handleCloudInstance(a, GetState.iNext, &commonOpts);
3132
3133#ifdef VBOX_WITH_CLOUD_NET
3134 case kCloud_Network:
3135 return handleCloudNetwork(a, GetState.iNext, &commonOpts);
3136#endif /* VBOX_WITH_CLOUD_NET */
3137
3138 /* "cloud machine ..." handling is in VBoxManageCloudMachine.cpp */
3139 case kCloud_Machine:
3140 return handleCloudMachine(a, GetState.iNext,
3141 commonOpts.provider.pszProviderName,
3142 commonOpts.profile.pszProfileName);
3143
3144 /* ... including aliases that mimic the local vm commands */
3145 case kCloud_ShowVMInfo:
3146 return handleCloudShowVMInfo(a, GetState.iNext,
3147 commonOpts.provider.pszProviderName,
3148 commonOpts.profile.pszProfileName);
3149
3150 case VINF_GETOPT_NOT_OPTION:
3151 return errorUnknownSubcommand(ValueUnion.psz);
3152
3153 default:
3154 return errorGetOpt(c, &ValueUnion);
3155 }
3156 }
3157
3158 return errorNoSubcommand();
3159}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use