VirtualBox

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

Last change on this file since 94238 was 94238, checked in by vboxsync, 3 years ago

FE/VBoxManage: Some missing conversion of errorSyntax in VBoxManageCloud.cpp, ​bugref:9186 [scm fix]

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