/* $Id: VBoxManageCloud.cpp 99931 2023-05-23 11:43:32Z vboxsync $ */ /** @file * VBoxManageCloud - The cloud related commands. */ /* * Copyright (C) 2006-2023 Oracle and/or its affiliates. * * This file is part of VirtualBox base platform packages, as * available from https://www.virtualbox.org. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, in version 3 of the * License. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * * SPDX-License-Identifier: GPL-3.0-only */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "VBoxManage.h" #include using namespace com;//at least for Bstr DECLARE_TRANSLATION_CONTEXT(Cloud); /** * Common Cloud options. */ typedef struct { struct { const char *pszProviderName; ComPtr pCloudProvider; }provider; struct { const char *pszProfileName; ComPtr pCloudProfile; }profile; } CLOUDCOMMONOPT; typedef CLOUDCOMMONOPT *PCLOUDCOMMONOPT; static HRESULT checkAndSetCommonOptions(HandlerArg *a, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; Bstr bstrProvider(pCommonOpts->provider.pszProviderName); Bstr bstrProfile(pCommonOpts->profile.pszProfileName); /* check for required options */ if (bstrProvider.isEmpty()) { errorSyntax(Cloud::tr("Parameter --provider is required")); return E_FAIL; } if (bstrProfile.isEmpty()) { errorSyntax(Cloud::tr("Parameter --profile is required")); return E_FAIL; } ComPtr pVirtualBox = a->virtualBox; ComPtr pCloudProviderManager; CHECK_ERROR2_RET(hrc, pVirtualBox, COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProvider; CHECK_ERROR2_RET(hrc, pCloudProviderManager, GetProviderByShortName(bstrProvider.raw(), pCloudProvider.asOutParam()), RTEXITCODE_FAILURE); pCommonOpts->provider.pCloudProvider = pCloudProvider; ComPtr pCloudProfile; CHECK_ERROR2_RET(hrc, pCloudProvider, GetProfileByName(bstrProfile.raw(), pCloudProfile.asOutParam()), RTEXITCODE_FAILURE); pCommonOpts->profile.pCloudProfile = pCloudProfile; return hrc; } /** * List all available cloud instances for the specified cloud provider. * Available cloud instance is one which state whether "running" or "stopped". * * @returns RTEXITCODE * @param a is the list of passed arguments * @param iFirst is the position of the first unparsed argument in the arguments list * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common * arguments which have been already parsed before */ static RTEXITCODE listCloudInstances(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { static const RTGETOPTDEF s_aOptions[] = { { "--compartment-id", 'c', RTGETOPT_REQ_STRING }, { "--state", 's', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); Utf8Str strCompartmentId; com::SafeArray machineStates; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'c': strCompartmentId = ValueUnion.psz; break; case 's': { const char * const pszState = ValueUnion.psz; if (RTStrICmp(pszState, "creatingimage") == 0) machineStates.push_back(CloudMachineState_CreatingImage); else if (RTStrICmp(pszState, "paused") == 0) /* XXX */ machineStates.push_back(CloudMachineState_Stopped); else if (RTStrICmp(pszState, "provisioning") == 0) machineStates.push_back(CloudMachineState_Provisioning); else if (RTStrICmp(pszState, "running") == 0) machineStates.push_back(CloudMachineState_Running); else if (RTStrICmp(pszState, "starting") == 0) machineStates.push_back(CloudMachineState_Starting); else if (RTStrICmp(pszState, "stopped") == 0) machineStates.push_back(CloudMachineState_Stopped); else if (RTStrICmp(pszState, "stopping") == 0) machineStates.push_back(CloudMachineState_Stopping); else if (RTStrICmp(pszState, "terminated") == 0) machineStates.push_back(CloudMachineState_Terminated); else if (RTStrICmp(pszState, "terminating") == 0) machineStates.push_back(CloudMachineState_Terminating); else return errorArgument(Cloud::tr("Unknown cloud instance state \"%s\""), pszState); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } HRESULT hrc = S_OK; /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pVirtualBox = a->virtualBox; ComPtr pCloudProviderManager; CHECK_ERROR2_RET(hrc, pVirtualBox, COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProvider; CHECK_ERROR2_RET(hrc, pCloudProviderManager, GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProfile; CHECK_ERROR2_RET(hrc, pCloudProvider, GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()), RTEXITCODE_FAILURE); if (strCompartmentId.isNotEmpty()) { CHECK_ERROR2_RET(hrc, pCloudProfile, SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()), RTEXITCODE_FAILURE); } else { RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n" "Trying to get the compartment from the passed cloud profile \'%s\'\n"), pCommonOpts->profile.pszProfileName); Bstr bStrCompartmentId; CHECK_ERROR2_RET(hrc, pCloudProfile, GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()), RTEXITCODE_FAILURE); strCompartmentId = bStrCompartmentId; if (strCompartmentId.isNotEmpty()) RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str()); else return errorSyntax(Cloud::tr("Parameter --compartment-id is required")); } Bstr bstrProfileName; pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam()); ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); ComPtr pVMNamesHolder; ComPtr pVMIdsHolder; com::SafeArray arrayVMNames; com::SafeArray arrayVMIds; ComPtr pProgress; RTPrintf(Cloud::tr("Reply is in the form \'instance name\' = \'instance id\'\n")); CHECK_ERROR2_RET(hrc, oCloudClient, ListInstances(ComSafeArrayAsInParam(machineStates), pVMNamesHolder.asOutParam(), pVMIdsHolder.asOutParam(), pProgress.asOutParam()), RTEXITCODE_FAILURE); showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list instances")), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("The list of the instances for the cloud profile \'%ls\'\nand compartment \'%s\':\n"), bstrProfileName.raw(), strCompartmentId.c_str()); size_t cIds = arrayVMIds.size(); size_t cNames = arrayVMNames.size(); for (size_t k = 0; k < cNames; k++) { Bstr value; if (k < cIds) value = arrayVMIds[k]; RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw()); } return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } /** * List all available cloud images for the specified cloud provider. * * @returns RTEXITCODE * @param a is the list of passed arguments * @param iFirst is the position of the first unparsed argument in the arguments list * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common * arguments which have been already parsed before */ static RTEXITCODE listCloudImages(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { static const RTGETOPTDEF s_aOptions[] = { { "--compartment-id", 'c', RTGETOPT_REQ_STRING }, { "--state", 's', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); Utf8Str strCompartmentId; com::SafeArray imageStates; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'c': strCompartmentId = ValueUnion.psz; break; case 's': { const char * const pszState = ValueUnion.psz; if (RTStrICmp(pszState, "available") == 0) imageStates.push_back(CloudImageState_Available); else if (RTStrICmp(pszState, "deleted") == 0) imageStates.push_back(CloudImageState_Deleted); else if (RTStrICmp(pszState, "disabled") == 0) imageStates.push_back(CloudImageState_Disabled); else if (RTStrICmp(pszState, "exporting") == 0) imageStates.push_back(CloudImageState_Exporting); else if (RTStrICmp(pszState, "importing") == 0) imageStates.push_back(CloudImageState_Importing); else if (RTStrICmp(pszState, "provisioning") == 0) imageStates.push_back(CloudImageState_Provisioning); else return errorArgument(Cloud::tr("Unknown cloud image state \"%s\""), pszState); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } HRESULT hrc = S_OK; /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pVirtualBox = a->virtualBox; ComPtr pCloudProviderManager; CHECK_ERROR2_RET(hrc, pVirtualBox, COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProvider; CHECK_ERROR2_RET(hrc, pCloudProviderManager, GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProfile; CHECK_ERROR2_RET(hrc, pCloudProvider, GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()), RTEXITCODE_FAILURE); if (strCompartmentId.isNotEmpty()) { CHECK_ERROR2_RET(hrc, pCloudProfile, SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()), RTEXITCODE_FAILURE); } else { RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n" "Trying to get the compartment from the passed cloud profile \'%s\'\n"), pCommonOpts->profile.pszProfileName); Bstr bStrCompartmentId; CHECK_ERROR2_RET(hrc, pCloudProfile, GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()), RTEXITCODE_FAILURE); strCompartmentId = bStrCompartmentId; if (strCompartmentId.isNotEmpty()) RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str()); else return errorSyntax(Cloud::tr("Parameter --compartment-id is required")); } Bstr bstrProfileName; pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam()); ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); ComPtr pVMNamesHolder; ComPtr pVMIdsHolder; com::SafeArray arrayVMNames; com::SafeArray arrayVMIds; ComPtr pProgress; RTPrintf(Cloud::tr("Reply is in the form \'image name\' = \'image id\'\n")); CHECK_ERROR2_RET(hrc, oCloudClient, ListImages(ComSafeArrayAsInParam(imageStates), pVMNamesHolder.asOutParam(), pVMIdsHolder.asOutParam(), pProgress.asOutParam()), RTEXITCODE_FAILURE); showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list images")), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVMNamesHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMNames)), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVMIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVMIds)), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("The list of the images for the cloud profile \'%ls\'\nand compartment \'%s\':\n"), bstrProfileName.raw(), strCompartmentId.c_str()); size_t cNames = arrayVMNames.size(); size_t cIds = arrayVMIds.size(); for (size_t k = 0; k < cNames; k++) { Bstr value; if (k < cIds) value = arrayVMIds[k]; RTPrintf("\t%ls = %ls\n", arrayVMNames[k], value.raw()); } return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } /** * List all available cloud vnic attachments for the specified cloud provider. * * @returns RTEXITCODE * @param a is the list of passed arguments * @param iFirst is the position of the first unparsed argument in the arguments list * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common * arguments which have been already parsed before */ static RTEXITCODE listCloudVnicAttachments(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { static const RTGETOPTDEF s_aOptions[] = { { "--compartment-id", 'c', RTGETOPT_REQ_STRING }, { "--filter", 'f', RTGETOPT_REQ_STRING },/*instanceId=, vnicId=, domainName=*/ { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); com::SafeArray parameters; Utf8Str strCompartmentId; Utf8Str filterList; HRESULT hrc = S_OK; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'c': strCompartmentId = ValueUnion.psz; Bstr(Utf8Str("compartmentId=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'f': filterList.append(ValueUnion.psz).append(","); Bstr(Utf8Str(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } RTPrintf(Cloud::tr("Filters: \'%s\' \n"), filterList.c_str()); /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pVirtualBox = a->virtualBox; ComPtr pCloudProviderManager; CHECK_ERROR2_RET(hrc, pVirtualBox, COMGETTER(CloudProviderManager)(pCloudProviderManager.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProvider; CHECK_ERROR2_RET(hrc, pCloudProviderManager, GetProviderByShortName(Bstr(pCommonOpts->provider.pszProviderName).raw(), pCloudProvider.asOutParam()), RTEXITCODE_FAILURE); ComPtr pCloudProfile; CHECK_ERROR2_RET(hrc, pCloudProvider, GetProfileByName(Bstr(pCommonOpts->profile.pszProfileName).raw(), pCloudProfile.asOutParam()), RTEXITCODE_FAILURE); if (strCompartmentId.isNotEmpty()) { CHECK_ERROR2_RET(hrc, pCloudProfile, SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()), RTEXITCODE_FAILURE); } else { RTPrintf(Cloud::tr("Parameter \'compartment\' is empty or absent.\n" "Trying to get the compartment from the passed cloud profile \'%s\'\n"), pCommonOpts->profile.pszProfileName); Bstr bStrCompartmentId; CHECK_ERROR2_RET(hrc, pCloudProfile, GetProperty(Bstr("compartment").raw(), bStrCompartmentId.asOutParam()), RTEXITCODE_FAILURE); strCompartmentId = bStrCompartmentId; if (strCompartmentId.isNotEmpty()) RTPrintf(Cloud::tr("Found the compartment \'%s\':\n"), strCompartmentId.c_str()); else return errorArgument(Cloud::tr("Parameter --compartment-id is required.")); } Bstr bstrProfileName; pCloudProfile->COMGETTER(Name)(bstrProfileName.asOutParam()); ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); ComPtr pVnicAttachmentIdsHolder; ComPtr pVnicIdsHolder; com::SafeArray arrayVnicAttachmentIds; com::SafeArray arrayVnicIds; ComPtr pProgress; RTPrintf(Cloud::tr("Reply is in the form \'Vnic attachment \': \n\t \'Vnic \'\n")); CHECK_ERROR2_RET(hrc, oCloudClient, ListVnicAttachments(ComSafeArrayAsInParam(parameters), pVnicAttachmentIdsHolder.asOutParam(), pVnicIdsHolder.asOutParam(), pProgress.asOutParam()), RTEXITCODE_FAILURE); showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Failed to list Vnic attachments")), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVnicAttachmentIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVnicAttachmentIds)), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVnicIdsHolder, COMGETTER(Values)(ComSafeArrayAsOutParam(arrayVnicIds)), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("The list of the Vnic attachments:\n")); size_t cVnicAttchIds = arrayVnicAttachmentIds.size(); size_t cVnicIds = arrayVnicIds.size(); if (cVnicAttchIds == 0) RTPrintf(Cloud::tr("\tEmpty\n")); else { Bstr value; for (size_t k = 0; k < cVnicAttchIds; k++) { if (k < cVnicIds) value = arrayVnicIds[k]; RTPrintf(Cloud::tr("Vnic attachment id [%ls]:\n\t Vnic id - %ls\n"), arrayVnicAttachmentIds[k], value.raw()); } } return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } /** * General function which handles the "list" commands * * @returns RTEXITCODE * @param a is the list of passed arguments * @param iFirst is the position of the first unparsed argument in the arguments list * @param pCommonOpts is a pointer to the structure CLOUDCOMMONOPT with some common * arguments which have been already parsed before */ static RTEXITCODE handleCloudLists(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { enum { kCloudListIota = 1000, kCloudList_Images, kCloudList_Instances, kCloudList_Machines, kCloudList_Networks, kCloudList_Objects, kCloudList_Subnets, kCloudList_Vcns, kCloudList_VnicAttachments, }; static const RTGETOPTDEF s_aOptions[] = { { "images", kCloudList_Images, RTGETOPT_REQ_NOTHING }, { "instances", kCloudList_Instances, RTGETOPT_REQ_NOTHING }, { "machines", kCloudList_Machines, RTGETOPT_REQ_NOTHING }, { "networks", kCloudList_Networks, RTGETOPT_REQ_NOTHING }, { "objects", kCloudList_Objects, RTGETOPT_REQ_NOTHING }, { "subnets", kCloudList_Subnets, RTGETOPT_REQ_NOTHING }, { "vcns", kCloudList_Vcns, RTGETOPT_REQ_NOTHING }, { "vms", kCloudList_Machines, RTGETOPT_REQ_NOTHING }, { "vnicattachments", kCloudList_VnicAttachments, RTGETOPT_REQ_NOTHING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "-?", 'h', RTGETOPT_REQ_NOTHING }, { "-help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, }; if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } RTGETOPTSTATE GetState; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); int c; RTGETOPTUNION ValueUnion; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case kCloudList_Images: setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_IMAGES); return listCloudImages(a, GetState.iNext, pCommonOpts); case kCloudList_Instances: setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_INSTANCES); return listCloudInstances(a, GetState.iNext, pCommonOpts); case kCloudList_Machines: return listCloudMachines(a, GetState.iNext, pCommonOpts->provider.pszProviderName, pCommonOpts->profile.pszProfileName); case kCloudList_VnicAttachments: setCurrentSubcommand(HELP_SCOPE_CLOUD_LIST_VNICATTACHMENTS); return listCloudVnicAttachments(a, GetState.iNext, pCommonOpts); case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } return errorNoSubcommand(); } static RTEXITCODE createCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; enum { kInstanceIota = 1000, kInstance_ShapeCpu, kInstance_ShapeMemory, }; static const RTGETOPTDEF s_aOptions[] = { { "--image-id", 'i', RTGETOPT_REQ_STRING }, { "--boot-volume-id", 'v', RTGETOPT_REQ_STRING }, { "--display-name", 'n', RTGETOPT_REQ_STRING }, { "--launch-mode", 'm', RTGETOPT_REQ_STRING }, { "--shape", 's', RTGETOPT_REQ_STRING }, { "--shape-cpus", kInstance_ShapeCpu, RTGETOPT_REQ_UINT32 }, { "--shape-memory", kInstance_ShapeMemory, RTGETOPT_REQ_UINT32 }, { "--domain-name", 'd', RTGETOPT_REQ_STRING }, { "--boot-disk-size", 'b', RTGETOPT_REQ_STRING }, { "--publicip", 'p', RTGETOPT_REQ_STRING }, { "--subnet", 't', RTGETOPT_REQ_STRING }, { "--privateip", 'P', RTGETOPT_REQ_STRING }, { "--launch", 'l', RTGETOPT_REQ_STRING }, { "--public-ssh-key", 'k', RTGETOPT_REQ_STRING }, { "--cloud-init-script-path", 'c', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } ComPtr pAppliance; CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE); ULONG vsdNum = 1; CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(1, &vsdNum), RTEXITCODE_FAILURE); com::SafeIfaceArray virtualSystemDescriptions; CHECK_ERROR2_RET(hrc, pAppliance, COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(virtualSystemDescriptions)), RTEXITCODE_FAILURE); ComPtr pVSD = virtualSystemDescriptions[0]; Utf8Str strDisplayName, strImageId, strBootVolumeId, strPublicSSHKey; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': strImageId = ValueUnion.psz; pVSD->AddDescription(VirtualSystemDescriptionType_CloudImageId, Bstr(ValueUnion.psz).raw(), NULL); break; case 'v': strBootVolumeId = ValueUnion.psz; pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootVolumeId, Bstr(ValueUnion.psz).raw(), NULL); break; case 'n': strDisplayName = ValueUnion.psz; pVSD->AddDescription(VirtualSystemDescriptionType_Name, Bstr(ValueUnion.psz).raw(), NULL); break; case 'm': pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCILaunchMode, Bstr(ValueUnion.psz).raw(), NULL); break; case 's': pVSD->AddDescription(VirtualSystemDescriptionType_CloudInstanceShape, Bstr(ValueUnion.psz).raw(), NULL); break; case kInstance_ShapeCpu: pVSD->AddDescription(VirtualSystemDescriptionType_CloudShapeCpus, BstrFmt("%RI32", ValueUnion.u32).raw(), NULL); break; case kInstance_ShapeMemory: pVSD->AddDescription(VirtualSystemDescriptionType_CloudShapeMemory, BstrFmt("%RI32", ValueUnion.u32).raw(), NULL); break; case 'd': pVSD->AddDescription(VirtualSystemDescriptionType_CloudDomain, Bstr(ValueUnion.psz).raw(), NULL); break; case 'b': pVSD->AddDescription(VirtualSystemDescriptionType_CloudBootDiskSize, Bstr(ValueUnion.psz).raw(), NULL); break; case 'p': pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicIP, Bstr(ValueUnion.psz).raw(), NULL); break; case 'P': pVSD->AddDescription(VirtualSystemDescriptionType_CloudPrivateIP, Bstr(ValueUnion.psz).raw(), NULL); break; case 't': pVSD->AddDescription(VirtualSystemDescriptionType_CloudOCISubnet, Bstr(ValueUnion.psz).raw(), NULL); break; case 'l': { Utf8Str strLaunch(ValueUnion.psz); if (strLaunch.isNotEmpty() && (strLaunch.equalsIgnoreCase("true") || strLaunch.equalsIgnoreCase("false"))) pVSD->AddDescription(VirtualSystemDescriptionType_CloudLaunchInstance, Bstr(ValueUnion.psz).raw(), NULL); break; } case 'k': strPublicSSHKey = ValueUnion.psz; pVSD->AddDescription(VirtualSystemDescriptionType_CloudPublicSSHKey, Bstr(ValueUnion.psz).raw(), NULL); break; case 'c': pVSD->AddDescription(VirtualSystemDescriptionType_CloudInitScriptPath, Bstr(ValueUnion.psz).raw(), NULL); break; case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strPublicSSHKey.isEmpty()) RTPrintf(Cloud::tr("Warning!!! Public SSH key doesn't present in the passed arguments...\n")); if (strImageId.isNotEmpty() && strBootVolumeId.isNotEmpty()) return errorArgument(Cloud::tr("Parameters --image-id and --boot-volume-id are mutually exclusive. " "Only one of them must be presented.")); if (strImageId.isEmpty() && strBootVolumeId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter --image-id or --boot-volume-id. One of them must be presented.")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; pVSD->AddDescription(VirtualSystemDescriptionType_CloudProfileName, Bstr(pCommonOpts->profile.pszProfileName).raw(), NULL); ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); ComPtr infoArray; com::SafeArray pStrInfoArray; ComPtr pProgress; #if 0 /* * OCI API returns an error during an instance creation if the image isn't available * or in the inappropriate state. So the check can be omitted. */ RTPrintf(Cloud::tr("Checking the cloud image with id \'%s\'...\n"), strImageId.c_str()); CHECK_ERROR2_RET(hrc, oCloudClient, GetImageInfo(Bstr(strImageId).raw(), infoArray.asOutParam(), pProgress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Checking the cloud image failed")), RTEXITCODE_FAILURE); pProgress.setNull(); #endif if (strImageId.isNotEmpty()) RTPrintf(Cloud::tr("Creating cloud instance with name \'%s\' from the image \'%s\'...\n"), strDisplayName.c_str(), strImageId.c_str()); else RTPrintf(Cloud::tr("Creating cloud instance with name \'%s\' from the boot volume \'%s\'...\n"), strDisplayName.c_str(), strBootVolumeId.c_str()); CHECK_ERROR2_RET(hrc, oCloudClient, LaunchVM(pVSD, pProgress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Creating cloud instance failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud instance was created successfully\n")); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE updateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { RT_NOREF(a); RT_NOREF(iFirst); RT_NOREF(pCommonOpts); return RTEXITCODE_SUCCESS; } static RTEXITCODE showCloudInstanceInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strInstanceId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strInstanceId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strInstanceId = ValueUnion.psz; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Getting information about cloud instance with id %s...\n"), strInstanceId.c_str()); RTPrintf(Cloud::tr("Reply is in the form \'setting name\' = \'value\'\n")); ComPtr pAppliance; CHECK_ERROR2_RET(hrc, a->virtualBox, CreateAppliance(pAppliance.asOutParam()), RTEXITCODE_FAILURE); com::SafeIfaceArray vsdArray; ULONG requestedVSDnums = 1; ULONG newVSDnums = 0; CHECK_ERROR2_RET(hrc, pAppliance, CreateVirtualSystemDescriptions(requestedVSDnums, &newVSDnums), RTEXITCODE_FAILURE); if (requestedVSDnums != newVSDnums) return RTEXITCODE_FAILURE; CHECK_ERROR2_RET(hrc, pAppliance, COMGETTER(VirtualSystemDescriptions)(ComSafeArrayAsOutParam(vsdArray)), RTEXITCODE_FAILURE); ComPtr instanceDescription = vsdArray[0]; ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, GetInstanceInfo(Bstr(strInstanceId).raw(), instanceDescription, progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Getting information about cloud instance failed")), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Cloud instance info (provider '%s'):\n"), pCommonOpts->provider.pszProviderName); struct vsdHReadable { VirtualSystemDescriptionType_T vsdType; Utf8Str strFound; Utf8Str strNotFound; }; const size_t vsdHReadableArraySize = 15;//the number of items in the vsdHReadableArray vsdHReadable vsdHReadableArray[vsdHReadableArraySize] = { {VirtualSystemDescriptionType_CloudDomain, Cloud::tr("Availability domain = %ls\n"), Cloud::tr("Availability domain wasn't found\n")}, {VirtualSystemDescriptionType_Name, Cloud::tr("Instance displayed name = %ls\n"), Cloud::tr("Instance displayed name wasn't found\n")}, {VirtualSystemDescriptionType_CloudInstanceState, Cloud::tr("Instance state = %ls\n"), Cloud::tr("Instance state wasn't found\n")}, {VirtualSystemDescriptionType_CloudInstanceId, Cloud::tr("Instance Id = %ls\n"), Cloud::tr("Instance Id wasn't found\n")}, {VirtualSystemDescriptionType_CloudInstanceDisplayName, Cloud::tr("Instance name = %ls\n"), Cloud::tr("Instance name wasn't found\n")}, {VirtualSystemDescriptionType_CloudImageId, Cloud::tr("Bootable image Id = %ls\n"), Cloud::tr("Image Id whom the instance is booted up wasn't found\n")}, {VirtualSystemDescriptionType_CloudInstanceShape, Cloud::tr("Shape of the instance = %ls\n"), Cloud::tr("The shape of the instance wasn't found\n")}, {VirtualSystemDescriptionType_OS, Cloud::tr("Type of guest OS = %ls\n"), Cloud::tr("Type of guest OS wasn't found\n")}, {VirtualSystemDescriptionType_Memory, Cloud::tr("RAM = %ls MB\n"), Cloud::tr("Value for RAM wasn't found\n")}, {VirtualSystemDescriptionType_CPU, Cloud::tr("CPUs = %ls\n"), Cloud::tr("Numbers of CPUs weren't found\n")}, {VirtualSystemDescriptionType_CloudPublicIP, Cloud::tr("Instance public IP = %ls\n"), Cloud::tr("Public IP wasn't found\n")}, {VirtualSystemDescriptionType_Miscellaneous, "%ls\n", Cloud::tr("Miscellanious wasn't found\n")}, {VirtualSystemDescriptionType_CloudInstanceFreeFormTags, "%ls\n", Cloud::tr("Free-form tags weren't found\n")}, {VirtualSystemDescriptionType_CloudInstanceMetadata, "%ls\n", Cloud::tr("Metadata was't found\n")}, {VirtualSystemDescriptionType_CloudInitScriptPath, "Cloud-init script: \n\t%ls\n", Cloud::tr("Cloud-init script wasn't found\n")} }; com::SafeArray retTypes; com::SafeArray aRefs; com::SafeArray aOvfValues; com::SafeArray aVBoxValues; com::SafeArray aExtraConfigValues; for (size_t i=0; iGetDescriptionByType(vsdHReadableArray[i].vsdType, ComSafeArrayAsOutParam(retTypes), ComSafeArrayAsOutParam(aRefs), ComSafeArrayAsOutParam(aOvfValues), ComSafeArrayAsOutParam(aVBoxValues), ComSafeArrayAsOutParam(aExtraConfigValues)); if (FAILED(hrc) || aVBoxValues.size() == 0) LogRel((vsdHReadableArray[i].strNotFound.c_str())); else { LogRel(("Size is %d", aVBoxValues.size())); for (size_t j = 0; jargc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strInstanceId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strInstanceId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strInstanceId = ValueUnion.psz; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Starting cloud instance with id %s...\n"), strInstanceId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, StartInstance(Bstr(strInstanceId).raw(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Starting the cloud instance failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was started\n"), strInstanceId.c_str(), pCommonOpts->provider.pszProviderName, pCommonOpts->profile.pszProfileName); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE pauseCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strInstanceId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strInstanceId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strInstanceId = ValueUnion.psz; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Pausing cloud instance with id %s...\n"), strInstanceId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, PauseInstance(Bstr(strInstanceId).raw(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Pause the cloud instance failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was paused\n"), strInstanceId.c_str(), pCommonOpts->provider.pszProviderName, pCommonOpts->profile.pszProfileName); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE terminateCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strInstanceId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strInstanceId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strInstanceId = ValueUnion.psz; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Terminating cloud instance with id %s...\n"), strInstanceId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, TerminateInstance(Bstr(strInstanceId).raw(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Termination the cloud instance failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was terminated\n"), strInstanceId.c_str(), pCommonOpts->provider.pszProviderName, pCommonOpts->profile.pszProfileName); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE resetCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strInstanceId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strInstanceId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strInstanceId = ValueUnion.psz; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Reset cloud instance with id %s...\n"), strInstanceId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, ResetInstance(Bstr(strInstanceId).raw(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Reset the cloud instance failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud instance with id %s (provider = '%s', profile = '%s') was reset\n"), strInstanceId.c_str(), pCommonOpts->provider.pszProviderName, pCommonOpts->profile.pszProfileName); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE handleCloudInstance(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { enum { kCloudInstanceIota = 1000, kCloudInstance_Create, kCloudInstance_Info, kCloudInstance_Pause, kCloudInstance_Start, kCloudInstance_Terminate, kCloudInstance_Update, kCloudInstance_Reset, }; static const RTGETOPTDEF s_aOptions[] = { { "create", kCloudInstance_Create, RTGETOPT_REQ_NOTHING }, { "info", kCloudInstance_Info, RTGETOPT_REQ_NOTHING }, { "pause", kCloudInstance_Pause, RTGETOPT_REQ_NOTHING }, { "start", kCloudInstance_Start, RTGETOPT_REQ_NOTHING }, { "terminate", kCloudInstance_Terminate, RTGETOPT_REQ_NOTHING }, { "update", kCloudInstance_Update, RTGETOPT_REQ_NOTHING }, { "reset", kCloudInstance_Reset, RTGETOPT_REQ_NOTHING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "-?", 'h', RTGETOPT_REQ_NOTHING }, { "-help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, }; if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } RTGETOPTSTATE GetState; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); int c; RTGETOPTUNION ValueUnion; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { /* Sub-commands: */ case kCloudInstance_Create: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_CREATE); return createCloudInstance(a, GetState.iNext, pCommonOpts); case kCloudInstance_Start: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_START); return startCloudInstance(a, GetState.iNext, pCommonOpts); case kCloudInstance_Pause: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_PAUSE); return pauseCloudInstance(a, GetState.iNext, pCommonOpts); case kCloudInstance_Info: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_INFO); return showCloudInstanceInfo(a, GetState.iNext, pCommonOpts); case kCloudInstance_Update: // setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_UPDATE); return updateCloudInstance(a, GetState.iNext, pCommonOpts); case kCloudInstance_Terminate: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_TERMINATE); return terminateCloudInstance(a, GetState.iNext, pCommonOpts); case kCloudInstance_Reset: setCurrentSubcommand(HELP_SCOPE_CLOUD_INSTANCE_RESET); return resetCloudInstance(a, GetState.iNext, pCommonOpts); case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } return errorNoSubcommand(); } static RTEXITCODE createCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--object-name", 'o', RTGETOPT_REQ_STRING }, { "--bucket-name", 'b', RTGETOPT_REQ_STRING }, { "--compartment-id", 'c', RTGETOPT_REQ_STRING }, { "--instance-id", 'i', RTGETOPT_REQ_STRING }, { "--display-name", 'd', RTGETOPT_REQ_STRING }, { "--launch-mode", 'm', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strCompartmentId; Utf8Str strInstanceId; Utf8Str strDisplayName; Utf8Str strBucketName; Utf8Str strObjectName; com::SafeArray parameters; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'c': strCompartmentId=ValueUnion.psz; Bstr(Utf8Str("compartment-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'i': strInstanceId=ValueUnion.psz; Bstr(Utf8Str("instance-id=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'd': strDisplayName=ValueUnion.psz; Bstr(Utf8Str("display-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'o': strObjectName=ValueUnion.psz; Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'b': strBucketName=ValueUnion.psz; Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'm': strBucketName=ValueUnion.psz; Bstr(Utf8Str("launch-mode=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strInstanceId.isNotEmpty() && strObjectName.isNotEmpty()) return errorArgument(Cloud::tr("Conflicting parameters: --instance-id and --object-name can't be used together. Choose one.")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); if (strInstanceId.isNotEmpty()) RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the instance \'%s\'...\n"), strDisplayName.c_str(), strInstanceId.c_str()); else RTPrintf(Cloud::tr("Creating cloud image with name \'%s\' from the object \'%s\' in the bucket \'%s\'...\n"), strDisplayName.c_str(), strObjectName.c_str(), strBucketName.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, CreateImage(ComSafeArrayAsInParam(parameters), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Creating cloud image failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud image was created successfully\n")); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE exportCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "--bucket-name", 'b', RTGETOPT_REQ_STRING }, { "--object-name", 'o', RTGETOPT_REQ_STRING }, { "--display-name", 'd', RTGETOPT_REQ_STRING }, { "--launch-mode", 'm', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strImageId; /* XXX: this is vbox "image", i.e. medium */ Utf8Str strBucketName; Utf8Str strObjectName; Utf8Str strDisplayName; Utf8Str strLaunchMode; com::SafeArray parameters; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'b': /* --bucket-name */ { if (strBucketName.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --bucket-name")); strBucketName = ValueUnion.psz; if (strBucketName.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --bucket-name")); break; } case 'o': /* --object-name */ { if (strObjectName.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --object-name")); strObjectName = ValueUnion.psz; if (strObjectName.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --object-name")); break; } case 'i': /* --id */ { if (strImageId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strImageId = ValueUnion.psz; if (strImageId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'd': /* --display-name */ { if (strDisplayName.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --display-name")); strDisplayName = ValueUnion.psz; if (strDisplayName.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --display-name")); break; } case 'm': /* --launch-mode */ { if (strLaunchMode.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --launch-mode")); strLaunchMode = ValueUnion.psz; if (strLaunchMode.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --launch-mode")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strImageId.isNotEmpty()) BstrFmt("image-id=%s", strImageId.c_str()).detachTo(parameters.appendedRaw()); else return errorArgument(Cloud::tr("Missing parameter: --id")); if (strBucketName.isNotEmpty()) BstrFmt("bucket-name=%s", strBucketName.c_str()).detachTo(parameters.appendedRaw()); else return errorArgument(Cloud::tr("Missing parameter: --bucket-name")); if (strObjectName.isNotEmpty()) BstrFmt("object-name=%s", strObjectName.c_str()).detachTo(parameters.appendedRaw()); if (strDisplayName.isNotEmpty()) BstrFmt("display-name=%s", strDisplayName.c_str()).detachTo(parameters.appendedRaw()); if (strLaunchMode.isNotEmpty()) BstrFmt("launch-mode=%s", strLaunchMode.c_str()).detachTo(parameters.appendedRaw()); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); if (strObjectName.isNotEmpty()) RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with name \'%s\'...\n"), strImageId.c_str(), strObjectName.c_str()); else RTPrintf(Cloud::tr("Exporting image \'%s\' to the Cloud with default name\n"), strImageId.c_str()); ComPtr pVirtualBox = a->virtualBox; SafeIfaceArray aImageList; CHECK_ERROR2_RET(hrc, pVirtualBox, COMGETTER(HardDisks)(ComSafeArrayAsOutParam(aImageList)), RTEXITCODE_FAILURE); ComPtr pImage; size_t cImages = aImageList.size(); bool fFound = false; for (size_t i = 0; i < cImages; ++i) { pImage = aImageList[i]; Bstr bstrImageId; hrc = pImage->COMGETTER(Id)(bstrImageId.asOutParam()); if (FAILED(hrc)) continue; com::Guid imageId(bstrImageId); if (!imageId.isValid() || imageId.isZero()) continue; if (!strImageId.compare(imageId.toString())) { fFound = true; RTPrintf(Cloud::tr("Image %s was found\n"), strImageId.c_str()); break; } } if (!fFound) { RTPrintf(Cloud::tr("Process of exporting the image to the Cloud was interrupted. The image wasn't found.\n")); return RTEXITCODE_FAILURE; } ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, ExportImage(pImage, ComSafeArrayAsInParam(parameters), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Export the image to the Cloud failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Export the image to the Cloud was successfull\n")); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE importCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "--bucket-name", 'b', RTGETOPT_REQ_STRING }, { "--object-name", 'o', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strImageId; Utf8Str strCompartmentId; Utf8Str strBucketName; Utf8Str strObjectName; Utf8Str strDisplayName; com::SafeArray parameters; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': strImageId=ValueUnion.psz; break; case 'b': strBucketName=ValueUnion.psz; Bstr(Utf8Str("bucket-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'o': strObjectName=ValueUnion.psz; Bstr(Utf8Str("object-name=").append(ValueUnion.psz)).detachTo(parameters.appendedRaw()); break; case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComPtr pVirtualBox = a->virtualBox; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Creating an object \'%s\' from the cloud image \'%s\'...\n"), strObjectName.c_str(), strImageId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, ImportImage(Bstr(strImageId).raw(), ComSafeArrayAsInParam(parameters), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Cloud image import failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) { RTPrintf(Cloud::tr("Cloud image was imported successfully. Find the downloaded object with the name %s " "in the system temp folder (find the possible environment variables like TEMP, TMP and etc.)\n"), strObjectName.c_str()); } return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE showCloudImageInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strImageId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': strImageId = ValueUnion.psz; break; case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Getting information about the cloud image with id \'%s\'...\n"), strImageId.c_str()); ComPtr infoArray; com::SafeArray pStrInfoArray; ComPtr pProgress; RTPrintf(Cloud::tr("Reply is in the form \'image property\' = \'value\'\n")); CHECK_ERROR2_RET(hrc, oCloudClient, GetImageInfo(Bstr(strImageId).raw(), infoArray.asOutParam(), pProgress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(pProgress); CHECK_PROGRESS_ERROR_RET(pProgress, (Cloud::tr("Getting information about the cloud image failed")), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, infoArray, COMGETTER(Values)(ComSafeArrayAsOutParam(pStrInfoArray)), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("General information about the image:\n")); size_t cParamNames = pStrInfoArray.size(); for (size_t k = 0; k < cParamNames; k++) { Utf8Str data(pStrInfoArray[k]); RTPrintf("\t%s\n", data.c_str()); } return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE updateCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { RT_NOREF(a); RT_NOREF(iFirst); RT_NOREF(pCommonOpts); return RTEXITCODE_SUCCESS; } static RTEXITCODE deleteCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--id", 'i', RTGETOPT_REQ_STRING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } Utf8Str strImageId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'i': { if (strImageId.isNotEmpty()) return errorArgument(Cloud::tr("Duplicate parameter: --id")); strImageId = ValueUnion.psz; if (strImageId.isEmpty()) return errorArgument(Cloud::tr("Empty parameter: --id")); break; } case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; if (strImageId.isEmpty()) return errorArgument(Cloud::tr("Missing parameter: --id")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Deleting cloud image with id %s...\n"), strImageId.c_str()); ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, DeleteImage(Bstr(strImageId).raw(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Deleting cloud image failed")), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud image was deleted successfully\n")); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE handleCloudImage(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { enum { kCloudImageIota = 1000, kCloudImage_Create, kCloudImage_Delete, kCloudImage_Export, kCloudImage_Import, kCloudImage_Info, kCloudImage_Update, }; static const RTGETOPTDEF s_aOptions[] = { { "create", kCloudImage_Create, RTGETOPT_REQ_NOTHING }, { "delete", kCloudImage_Delete, RTGETOPT_REQ_NOTHING }, { "export", kCloudImage_Export, RTGETOPT_REQ_NOTHING }, { "import", kCloudImage_Import, RTGETOPT_REQ_NOTHING }, { "info", kCloudImage_Info, RTGETOPT_REQ_NOTHING }, { "update", kCloudImage_Update, RTGETOPT_REQ_NOTHING }, { "help", 'h', RTGETOPT_REQ_NOTHING }, { "-?", 'h', RTGETOPT_REQ_NOTHING }, { "-help", 'h', RTGETOPT_REQ_NOTHING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, }; if (a->argc == iFirst) { RTPrintf(Cloud::tr("Empty command parameter list, show help.\n")); printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; } RTGETOPTSTATE GetState; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); int c; RTGETOPTUNION ValueUnion; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { /* Sub-commands: */ case kCloudImage_Create: setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_CREATE); return createCloudImage(a, GetState.iNext, pCommonOpts); case kCloudImage_Export: setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_EXPORT); return exportCloudImage(a, GetState.iNext, pCommonOpts); case kCloudImage_Import: setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_IMPORT); return importCloudImage(a, GetState.iNext, pCommonOpts); case kCloudImage_Info: setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_INFO); return showCloudImageInfo(a, GetState.iNext, pCommonOpts); case kCloudImage_Update: // setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_UPDATE); return updateCloudImage(a, GetState.iNext, pCommonOpts); case kCloudImage_Delete: setCurrentSubcommand(HELP_SCOPE_CLOUD_IMAGE_DELETE); return deleteCloudImage(a, GetState.iNext, pCommonOpts); case 'h': printHelp(g_pStdOut); return RTEXITCODE_SUCCESS; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } return errorNoSubcommand(); } #ifdef VBOX_WITH_CLOUD_NET struct CloudNetworkOptions { BOOL fEnable; BOOL fDisable; Bstr strNetworkId; Bstr strNetworkName; }; typedef struct CloudNetworkOptions CLOUDNETOPT; typedef CLOUDNETOPT *PCLOUDNETOPT; static RTEXITCODE createUpdateCloudNetworkCommon(ComPtr cloudNetwork, CLOUDNETOPT& options, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; Bstr strProvider = pCommonOpts->provider.pszProviderName; Bstr strProfile = pCommonOpts->profile.pszProfileName; if (options.fEnable) { CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(TRUE), RTEXITCODE_FAILURE); } if (options.fDisable) { CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Enabled)(FALSE), RTEXITCODE_FAILURE); } if (options.strNetworkId.isNotEmpty()) { CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(NetworkId)(options.strNetworkId.raw()), RTEXITCODE_FAILURE); } if (strProvider.isNotEmpty()) { CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Provider)(strProvider.raw()), RTEXITCODE_FAILURE); } if (strProfile.isNotEmpty()) { CHECK_ERROR2_RET(hrc, cloudNetwork, COMSETTER(Profile)(strProfile.raw()), RTEXITCODE_FAILURE); } return RTEXITCODE_SUCCESS; } static RTEXITCODE createCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; /* Required parameters, the rest is handled in update */ static const RTGETOPTDEF s_aOptions[] = { { "--disable", 'd', RTGETOPT_REQ_NOTHING }, { "--enable", 'e', RTGETOPT_REQ_NOTHING }, { "--network-id", 'i', RTGETOPT_REQ_STRING }, { "--name", 'n', RTGETOPT_REQ_STRING }, }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); CLOUDNETOPT options; options.fEnable = FALSE; options.fDisable = FALSE; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'd': options.fDisable = TRUE; break; case 'e': options.fEnable = TRUE; break; case 'i': options.strNetworkId=ValueUnion.psz; break; case 'n': options.strNetworkName=ValueUnion.psz; break; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } if (options.strNetworkName.isEmpty()) return errorArgument(Cloud::tr("Missing --name parameter")); if (options.strNetworkId.isEmpty()) return errorArgument(Cloud::tr("Missing --network-id parameter")); ComPtr pVirtualBox = a->virtualBox; ComPtr cloudNetwork; CHECK_ERROR2_RET(hrc, pVirtualBox, CreateCloudNetwork(options.strNetworkName.raw(), cloudNetwork.asOutParam()), RTEXITCODE_FAILURE); /* Fill out the created network */ RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts); if (RT_SUCCESS(rc)) RTPrintf(Cloud::tr("Cloud network was created successfully\n")); return rc; } static RTEXITCODE showCloudNetworkInfo(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { RT_NOREF(pCommonOpts); HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--name", 'n', RTGETOPT_REQ_STRING }, }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); Bstr strNetworkName; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'n': strNetworkName=ValueUnion.psz; break; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } if (strNetworkName.isEmpty()) return errorArgument(Cloud::tr("Missing --name parameter")); ComPtr pVirtualBox = a->virtualBox; ComPtr cloudNetwork; CHECK_ERROR2_RET(hrc, pVirtualBox, FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()), RTEXITCODE_FAILURE); RTPrintf(Cloud::tr("Name: %ls\n"), strNetworkName.raw()); BOOL fEnabled = FALSE; cloudNetwork->COMGETTER(Enabled)(&fEnabled); RTPrintf(Cloud::tr("State: %s\n"), fEnabled ? Cloud::tr("Enabled") : Cloud::tr("Disabled")); Bstr Provider; cloudNetwork->COMGETTER(Provider)(Provider.asOutParam()); RTPrintf(Cloud::tr("CloudProvider: %ls\n"), Provider.raw()); Bstr Profile; cloudNetwork->COMGETTER(Profile)(Profile.asOutParam()); RTPrintf(Cloud::tr("CloudProfile: %ls\n"), Profile.raw()); Bstr NetworkId; cloudNetwork->COMGETTER(NetworkId)(NetworkId.asOutParam()); RTPrintf(Cloud::tr("CloudNetworkId: %ls\n"), NetworkId.raw()); Bstr netName = BstrFmt("cloud-%ls", strNetworkName.raw()); RTPrintf(Cloud::tr("VBoxNetworkName: %ls\n\n"), netName.raw()); return RTEXITCODE_SUCCESS; } static RTEXITCODE updateCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--disable", 'd', RTGETOPT_REQ_NOTHING }, { "--enable", 'e', RTGETOPT_REQ_NOTHING }, { "--network-id", 'i', RTGETOPT_REQ_STRING }, { "--name", 'n', RTGETOPT_REQ_STRING }, }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); CLOUDNETOPT options; options.fEnable = FALSE; options.fDisable = FALSE; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'd': options.fDisable = TRUE; break; case 'e': options.fEnable = TRUE; break; case 'i': options.strNetworkId=ValueUnion.psz; break; case 'n': options.strNetworkName=ValueUnion.psz; break; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } if (options.strNetworkName.isEmpty()) return errorArgument(Cloud::tr("Missing --name parameter")); ComPtr pVirtualBox = a->virtualBox; ComPtr cloudNetwork; CHECK_ERROR2_RET(hrc, pVirtualBox, FindCloudNetworkByName(options.strNetworkName.raw(), cloudNetwork.asOutParam()), RTEXITCODE_FAILURE); RTEXITCODE rc = createUpdateCloudNetworkCommon(cloudNetwork, options, pCommonOpts); if (RT_SUCCESS(rc)) RTPrintf(Cloud::tr("Cloud network %ls was updated successfully\n"), options.strNetworkName.raw()); return rc; } static RTEXITCODE deleteCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { RT_NOREF(pCommonOpts); HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--name", 'n', RTGETOPT_REQ_STRING }, }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); Bstr strNetworkName; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'n': strNetworkName=ValueUnion.psz; break; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } if (strNetworkName.isEmpty()) return errorArgument(Cloud::tr("Missing --name parameter")); ComPtr pVirtualBox = a->virtualBox; ComPtr cloudNetwork; CHECK_ERROR2_RET(hrc, pVirtualBox, FindCloudNetworkByName(strNetworkName.raw(), cloudNetwork.asOutParam()), RTEXITCODE_FAILURE); CHECK_ERROR2_RET(hrc, pVirtualBox, RemoveCloudNetwork(cloudNetwork), RTEXITCODE_FAILURE); if (SUCCEEDED(hrc)) RTPrintf(Cloud::tr("Cloud network %ls was deleted successfully\n"), strNetworkName.raw()); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE setupCloudNetworkEnv(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { RT_NOREF(pCommonOpts); HRESULT hrc = S_OK; static const RTGETOPTDEF s_aOptions[] = { { "--gateway-os-name", 'n', RTGETOPT_REQ_STRING }, { "--gateway-os-version", 'v', RTGETOPT_REQ_STRING }, { "--gateway-shape", 's', RTGETOPT_REQ_STRING }, { "--tunnel-network-name", 't', RTGETOPT_REQ_STRING }, { "--tunnel-network-range", 'r', RTGETOPT_REQ_STRING }, { "--compartment-id", 'c', RTGETOPT_REQ_STRING } }; RTGETOPTSTATE GetState; RTGETOPTUNION ValueUnion; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); Bstr strGatewayOsName; Bstr strGatewayOsVersion; Bstr strGatewayShape; Bstr strTunnelNetworkName; Bstr strTunnelNetworkRange; Bstr strCompartmentId; int c; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'n': strGatewayOsName=ValueUnion.psz; break; case 'v': strGatewayOsVersion=ValueUnion.psz; break; case 's': strGatewayShape=ValueUnion.psz; break; case 't': strTunnelNetworkName=ValueUnion.psz; break; case 'r': strTunnelNetworkRange=ValueUnion.psz; break; case 'c': strCompartmentId=ValueUnion.psz; break; case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } /* Delayed check. It allows us to print help information.*/ hrc = checkAndSetCommonOptions(a, pCommonOpts); if (FAILED(hrc)) return RTEXITCODE_FAILURE; ComPtr pVirtualBox = a->virtualBox; RTPrintf(Cloud::tr("Setting up tunnel network in the cloud...\n")); ComPtr pCloudProfile = pCommonOpts->profile.pCloudProfile; /* Use user-specified profile instead of default one. */ if (strCompartmentId.isNotEmpty()) { CHECK_ERROR2_RET(hrc, pCloudProfile, SetProperty(Bstr("compartment").raw(), Bstr(strCompartmentId).raw()), RTEXITCODE_FAILURE); } ComObjPtr oCloudClient; CHECK_ERROR2_RET(hrc, pCloudProfile, CreateCloudClient(oCloudClient.asOutParam()), RTEXITCODE_FAILURE); ComPtr cloudNetworkEnv; ComPtr progress; CHECK_ERROR2_RET(hrc, oCloudClient, SetupCloudNetworkEnvironment(strTunnelNetworkName.raw(), strTunnelNetworkRange.raw(), strGatewayOsName.raw(), strGatewayOsVersion.raw(), strGatewayShape.raw(), cloudNetworkEnv.asOutParam(), progress.asOutParam()), RTEXITCODE_FAILURE); hrc = showProgress(progress); CHECK_PROGRESS_ERROR_RET(progress, (Cloud::tr("Setting up cloud network environment failed")), RTEXITCODE_FAILURE); Bstr tunnelNetworkId; hrc = cloudNetworkEnv->COMGETTER(TunnelNetworkId)(tunnelNetworkId.asOutParam()); RTPrintf(Cloud::tr("Cloud network environment was set up successfully. Tunnel network id is: %ls\n"), tunnelNetworkId.raw()); return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; } static RTEXITCODE handleCloudNetwork(HandlerArg *a, int iFirst, PCLOUDCOMMONOPT pCommonOpts) { enum { kCloudNetworkIota = 1000, kCloudNetwork_Create, kCloudNetwork_Delete, kCloudNetwork_Info, kCloudNetwork_Setup, kCloudNetwork_Update, }; static const RTGETOPTDEF s_aOptions[] = { { "create", kCloudNetwork_Create, RTGETOPT_REQ_NOTHING }, { "delete", kCloudNetwork_Delete, RTGETOPT_REQ_NOTHING }, { "info", kCloudNetwork_Info, RTGETOPT_REQ_NOTHING }, { "setup", kCloudNetwork_Setup, RTGETOPT_REQ_NOTHING }, { "update", kCloudNetwork_Update, RTGETOPT_REQ_NOTHING }, }; if (a->argc < 1) return errorNoSubcommand(); RTGETOPTSTATE GetState; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), iFirst, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); int c; RTGETOPTUNION ValueUnion; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { /* Sub-commands: */ case kCloudNetwork_Create: return createCloudNetwork(a, GetState.iNext, pCommonOpts); case kCloudNetwork_Info: return showCloudNetworkInfo(a, GetState.iNext, pCommonOpts); case kCloudNetwork_Update: return updateCloudNetwork(a, GetState.iNext, pCommonOpts); case kCloudNetwork_Delete: return deleteCloudNetwork(a, GetState.iNext, pCommonOpts); case kCloudNetwork_Setup: return setupCloudNetworkEnv(a, GetState.iNext, pCommonOpts); case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } return errorNoSubcommand(); } #endif /* VBOX_WITH_CLOUD_NET */ RTEXITCODE handleCloud(HandlerArg *a) { enum { kCloudIota = 1000, kCloud_Image, kCloud_Instance, kCloud_List, kCloud_Machine, kCloud_Network, kCloud_Object, kCloud_ShowVMInfo, kCloud_Volume, }; static const RTGETOPTDEF s_aOptions[] = { /* common options */ { "--provider", 'v', RTGETOPT_REQ_STRING }, { "--profile", 'f', RTGETOPT_REQ_STRING }, { "image", kCloud_Image, RTGETOPT_REQ_NOTHING }, { "instance", kCloud_Instance, RTGETOPT_REQ_NOTHING }, { "list", kCloud_List, RTGETOPT_REQ_NOTHING }, { "machine", kCloud_Machine, RTGETOPT_REQ_NOTHING }, { "network", kCloud_Network, RTGETOPT_REQ_NOTHING }, { "object", kCloud_Object, RTGETOPT_REQ_NOTHING }, { "showvminfo", kCloud_ShowVMInfo, RTGETOPT_REQ_NOTHING }, { "volume", kCloud_Volume, RTGETOPT_REQ_NOTHING }, }; if (a->argc < 1) return errorNoSubcommand(); RTGETOPTSTATE GetState; int vrc = RTGetOptInit(&GetState, a->argc, a->argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, 0); AssertRCReturn(vrc, RTEXITCODE_FAILURE); CLOUDCOMMONOPT commonOpts = { {NULL, NULL}, {NULL, NULL} }; int c; RTGETOPTUNION ValueUnion; while ((c = RTGetOpt(&GetState, &ValueUnion)) != 0) { switch (c) { case 'v': // --provider commonOpts.provider.pszProviderName = ValueUnion.psz; break; case 'f': // --profile commonOpts.profile.pszProfileName = ValueUnion.psz; break; /* Sub-commands: */ case kCloud_List: return handleCloudLists(a, GetState.iNext, &commonOpts); case kCloud_Image: return handleCloudImage(a, GetState.iNext, &commonOpts); case kCloud_Instance: return handleCloudInstance(a, GetState.iNext, &commonOpts); #ifdef VBOX_WITH_CLOUD_NET case kCloud_Network: return handleCloudNetwork(a, GetState.iNext, &commonOpts); #endif /* VBOX_WITH_CLOUD_NET */ /* "cloud machine ..." handling is in VBoxManageCloudMachine.cpp */ case kCloud_Machine: return handleCloudMachine(a, GetState.iNext, commonOpts.provider.pszProviderName, commonOpts.profile.pszProfileName); /* ... including aliases that mimic the local vm commands */ case kCloud_ShowVMInfo: return handleCloudShowVMInfo(a, GetState.iNext, commonOpts.provider.pszProviderName, commonOpts.profile.pszProfileName); case VINF_GETOPT_NOT_OPTION: return errorUnknownSubcommand(ValueUnion.psz); default: return errorGetOpt(c, &ValueUnion); } } return errorNoSubcommand(); }