VirtualBox

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

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

Removed the function listCloudVnicAttachments() as one hasn't been fully implemented yet.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 90.1 KB
Line 
1/* $Id: VBoxManageCloud.cpp 98702 2023-02-23 13:34:54Z 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 = 13;//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("Free-form tags or metadata weren't found\n")},
854 {VirtualSystemDescriptionType_CloudInitScriptPath, "%ls\n", Cloud::tr("Cloud-init script wasn't found\n")}
855 };
856
857 com::SafeArray<VirtualSystemDescriptionType_T> retTypes;
858 com::SafeArray<BSTR> aRefs;
859 com::SafeArray<BSTR> aOvfValues;
860 com::SafeArray<BSTR> aVBoxValues;
861 com::SafeArray<BSTR> aExtraConfigValues;
862
863 for (size_t i=0; i<vsdHReadableArraySize ; ++i)
864 {
865 hrc = instanceDescription->GetDescriptionByType(vsdHReadableArray[i].vsdType,
866 ComSafeArrayAsOutParam(retTypes),
867 ComSafeArrayAsOutParam(aRefs),
868 ComSafeArrayAsOutParam(aOvfValues),
869 ComSafeArrayAsOutParam(aVBoxValues),
870 ComSafeArrayAsOutParam(aExtraConfigValues));
871 if (FAILED(hrc) || aVBoxValues.size() == 0)
872 LogRel((vsdHReadableArray[i].strNotFound.c_str()));
873 else
874 {
875 LogRel(("Size is %d", aVBoxValues.size()));
876 for (size_t j = 0; j<aVBoxValues.size(); ++j)
877 {
878 RTPrintf(vsdHReadableArray[i].strFound.c_str(), aVBoxValues[j]);
879 }
880 }
881
882 retTypes.setNull();
883 aRefs.setNull();
884 aOvfValues.setNull();
885 aVBoxValues.setNull();
886 aExtraConfigValues.setNull();
887 }
888
889 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
890}
891
892static RTEXITCODE startCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
893{
894 HRESULT hrc = S_OK;
895
896 static const RTGETOPTDEF s_aOptions[] =
897 {
898 { "--id", 'i', RTGETOPT_REQ_STRING },
899 { "help", 'h', RTGETOPT_REQ_NOTHING },
900 { "--help", 'h', RTGETOPT_REQ_NOTHING }
901 };
902 RTGETOPTSTATE GetState;
903 RTGETOPTUNION ValueUnion;
904 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
905 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
906 if (a->argc == iFirst)
907 {
908 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
909 printHelp(g_pStdOut);
910 return RTEXITCODE_SUCCESS;
911 }
912
913 Utf8Str strInstanceId;
914
915 int c;
916 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
917 {
918 switch (c)
919 {
920 case 'i':
921 {
922 if (strInstanceId.isNotEmpty())
923 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
924
925 strInstanceId = ValueUnion.psz;
926 if (strInstanceId.isEmpty())
927 return errorArgument(Cloud::tr("Empty parameter: --id"));
928
929 break;
930 }
931 case 'h':
932 printHelp(g_pStdOut);
933 return RTEXITCODE_SUCCESS;
934 case VINF_GETOPT_NOT_OPTION:
935 return errorUnknownSubcommand(ValueUnion.psz);
936
937 default:
938 return errorGetOpt(c, &ValueUnion);
939 }
940 }
941
942 /* Delayed check. It allows us to print help information.*/
943 hrc = checkAndSetCommonOptions(a, pCommonOpts);
944 if (FAILED(hrc))
945 return RTEXITCODE_FAILURE;
946
947 if (strInstanceId.isEmpty())
948 return errorArgument(Cloud::tr("Missing parameter: --id"));
949
950 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
951
952 ComObjPtr<ICloudClient> oCloudClient;
953 CHECK_ERROR2_RET(hrc, pCloudProfile,
954 CreateCloudClient(oCloudClient.asOutParam()),
955 RTEXITCODE_FAILURE);
956 RTPrintf(Cloud::tr("Starting cloud instance with id %s...\n"), strInstanceId.c_str());
957
958 ComPtr<IProgress> progress;
959 CHECK_ERROR2_RET(hrc, oCloudClient,
960 StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
961 RTEXITCODE_FAILURE);
962 hrc = showProgress(progress);
963 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Starting the cloud instance failed")), RTEXITCODE_FAILURE);
964
965 if (SUCCEEDED(hrc))
966 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n"),
967 strInstanceId.c_str(),
968 pCommonOpts->provider.pszProviderName,
969 pCommonOpts->profile.pszProfileName);
970
971 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
972}
973
974static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
975{
976 HRESULT hrc = S_OK;
977
978 static const RTGETOPTDEF s_aOptions[] =
979 {
980 { "--id", 'i', RTGETOPT_REQ_STRING },
981 { "help", 'h', RTGETOPT_REQ_NOTHING },
982 { "--help", 'h', RTGETOPT_REQ_NOTHING }
983 };
984 RTGETOPTSTATE GetState;
985 RTGETOPTUNION ValueUnion;
986 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
987 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
988 if (a->argc == iFirst)
989 {
990 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
991 printHelp(g_pStdOut);
992 return RTEXITCODE_SUCCESS;
993 }
994
995 Utf8Str strInstanceId;
996
997 int c;
998 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
999 {
1000 switch (c)
1001 {
1002 case 'i':
1003 {
1004 if (strInstanceId.isNotEmpty())
1005 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1006
1007 strInstanceId = ValueUnion.psz;
1008 if (strInstanceId.isEmpty())
1009 return errorArgument(Cloud::tr("Empty parameter: --id"));
1010
1011 break;
1012 }
1013 case 'h':
1014 printHelp(g_pStdOut);
1015 return RTEXITCODE_SUCCESS;
1016 case VINF_GETOPT_NOT_OPTION:
1017 return errorUnknownSubcommand(ValueUnion.psz);
1018
1019 default:
1020 return errorGetOpt(c, &ValueUnion);
1021 }
1022 }
1023
1024 /* Delayed check. It allows us to print help information.*/
1025 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1026 if (FAILED(hrc))
1027 return RTEXITCODE_FAILURE;
1028
1029 if (strInstanceId.isEmpty())
1030 return errorArgument(Cloud::tr("Missing parameter: --id"));
1031
1032 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1033
1034 ComObjPtr<ICloudClient> oCloudClient;
1035 CHECK_ERROR2_RET(hrc, pCloudProfile,
1036 CreateCloudClient(oCloudClient.asOutParam()),
1037 RTEXITCODE_FAILURE);
1038 RTPrintf(Cloud::tr("Pausing cloud instance with id %s...\n"), strInstanceId.c_str());
1039
1040 ComPtr<IProgress> progress;
1041 CHECK_ERROR2_RET(hrc, oCloudClient,
1042 PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1043 RTEXITCODE_FAILURE);
1044 hrc = showProgress(progress);
1045 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Pause the cloud instance failed")), RTEXITCODE_FAILURE);
1046
1047 if (SUCCEEDED(hrc))
1048 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n"),
1049 strInstanceId.c_str(),
1050 pCommonOpts->provider.pszProviderName,
1051 pCommonOpts->profile.pszProfileName);
1052
1053 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1054}
1055
1056static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1057{
1058 HRESULT hrc = S_OK;
1059
1060 static const RTGETOPTDEF s_aOptions[] =
1061 {
1062 { "--id", 'i', RTGETOPT_REQ_STRING },
1063 { "help", 'h', RTGETOPT_REQ_NOTHING },
1064 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1065 };
1066 RTGETOPTSTATE GetState;
1067 RTGETOPTUNION ValueUnion;
1068 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1069 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1070 if (a->argc == iFirst)
1071 {
1072 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1073 printHelp(g_pStdOut);
1074 return RTEXITCODE_SUCCESS;
1075 }
1076
1077 Utf8Str strInstanceId;
1078
1079 int c;
1080 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1081 {
1082 switch (c)
1083 {
1084 case 'i':
1085 {
1086 if (strInstanceId.isNotEmpty())
1087 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1088
1089 strInstanceId = ValueUnion.psz;
1090 if (strInstanceId.isEmpty())
1091 return errorArgument(Cloud::tr("Empty parameter: --id"));
1092
1093 break;
1094 }
1095 case 'h':
1096 printHelp(g_pStdOut);
1097 return RTEXITCODE_SUCCESS;
1098 case VINF_GETOPT_NOT_OPTION:
1099 return errorUnknownSubcommand(ValueUnion.psz);
1100
1101 default:
1102 return errorGetOpt(c, &ValueUnion);
1103 }
1104 }
1105
1106 /* Delayed check. It allows us to print help information.*/
1107 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1108 if (FAILED(hrc))
1109 return RTEXITCODE_FAILURE;
1110
1111 if (strInstanceId.isEmpty())
1112 return errorArgument(Cloud::tr("Missing parameter: --id"));
1113
1114
1115 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1116
1117 ComObjPtr<ICloudClient> oCloudClient;
1118 CHECK_ERROR2_RET(hrc, pCloudProfile,
1119 CreateCloudClient(oCloudClient.asOutParam()),
1120 RTEXITCODE_FAILURE);
1121 RTPrintf(Cloud::tr("Terminating cloud instance with id %s...\n"), strInstanceId.c_str());
1122
1123 ComPtr<IProgress> progress;
1124 CHECK_ERROR2_RET(hrc, oCloudClient,
1125 TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1126 RTEXITCODE_FAILURE);
1127 hrc = showProgress(progress);
1128 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Termination the cloud instance failed")), RTEXITCODE_FAILURE);
1129
1130 if (SUCCEEDED(hrc))
1131 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n"),
1132 strInstanceId.c_str(),
1133 pCommonOpts->provider.pszProviderName,
1134 pCommonOpts->profile.pszProfileName);
1135
1136 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1137}
1138
1139static RTEXITCODE resetCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1140{
1141 HRESULT hrc = S_OK;
1142
1143 static const RTGETOPTDEF s_aOptions[] =
1144 {
1145 { "--id", 'i', RTGETOPT_REQ_STRING },
1146 { "help", 'h', RTGETOPT_REQ_NOTHING },
1147 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1148 };
1149 RTGETOPTSTATE GetState;
1150 RTGETOPTUNION ValueUnion;
1151 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1152 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1153 if (a->argc == iFirst)
1154 {
1155 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1156 printHelp(g_pStdOut);
1157 return RTEXITCODE_SUCCESS;
1158 }
1159
1160 Utf8Str strInstanceId;
1161
1162 int c;
1163 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1164 {
1165 switch (c)
1166 {
1167 case 'i':
1168 {
1169 if (strInstanceId.isNotEmpty())
1170 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1171
1172 strInstanceId = ValueUnion.psz;
1173 if (strInstanceId.isEmpty())
1174 return errorArgument(Cloud::tr("Empty parameter: --id"));
1175
1176 break;
1177 }
1178 case 'h':
1179 printHelp(g_pStdOut);
1180 return RTEXITCODE_SUCCESS;
1181 case VINF_GETOPT_NOT_OPTION:
1182 return errorUnknownSubcommand(ValueUnion.psz);
1183
1184 default:
1185 return errorGetOpt(c, &ValueUnion);
1186 }
1187 }
1188
1189 /* Delayed check. It allows us to print help information.*/
1190 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1191 if (FAILED(hrc))
1192 return RTEXITCODE_FAILURE;
1193
1194 if (strInstanceId.isEmpty())
1195 return errorArgument(Cloud::tr("Missing parameter: --id"));
1196
1197 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1198
1199 ComObjPtr<ICloudClient> oCloudClient;
1200 CHECK_ERROR2_RET(hrc, pCloudProfile,
1201 CreateCloudClient(oCloudClient.asOutParam()),
1202 RTEXITCODE_FAILURE);
1203 RTPrintf(Cloud::tr("Reset cloud instance with id %s...\n"), strInstanceId.c_str());
1204
1205 ComPtr<IProgress> progress;
1206 CHECK_ERROR2_RET(hrc, oCloudClient,
1207 ResetInstance(Bstr(strInstanceId).raw(), progress.asOutParam()),
1208 RTEXITCODE_FAILURE);
1209 hrc = showProgress(progress);
1210 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reset the cloud instance failed")), RTEXITCODE_FAILURE);
1211
1212 if (SUCCEEDED(hrc))
1213 RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was reset\n"),
1214 strInstanceId.c_str(),
1215 pCommonOpts->provider.pszProviderName,
1216 pCommonOpts->profile.pszProfileName);
1217
1218 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1219}
1220
1221static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1222{
1223 enum
1224 {
1225 kCloudInstanceIota = 1000,
1226 kCloudInstance_Create,
1227 kCloudInstance_Info,
1228 kCloudInstance_Pause,
1229 kCloudInstance_Start,
1230 kCloudInstance_Terminate,
1231 kCloudInstance_Update,
1232 kCloudInstance_Reset,
1233 };
1234
1235 static const RTGETOPTDEF s_aOptions[] =
1236 {
1237 { "create", kCloudInstance_Create, RTGETOPT_REQ_NOTHING },
1238 { "info", kCloudInstance_Info, RTGETOPT_REQ_NOTHING },
1239 { "pause", kCloudInstance_Pause, RTGETOPT_REQ_NOTHING },
1240 { "start", kCloudInstance_Start, RTGETOPT_REQ_NOTHING },
1241 { "terminate", kCloudInstance_Terminate, RTGETOPT_REQ_NOTHING },
1242 { "update", kCloudInstance_Update, RTGETOPT_REQ_NOTHING },
1243 { "reset", kCloudInstance_Reset, RTGETOPT_REQ_NOTHING },
1244
1245 { "help", 'h', RTGETOPT_REQ_NOTHING },
1246 { "-?", 'h', RTGETOPT_REQ_NOTHING },
1247 { "-help", 'h', RTGETOPT_REQ_NOTHING },
1248 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1249 };
1250
1251 if (a->argc == iFirst)
1252 {
1253 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1254 printHelp(g_pStdOut);
1255 return RTEXITCODE_SUCCESS;
1256 }
1257
1258 RTGETOPTSTATE GetState;
1259 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1260 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1261
1262 int c;
1263 RTGETOPTUNION ValueUnion;
1264 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1265 {
1266 switch (c)
1267 {
1268 /* Sub-commands: */
1269 case kCloudInstance_Create:
1270 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_CREATE);
1271 return createCloudInstance(a, GetState.iNext, pCommonOpts);
1272
1273 case kCloudInstance_Start:
1274 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_START);
1275 return startCloudInstance(a, GetState.iNext, pCommonOpts);
1276
1277 case kCloudInstance_Pause:
1278 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_PAUSE);
1279 return pauseCloudInstance(a, GetState.iNext, pCommonOpts);
1280
1281 case kCloudInstance_Info:
1282 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_INFO);
1283 return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts);
1284
1285 case kCloudInstance_Update:
1286// setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_UPDATE);
1287 return updateCloudInstance(a, GetState.iNext, pCommonOpts);
1288
1289 case kCloudInstance_Terminate:
1290 setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_TERMINATE);
1291 return terminateCloudInstance(a, GetState.iNext, pCommonOpts);
1292
1293 case kCloudInstance_Reset:
1294// setCurrentSubcommand(HELP_SCOPE_CLOUDINSTANCE_RESET);
1295 return resetCloudInstance(a, GetState.iNext, pCommonOpts);
1296
1297 case 'h':
1298 printHelp(g_pStdOut);
1299 return RTEXITCODE_SUCCESS;
1300
1301 case VINF_GETOPT_NOT_OPTION:
1302 return errorUnknownSubcommand(ValueUnion.psz);
1303
1304 default:
1305 return errorGetOpt(c, &ValueUnion);
1306 }
1307 }
1308
1309 return errorNoSubcommand();
1310}
1311
1312
1313static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1314{
1315 HRESULT hrc = S_OK;
1316
1317 static const RTGETOPTDEF s_aOptions[] =
1318 {
1319 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1320 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1321 { "--compartment-id", 'c', RTGETOPT_REQ_STRING },
1322 { "--instance-id", 'i', RTGETOPT_REQ_STRING },
1323 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1324 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1325 { "help", 'h', RTGETOPT_REQ_NOTHING },
1326 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1327 };
1328 RTGETOPTSTATE GetState;
1329 RTGETOPTUNION ValueUnion;
1330 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1331 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1332 if (a->argc == iFirst)
1333 {
1334 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1335 printHelp(g_pStdOut);
1336 return RTEXITCODE_SUCCESS;
1337 }
1338
1339 Utf8Str strCompartmentId;
1340 Utf8Str strInstanceId;
1341 Utf8Str strDisplayName;
1342 Utf8Str strBucketName;
1343 Utf8Str strObjectName;
1344 com::SafeArray<BSTR> parameters;
1345
1346 int c;
1347 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1348 {
1349 switch (c)
1350 {
1351 case 'c':
1352 strCompartmentId=ValueUnion.psz;
1353 Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1354 break;
1355 case 'i':
1356 strInstanceId=ValueUnion.psz;
1357 Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1358 break;
1359 case 'd':
1360 strDisplayName=ValueUnion.psz;
1361 Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1362 break;
1363 case 'o':
1364 strObjectName=ValueUnion.psz;
1365 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1366 break;
1367 case 'b':
1368 strBucketName=ValueUnion.psz;
1369 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1370 break;
1371 case 'm':
1372 strBucketName=ValueUnion.psz;
1373 Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1374 break;
1375 case 'h':
1376 printHelp(g_pStdOut);
1377 return RTEXITCODE_SUCCESS;
1378 case VINF_GETOPT_NOT_OPTION:
1379 return errorUnknownSubcommand(ValueUnion.psz);
1380 default:
1381 return errorGetOpt(c, &ValueUnion);
1382 }
1383 }
1384
1385 /* Delayed check. It allows us to print help information.*/
1386 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1387 if (FAILED(hrc))
1388 return RTEXITCODE_FAILURE;
1389
1390 if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty())
1391 return errorArgument(Cloud::tr("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one."));
1392
1393 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1394
1395 ComObjPtr<ICloudClient> oCloudClient;
1396 CHECK_ERROR2_RET(hrc, pCloudProfile,
1397 CreateCloudClient(oCloudClient.asOutParam()),
1398 RTEXITCODE_FAILURE);
1399 if (strInstanceId.isNotEmpty())
1400 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the instance \'%s\'...\n"),
1401 strDisplayName.c_str(), strInstanceId.c_str());
1402 else
1403 RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n"),
1404 strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str());
1405
1406 ComPtr<IProgress> progress;
1407 CHECK_ERROR2_RET(hrc, oCloudClient,
1408 CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1409 RTEXITCODE_FAILURE);
1410 hrc = showProgress(progress);
1411 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Creating cloud image failed")), RTEXITCODE_FAILURE);
1412
1413 if (SUCCEEDED(hrc))
1414 RTPrintf(Cloud::tr("Cloud image was created successfully\n"));
1415
1416 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1417}
1418
1419
1420static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1421{
1422 HRESULT hrc = S_OK;
1423
1424 static const RTGETOPTDEF s_aOptions[] =
1425 {
1426 { "--id", 'i', RTGETOPT_REQ_STRING },
1427 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1428 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1429 { "--display-name", 'd', RTGETOPT_REQ_STRING },
1430 { "--launch-mode", 'm', RTGETOPT_REQ_STRING },
1431 { "help", 'h', RTGETOPT_REQ_NOTHING },
1432 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1433 };
1434 RTGETOPTSTATE GetState;
1435 RTGETOPTUNION ValueUnion;
1436 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1437 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1438 if (a->argc == iFirst)
1439 {
1440 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1441 printHelp(g_pStdOut);
1442 return RTEXITCODE_SUCCESS;
1443 }
1444
1445 Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */
1446 Utf8Str strBucketName;
1447 Utf8Str strObjectName;
1448 Utf8Str strDisplayName;
1449 Utf8Str strLaunchMode;
1450 com::SafeArray<BSTR> parameters;
1451
1452 int c;
1453 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1454 {
1455 switch (c)
1456 {
1457 case 'b': /* --bucket-name */
1458 {
1459 if (strBucketName.isNotEmpty())
1460 return errorArgument(Cloud::tr("Duplicate parameter: --bucket-name"));
1461
1462 strBucketName = ValueUnion.psz;
1463 if (strBucketName.isEmpty())
1464 return errorArgument(Cloud::tr("Empty parameter: --bucket-name"));
1465
1466 break;
1467 }
1468
1469 case 'o': /* --object-name */
1470 {
1471 if (strObjectName.isNotEmpty())
1472 return errorArgument(Cloud::tr("Duplicate parameter: --object-name"));
1473
1474 strObjectName = ValueUnion.psz;
1475 if (strObjectName.isEmpty())
1476 return errorArgument(Cloud::tr("Empty parameter: --object-name"));
1477
1478 break;
1479 }
1480
1481 case 'i': /* --id */
1482 {
1483 if (strImageId.isNotEmpty())
1484 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1485
1486 strImageId = ValueUnion.psz;
1487 if (strImageId.isEmpty())
1488 return errorArgument(Cloud::tr("Empty parameter: --id"));
1489
1490 break;
1491 }
1492
1493 case 'd': /* --display-name */
1494 {
1495 if (strDisplayName.isNotEmpty())
1496 return errorArgument(Cloud::tr("Duplicate parameter: --display-name"));
1497
1498 strDisplayName = ValueUnion.psz;
1499 if (strDisplayName.isEmpty())
1500 return errorArgument(Cloud::tr("Empty parameter: --display-name"));
1501
1502 break;
1503 }
1504
1505 case 'm': /* --launch-mode */
1506 {
1507 if (strLaunchMode.isNotEmpty())
1508 return errorArgument(Cloud::tr("Duplicate parameter: --launch-mode"));
1509
1510 strLaunchMode = ValueUnion.psz;
1511 if (strLaunchMode.isEmpty())
1512 return errorArgument(Cloud::tr("Empty parameter: --launch-mode"));
1513
1514 break;
1515 }
1516
1517 case 'h':
1518 printHelp(g_pStdOut);
1519 return RTEXITCODE_SUCCESS;
1520
1521 case VINF_GETOPT_NOT_OPTION:
1522 return errorUnknownSubcommand(ValueUnion.psz);
1523
1524 default:
1525 return errorGetOpt(c, &ValueUnion);
1526 }
1527 }
1528
1529 /* Delayed check. It allows us to print help information.*/
1530 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1531 if (FAILED(hrc))
1532 return RTEXITCODE_FAILURE;
1533
1534 if (strImageId.isNotEmpty())
1535 BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw());
1536 else
1537 return errorArgument(Cloud::tr("Missing parameter: --id"));
1538
1539 if (strBucketName.isNotEmpty())
1540 BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw());
1541 else
1542 return errorArgument(Cloud::tr("Missing parameter: --bucket-name"));
1543
1544 if (strObjectName.isNotEmpty())
1545 BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw());
1546
1547 if (strDisplayName.isNotEmpty())
1548 BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw());
1549
1550 if (strLaunchMode.isNotEmpty())
1551 BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw());
1552
1553
1554 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1555
1556 ComObjPtr<ICloudClient> oCloudClient;
1557 CHECK_ERROR2_RET(hrc, pCloudProfile,
1558 CreateCloudClient(oCloudClient.asOutParam()),
1559 RTEXITCODE_FAILURE);
1560
1561 if (strObjectName.isNotEmpty())
1562 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with name \'%s\'...\n"),
1563 strImageId.c_str(), strObjectName.c_str());
1564 else
1565 RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with default name\n"),
1566 strImageId.c_str());
1567
1568 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1569 SafeIfaceArray<IMedium> aImageList;
1570 CHECK_ERROR2_RET(hrc, pVirtualBox,
1571 COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)),
1572 RTEXITCODE_FAILURE);
1573
1574 ComPtr<IMedium> pImage;
1575 size_t cImages = aImageList.size();
1576 bool fFound = false;
1577 for (size_t i = 0; i < cImages; ++i)
1578 {
1579 pImage = aImageList[i];
1580 Bstr bstrImageId;
1581 hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam());
1582 if (FAILED(hrc))
1583 continue;
1584
1585 com::Guid imageId(bstrImageId);
1586
1587 if (!imageId.isValid() || imageId.isZero())
1588 continue;
1589
1590 if (!strImageId.compare(imageId.toString()))
1591 {
1592 fFound = true;
1593 RTPrintf(Cloud::tr("Image %s was found\n"), strImageId.c_str());
1594 break;
1595 }
1596 }
1597
1598 if (!fFound)
1599 {
1600 RTPrintf(Cloud::tr("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n"));
1601 return RTEXITCODE_FAILURE;
1602 }
1603
1604 ComPtr<IProgress> progress;
1605 CHECK_ERROR2_RET(hrc, oCloudClient,
1606 ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1607 RTEXITCODE_FAILURE);
1608 hrc = showProgress(progress);
1609 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Export the image to the Cloud failed")), RTEXITCODE_FAILURE);
1610
1611 if (SUCCEEDED(hrc))
1612 RTPrintf(Cloud::tr("Export the image to the Cloud was successfull\n"));
1613
1614 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1615}
1616
1617static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1618{
1619 HRESULT hrc = S_OK;
1620
1621 static const RTGETOPTDEF s_aOptions[] =
1622 {
1623 { "--id", 'i', RTGETOPT_REQ_STRING },
1624 { "--bucket-name", 'b', RTGETOPT_REQ_STRING },
1625 { "--object-name", 'o', RTGETOPT_REQ_STRING },
1626 { "help", 'h', RTGETOPT_REQ_NOTHING },
1627 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1628 };
1629 RTGETOPTSTATE GetState;
1630 RTGETOPTUNION ValueUnion;
1631 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1632 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1633 if (a->argc == iFirst)
1634 {
1635 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1636 printHelp(g_pStdOut);
1637 return RTEXITCODE_SUCCESS;
1638 }
1639
1640 Utf8Str strImageId;
1641 Utf8Str strCompartmentId;
1642 Utf8Str strBucketName;
1643 Utf8Str strObjectName;
1644 Utf8Str strDisplayName;
1645 com::SafeArray<BSTR> parameters;
1646
1647 int c;
1648 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1649 {
1650 switch (c)
1651 {
1652 case 'i':
1653 strImageId=ValueUnion.psz;
1654 break;
1655 case 'b':
1656 strBucketName=ValueUnion.psz;
1657 Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1658 break;
1659 case 'o':
1660 strObjectName=ValueUnion.psz;
1661 Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw());
1662 break;
1663 case 'h':
1664 printHelp(g_pStdOut);
1665 return RTEXITCODE_SUCCESS;
1666 case VINF_GETOPT_NOT_OPTION:
1667 return errorUnknownSubcommand(ValueUnion.psz);
1668 default:
1669 return errorGetOpt(c, &ValueUnion);
1670 }
1671 }
1672
1673 /* Delayed check. It allows us to print help information.*/
1674 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1675 if (FAILED(hrc))
1676 return RTEXITCODE_FAILURE;
1677
1678 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1679
1680 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
1681 ComObjPtr<ICloudClient> oCloudClient;
1682 CHECK_ERROR2_RET(hrc, pCloudProfile,
1683 CreateCloudClient(oCloudClient.asOutParam()),
1684 RTEXITCODE_FAILURE);
1685 RTPrintf(Cloud::tr("Creating an object \'%s\' from the cloud image \'%s\'...\n"), strObjectName.c_str(), strImageId.c_str());
1686
1687 ComPtr<IProgress> progress;
1688 CHECK_ERROR2_RET(hrc, oCloudClient,
1689 ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()),
1690 RTEXITCODE_FAILURE);
1691 hrc = showProgress(progress);
1692 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Cloud image import failed")), RTEXITCODE_FAILURE);
1693
1694 if (SUCCEEDED(hrc))
1695 {
1696 RTPrintf(Cloud::tr("Cloud image was imported successfully. Find the downloaded object with the name %s "
1697 "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n"),
1698 strObjectName.c_str());
1699 }
1700
1701 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1702}
1703
1704static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1705{
1706 HRESULT hrc = S_OK;
1707
1708 static const RTGETOPTDEF s_aOptions[] =
1709 {
1710 { "--id", 'i', RTGETOPT_REQ_STRING },
1711 { "help", 'h', RTGETOPT_REQ_NOTHING },
1712 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1713 };
1714 RTGETOPTSTATE GetState;
1715 RTGETOPTUNION ValueUnion;
1716 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1717 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1718 if (a->argc == iFirst)
1719 {
1720 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1721 printHelp(g_pStdOut);
1722 return RTEXITCODE_SUCCESS;
1723 }
1724
1725 Utf8Str strImageId;
1726
1727 int c;
1728 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1729 {
1730 switch (c)
1731 {
1732 case 'i':
1733 strImageId = ValueUnion.psz;
1734 break;
1735 case 'h':
1736 printHelp(g_pStdOut);
1737 return RTEXITCODE_SUCCESS;
1738 case VINF_GETOPT_NOT_OPTION:
1739 return errorUnknownSubcommand(ValueUnion.psz);
1740 default:
1741 return errorGetOpt(c, &ValueUnion);
1742 }
1743 }
1744
1745 /* Delayed check. It allows us to print help information.*/
1746 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1747 if (FAILED(hrc))
1748 return RTEXITCODE_FAILURE;
1749
1750 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1751
1752 ComObjPtr<ICloudClient> oCloudClient;
1753 CHECK_ERROR2_RET(hrc, pCloudProfile,
1754 CreateCloudClient(oCloudClient.asOutParam()),
1755 RTEXITCODE_FAILURE);
1756 RTPrintf(Cloud::tr("Getting information about the cloud image with id \'%s\'...\n"), strImageId.c_str());
1757
1758 ComPtr<IStringArray> infoArray;
1759 com::SafeArray<BSTR> pStrInfoArray;
1760 ComPtr<IProgress> pProgress;
1761
1762 RTPrintf(Cloud::tr("Reply is in the form \'image property\' = \'value\'\n"));
1763 CHECK_ERROR2_RET(hrc, oCloudClient,
1764 GetImageInfo(Bstr(strImageId).raw(),
1765 infoArray.asOutParam(),
1766 pProgress.asOutParam()),
1767 RTEXITCODE_FAILURE);
1768
1769 hrc = showProgress(pProgress);
1770 CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Getting information about the cloud image failed")), RTEXITCODE_FAILURE);
1771
1772 CHECK_ERROR2_RET(hrc,
1773 infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)),
1774 RTEXITCODE_FAILURE);
1775
1776 RTPrintf(Cloud::tr("General information about the image:\n"));
1777 size_t cParamNames = pStrInfoArray.size();
1778 for (size_t k = 0; k < cParamNames; k++)
1779 {
1780 Utf8Str data(pStrInfoArray[k]);
1781 RTPrintf("\t%s\n", data.c_str());
1782 }
1783
1784 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1785}
1786
1787static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1788{
1789 RT_NOREF(a);
1790 RT_NOREF(iFirst);
1791 RT_NOREF(pCommonOpts);
1792 return RTEXITCODE_SUCCESS;
1793}
1794
1795static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1796{
1797 HRESULT hrc = S_OK;
1798
1799 static const RTGETOPTDEF s_aOptions[] =
1800 {
1801 { "--id", 'i', RTGETOPT_REQ_STRING },
1802 { "help", 'h', RTGETOPT_REQ_NOTHING },
1803 { "--help", 'h', RTGETOPT_REQ_NOTHING }
1804 };
1805 RTGETOPTSTATE GetState;
1806 RTGETOPTUNION ValueUnion;
1807 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1808 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1809 if (a->argc == iFirst)
1810 {
1811 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1812 printHelp(g_pStdOut);
1813 return RTEXITCODE_SUCCESS;
1814 }
1815
1816 Utf8Str strImageId;
1817
1818 int c;
1819 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1820 {
1821 switch (c)
1822 {
1823 case 'i':
1824 {
1825 if (strImageId.isNotEmpty())
1826 return errorArgument(Cloud::tr("Duplicate parameter: --id"));
1827
1828 strImageId = ValueUnion.psz;
1829 if (strImageId.isEmpty())
1830 return errorArgument(Cloud::tr("Empty parameter: --id"));
1831
1832 break;
1833 }
1834
1835 case 'h':
1836 printHelp(g_pStdOut);
1837 return RTEXITCODE_SUCCESS;
1838 case VINF_GETOPT_NOT_OPTION:
1839 return errorUnknownSubcommand(ValueUnion.psz);
1840
1841 default:
1842 return errorGetOpt(c, &ValueUnion);
1843 }
1844 }
1845
1846 /* Delayed check. It allows us to print help information.*/
1847 hrc = checkAndSetCommonOptions(a, pCommonOpts);
1848 if (FAILED(hrc))
1849 return RTEXITCODE_FAILURE;
1850
1851 if (strImageId.isEmpty())
1852 return errorArgument(Cloud::tr("Missing parameter: --id"));
1853
1854
1855 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
1856
1857 ComObjPtr<ICloudClient> oCloudClient;
1858 CHECK_ERROR2_RET(hrc, pCloudProfile,
1859 CreateCloudClient(oCloudClient.asOutParam()),
1860 RTEXITCODE_FAILURE);
1861 RTPrintf(Cloud::tr("Deleting cloud image with id %s...\n"), strImageId.c_str());
1862
1863 ComPtr<IProgress> progress;
1864 CHECK_ERROR2_RET(hrc, oCloudClient,
1865 DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()),
1866 RTEXITCODE_FAILURE);
1867 hrc = showProgress(progress);
1868 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Deleting cloud image failed")), RTEXITCODE_FAILURE);
1869
1870 if (SUCCEEDED(hrc))
1871 RTPrintf(Cloud::tr("Cloud image was deleted successfully\n"));
1872
1873 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1874}
1875
1876static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
1877{
1878 enum
1879 {
1880 kCloudImageIota = 1000,
1881 kCloudImage_Create,
1882 kCloudImage_Delete,
1883 kCloudImage_Export,
1884 kCloudImage_Import,
1885 kCloudImage_Info,
1886 kCloudImage_Update,
1887 };
1888
1889 static const RTGETOPTDEF s_aOptions[] =
1890 {
1891 { "create", kCloudImage_Create, RTGETOPT_REQ_NOTHING },
1892 { "delete", kCloudImage_Delete, RTGETOPT_REQ_NOTHING },
1893 { "export", kCloudImage_Export, RTGETOPT_REQ_NOTHING },
1894 { "import", kCloudImage_Import, RTGETOPT_REQ_NOTHING },
1895 { "info", kCloudImage_Info, RTGETOPT_REQ_NOTHING },
1896 { "update", kCloudImage_Update, RTGETOPT_REQ_NOTHING },
1897
1898 { "help", 'h', RTGETOPT_REQ_NOTHING },
1899 { "-?", 'h', RTGETOPT_REQ_NOTHING },
1900 { "-help", 'h', RTGETOPT_REQ_NOTHING },
1901 { "--help", 'h', RTGETOPT_REQ_NOTHING },
1902 };
1903
1904 if (a->argc == iFirst)
1905 {
1906 RTPrintf(Cloud::tr("Empty command parameter list, show help.\n"));
1907 printHelp(g_pStdOut);
1908 return RTEXITCODE_SUCCESS;
1909 }
1910
1911 RTGETOPTSTATE GetState;
1912 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
1913 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
1914
1915 int c;
1916 RTGETOPTUNION ValueUnion;
1917 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
1918 {
1919 switch (c)
1920 {
1921 /* Sub-commands: */
1922 case kCloudImage_Create:
1923 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_CREATE);
1924 return createCloudImage(a, GetState.iNext, pCommonOpts);
1925
1926 case kCloudImage_Export:
1927 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_EXPORT);
1928 return exportCloudImage(a, GetState.iNext, pCommonOpts);
1929
1930 case kCloudImage_Import:
1931 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_IMPORT);
1932 return importCloudImage(a, GetState.iNext, pCommonOpts);
1933
1934 case kCloudImage_Info:
1935 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_INFO);
1936 return showCloudImageInfo(a, GetState.iNext, pCommonOpts);
1937
1938 case kCloudImage_Update:
1939// setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_UPDATE);
1940 return updateCloudImage(a, GetState.iNext, pCommonOpts);
1941
1942 case kCloudImage_Delete:
1943 setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_DELETE);
1944 return deleteCloudImage(a, GetState.iNext, pCommonOpts);
1945
1946 case 'h':
1947 printHelp(g_pStdOut);
1948 return RTEXITCODE_SUCCESS;
1949
1950 case VINF_GETOPT_NOT_OPTION:
1951 return errorUnknownSubcommand(ValueUnion.psz);
1952
1953 default:
1954 return errorGetOpt(c, &ValueUnion);
1955 }
1956 }
1957
1958 return errorNoSubcommand();
1959}
1960
1961#ifdef VBOX_WITH_CLOUD_NET
1962struct CloudNetworkOptions
1963{
1964 BOOL fEnable;
1965 BOOL fDisable;
1966 Bstr strNetworkId;
1967 Bstr strNetworkName;
1968};
1969typedef struct CloudNetworkOptions CLOUDNETOPT;
1970typedef CLOUDNETOPT *PCLOUDNETOPT;
1971
1972static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr<ICloudNetwork> cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts)
1973{
1974 HRESULT hrc = S_OK;
1975
1976 Bstr strProvider = pCommonOpts->provider.pszProviderName;
1977 Bstr strProfile = pCommonOpts->profile.pszProfileName;
1978
1979 if (options.fEnable)
1980 {
1981 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE);
1982 }
1983 if (options.fDisable)
1984 {
1985 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE);
1986 }
1987 if (options.strNetworkId.isNotEmpty())
1988 {
1989 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE);
1990 }
1991 if (strProvider.isNotEmpty())
1992 {
1993 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE);
1994 }
1995 if (strProfile.isNotEmpty())
1996 {
1997 CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE);
1998 }
1999
2000 return RTEXITCODE_SUCCESS;
2001}
2002
2003
2004static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2005{
2006 HRESULT hrc = S_OK;
2007 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2008 if (FAILED(hrc))
2009 return RTEXITCODE_FAILURE;
2010
2011 /* Required parameters, the rest is handled in update */
2012 static const RTGETOPTDEF s_aOptions[] =
2013 {
2014 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2015 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2016 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2017 { "--name", 'n', RTGETOPT_REQ_STRING },
2018 };
2019
2020 RTGETOPTSTATE GetState;
2021 RTGETOPTUNION ValueUnion;
2022 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2023 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2024
2025 CLOUDNETOPT options;
2026 options.fEnable = FALSE;
2027 options.fDisable = FALSE;
2028
2029 int c;
2030 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2031 {
2032 switch (c)
2033 {
2034 case 'd':
2035 options.fDisable = TRUE;
2036 break;
2037 case 'e':
2038 options.fEnable = TRUE;
2039 break;
2040 case 'i':
2041 options.strNetworkId=ValueUnion.psz;
2042 break;
2043 case 'n':
2044 options.strNetworkName=ValueUnion.psz;
2045 break;
2046 case VINF_GETOPT_NOT_OPTION:
2047 return errorUnknownSubcommand(ValueUnion.psz);
2048 default:
2049 return errorGetOpt(c, &ValueUnion);
2050 }
2051 }
2052
2053 if (options.strNetworkName.isEmpty())
2054 return errorArgument(Cloud::tr("Missing --name parameter"));
2055 if (options.strNetworkId.isEmpty())
2056 return errorArgument(Cloud::tr("Missing --network-id parameter"));
2057
2058 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2059
2060 ComPtr<ICloudNetwork> cloudNetwork;
2061 CHECK_ERROR2_RET(hrc, pVirtualBox,
2062 CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2063 RTEXITCODE_FAILURE);
2064
2065 /* Fill out the created network */
2066 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2067 if (RT_SUCCESS(rc))
2068 RTPrintf(Cloud::tr("Cloud network was created successfully\n"));
2069
2070 return rc;
2071}
2072
2073
2074static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2075{
2076 RT_NOREF(pCommonOpts);
2077 HRESULT hrc = S_OK;
2078 static const RTGETOPTDEF s_aOptions[] =
2079 {
2080 { "--name", 'n', RTGETOPT_REQ_STRING },
2081 };
2082 RTGETOPTSTATE GetState;
2083 RTGETOPTUNION ValueUnion;
2084 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2085 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2086
2087 Bstr strNetworkName;
2088
2089 int c;
2090 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2091 {
2092 switch (c)
2093 {
2094 case 'n':
2095 strNetworkName=ValueUnion.psz;
2096 break;
2097 case VINF_GETOPT_NOT_OPTION:
2098 return errorUnknownSubcommand(ValueUnion.psz);
2099 default:
2100 return errorGetOpt(c, &ValueUnion);
2101 }
2102 }
2103
2104 if (strNetworkName.isEmpty())
2105 return errorArgument(Cloud::tr("Missing --name parameter"));
2106
2107 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2108 ComPtr<ICloudNetwork> cloudNetwork;
2109 CHECK_ERROR2_RET(hrc, pVirtualBox,
2110 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2111 RTEXITCODE_FAILURE);
2112
2113 RTPrintf(Cloud::tr("Name: %ls\n"), strNetworkName.raw());
2114 BOOL fEnabled = FALSE;
2115 cloudNetwork->COMGETTER(Enabled)(&fEnabled);
2116 RTPrintf(Cloud::tr("State: %s\n"), fEnabled ? Cloud::tr("Enabled") : Cloud::tr("Disabled"));
2117 Bstr Provider;
2118 cloudNetwork->COMGETTER(Provider)(Provider.asOutParam());
2119 RTPrintf(Cloud::tr("CloudProvider: %ls\n"), Provider.raw());
2120 Bstr Profile;
2121 cloudNetwork->COMGETTER(Profile)(Profile.asOutParam());
2122 RTPrintf(Cloud::tr("CloudProfile: %ls\n"), Profile.raw());
2123 Bstr NetworkId;
2124 cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam());
2125 RTPrintf(Cloud::tr("CloudNetworkId: %ls\n"), NetworkId.raw());
2126 Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw());
2127 RTPrintf(Cloud::tr("VBoxNetworkName: %ls\n\n"), netName.raw());
2128
2129 return RTEXITCODE_SUCCESS;
2130}
2131
2132
2133static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2134{
2135 HRESULT hrc = S_OK;
2136
2137 static const RTGETOPTDEF s_aOptions[] =
2138 {
2139 { "--disable", 'd', RTGETOPT_REQ_NOTHING },
2140 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
2141 { "--network-id", 'i', RTGETOPT_REQ_STRING },
2142 { "--name", 'n', RTGETOPT_REQ_STRING },
2143 };
2144
2145 RTGETOPTSTATE GetState;
2146 RTGETOPTUNION ValueUnion;
2147 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2148 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2149
2150 CLOUDNETOPT options;
2151 options.fEnable = FALSE;
2152 options.fDisable = FALSE;
2153
2154 int c;
2155 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2156 {
2157 switch (c)
2158 {
2159 case 'd':
2160 options.fDisable = TRUE;
2161 break;
2162 case 'e':
2163 options.fEnable = TRUE;
2164 break;
2165 case 'i':
2166 options.strNetworkId=ValueUnion.psz;
2167 break;
2168 case 'n':
2169 options.strNetworkName=ValueUnion.psz;
2170 break;
2171 case VINF_GETOPT_NOT_OPTION:
2172 return errorUnknownSubcommand(ValueUnion.psz);
2173 default:
2174 return errorGetOpt(c, &ValueUnion);
2175 }
2176 }
2177
2178 if (options.strNetworkName.isEmpty())
2179 return errorArgument(Cloud::tr("Missing --name parameter"));
2180
2181 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2182 ComPtr<ICloudNetwork> cloudNetwork;
2183 CHECK_ERROR2_RET(hrc, pVirtualBox,
2184 FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()),
2185 RTEXITCODE_FAILURE);
2186
2187 RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts);
2188 if (RT_SUCCESS(rc))
2189 RTPrintf(Cloud::tr("Cloud network %ls was updated successfully\n"), options.strNetworkName.raw());
2190
2191 return rc;
2192}
2193
2194
2195static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2196{
2197 RT_NOREF(pCommonOpts);
2198 HRESULT hrc = S_OK;
2199 static const RTGETOPTDEF s_aOptions[] =
2200 {
2201 { "--name", 'n', RTGETOPT_REQ_STRING },
2202 };
2203 RTGETOPTSTATE GetState;
2204 RTGETOPTUNION ValueUnion;
2205 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2206 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2207
2208 Bstr strNetworkName;
2209
2210 int c;
2211 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2212 {
2213 switch (c)
2214 {
2215 case 'n':
2216 strNetworkName=ValueUnion.psz;
2217 break;
2218 case VINF_GETOPT_NOT_OPTION:
2219 return errorUnknownSubcommand(ValueUnion.psz);
2220 default:
2221 return errorGetOpt(c, &ValueUnion);
2222 }
2223 }
2224
2225 if (strNetworkName.isEmpty())
2226 return errorArgument(Cloud::tr("Missing --name parameter"));
2227
2228 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2229 ComPtr<ICloudNetwork> cloudNetwork;
2230 CHECK_ERROR2_RET(hrc, pVirtualBox,
2231 FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()),
2232 RTEXITCODE_FAILURE);
2233
2234 CHECK_ERROR2_RET(hrc, pVirtualBox,
2235 RemoveCloudNetwork(cloudNetwork),
2236 RTEXITCODE_FAILURE);
2237
2238 if (SUCCEEDED(hrc))
2239 RTPrintf(Cloud::tr("Cloud network %ls was deleted successfully\n"), strNetworkName.raw());
2240
2241 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2242}
2243
2244
2245static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2246{
2247 RT_NOREF(pCommonOpts);
2248 HRESULT hrc = S_OK;
2249 static const RTGETOPTDEF s_aOptions[] =
2250 {
2251 { "--gateway-os-name", 'n', RTGETOPT_REQ_STRING },
2252 { "--gateway-os-version", 'v', RTGETOPT_REQ_STRING },
2253 { "--gateway-shape", 's', RTGETOPT_REQ_STRING },
2254 { "--tunnel-network-name", 't', RTGETOPT_REQ_STRING },
2255 { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING },
2256 { "--compartment-id", 'c', RTGETOPT_REQ_STRING }
2257 };
2258 RTGETOPTSTATE GetState;
2259 RTGETOPTUNION ValueUnion;
2260 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2261 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2262
2263 Bstr strGatewayOsName;
2264 Bstr strGatewayOsVersion;
2265 Bstr strGatewayShape;
2266 Bstr strTunnelNetworkName;
2267 Bstr strTunnelNetworkRange;
2268 Bstr strCompartmentId;
2269
2270 int c;
2271 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2272 {
2273 switch (c)
2274 {
2275 case 'n':
2276 strGatewayOsName=ValueUnion.psz;
2277 break;
2278 case 'v':
2279 strGatewayOsVersion=ValueUnion.psz;
2280 break;
2281 case 's':
2282 strGatewayShape=ValueUnion.psz;
2283 break;
2284 case 't':
2285 strTunnelNetworkName=ValueUnion.psz;
2286 break;
2287 case 'r':
2288 strTunnelNetworkRange=ValueUnion.psz;
2289 break;
2290 case 'c':
2291 strCompartmentId=ValueUnion.psz;
2292 break;
2293 case VINF_GETOPT_NOT_OPTION:
2294 return errorUnknownSubcommand(ValueUnion.psz);
2295 default:
2296 return errorGetOpt(c, &ValueUnion);
2297 }
2298 }
2299
2300 /* Delayed check. It allows us to print help information.*/
2301 hrc = checkAndSetCommonOptions(a, pCommonOpts);
2302 if (FAILED(hrc))
2303 return RTEXITCODE_FAILURE;
2304
2305 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
2306
2307 RTPrintf(Cloud::tr("Setting up tunnel network in the cloud...\n"));
2308
2309 ComPtr<ICloudProfile> pCloudProfile = pCommonOpts->profile.pCloudProfile;
2310
2311 /* Use user-specified profile instead of default one. */
2312 if (strCompartmentId.isNotEmpty())
2313 {
2314 CHECK_ERROR2_RET(hrc, pCloudProfile,
2315 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
2316 RTEXITCODE_FAILURE);
2317 }
2318
2319 ComObjPtr<ICloudClient> oCloudClient;
2320 CHECK_ERROR2_RET(hrc, pCloudProfile,
2321 CreateCloudClient(oCloudClient.asOutParam()),
2322 RTEXITCODE_FAILURE);
2323
2324 ComPtr<ICloudNetworkEnvironmentInfo> cloudNetworkEnv;
2325 ComPtr<IProgress> progress;
2326 CHECK_ERROR2_RET(hrc, oCloudClient,
2327 SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(),
2328 strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(),
2329 cloudNetworkEnv.asOutParam(), progress.asOutParam()),
2330 RTEXITCODE_FAILURE);
2331
2332 hrc = showProgress(progress);
2333 CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Setting up cloud network environment failed")), RTEXITCODE_FAILURE);
2334
2335 Bstr tunnelNetworkId;
2336 hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam());
2337 RTPrintf(Cloud::tr("Cloud network environment was set up successfully. Tunnel network id is: %ls\n"), tunnelNetworkId.raw());
2338
2339 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
2340}
2341
2342
2343static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
2344{
2345 enum
2346 {
2347 kCloudNetworkIota = 1000,
2348 kCloudNetwork_Create,
2349 kCloudNetwork_Delete,
2350 kCloudNetwork_Info,
2351 kCloudNetwork_Setup,
2352 kCloudNetwork_Update,
2353 };
2354
2355 static const RTGETOPTDEF s_aOptions[] =
2356 {
2357 { "create", kCloudNetwork_Create, RTGETOPT_REQ_NOTHING },
2358 { "delete", kCloudNetwork_Delete, RTGETOPT_REQ_NOTHING },
2359 { "info", kCloudNetwork_Info, RTGETOPT_REQ_NOTHING },
2360 { "setup", kCloudNetwork_Setup, RTGETOPT_REQ_NOTHING },
2361 { "update", kCloudNetwork_Update, RTGETOPT_REQ_NOTHING },
2362 };
2363
2364 if (a->argc < 1)
2365 return errorNoSubcommand();
2366
2367 RTGETOPTSTATE GetState;
2368 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
2369 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2370
2371 int c;
2372 RTGETOPTUNION ValueUnion;
2373 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2374 {
2375 switch (c)
2376 {
2377 /* Sub-commands: */
2378 case kCloudNetwork_Create:
2379 return createCloudNetwork(a, GetState.iNext, pCommonOpts);
2380
2381 case kCloudNetwork_Info:
2382 return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts);
2383
2384 case kCloudNetwork_Update:
2385 return updateCloudNetwork(a, GetState.iNext, pCommonOpts);
2386
2387 case kCloudNetwork_Delete:
2388 return deleteCloudNetwork(a, GetState.iNext, pCommonOpts);
2389
2390 case kCloudNetwork_Setup:
2391 return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts);
2392
2393 case VINF_GETOPT_NOT_OPTION:
2394 return errorUnknownSubcommand(ValueUnion.psz);
2395
2396 default:
2397 return errorGetOpt(c, &ValueUnion);
2398 }
2399 }
2400
2401 return errorNoSubcommand();
2402}
2403#endif /* VBOX_WITH_CLOUD_NET */
2404
2405
2406RTEXITCODE handleCloud(HandlerArg *a)
2407{
2408 enum
2409 {
2410 kCloudIota = 1000,
2411 kCloud_Image,
2412 kCloud_Instance,
2413 kCloud_List,
2414 kCloud_Machine,
2415 kCloud_Network,
2416 kCloud_Object,
2417 kCloud_ShowVMInfo,
2418 kCloud_Volume,
2419 };
2420
2421 static const RTGETOPTDEF s_aOptions[] =
2422 {
2423 /* common options */
2424 { "--provider", 'v', RTGETOPT_REQ_STRING },
2425 { "--profile", 'f', RTGETOPT_REQ_STRING },
2426
2427 { "image", kCloud_Image, RTGETOPT_REQ_NOTHING },
2428 { "instance", kCloud_Instance, RTGETOPT_REQ_NOTHING },
2429 { "list", kCloud_List, RTGETOPT_REQ_NOTHING },
2430 { "machine", kCloud_Machine, RTGETOPT_REQ_NOTHING },
2431 { "network", kCloud_Network, RTGETOPT_REQ_NOTHING },
2432 { "object", kCloud_Object, RTGETOPT_REQ_NOTHING },
2433 { "showvminfo", kCloud_ShowVMInfo, RTGETOPT_REQ_NOTHING },
2434 { "volume", kCloud_Volume, RTGETOPT_REQ_NOTHING },
2435 };
2436
2437 if (a->argc < 1)
2438 return errorNoSubcommand();
2439
2440 RTGETOPTSTATE GetState;
2441 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
2442 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
2443
2444 CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} };
2445 int c;
2446 RTGETOPTUNION ValueUnion;
2447 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
2448 {
2449 switch (c)
2450 {
2451 case 'v': // --provider
2452 commonOpts.provider.pszProviderName = ValueUnion.psz;
2453 break;
2454
2455 case 'f': // --profile
2456 commonOpts.profile.pszProfileName = ValueUnion.psz;
2457 break;
2458
2459 /* Sub-commands: */
2460 case kCloud_List:
2461 return handleCloudLists(a, GetState.iNext, &commonOpts);
2462
2463 case kCloud_Image:
2464 return handleCloudImage(a, GetState.iNext, &commonOpts);
2465
2466 case kCloud_Instance:
2467 return handleCloudInstance(a, GetState.iNext, &commonOpts);
2468
2469#ifdef VBOX_WITH_CLOUD_NET
2470 case kCloud_Network:
2471 return handleCloudNetwork(a, GetState.iNext, &commonOpts);
2472#endif /* VBOX_WITH_CLOUD_NET */
2473
2474 /* "cloud machine ..." handling is in VBoxManageCloudMachine.cpp */
2475 case kCloud_Machine:
2476 return handleCloudMachine(a, GetState.iNext,
2477 commonOpts.provider.pszProviderName,
2478 commonOpts.profile.pszProfileName);
2479
2480 /* ... including aliases that mimic the local vm commands */
2481 case kCloud_ShowVMInfo:
2482 return handleCloudShowVMInfo(a, GetState.iNext,
2483 commonOpts.provider.pszProviderName,
2484 commonOpts.profile.pszProfileName);
2485
2486 case VINF_GETOPT_NOT_OPTION:
2487 return errorUnknownSubcommand(ValueUnion.psz);
2488
2489 default:
2490 return errorGetOpt(c, &ValueUnion);
2491 }
2492 }
2493
2494 return errorNoSubcommand();
2495}
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