diff --git a/samples/vboxwrapper/vbox_vboxmanage.cpp b/samples/vboxwrapper/vbox_vboxmanage.cpp index dbf99abc32a..1580b1f43db 100644 --- a/samples/vboxwrapper/vbox_vboxmanage.cpp +++ b/samples/vboxwrapper/vbox_vboxmanage.cpp @@ -16,6 +16,7 @@ // along with BOINC. If not, see . #ifdef _WIN32 +#include #include "boinc_win.h" #include "win_util.h" #else @@ -500,18 +501,80 @@ namespace vboxmanage { // Adding virtual hard drive to VM // - vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str()); + string command_fix_part; + + command_fix_part = "storageattach \"" + vm_name + "\" "; + command_fix_part += "--storagectl \"Hard Disk Controller\" "; + command_fix_part += "--port 0 "; + command_fix_part += "--device 0 "; + command_fix_part += "--type hdd "; + + if (!multiattach_vdi_file.size()) { + // the traditional method: + // copy the vdi file from the projects dir to the slots dir and rename it vm_image.vdi + // each copy must get a new (random) UUID + // + vboxlog_msg("Adding virtual disk drive to VM. (%s)", image_filename.c_str()); + command = command_fix_part; + command += "--setuuid \"\" "; + command += "--medium \"" + virtual_machine_slot_directory + "/" + image_filename + "\" "; - command = "storageattach \"" + vm_name + "\" "; - command += "--storagectl \"Hard Disk Controller\" "; - command += "--port 0 "; - command += "--device 0 "; - command += "--type hdd "; - command += "--setuuid \"\" "; - command += "--medium \"" + virtual_machine_slot_directory + "/" + image_filename + "\" "; + retval = vbm_popen(command, output, "storage attach (fixed disk)"); + if (retval) return retval; + } else { + // Use MultiAttach mode and differencing images + // See: https://www.virtualbox.org/manual/ch05.html#hdimagewrites + // https://www.virtualbox.org/manual/ch05.html#diffimages + // the vdi file downloaded to the projects dir becomes the parent (read only) + // "--setuid" must not be used + // each task gets it's own differencing image (writable) + // differencing images are written to the VM's snapshot folder + // + string medium_file = aid.project_dir; + medium_file += "/" + multiattach_vdi_file; + +#ifdef _WIN32 + replace(medium_file.begin(), medium_file.end(), '\\', '/'); +#endif + + vboxlog_msg("Adding virtual disk drive to VM. (%s)", multiattach_vdi_file.c_str()); + command = "list hdds"; + + retval = vbm_popen(command, output, "check if parent hdd is registered", false, false); + if (retval) return retval; + +#ifdef _WIN32 + replace(output.begin(), output.end(), '\\', '/'); +#endif + + if (output.find(medium_file) == string::npos) { + // parent hdd is not registered + // vdi files can't be registered and set to multiattach mode within 1 step. + // They must first be attached to a VM in normal mode, then detached from the VM + // + command = command_fix_part; + command += "--medium \"" + medium_file + "\" "; + + retval = vbm_popen(command, output, "register parent hdd", false, false); + if (retval) return retval; + + command = command_fix_part; + command += "--medium none "; + + retval = vbm_popen(command, output, "detach parent vdi", false, false); + if (retval) return retval; + // the vdi file is now registered and ready to be attached in multiattach mode + // + } + + command = command_fix_part; + command += "--mtype multiattach "; + command += "--medium \"" + medium_file + "\" "; + + retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)"); + if (retval) return retval; + } - retval = vbm_popen(command, output, "storage attach (fixed disk)"); - if (retval) return retval; // Add guest additions to the VM // diff --git a/samples/vboxwrapper/vboxjob.cpp b/samples/vboxwrapper/vboxjob.cpp index 73c7e0738f4..c1013aea37c 100644 --- a/samples/vboxwrapper/vboxjob.cpp +++ b/samples/vboxwrapper/vboxjob.cpp @@ -109,6 +109,7 @@ void VBOX_JOB::clear() { heartbeat_filename.clear(); completion_trigger_file.clear(); temporary_exit_trigger_file.clear(); + multiattach_vdi_file.clear(); enable_cern_dataformat = false; enable_shared_directory = false; enable_scratch_directory = false; @@ -170,6 +171,7 @@ int VBOX_JOB::parse() { else if (xp.parse_string("heartbeat_filename", heartbeat_filename)) continue; else if (xp.parse_string("completion_trigger_file", completion_trigger_file)) continue; else if (xp.parse_string("temporary_exit_trigger_file", temporary_exit_trigger_file)) continue; + else if (xp.parse_string("multiattach_vdi_file", multiattach_vdi_file)) continue; else if (xp.parse_bool("enable_cern_dataformat", enable_cern_dataformat)) continue; else if (xp.parse_bool("enable_network", enable_network)) continue; else if (xp.parse_bool("network_bridged_mode", network_bridged_mode)) continue; diff --git a/samples/vboxwrapper/vboxjob.h b/samples/vboxwrapper/vboxjob.h index 3a4627b4971..d189685f803 100644 --- a/samples/vboxwrapper/vboxjob.h +++ b/samples/vboxwrapper/vboxjob.h @@ -166,6 +166,10 @@ class VBOX_JOB { // File can optionally contain is_notice bool (second line) // and stderr text (subsequent lines). // Addresses a problem where VM doesn't shut down properly + + std::string multiattach_vdi_file; + // Name of the vdi file (without path) to be attached in multiattach mode. + // The file is expected to be in the project's base directory. }; #endif