VirtualBox

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

Last change on this file since 98778 was 98778, checked in by vboxsync, 22 months ago

bugref:9527. Added 3 new values into VirtualSystemDescription: CloudInstanceMetadata, CloudInstanceFreeFormTags, CloudImageFreeFormTags.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette