Skip to content

Commit a5ca655

Browse files
authored
Merge pull request #4843 from computezrmle/vboxwrapper_improvements
Vboxwrapper improvements
2 parents 6589356 + 5b44ed2 commit a5ca655

File tree

2 files changed

+145
-40
lines changed

2 files changed

+145
-40
lines changed

samples/vboxwrapper/vbox_common.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,13 +1186,25 @@ int VBOX_BASE::vbm_popen(string& command, string& output, const char* item, bool
11861186
// Error Code: VBOX_E_INVALID_OBJECT_STATE (0x80bb0007)
11871187
//
11881188
if (VBOX_E_INVALID_OBJECT_STATE == (unsigned int)retval) {
1189-
if (retry_notes.find("Another VirtualBox management") == string::npos) {
1190-
retry_notes += "Another VirtualBox management application has locked the session for\n";
1191-
retry_notes += "this VM. BOINC cannot properly monitor this VM\n";
1192-
retry_notes += "and so this job will be aborted.\n\n";
1193-
}
1194-
if (retry_count) {
1195-
sleep_interval *= 2;
1189+
if ((output.find("Cannot attach medium") != string::npos) &&
1190+
(output.find("the media type") != string::npos) &&
1191+
(output.find("MultiAttach") != string::npos) &&
1192+
(output.find("can only be attached to machines that were created with VirtualBox 4.0 or later") != string::npos)) {
1193+
// VirtualBox occasionally writes the 'MultiAttach' attribute to
1194+
// the disk entry in VirtualBox.xml although this is not allowed there.
1195+
// As a result all VMs trying to connect that disk fail.
1196+
// Report the error back immediately without a retry.
1197+
//
1198+
break;
1199+
} else {
1200+
if (retry_notes.find("Another VirtualBox management") == string::npos) {
1201+
retry_notes += "Another VirtualBox management application has locked the session for\n";
1202+
retry_notes += "this VM. BOINC cannot properly monitor this VM\n";
1203+
retry_notes += "and so this job will be aborted.\n\n";
1204+
}
1205+
if (retry_count) {
1206+
sleep_interval *= 2;
1207+
}
11961208
}
11971209
}
11981210

@@ -1482,4 +1494,3 @@ VBOX_VM::VBOX_VM() {
14821494

14831495
VBOX_VM::~VBOX_VM() {
14841496
}
1485-

samples/vboxwrapper/vbox_vboxmanage.cpp

Lines changed: 126 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
1717

1818
#ifdef _WIN32
19-
#include <algorithm>
2019
#include "boinc_win.h"
2120
#include "win_util.h"
2221
#else
22+
#include <algorithm>
2323
#include <sys/wait.h>
2424
#include <sys/types.h>
2525
#include <sys/stat.h>
@@ -543,53 +543,147 @@ namespace vboxmanage {
543543
// See: https://www.virtualbox.org/manual/ch05.html#hdimagewrites
544544
// https://www.virtualbox.org/manual/ch05.html#diffimages
545545
// the vdi file downloaded to the projects dir becomes the parent (read only)
546-
// "--setuid" must not be used
547546
// each task gets it's own differencing image (writable)
548547
// differencing images are written to the VM's snapshot folder
549548
//
550549
string medium_file = aid.project_dir;
551550
medium_file += "/" + multiattach_vdi_file;
552551

553-
#ifdef _WIN32
554-
replace(medium_file.begin(), medium_file.end(), '\\', '/');
555-
#endif
556-
557552
vboxlog_msg("Adding virtual disk drive to VM. (%s)", multiattach_vdi_file.c_str());
558-
command = "list hdds";
559553

560-
retval = vbm_popen(command, output, "check if parent hdd is registered", false, false);
561-
if (retval) return retval;
554+
int retry_count = 0;
555+
bool log_error = false;
556+
bool vbox_bug_mitigation = false;
562557

563-
#ifdef _WIN32
564-
replace(output.begin(), output.end(), '\\', '/');
565-
#endif
558+
do {
559+
string set_new_uuid = "";
560+
string type_line = "";
561+
size_t type_start;
562+
size_t type_end;
563+
564+
command = "showhdinfo \"" + medium_file + "\" ";
565+
566+
retval = vbm_popen(command, output, "check if parent hdd is registered", false);
567+
if (retval) {
568+
// showhdinfo implicitly registers unregistered hdds.
569+
// Hence, this has to be handled first.
570+
//
571+
if ((output.rfind("VBoxManage: error:", 0) != string::npos) &&
572+
(output.find("Cannot register the hard disk") != string::npos) &&
573+
(output.find("because a hard disk") != string::npos) &&
574+
(output.find("with UUID") != string::npos) &&
575+
(output.find("already exists") != string::npos)) {
576+
// May happen if the project admin didn't set a new UUID.
577+
set_new_uuid = "--setuuid \"\" ";
578+
579+
vboxlog_msg("Disk UUID conflicts with an already existing disk.\nWill set a new UUID for '%s'.\nThe project admin should be informed to do this server side running:\nvboxmanage clonemedium <inputfile> <outputfile>\n",
580+
multiattach_vdi_file.c_str()
581+
);
582+
} else {
583+
// other errors
584+
vboxlog_msg("Error in check if parent hdd is registered.\nCommand:\n%s\nOutput:\n%s",
585+
command.c_str(),
586+
output.c_str()
587+
);
588+
return retval;
589+
}
590+
}
566591

567-
if (output.find(medium_file) == string::npos) {
568-
// parent hdd is not registered
569-
// vdi files can't be registered and set to multiattach mode within 1 step.
570-
// They must first be attached to a VM in normal mode, then detached from the VM
592+
// Output from showhdinfo should look a little like this:
593+
// UUID: c119bcaf-636c-41f6-86c9-384739a31339
594+
// Parent UUID: base
595+
// State: created
596+
// Type: multiattach
597+
// Location: C:\Users\romw\VirtualBox VMs\test2\test2.vdi
598+
// Storage format: VDI
599+
// Format variant: dynamic default
600+
// Capacity: 2048 MBytes
601+
// Size on disk: 2 MBytes
602+
// Encryption: disabled
603+
// Property: AllocationBlockSize=1048576
604+
// Child UUIDs: dcb0daa5-3bf9-47cb-bfff-c65e74484615
571605
//
572-
command = command_fix_part;
573-
command += "--medium \"" + medium_file + "\" ";
574606

575-
retval = vbm_popen(command, output, "register parent hdd", false, false);
576-
if (retval) return retval;
607+
type_line = output;
608+
transform(type_line.cbegin(), type_line.cend(),
609+
type_line.begin(), [](unsigned char c) { return tolower(c); });
610+
type_start = type_line.find("\ntype: ") + 1;
611+
type_end = type_line.find("\n", type_start) - type_start;
612+
type_line = type_line.substr(type_start, type_end);
577613

578-
command = command_fix_part;
579-
command += "--medium none ";
614+
if (type_line.find("multiattach") == string::npos) {
615+
// Parent hdd is not (yet) of type multiattach.
616+
// Vdi files can't be registered and set to multiattach mode within 1 step.
617+
// They must first be attached to a VM in normal mode, then detached from the VM
580618

581-
retval = vbm_popen(command, output, "detach parent vdi", false, false);
582-
if (retval) return retval;
583-
// the vdi file is now registered and ready to be attached in multiattach mode
584-
//
585-
}
619+
command = command_fix_part;
620+
command += set_new_uuid + "--medium \"" + medium_file + "\" ";
586621

587-
command = command_fix_part;
588-
command += "--mtype multiattach ";
589-
command += "--medium \"" + medium_file + "\" ";
622+
retval = vbm_popen(command, output, "register parent vdi");
623+
if (retval) return retval;
590624

591-
retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)");
592-
if (retval) return retval;
625+
command = command_fix_part;
626+
command += "--medium none ";
627+
628+
retval = vbm_popen(command, output, "detach parent vdi");
629+
if (retval) return retval;
630+
// the vdi file is now registered and ready to be attached in multiattach mode
631+
//
632+
}
633+
634+
do {
635+
command = command_fix_part;
636+
command += "--mtype multiattach ";
637+
command += "--medium \"" + medium_file + "\" ";
638+
639+
retval = vbm_popen(command, output, "storage attach (fixed disk - multiattach mode)", log_error);
640+
if (retval) {
641+
// VirtualBox occasionally writes the 'MultiAttach' attribute to
642+
// the disk entry in VirtualBox.xml although this is not allowed there.
643+
// As a result all VMs trying to connect that disk fail.
644+
// The error needs to be cleaned here to allow vboxwrapper to
645+
// succeed even with uncorrected VirtualBox versions.
646+
//
647+
// After cleanup attaching the disk should be tried again.
648+
649+
if ((retry_count < 1) &&
650+
(output.find("Cannot attach medium") != string::npos) &&
651+
(output.find("the media type") != string::npos) &&
652+
(output.find("MultiAttach") != string::npos) &&
653+
(output.find("can only be attached to machines that were created with VirtualBox 4.0 or later") != string::npos)) {
654+
// try to deregister the medium from the global media store
655+
command = "closemedium \"" + medium_file + "\" ";
656+
657+
retval = vbm_popen(command, output, "deregister parent vdi");
658+
if (retval) return retval;
659+
660+
retry_count++;
661+
log_error = true;
662+
boinc_sleep(1.0);
663+
break;
664+
}
665+
666+
if (retry_count >= 1) {
667+
// in case of other errors or if retry also failed
668+
vboxlog_msg("Error in storage attach (fixed disk - multiattach mode).\nCommand:\n%s\nOutput:\n%s",
669+
command.c_str(),
670+
output.c_str()
671+
);
672+
return retval;
673+
}
674+
675+
retry_count++;
676+
log_error = true;
677+
boinc_sleep(1.0);
678+
679+
} else {
680+
vbox_bug_mitigation = true;
681+
break;
682+
}
683+
}
684+
while (true);
685+
}
686+
while (!vbox_bug_mitigation);
593687
}
594688

595689

0 commit comments

Comments
 (0)