VirtualBox

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

Last change on this file since 78354 was 78148, checked in by vboxsync, 6 years ago

OCI: Change ICloudClient::listImages and listInstances signatures to
return a progress. Since we cannot asynchronously update by-value
string arrays, introduce a wrapper IStringArray interface and use it.
Adapt VBoxManage to that API change.

Ifdef out the single use of listInstances in GUI. Ok dsen, he will
adapt the GUI code.

Since extpack cannot directly use code from Main and since
IStringArray implementation is really trivial, just do one in the
extpack at least for now so that this change is not bogged down in
technicalities.

The actual implementation of list methods is still synchronous and
just returns completed progress at the end. It will be made
asynchronous in a separate commit.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/* $Id: VBoxManageCloud.cpp 78148 2019-04-16 16:48:18Z vboxsync $ */
2/** @file
3 * VBoxManageCloud - The cloud related commands.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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/uuid.h>
31#include <iprt/file.h>
32#include <VBox/log.h>
33
34#include "VBoxManage.h"
35
36#include <list>
37
38using namespace com;//at least for Bstr
39
40/**
41 * Common Cloud options.
42 */
43typedef struct
44{
45 const char *pszProviderName;
46 const char *pszProfileName;
47} CLOUDCOMMONOPT;
48typedef CLOUDCOMMONOPT *PCLOUDCOMMONOPT;
49
50/**
51 * List all available cloud instances for the specified cloud provider.
52 * Available cloud instance is one which state whether "running" or "stopped".
53 *
54 * @returns RTEXITCODE
55 * @param a is the list of passed arguments
56 * @param iFirst is the position of the first unparsed argument in the arguments list
57 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
58 * arguments which have been already parsed before
59 */
60static RTEXITCODE listCloudInstances(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
61{
62 static const RTGETOPTDEF s_aOptions[] =
63 {
64 { "--compartment-id", 'c', RTGETOPT_REQ_STRING }
65 };
66 RTGETOPTSTATE GetState;
67 RTGETOPTUNION ValueUnion;
68 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
69 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
70
71 Utf8Str strCompartmentId;
72 int c;
73 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
74 {
75 switch (c)
76 {
77 case 'c':
78 strCompartmentId = ValueUnion.psz;
79 break;
80 case VINF_GETOPT_NOT_OPTION:
81 return errorUnknownSubcommand(ValueUnion.psz);
82 default:
83 return errorGetOpt(c, &ValueUnion);
84 }
85 }
86
87 HRESULT hrc = S_OK;
88 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
89 ComPtr<ICloudProviderManager> pCloudProviderManager;
90 CHECK_ERROR2_RET(hrc, pVirtualBox,
91 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
92 RTEXITCODE_FAILURE);
93 ComPtr<ICloudProvider> pCloudProvider;
94
95 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
96 GetProviderByShortName(Bstr(pCommonOpts->pszProviderName).raw(), pCloudProvider.asOutParam()),
97 RTEXITCODE_FAILURE);
98 ComPtr<ICloudProfile> pCloudProfile;
99
100 CHECK_ERROR2_RET(hrc, pCloudProvider,
101 GetProfileByName(Bstr(pCommonOpts->pszProfileName).raw(), pCloudProfile.asOutParam()),
102 RTEXITCODE_FAILURE);
103
104 if (strCompartmentId.isNotEmpty())
105 {
106 CHECK_ERROR2_RET(hrc, pCloudProfile,
107 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),
108 RTEXITCODE_FAILURE);
109 }
110 else
111 {
112 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
113 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->pszProfileName);
114 Bstr bStrCompartmentId;
115 CHECK_ERROR2_RET(hrc, pCloudProfile,
116 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
117 RTEXITCODE_FAILURE);
118 strCompartmentId = bStrCompartmentId;
119 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
120 }
121
122 Bstr bstrProfileName;
123 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
124
125 ComObjPtr<ICloudClient> oCloudClient;
126 CHECK_ERROR2_RET(hrc, pCloudProfile,
127 CreateCloudClient(oCloudClient.asOutParam()),
128 RTEXITCODE_FAILURE);
129
130 ComPtr<IStringArray> pVMNamesHolder;
131 ComPtr<IStringArray> pVMIdsHolder;
132 com::SafeArray<BSTR> arrayVMNames;
133 com::SafeArray<BSTR> arrayVMIds;
134 ComPtr<IProgress> pProgress;
135
136 RTPrintf("Getting a list of available cloud instances...\n");
137 RTPrintf("Reply is in the form \'instance name\' = \'instance id\'\n");
138 CHECK_ERROR2_RET(hrc, oCloudClient,
139 ListInstances(CloudMachineState_Running,
140 pVMNamesHolder.asOutParam(),
141 pVMIdsHolder.asOutParam(),
142 pProgress.asOutParam()),
143 RTEXITCODE_FAILURE);
144 showProgress(pProgress);
145 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list instances"), RTEXITCODE_FAILURE);
146
147 CHECK_ERROR2_RET(hrc,
148 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
149 RTEXITCODE_FAILURE);
150 CHECK_ERROR2_RET(hrc,
151 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
152 RTEXITCODE_FAILURE);
153
154 RTPrintf("List of available instances for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
155 bstrProfileName.raw(), strCompartmentId.c_str());
156 size_t cIds = arrayVMIds.size();
157 size_t cNames = arrayVMNames.size();
158 for (size_t k = 0; k < cNames; k++)
159 {
160 Bstr value;
161 if (k < cIds)
162 value = arrayVMIds[k];
163 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
164 }
165
166 pVMNamesHolder.setNull();
167 pVMIdsHolder.setNull();
168 arrayVMNames.setNull();
169 arrayVMIds.setNull();
170 pProgress.setNull();
171 CHECK_ERROR2_RET(hrc, oCloudClient,
172 ListInstances(CloudMachineState_Stopped,
173 pVMNamesHolder.asOutParam(),
174 pVMIdsHolder.asOutParam(),
175 pProgress.asOutParam()),
176 RTEXITCODE_FAILURE);
177 showProgress(pProgress);
178 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list instances"), RTEXITCODE_FAILURE);
179
180 CHECK_ERROR2_RET(hrc,
181 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
182 RTEXITCODE_FAILURE);
183 CHECK_ERROR2_RET(hrc,
184 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
185 RTEXITCODE_FAILURE);
186
187 cNames = arrayVMNames.size();
188 cIds = arrayVMIds.size();
189 for (size_t k = 0; k < cNames; k++)
190 {
191 Bstr value;
192 if (k < cIds)
193 value = arrayVMIds[k];
194 RTPrintf("\t%ls=%ls\n", arrayVMNames[k], value.raw());
195 }
196
197 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
198}
199
200/**
201 * List all available cloud images for the specified cloud provider.
202 *
203 * @returns RTEXITCODE
204 * @param a is the list of passed arguments
205 * @param iFirst is the position of the first unparsed argument in the arguments list
206 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
207 * arguments which have been already parsed before
208 */
209static RTEXITCODE listCloudImages(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
210{
211 static const RTGETOPTDEF s_aOptions[] =
212 {
213 { "--compartment-id", 'c', RTGETOPT_REQ_STRING }
214 };
215 RTGETOPTSTATE GetState;
216 RTGETOPTUNION ValueUnion;
217 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
218 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
219
220 Utf8Str strCompartmentId;
221 int c;
222 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
223 {
224 switch (c)
225 {
226 case 'c':
227 strCompartmentId = ValueUnion.psz;
228 break;
229 case VINF_GETOPT_NOT_OPTION:
230 return errorUnknownSubcommand(ValueUnion.psz);
231 default:
232 return errorGetOpt(c, &ValueUnion);
233 }
234 }
235
236 HRESULT hrc = S_OK;
237 ComPtr<IVirtualBox> pVirtualBox = a->virtualBox;
238 ComPtr<ICloudProviderManager> pCloudProviderManager;
239 CHECK_ERROR2_RET(hrc, pVirtualBox,
240 COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()),
241 RTEXITCODE_FAILURE);
242 ComPtr<ICloudProvider> pCloudProvider;
243
244 CHECK_ERROR2_RET(hrc, pCloudProviderManager,
245 GetProviderByShortName(Bstr(pCommonOpts->pszProviderName).raw(), pCloudProvider.asOutParam()),
246 RTEXITCODE_FAILURE);
247 ComPtr<ICloudProfile> pCloudProfile;
248
249 CHECK_ERROR2_RET(hrc, pCloudProvider,
250 GetProfileByName(Bstr(pCommonOpts->pszProfileName).raw(), pCloudProfile.asOutParam()),
251 RTEXITCODE_FAILURE);
252 if (strCompartmentId.isNotEmpty())
253 {
254 CHECK_ERROR2_RET(hrc, pCloudProfile,
255 SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()),\
256 RTEXITCODE_FAILURE);
257 }
258 else
259 {
260 RTPrintf("Parameter \'compartment\' is empty or absent.\n"
261 "Trying to get the compartment from the passed cloud profile \'%s\'\n", pCommonOpts->pszProfileName);
262 Bstr bStrCompartmentId;
263 CHECK_ERROR2_RET(hrc, pCloudProfile,
264 GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()),
265 RTEXITCODE_FAILURE);
266 strCompartmentId = bStrCompartmentId;
267 RTPrintf("Found the compartment \'%s\':\n", strCompartmentId.c_str());
268 }
269
270 Bstr bstrProfileName;
271 pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam());
272
273 ComObjPtr<ICloudClient> oCloudClient;
274 CHECK_ERROR2_RET(hrc, pCloudProfile,
275 CreateCloudClient(oCloudClient.asOutParam()),
276 RTEXITCODE_FAILURE);
277
278 ComPtr<IStringArray> pVMNamesHolder;
279 ComPtr<IStringArray> pVMIdsHolder;
280 com::SafeArray<BSTR> arrayVMNames;
281 com::SafeArray<BSTR> arrayVMIds;
282 ComPtr<IProgress> pProgress;
283
284 RTPrintf("Getting a list of available cloud images...\n");
285 RTPrintf("Reply is in the form \'image name\' = \'image id\'\n");
286 CHECK_ERROR2_RET(hrc, oCloudClient,
287 ListImages(CloudImageState_Available,
288 pVMNamesHolder.asOutParam(),
289 pVMIdsHolder.asOutParam(),
290 pProgress.asOutParam()),
291 RTEXITCODE_FAILURE);
292 showProgress(pProgress);
293 CHECK_PROGRESS_ERROR_RET(pProgress, ("Failed to list images"), RTEXITCODE_FAILURE);
294
295 CHECK_ERROR2_RET(hrc,
296 pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)),
297 RTEXITCODE_FAILURE);
298 CHECK_ERROR2_RET(hrc,
299 pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)),
300 RTEXITCODE_FAILURE);
301
302 RTPrintf("List of available images for the cloud profile \'%ls\' \nand compartment \'%s\':\n",
303 bstrProfileName.raw(), strCompartmentId.c_str());
304 size_t cNames = arrayVMNames.size();
305 size_t cIds = arrayVMIds.size();
306 for (size_t k = 0; k < cNames; k++)
307 {
308 Bstr value;
309 if (k < cIds)
310 value = arrayVMIds[k];
311 RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw());
312 }
313
314 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
315}
316
317/**
318 * General function which handles the "list" commands
319 *
320 * @returns RTEXITCODE
321 * @param a is the list of passed arguments
322 * @param iFirst is the position of the first unparsed argument in the arguments list
323 * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common
324 * arguments which have been already parsed before
325 */
326static RTEXITCODE handleCloudLists(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts)
327{
328 if (a->argc < 1)
329 return errorNoSubcommand();
330
331 static const RTGETOPTDEF s_aOptions[] =
332 {
333 { "images", 1000, RTGETOPT_REQ_NOTHING },
334 { "instances", 1001, RTGETOPT_REQ_NOTHING },
335 { "networks", 1002, RTGETOPT_REQ_NOTHING },
336 { "subnets", 1003, RTGETOPT_REQ_NOTHING },
337 { "vcns", 1004, RTGETOPT_REQ_NOTHING },
338 { "objects", 1005, RTGETOPT_REQ_NOTHING }
339 };
340
341
342 Bstr bstrProvider(pCommonOpts->pszProviderName);
343 Bstr bstrProfile(pCommonOpts->pszProfileName);
344
345 /* check for required options */
346 if (bstrProvider.isEmpty())
347 return errorSyntax(USAGE_CLOUDPROFILE, "Parameter --provider is required");
348 if (bstrProfile.isEmpty())
349 return errorSyntax(USAGE_CLOUDPROFILE, "Parameter --profile is required");
350
351 RTGETOPTSTATE GetState;
352 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0);
353 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
354
355 int c;
356 RTGETOPTUNION ValueUnion;
357 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
358 {
359 switch (c)
360 {
361 case 1000:
362// setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_CREATE);
363 return listCloudImages(a, GetState.iNext, pCommonOpts);
364 case 1001:
365// setCurrentSubcommand(HELP_SCOPE_CLOUDIMAGE_INFO);
366 return listCloudInstances(a, GetState.iNext, pCommonOpts);
367 case VINF_GETOPT_NOT_OPTION:
368 return errorUnknownSubcommand(ValueUnion.psz);
369
370 default:
371 return errorGetOpt(c, &ValueUnion);
372 }
373 }
374
375 return errorNoSubcommand();
376}
377
378RTEXITCODE handleCloud(HandlerArg *a)
379{
380 if (a->argc < 1)
381 return errorNoSubcommand();
382
383 static const RTGETOPTDEF s_aOptions[] =
384 {
385 /* common options */
386 { "--provider", 'v', RTGETOPT_REQ_STRING },
387 { "--profile", 'f', RTGETOPT_REQ_STRING },
388 { "list", 1000, RTGETOPT_REQ_NOTHING },
389 { "image", 1001, RTGETOPT_REQ_NOTHING },
390 { "instance", 1002, RTGETOPT_REQ_NOTHING },
391 { "network", 1003, RTGETOPT_REQ_NOTHING },
392 { "volume", 1004, RTGETOPT_REQ_NOTHING },
393 { "object", 1005, RTGETOPT_REQ_NOTHING }
394 };
395
396 RTGETOPTSTATE GetState;
397 int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0);
398 AssertRCReturn(vrc, RTEXITCODE_FAILURE);
399
400 CLOUDCOMMONOPT CommonOpts = { NULL, NULL };
401 int c;
402 RTGETOPTUNION ValueUnion;
403 while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0)
404 {
405 switch (c)
406 {
407 case 'v': // --provider
408 CommonOpts.pszProviderName = ValueUnion.psz;
409 break;
410 case 'f': // --profile
411 CommonOpts.pszProfileName = ValueUnion.psz;
412 break;
413 /* Sub-commands: */
414 case 1000:
415// setCurrentSubcommand(HELP_SCOPE_CLOUDLIST);
416 return handleCloudLists(a, GetState.iNext, &CommonOpts);
417 case VINF_GETOPT_NOT_OPTION:
418 return errorUnknownSubcommand(ValueUnion.psz);
419
420 default:
421 return errorGetOpt(c, &ValueUnion);
422 }
423 }
424
425 return errorNoSubcommand();
426}
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