Changeset 93312 in vbox for trunk/src/VBox/Main/src-client
- Timestamp:
- Jan 18, 2022 1:15:12 PM (3 years ago)
- Location:
- trunk/src/VBox/Main/src-client
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-client/CloudGateway.cpp
r93115 r93312 37 37 #include <iprt/vfs.h> 38 38 #include <iprt/uri.h> 39 #ifdef DEBUG 40 #include <iprt/file.h> 41 #include <VBox/com/utils.h> 42 #endif 43 44 #ifdef VBOX_WITH_LIBSSH 45 /* Prevent inclusion of Winsock2.h */ 46 #define _WINSOCK2API_ 47 #include <libssh/libssh.h> 48 #endif /* VBOX_WITH_LIBSSH */ 49 39 50 40 51 static HRESULT setMacAddress(const Utf8Str& str, RTMAC& mac) … … 49 60 } 50 61 62 51 63 HRESULT GatewayInfo::setCloudMacAddress(const Utf8Str& mac) 52 64 { … … 54 66 } 55 67 68 56 69 HRESULT GatewayInfo::setLocalMacAddress(const Utf8Str& mac) 57 70 { … … 59 72 } 60 73 61 Utf8Str GatewayInfo::getCloudMacAddressWithoutColons() const62 {63 return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",64 mCloudMacAddress.au8[0], mCloudMacAddress.au8[1], mCloudMacAddress.au8[2],65 mCloudMacAddress.au8[3], mCloudMacAddress.au8[4], mCloudMacAddress.au8[5]);66 }67 68 Utf8Str GatewayInfo::getLocalMacAddressWithoutColons() const69 {70 return Utf8StrFmt("%02X%02X%02X%02X%02X%02X",71 mLocalMacAddress.au8[0], mLocalMacAddress.au8[1], mLocalMacAddress.au8[2],72 mLocalMacAddress.au8[3], mLocalMacAddress.au8[4], mLocalMacAddress.au8[5]);73 }74 75 Utf8Str GatewayInfo::getLocalMacAddressWithColons() const76 {77 return Utf8StrFmt("%RTmac", &mLocalMacAddress);78 }79 74 80 75 class CloudError … … 89 84 Utf8Str mText; 90 85 }; 86 91 87 92 88 static void handleErrors(HRESULT hrc, const char *pszFormat, ...) … … 104 100 } 105 101 102 106 103 class CloudClient 107 104 { … … 110 107 ~CloudClient() {}; 111 108 112 void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway s);113 void stopCloudGateway(const GatewayInfo& gateway s);109 void startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway); 110 void stopCloudGateway(const GatewayInfo& gateway); 114 111 115 112 private: … … 119 116 ComPtr<ICloudClient> mClient; 120 117 }; 118 121 119 122 120 CloudClient::CloudClient(ComPtr<IVirtualBox> virtualBox, const Bstr& strProvider, const Bstr& strProfile) … … 132 130 } 133 131 134 void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateways) 132 133 void CloudClient::startCloudGateway(const ComPtr<ICloudNetwork> &network, GatewayInfo& gateway) 135 134 { 136 135 ComPtr<IProgress> progress; 137 136 ComPtr<ICloudNetworkGatewayInfo> gatewayInfo; 138 HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateway s.mPublicSshKey).raw(),137 HRESULT hrc = mClient->StartCloudNetworkGateway(network, Bstr(gateway.mPublicSshKey).raw(), 139 138 gatewayInfo.asOutParam(), progress.asOutParam()); 140 139 handleErrors(hrc, "Failed to launch compute instance"); … … 145 144 hrc = gatewayInfo->COMGETTER(InstanceId)(instanceId.asOutParam()); 146 145 handleErrors(hrc, "Failed to get launched compute instance id"); 147 gateway s.mGatewayInstanceId = instanceId;146 gateway.mGatewayInstanceId = instanceId; 148 147 149 148 Bstr publicIP; 150 149 hrc = gatewayInfo->COMGETTER(PublicIP)(publicIP.asOutParam()); 151 150 handleErrors(hrc, "Failed to get cloud gateway public IP address"); 152 gateway s.mCloudPublicIp = publicIP;151 gateway.mCloudPublicIp = publicIP; 153 152 154 153 Bstr secondaryPublicIP; 155 154 hrc = gatewayInfo->COMGETTER(SecondaryPublicIP)(secondaryPublicIP.asOutParam()); 156 155 handleErrors(hrc, "Failed to get cloud gateway secondary public IP address"); 157 gateway s.mCloudSecondaryPublicIp = secondaryPublicIP;156 gateway.mCloudSecondaryPublicIp = secondaryPublicIP; 158 157 159 158 Bstr macAddress; 160 159 hrc = gatewayInfo->COMGETTER(MacAddress)(macAddress.asOutParam()); 161 160 handleErrors(hrc, "Failed to get cloud gateway public IP address"); 162 gateways.setCloudMacAddress(macAddress); 163 } 164 165 void CloudClient::stopCloudGateway(const GatewayInfo& gateways) 161 gateway.setCloudMacAddress(macAddress); 162 } 163 164 165 void CloudClient::stopCloudGateway(const GatewayInfo& gateway) 166 166 { 167 167 ComPtr<IProgress> progress; 168 HRESULT hrc = mClient->TerminateInstance(Bstr(gateway s.mGatewayInstanceId).raw(), progress.asOutParam());168 HRESULT hrc = mClient->TerminateInstance(Bstr(gateway.mGatewayInstanceId).raw(), progress.asOutParam()); 169 169 handleErrors(hrc, "Failed to terminate compute instance"); 170 170 #if 0 … … 176 176 177 177 178 static HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways)178 HRESULT startCloudGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateway) 179 179 { 180 180 HRESULT hrc = S_OK; 181 181 182 182 try { 183 hrc = network->COMGETTER(Provider)(gateway s.mCloudProvider.asOutParam());184 hrc = network->COMGETTER(Profile)(gateway s.mCloudProfile.asOutParam());185 CloudClient client(virtualBox, gateway s.mCloudProvider, gateways.mCloudProfile);186 client.startCloudGateway(network, gateway s);183 hrc = network->COMGETTER(Provider)(gateway.mCloudProvider.asOutParam()); 184 hrc = network->COMGETTER(Profile)(gateway.mCloudProfile.asOutParam()); 185 CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile); 186 client.startCloudGateway(network, gateway); 187 187 } 188 188 catch (CloudError e) … … 195 195 196 196 197 static HRESULT attachToLocalNetwork(ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork) 198 { 199 ComPtr<IMachine> sessionMachine; 200 HRESULT hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam()); 201 if (FAILED(hrc)) 202 { 203 LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc)); 204 return hrc; 205 } 206 207 ComPtr<INetworkAdapter> networkAdapter; 208 hrc = sessionMachine->GetNetworkAdapter(1, networkAdapter.asOutParam()); 209 if (FAILED(hrc)) 210 { 211 LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc)); 212 return hrc; 213 } 214 215 BstrFmt network("cloud-%s", aCloudNetwork.c_str()); 216 hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw()); 217 if (FAILED(hrc)) 218 { 219 LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc)); 220 return hrc; 221 } 222 223 hrc = sessionMachine->SaveSettings(); 224 if (FAILED(hrc)) 225 LogRel(("CLOUD-NET: Failed to save 'lgw' settings. hrc=%x\n", hrc)); 226 return hrc; 227 } 228 229 static HRESULT startLocalGateway(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, const com::Utf8Str &aCloudNetwork, GatewayInfo& gateways) 230 { 231 /* 232 * It would be really beneficial if we do not create a local gateway VM each time a target starts. 233 * We probably just need to make sure its configuration matches the one required by the cloud network 234 * attachment and update configuration if necessary. 235 */ 236 Bstr strGatewayVM = BstrFmt("lgw-%ls", gateways.mTargetVM.raw()); 237 ComPtr<IMachine> machine; 238 HRESULT hrc = virtualBox->FindMachine(strGatewayVM.raw(), machine.asOutParam()); 239 if (SUCCEEDED(hrc)) 240 { 241 hrc = machine->LockMachine(aSession, LockType_Write); 242 if (FAILED(hrc)) 243 { 244 LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc)); 245 return hrc; 246 } 247 248 hrc = attachToLocalNetwork(aSession, aCloudNetwork); 249 } 250 else 251 { 252 SafeArray<IN_BSTR> groups; 253 groups.push_back(Bstr("/gateways").mutableRaw()); 254 hrc = virtualBox->CreateMachine(NULL, Bstr(strGatewayVM).raw(), ComSafeArrayAsInParam(groups), Bstr("Ubuntu_64").raw(), Bstr("").raw(), machine.asOutParam()); 255 if (FAILED(hrc)) 256 { 257 LogRel(("CLOUD-NET: Failed to create '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 258 return hrc; 259 } 260 /* Initial configuration */ 261 hrc = machine->ApplyDefaults(NULL); 262 if (FAILED(hrc)) 263 { 264 LogRel(("CLOUD-NET: Failed to apply defaults to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 265 return hrc; 266 } 267 268 /* Add second network adapter */ 269 ComPtr<INetworkAdapter> networkAdapter; 270 hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam()); 271 if (FAILED(hrc)) 272 { 273 LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc)); 274 return hrc; 275 } 276 277 hrc = networkAdapter->COMSETTER(AttachmentType)(NetworkAttachmentType_Internal); 278 if (FAILED(hrc)) 279 { 280 LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc)); 281 return hrc; 282 } 283 284 BstrFmt network("cloud-%s", aCloudNetwork.c_str()); 285 hrc = networkAdapter->COMSETTER(InternalNetwork)(network.raw()); 286 if (FAILED(hrc)) 287 { 288 LogRel(("CLOUD-NET: Failed to set network name for the second network adapter. hrc=%x\n", hrc)); 289 return hrc; 290 } 291 292 hrc = networkAdapter->COMSETTER(PromiscModePolicy)(NetworkAdapterPromiscModePolicy_AllowAll); 293 if (FAILED(hrc)) 294 { 295 LogRel(("CLOUD-NET: Failed to set promiscuous mode policy for the second network adapter. hrc=%x\n", hrc)); 296 return hrc; 297 } 298 299 hrc = networkAdapter->COMSETTER(Enabled)(TRUE); 300 if (FAILED(hrc)) 301 { 302 LogRel(("CLOUD-NET: Failed to enable the second network adapter. hrc=%x\n", hrc)); 303 return hrc; 304 } 305 306 /* No need for audio -- disable it. */ 307 ComPtr<IAudioAdapter> audioAdapter; 308 hrc = machine->GetNetworkAdapter(1, networkAdapter.asOutParam()); 309 if (FAILED(hrc)) 310 { 311 LogRel(("CLOUD-NET: Failed to locate the second network adapter. hrc=%x\n", hrc)); 312 return hrc; 313 } 314 315 hrc = machine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); 316 if (FAILED(hrc)) 317 { 318 LogRel(("CLOUD-NET: Failed to set attachment type for the second network adapter. hrc=%x\n", hrc)); 319 return hrc; 320 } 321 322 hrc = audioAdapter->COMSETTER(Enabled)(FALSE); 323 if (FAILED(hrc)) 324 { 325 LogRel(("CLOUD-NET: Failed to disable the audio adapter. hrc=%x\n", hrc)); 326 return hrc; 327 } 328 329 /** @todo Disable USB? */ 330 331 /* Register the local gateway VM */ 332 hrc = virtualBox->RegisterMachine(machine); 333 if (FAILED(hrc)) 334 { 335 LogRel(("CLOUD-NET: Failed to register '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 336 return hrc; 337 } 338 339 /* 340 * Storage can only be attached to registered VMs which means we need to use session 341 * to lock VM in order to make it mutable again. 342 */ 343 ComPtr<ISystemProperties> systemProperties; 344 ComPtr<IMedium> hd; 345 Bstr defaultMachineFolder; 346 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); 347 if (FAILED(hrc)) 348 { 349 LogRel(("CLOUD-NET: Failed to obtain system properties. hrc=%x\n", hrc)); 350 return hrc; 351 } 352 hrc = systemProperties->COMGETTER(DefaultMachineFolder)(defaultMachineFolder.asOutParam()); 353 if (FAILED(hrc)) 354 { 355 LogRel(("CLOUD-NET: Failed to obtain default machine folder. hrc=%x\n", hrc)); 356 return hrc; 357 } 358 hrc = virtualBox->OpenMedium(BstrFmt("%ls\\gateways\\lgw.vdi", defaultMachineFolder.raw()).raw(), DeviceType_HardDisk, AccessMode_ReadWrite, FALSE, hd.asOutParam()); 359 if (FAILED(hrc)) 360 { 361 LogRel(("CLOUD-NET: Failed to open medium for '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 362 return hrc; 363 } 364 365 hrc = machine->LockMachine(aSession, LockType_Write); 366 if (FAILED(hrc)) 367 { 368 LogRel(("CLOUD-NET: Failed to lock '%ls' for modifications. hrc=%x\n", strGatewayVM.raw(), hrc)); 369 return hrc; 370 } 371 372 ComPtr<IMachine> sessionMachine; 373 hrc = aSession->COMGETTER(Machine)(sessionMachine.asOutParam()); 374 if (FAILED(hrc)) 375 { 376 LogRel(("CLOUD-NET: Failed to obtain a mutable machine. hrc=%x\n", hrc)); 377 return hrc; 378 } 379 380 hrc = sessionMachine->AttachDevice(Bstr("SATA").raw(), 0, 0, DeviceType_HardDisk, hd); 381 if (FAILED(hrc)) 382 { 383 LogRel(("CLOUD-NET: Failed to attach HD to '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 384 return hrc; 385 } 386 387 /* Save settings */ 388 hrc = sessionMachine->SaveSettings(); 389 if (FAILED(hrc)) 390 { 391 LogRel(("CLOUD-NET: Failed to save '%ls' settings. hrc=%x\n", strGatewayVM.raw(), hrc)); 392 return hrc; 393 } 394 } 395 /* Unlock the machine before start, it will be re-locked by LaunchVMProcess */ 396 aSession->UnlockMachine(); 397 398 #ifdef DEBUG 399 #define LGW_FRONTEND "gui" 400 #else 401 #define LGW_FRONTEND "headless" 402 #endif 403 ComPtr<IProgress> progress; 404 hrc = machine->LaunchVMProcess(aSession, Bstr(LGW_FRONTEND).raw(), ComSafeArrayNullInParam(), progress.asOutParam()); 405 if (FAILED(hrc)) 406 { 407 LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 408 return hrc; 409 } 410 411 hrc = progress->WaitForCompletion(-1); 412 if (FAILED(hrc)) 413 LogRel(("CLOUD-NET: Failed to launch '%ls'. hrc=%x\n", strGatewayVM.raw(), hrc)); 414 415 gateways.mGatewayVM = strGatewayVM; 416 417 ComPtr<IEventSource> es; 418 hrc = virtualBox->COMGETTER(EventSource)(es.asOutParam()); 419 ComPtr<IEventListener> listener; 420 hrc = es->CreateListener(listener.asOutParam()); 421 com::SafeArray <VBoxEventType_T> eventTypes(1); 422 eventTypes.push_back(VBoxEventType_OnGuestPropertyChanged); 423 hrc = es->RegisterListener(listener, ComSafeArrayAsInParam(eventTypes), false); 424 425 Bstr publicKey; 426 Bstr aMachStrGuid; 427 machine->COMGETTER(Id)(aMachStrGuid.asOutParam()); 428 Guid aMachGuid(aMachStrGuid); 429 430 uint64_t u64Started = RTTimeMilliTS(); 431 do 432 { 433 ComPtr<IEvent> ev; 434 hrc = es->GetEvent(listener, 1000 /* seconds */, ev.asOutParam()); 435 if (ev) 436 { 437 VBoxEventType_T aType; 438 hrc = ev->COMGETTER(Type)(&aType); 439 if (aType == VBoxEventType_OnGuestPropertyChanged) 440 { 441 ComPtr<IGuestPropertyChangedEvent> gpcev = ev; 442 Assert(gpcev); 443 Bstr aNextStrGuid; 444 gpcev->COMGETTER(MachineId)(aNextStrGuid.asOutParam()); 445 if (aMachGuid != Guid(aNextStrGuid)) 446 continue; 447 Bstr aNextName; 448 gpcev->COMGETTER(Name)(aNextName.asOutParam()); 449 if (aNextName == "/VirtualBox/Gateway/PublicKey") 450 { 451 gpcev->COMGETTER(Value)(publicKey.asOutParam()); 452 LogRel(("CLOUD-NET: Got public key from local gateway '%ls'\n", publicKey.raw())); 453 break; 454 } 455 } 456 457 } 458 } while (RTTimeMilliTS() - u64Started < 300 * 1000); /** @todo reasonable timeout */ 459 460 if (publicKey.isEmpty()) 461 { 462 LogRel(("CLOUD-NET: Failed to get ssh public key from '%ls'\n", strGatewayVM.raw())); 463 return E_FAIL; 464 } 465 466 gateways.mPublicSshKey = publicKey; 467 468 return hrc; 469 } 470 197 #if 0 /* Disabled until proxy support is implemented */ 471 198 static bool getProxyForIpAddr(ComPtr<IVirtualBox> virtualBox, const com::Utf8Str &strIpAddr, Bstr &strProxyType, Bstr &strProxyHost, Bstr &strProxyPort) 472 199 { … … 598 325 #endif /* VBOX_WITH_PROXY_INFO */ 599 326 } 600 601 602 static HRESULT exchangeInfoBetweenGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ISession> aSession, GatewayInfo& gateways) 603 { 604 RT_NOREF(virtualBox); 605 HRESULT hrc = S_OK; 606 do 607 { 608 ComPtr<IConsole> console; 609 hrc = aSession->COMGETTER(Console)(console.asOutParam()); 610 if (FAILED(hrc)) 611 { 612 LogRel(("CLOUD-NET: Failed to obtain console for 'lgw'. hrc=%x\n", hrc)); 613 break; 614 } 615 616 ComPtr<IGuest> guest; 617 hrc = console->COMGETTER(Guest)(guest.asOutParam()); 618 if (FAILED(hrc)) 619 { 620 LogRel(("CLOUD-NET: Failed to obtain guest for 'lgw'. hrc=%x\n", hrc)); 621 break; 622 } 623 624 ComPtr<IGuestSession> guestSession; 625 626 GuestSessionWaitResult_T enmWaitResult = GuestSessionWaitResult_None; 627 for (int cTriesLeft = 6; cTriesLeft > 0; cTriesLeft--) 628 { 629 RTThreadSleep(5000 /* ms */); 630 hrc = guest->CreateSession(Bstr("vbox").raw(), Bstr("vbox").raw(), NULL, Bstr("Cloud Gateway Impersonation").raw(), guestSession.asOutParam()); 631 if (FAILED(hrc)) 632 { 633 LogRel(("CLOUD-NET: Failed to create guest session for 'lgw'%s. hrc=%x\n", cTriesLeft > 1 ? ", will re-try" : "", hrc)); 634 continue; 635 } 636 hrc = guestSession->WaitFor(GuestSessionWaitForFlag_Start, 30 * 1000, &enmWaitResult); 637 if (FAILED(hrc)) 638 { 639 LogRel(("CLOUD-NET: WARNING! Failed to wait in guest session for 'lgw'%s. waitResult=%x hrc=%x\n", 640 cTriesLeft > 1 ? ", will re-try" : "", enmWaitResult, hrc)); 641 guestSession->Close(); 642 guestSession.setNull(); 643 continue; 644 } 645 if (enmWaitResult == GuestSessionWaitResult_Start) 646 break; 647 LogRel(("CLOUD-NET: WARNING! 'lgw' guest session waitResult=%x%s\n", 648 enmWaitResult, cTriesLeft > 1 ? ", will re-try" : "")); 649 guestSession->Close(); 650 guestSession.setNull(); 651 } 652 653 if (FAILED(hrc)) 654 { 655 LogRel(("CLOUD-NET: Failed to start guest session for 'lgw'. waitResult=%x hrc=%x\n", enmWaitResult, hrc)); 656 break; 657 } 658 659 GuestSessionStatus_T enmSessionStatus; 660 hrc = guestSession->COMGETTER(Status)(&enmSessionStatus); 661 if (FAILED(hrc)) 662 { 663 LogRel(("CLOUD-NET: Failed to get guest session status for 'lgw'. hrc=%x\n", hrc)); 664 break; 665 } 666 LogRel(("CLOUD-NET: Session status: %d\n", enmSessionStatus)); 667 668 Bstr strPrimaryProxyType; 669 Bstr strPrimaryProxyHost; 670 Bstr strPrimaryProxyPort; 671 Bstr strSecondaryProxyType; 672 Bstr strSecondaryProxyHost; 673 Bstr strSecondaryProxyPort; 674 675 ComPtr<IGuestProcess> guestProcess; 676 com::SafeArray<IN_BSTR> aArgs; 677 com::SafeArray<IN_BSTR> aEnv; 678 com::SafeArray<ProcessCreateFlag_T> aCreateFlags; 679 com::SafeArray<ProcessWaitForFlag_T> aWaitFlags; 680 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdOut); 681 aCreateFlags.push_back(ProcessCreateFlag_WaitForStdErr); 682 #define GUEST_CMD "/bin/sh" 683 aArgs.push_back(Bstr(GUEST_CMD).mutableRaw()); 684 aArgs.push_back(Bstr("-x").mutableRaw()); 685 aArgs.push_back(Bstr("/home/vbox/local-bridge.sh").mutableRaw()); 686 aArgs.push_back(Bstr(gateways.mCloudPublicIp).mutableRaw()); 687 aArgs.push_back(Bstr(gateways.mCloudSecondaryPublicIp).mutableRaw()); 688 aArgs.push_back(Bstr(gateways.getLocalMacAddressWithColons()).mutableRaw()); 689 if (getProxyForIpAddr(virtualBox, gateways.mCloudPublicIp, strPrimaryProxyType, strPrimaryProxyHost, strPrimaryProxyPort)) 690 { 691 aArgs.push_back(strPrimaryProxyType.mutableRaw()); 692 aArgs.push_back(strPrimaryProxyHost.mutableRaw()); 693 aArgs.push_back(strPrimaryProxyPort.mutableRaw()); 694 if (getProxyForIpAddr(virtualBox, gateways.mCloudSecondaryPublicIp, strSecondaryProxyType, strSecondaryProxyHost, strSecondaryProxyPort)) 695 { 696 aArgs.push_back(strSecondaryProxyType.mutableRaw()); 697 aArgs.push_back(strSecondaryProxyHost.mutableRaw()); 698 aArgs.push_back(strSecondaryProxyPort.mutableRaw()); 699 } 700 } 701 hrc = guestSession->ProcessCreate(Bstr(GUEST_CMD).raw(), 702 ComSafeArrayAsInParam(aArgs), 703 ComSafeArrayAsInParam(aEnv), 704 ComSafeArrayAsInParam(aCreateFlags), 705 180 * 1000 /* ms */, 706 guestProcess.asOutParam()); 707 if (FAILED(hrc)) 708 { 709 LogRel(("CLOUD-NET: Failed to create guest process '/bin/sh' for 'lgw'. hrc=%x\n", hrc)); 710 break; 711 } 712 713 ProcessWaitResult_T waitResult; 714 hrc = guestProcess->WaitFor(ProcessWaitForFlag_Start, 10 * 1000 /* ms */, &waitResult); 715 if (FAILED(hrc) || (waitResult != ProcessWaitResult_Start)) 716 { 717 LogRel(("CLOUD-NET: Failed to wait for guest process to start for 'lgw'. waitResult=%x hrc=%x\n", 718 waitResult, hrc)); 719 break; 720 } 721 LogRel(("CLOUD-NET: waitResult=%x\n", waitResult)); 722 723 uint32_t cNotSupported = 0; 724 bool fRead, fDone = false; 725 uint64_t u64Start = RTTimeMilliTS(); 726 do 727 { 728 /** @todo wait for stdout when it becomes supported! */ 729 hrc = guestProcess->WaitFor(ProcessWaitForFlag_Terminate | ProcessWaitForFlag_StdOut, 1000 /* ms */, &waitResult); 730 if (FAILED(hrc)) 731 { 732 LogRel(("CLOUD-NET: Failed to get output from guest process for 'lgw'. waitResult=%x hrc=%x\n", 733 waitResult, hrc)); 734 break; 735 } 736 if (waitResult == ProcessWaitResult_WaitFlagNotSupported) 737 ++cNotSupported; 738 else 739 { 740 if (cNotSupported) 741 { 742 LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported)); 743 cNotSupported = 0; 744 } 745 LogRel(("CLOUD-NET: waitResult=%x\n", waitResult)); 746 } 747 748 fRead = false; 749 switch (waitResult) 750 { 751 case ProcessWaitResult_WaitFlagNotSupported: 752 RTThreadYield(); 753 /* Fall through */ 754 case ProcessWaitResult_StdOut: 755 fRead = true; 756 break; 757 case ProcessWaitResult_Terminate: 758 fDone = true; 759 break; 760 case ProcessWaitResult_Timeout: 761 { 762 ProcessStatus_T enmProcStatus; 763 hrc = guestProcess->COMGETTER(Status)(&enmProcStatus); 764 if (FAILED(hrc)) 765 { 766 LogRel(("CLOUD-NET: Failed to query guest process status for 'lgw'. hrc=%x\n", hrc)); 767 fDone = true; 768 } 769 else 770 { 771 LogRel(("CLOUD-NET: Guest process timeout for 'lgw'. status=%d\n", enmProcStatus)); 772 if ( enmProcStatus == ProcessStatus_TimedOutKilled 773 || enmProcStatus == ProcessStatus_TimedOutAbnormally) 774 fDone = true; 775 } 776 fRead = true; 777 break; 778 } 779 default: 780 LogRel(("CLOUD-NET: Unexpected waitResult=%x\n", waitResult)); 781 break; 782 } 783 784 if (fRead) 785 { 786 SafeArray<BYTE> aStdOutData, aStdErrData; 787 hrc = guestProcess->Read(1 /* StdOut */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdOutData)); 788 if (FAILED(hrc)) 789 { 790 LogRel(("CLOUD-NET: Failed to read stdout from guest process for 'lgw'. hrc=%x\n", hrc)); 791 break; 792 } 793 hrc = guestProcess->Read(2 /* StdErr */, _64K, 60 * 1000 /* ms */, ComSafeArrayAsOutParam(aStdErrData)); 794 if (FAILED(hrc)) 795 { 796 LogRel(("CLOUD-NET: Failed to read stderr from guest process for 'lgw'. hrc=%x\n", hrc)); 797 break; 798 } 799 800 size_t cbStdOutData = aStdOutData.size(); 801 size_t cbStdErrData = aStdErrData.size(); 802 if (cbStdOutData == 0 && cbStdErrData == 0) 803 { 804 //LogRel(("CLOUD-NET: Empty output from guest process for 'lgw'. hrc=%x\n", hrc)); 805 continue; 806 } 807 808 if (cNotSupported) 809 { 810 LogRel(("CLOUD-NET: waitResult=9, repeated %u times\n", cNotSupported)); 811 cNotSupported = 0; 812 } 813 if (cbStdOutData) 814 LogRel(("CLOUD-NET: Got stdout from 'lgw':\n%.*s", aStdOutData.size(), aStdOutData.raw())); 815 if (cbStdErrData) 816 LogRel(("CLOUD-NET: Got stderr from 'lgw':\n%.*s", aStdErrData.size(), aStdErrData.raw())); 817 } 818 } 819 while (!fDone && RTTimeMilliTS() - u64Start < 180 * 1000 /* ms */); 820 821 } while (false); 822 823 return hrc; 824 } 825 826 827 HRESULT destroyLocalGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways) 828 { 829 if (gateways.mGatewayVM.isEmpty()) 327 #endif 328 329 HRESULT stopCloudGateway(ComPtr<IVirtualBox> virtualBox, GatewayInfo& gateway) 330 { 331 if (gateway.mGatewayInstanceId.isEmpty()) 830 332 return S_OK; 831 333 832 LogRel(("CLOUD-NET: Shutting down local gateway '%s'...\n", gateways.mGatewayVM.c_str())); 833 834 ComPtr<IMachine> localGateway; 835 HRESULT hrc = virtualBox->FindMachine(Bstr(gateways.mGatewayVM).raw(), localGateway.asOutParam()); 836 if (FAILED(hrc)) 837 { 838 LogRel(("CLOUD-NET: Failed to locate '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 839 return hrc; 840 } 841 842 MachineState_T tmp; 843 hrc = localGateway->COMGETTER(State)(&tmp); 844 if (tmp == MachineState_Running) 845 { 846 /* If the gateway VM is running we need to stop it */ 847 ComPtr<ISession> session; 848 hrc = session.createInprocObject(CLSID_Session); 849 if (FAILED(hrc)) 850 { 851 LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc)); 852 return hrc; 853 } 854 855 hrc = localGateway->LockMachine(session, LockType_Shared); 856 if (FAILED(hrc)) 857 { 858 LogRel(("CLOUD-NET: Failed to lock '%s' for control. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 859 return hrc; 860 } 861 862 ComPtr<IConsole> console; 863 hrc = session->COMGETTER(Console)(console.asOutParam()); 864 if (FAILED(hrc)) 865 { 866 LogRel(("CLOUD-NET: Failed to obtain console for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 867 return hrc; 868 } 869 870 ComPtr<IProgress> progress; 871 console->PowerDown(progress.asOutParam()); /* We assume the gateway disk to be immutable! */ 872 873 #if 0 874 hrc = progress->WaitForCompletion(-1); 875 if (FAILED(hrc)) 876 LogRel(("CLOUD-NET: Failed to stop '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 877 #endif 878 session->UnlockMachine(); 879 } 880 #if 0 881 /* 882 * Unfortunately we cannot unregister a machine we've just powered down and unlocked. 883 * It takes some time for the machine to unlock completely. 884 */ 885 /** @todo Removal of VM should probably be optional in the future. */ 886 SafeIfaceArray<IMedium> media; 887 hrc = pLocalGateway->Unregister(CleanupMode_DetachAllReturnHardDisksOnly, ComSafeArrayAsOutParam(media)); 888 if (FAILED(hrc)) 889 { 890 LogRel(("CLOUD-NET: Failed to unregister '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 891 return hrc; 892 } 893 ComPtr<IProgress> removalProgress; 894 hrc = pLocalGateway->DeleteConfig(ComSafeArrayAsInParam(media), removalProgress.asOutParam()); 895 if (FAILED(hrc)) 896 { 897 LogRel(("CLOUD-NET: Failed to delete machine files for '%s'. hrc=%x\n", gateways.mGatewayVM.c_str(), hrc)); 898 } 899 #endif 900 return hrc; 901 } 902 903 static HRESULT terminateCloudGateway(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways) 904 { 905 if (gateways.mGatewayInstanceId.isEmpty()) 906 return S_OK; 907 908 LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateways.mGatewayInstanceId.c_str())); 334 LogRel(("CLOUD-NET: Terminating cloud gateway instance '%s'...\n", gateway.mGatewayInstanceId.c_str())); 909 335 910 336 HRESULT hrc = S_OK; 911 337 try { 912 CloudClient client(virtualBox, gateways.mCloudProvider, gateways.mCloudProfile); 913 client.stopCloudGateway(gateways); 338 CloudClient client(virtualBox, gateway.mCloudProvider, gateway.mCloudProfile); 339 client.stopCloudGateway(gateway); 340 #if 0 341 # ifdef DEBUG 342 char szKeyPath[RTPATH_MAX]; 343 344 int rc = GetVBoxUserHomeDirectory(szKeyPath, sizeof(szKeyPath), false /* fCreateDir */); 345 if (RT_SUCCESS(rc)) 346 { 347 rc = RTPathAppend(szKeyPath, sizeof(szKeyPath), "gateway-key.pem"); 348 AssertRCReturn(rc, rc); 349 rc = RTFileDelete(szKeyPath); 350 if (RT_FAILURE(rc)) 351 LogRel(("WARNING! Failed to delete private key %s with rc=%d\n", szKeyPath, rc)); 352 } 353 else 354 LogRel(("WARNING! Failed to get VirtualBox user home directory with '%Rrc'\n", rc)); 355 # endif /* DEBUG */ 356 #endif 914 357 } 915 358 catch (CloudError e) … … 918 361 LogRel(("CLOUD-NET: Failed to terminate cloud gateway instance (rc=%x).\n", hrc)); 919 362 } 363 gateway.mGatewayInstanceId.setNull(); 920 364 return hrc; 921 365 } 922 366 923 HRESULT startGateways(ComPtr<IVirtualBox> virtualBox, ComPtr<ICloudNetwork> network, GatewayInfo& gateways) 924 { 925 /* Session used to launch and control the local gateway VM */ 926 ComPtr<ISession> session; 927 Bstr strNetwork; 928 HRESULT hrc = session.createInprocObject(CLSID_Session); 929 if (FAILED(hrc)) 930 LogRel(("CLOUD-NET: Failed to create a session. hrc=%x\n", hrc)); 367 368 HRESULT generateKeys(GatewayInfo& gateway) 369 { 370 #ifndef VBOX_WITH_LIBSSH 371 RT_NOREF(gateway); 372 return E_NOTIMPL; 373 #else /* VBOX_WITH_LIBSSH */ 374 ssh_key single_use_key; 375 int rc = ssh_pki_generate(SSH_KEYTYPE_RSA, 2048, &single_use_key); 376 if (rc != SSH_OK) 377 { 378 LogRel(("Failed to generate a key pair. rc = %d\n", rc)); 379 return E_FAIL; 380 } 381 382 char *pstrKey = NULL; 383 rc = ssh_pki_export_privkey_base64(single_use_key, NULL, NULL, NULL, &pstrKey); 384 if (rc != SSH_OK) 385 { 386 LogRel(("Failed to export private key. rc = %d\n", rc)); 387 return E_FAIL; 388 } 389 gateway.mPrivateSshKey = pstrKey; 390 #if 0 391 # ifdef DEBUG 392 char szConfigPath[RTPATH_MAX]; 393 394 rc = GetVBoxUserHomeDirectory(szConfigPath, sizeof(szConfigPath), false /* fCreateDir */); 395 if (RT_SUCCESS(rc)) 396 { 397 rc = RTPathAppend(szConfigPath, sizeof(szConfigPath), "gateway-key.pem"); 398 AssertRCReturn(rc, rc); 399 rc = ssh_pki_export_privkey_file(single_use_key, NULL, NULL, NULL, szConfigPath); 400 if (rc != SSH_OK) 401 { 402 LogRel(("Failed to export private key to %s with rc=%d\n", szConfigPath, rc)); 403 return E_FAIL; 404 } 405 # ifndef RT_OS_WINDOWS 406 rc = RTPathSetMode(szConfigPath, RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); /* Satisfy ssh client */ 407 AssertRCReturn(rc, rc); 408 # endif 409 } 931 410 else 932 hrc = network->COMGETTER(NetworkName)(strNetwork.asOutParam()); 933 if (SUCCEEDED(hrc)) 934 hrc = startLocalGateway(virtualBox, session, strNetwork, gateways); 935 if (SUCCEEDED(hrc)) 936 hrc = startCloudGateway(virtualBox, network, gateways); 937 if (SUCCEEDED(hrc)) 938 hrc = exchangeInfoBetweenGateways(virtualBox, session, gateways); 939 940 session->UnlockMachine(); 941 /** @todo Destroy gateways if unsuccessful (cleanup) */ 942 943 return hrc; 944 } 945 946 HRESULT stopGateways(ComPtr<IVirtualBox> virtualBox, const GatewayInfo& gateways) 947 { 948 HRESULT hrc = destroyLocalGateway(virtualBox, gateways); 949 AssertComRC(hrc); 950 hrc = terminateCloudGateway(virtualBox, gateways); 951 AssertComRC(hrc); 952 return hrc; 953 } 411 { 412 LogRel(("Failed to get VirtualBox user home directory with '%Rrc'\n", rc)); 413 return E_FAIL; 414 } 415 # endif /* DEBUG */ 416 #endif 417 ssh_string_free_char(pstrKey); 418 pstrKey = NULL; 419 rc = ssh_pki_export_pubkey_base64(single_use_key, &pstrKey); 420 if (rc != SSH_OK) 421 { 422 LogRel(("Failed to export public key. rc = %d\n", rc)); 423 return E_FAIL; 424 } 425 gateway.mPublicSshKey = Utf8StrFmt("ssh-rsa %s single-use-key", pstrKey); 426 ssh_string_free_char(pstrKey); 427 ssh_key_free(single_use_key); 428 429 return S_OK; 430 #endif /* VBOX_WITH_LIBSSH */ 431 } -
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r93115 r93312 657 657 } 658 658 659 #ifdef VBOX_WITH_CLOUD_NET660 {661 ComPtr<IVirtualBox> pVirtualBox;662 HRESULT rc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());663 AssertComRC(rc);664 if (SUCCEEDED(rc) && !pVirtualBox.isNull())665 stopGateways(pVirtualBox, mGateways);666 }667 #endif /* VBOX_WITH_CLOUD_NET */668 659 LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed())); 669 660 if (mVmListener) … … 8946 8937 break; 8947 8938 8939 #ifdef VBOX_WITH_CLOUD_NET 8940 /* 8941 * We stop cloud gateway here because we may have failed to connect to it, 8942 * configure it, or establish a tunnel. We definitely do not want an orphaned 8943 * instance running in the cloud. 8944 */ 8945 { 8946 ComPtr<IVirtualBox> pVirtualBox; 8947 HRESULT rc = that->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam()); 8948 AssertComRC(rc); 8949 if (SUCCEEDED(rc) && !pVirtualBox.isNull()) 8950 stopCloudGateway(pVirtualBox, that->mGateway); 8951 } 8952 #endif /* VBOX_WITH_CLOUD_NET */ 8948 8953 /* Terminate host interface networking. If pUVM is NULL, we've been 8949 8954 * manually called from powerUpThread() either before calling -
trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
r93115 r93312 335 335 { 336 336 InsertConfigString(pNode, pcszName, Utf8Str(rBstrValue)); 337 } 338 339 /** 340 * Helper that calls CFGMR3InsertPassword and throws an RTCError if that 341 * fails (Utf8Str variant). 342 * @param pNode See CFGMR3InsertPasswordN. 343 * @param pcszName See CFGMR3InsertPasswordN. 344 * @param rStrValue The string value. 345 */ 346 static void InsertConfigPassword(PCFGMNODE pNode, 347 const char *pcszName, 348 const Utf8Str &rStrValue) 349 { 350 int vrc = CFGMR3InsertPasswordN(pNode, 351 pcszName, 352 rStrValue.c_str(), 353 rStrValue.length()); 354 if (RT_FAILURE(vrc)) 355 throw ConfigError("CFGMR3InsertPasswordLengthKnown", vrc, pcszName); 337 356 } 338 357 … … 2758 2777 if (eAttachmentType == NetworkAttachmentType_Cloud) 2759 2778 { 2760 mGateway s.setLocalMacAddress(macAddrUtf8);2779 mGateway.setLocalMacAddress(macAddrUtf8); 2761 2780 /* We'll insert cloud MAC later, when it becomes known. */ 2762 2781 } … … 6381 6400 ComPtr<ICloudNetwork> network; 6382 6401 hrc = aNetworkAdapter->COMGETTER(CloudNetwork)(bstr.asOutParam()); H(); 6383 hrc = pMachine->COMGETTER(Name)(mGateway s.mTargetVM.asOutParam()); H();6402 hrc = pMachine->COMGETTER(Name)(mGateway.mTargetVM.asOutParam()); H(); 6384 6403 hrc = virtualBox->FindCloudNetworkByName(bstr.raw(), network.asOutParam()); H(); 6385 hrc = startGateways(virtualBox, network, mGateways); H(); 6386 InsertConfigBytes(pDevCfg, "MAC", &mGateways.mCloudMacAddress, sizeof(mGateways.mCloudMacAddress)); 6404 hrc = generateKeys(mGateway); 6405 if (FAILED(hrc)) 6406 { 6407 if (hrc == E_NOTIMPL) 6408 return VMSetError(VMR3GetVM(mpUVM), VERR_NOT_FOUND, RT_SRC_POS, 6409 N_("Failed to generate a key pair due to missing libssh\n" 6410 "To fix this problem, either build VirtualBox with libssh " 6411 "support or switch to another network attachment type in " 6412 "the VM settings.\n")); 6413 else 6414 return VMSetError(VMR3GetVM(mpUVM), VERR_INTERNAL_ERROR, RT_SRC_POS, 6415 N_("Failed to generate a key pair due to libssh error!\n")); 6416 } 6417 hrc = startCloudGateway(virtualBox, network, mGateway); H(); 6418 InsertConfigBytes(pDevCfg, "MAC", &mGateway.mCloudMacAddress, sizeof(mGateway.mCloudMacAddress)); 6387 6419 if (!bstr.isEmpty()) 6388 6420 { 6389 InsertConfigString(pLunL0, "Driver", " IntNet");6421 InsertConfigString(pLunL0, "Driver", "CloudTunnel"); 6390 6422 InsertConfigNode(pLunL0, "Config", &pCfg); 6391 InsertConfigString(pCfg, "Network", BstrFmt("cloud-%ls", bstr.raw())); 6392 InsertConfigInteger(pCfg, "TrunkType", kIntNetTrunkType_WhateverNone); 6393 InsertConfigString(pCfg, "IfPolicyPromisc", pszPromiscuousGuestPolicy); 6423 InsertConfigPassword(pCfg, "SshKey", mGateway.mPrivateSshKey); 6424 InsertConfigString(pCfg, "PrimaryIP", mGateway.mCloudPublicIp); 6425 InsertConfigString(pCfg, "SecondaryIP", mGateway.mCloudSecondaryPublicIp); 6426 InsertConfigBytes(pCfg, "TargetMAC", &mGateway.mLocalMacAddress, sizeof(mGateway.mLocalMacAddress)); 6394 6427 networkName = bstr; 6395 6428 trunkType = Bstr(TRUNKTYPE_WHATEVER);
Note:
See TracChangeset
for help on using the changeset viewer.