mirror of https://github.com/BOINC/boinc.git
- VBOX: If VirtualBox reports an error snag both the hypervisor system
log as well as the VM execution log. Maybe the hypervisor log will tell us what is up with the virtual floppy device. - VBOX: Don't retry commands that are expected to fail in normal use cases. It slows down getting the VM up and running. - VBOX: After starting the VM, use a timed loop waiting for the initial VM state change instead of just waiting for 5 seconds. Older machines can take longer than 5 seconds to switch from poweroff to starting. If we hit the main poll loop in that state the wrapper thinks we have crashed. - VBOX: Strip carriage returns from all the vboxmanage output on Windows. samples/vboxwrapper/ vbox.cpp, .h vboxwrapper.cpp svn path=/trunk/boinc/; revision=24967
This commit is contained in:
parent
f056c12866
commit
945267b14e
|
@ -26,3 +26,21 @@ David 2 Jan 2012
|
||||||
index.php
|
index.php
|
||||||
user/
|
user/
|
||||||
sandbox.php
|
sandbox.php
|
||||||
|
|
||||||
|
Rom 2 Jan 2012
|
||||||
|
- VBOX: If VirtualBox reports an error snag both the hypervisor system
|
||||||
|
log as well as the VM execution log. Maybe the hypervisor log
|
||||||
|
will tell us what is up with the virtual floppy device.
|
||||||
|
- VBOX: Don't retry commands that are expected to fail in normal use
|
||||||
|
cases. It slows down getting the VM up and running.
|
||||||
|
- VBOX: After starting the VM, use a timed loop waiting for the initial
|
||||||
|
VM state change instead of just waiting for 5 seconds. Older
|
||||||
|
machines can take longer than 5 seconds to switch from poweroff
|
||||||
|
to starting. If we hit the main poll loop in that state the wrapper
|
||||||
|
thinks we have crashed.
|
||||||
|
- VBOX: Strip carriage returns from all the vboxmanage output on
|
||||||
|
Windows.
|
||||||
|
|
||||||
|
samples/vboxwrapper/
|
||||||
|
vbox.cpp, .h
|
||||||
|
vboxwrapper.cpp
|
||||||
|
|
|
@ -83,6 +83,7 @@ VBOX_VM::~VBOX_VM() {
|
||||||
|
|
||||||
int VBOX_VM::run() {
|
int VBOX_VM::run() {
|
||||||
int retval;
|
int retval;
|
||||||
|
double timeout;
|
||||||
|
|
||||||
retval = initialize();
|
retval = initialize();
|
||||||
if (retval) return retval;
|
if (retval) return retval;
|
||||||
|
@ -106,8 +107,16 @@ int VBOX_VM::run() {
|
||||||
retval = start();
|
retval = start();
|
||||||
if (retval) return retval;
|
if (retval) return retval;
|
||||||
|
|
||||||
// Give time enough for external processes to begin the VM boot process
|
// Wait for up to 5 minutes for the VM to switch states. An older system
|
||||||
boinc_sleep(1.0);
|
// under load can take a while. Since the poll function can wait for up
|
||||||
|
// to a minute to execute a command we need to make this time based instead
|
||||||
|
// of interation based.
|
||||||
|
timeout = dtime() + 300;
|
||||||
|
do {
|
||||||
|
poll(false);
|
||||||
|
if (online) break;
|
||||||
|
boinc_sleep(1.0);
|
||||||
|
} while (timeout <= dtime());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -122,14 +131,14 @@ void VBOX_VM::cleanup() {
|
||||||
|
|
||||||
// If there are errors we can recover from, process them here.
|
// If there are errors we can recover from, process them here.
|
||||||
//
|
//
|
||||||
int VBOX_VM::vbm_popen(string& arguments, string& output, const char* item, bool log_error) {
|
int VBOX_VM::vbm_popen(string& arguments, string& output, const char* item, bool log_error, bool retry_failures) {
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int retry_count = 0;
|
int retry_count = 0;
|
||||||
string retry_notes;
|
string retry_notes;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
retval = vbm_popen_raw(arguments, output, item);
|
retval = vbm_popen_raw(arguments, output);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
|
|
||||||
// VirtualBox designed the concept of sessions to prevent multiple applications using
|
// VirtualBox designed the concept of sessions to prevent multiple applications using
|
||||||
|
@ -157,12 +166,24 @@ int VBOX_VM::vbm_popen(string& arguments, string& output, const char* item, bool
|
||||||
// Timeout?
|
// Timeout?
|
||||||
if (retry_count >= 6) break;
|
if (retry_count >= 6) break;
|
||||||
|
|
||||||
|
// Retry?
|
||||||
|
if (!retry_failures) break;
|
||||||
|
|
||||||
retry_count++;
|
retry_count++;
|
||||||
boinc_sleep(5.0);
|
boinc_sleep(5.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (retval);
|
while (retval);
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Remove \r from the log spew
|
||||||
|
for (string::iterator iter = output.begin(); iter != output.end(); ++iter) {
|
||||||
|
if (*iter == '\r') {
|
||||||
|
output.erase(iter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Add all relivent notes to the output string and log errors
|
// Add all relivent notes to the output string and log errors
|
||||||
//
|
//
|
||||||
if (retval && log_error) {
|
if (retval && log_error) {
|
||||||
|
@ -186,7 +207,7 @@ int VBOX_VM::vbm_popen(string& arguments, string& output, const char* item, bool
|
||||||
|
|
||||||
// Execute the vbox manage application and copy the output to the buffer.
|
// Execute the vbox manage application and copy the output to the buffer.
|
||||||
//
|
//
|
||||||
int VBOX_VM::vbm_popen_raw(string& arguments, string& output, const char* item) {
|
int VBOX_VM::vbm_popen_raw(string& arguments, string& output) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
string command;
|
string command;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
@ -240,7 +261,17 @@ int VBOX_VM::vbm_popen_raw(string& arguments, string& output, const char* item)
|
||||||
si.hStdInput = NULL;
|
si.hStdInput = NULL;
|
||||||
|
|
||||||
// Execute command
|
// Execute command
|
||||||
if (!CreateProcess(NULL, (LPTSTR)command.c_str(), NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
|
if (!CreateProcess(
|
||||||
|
NULL,
|
||||||
|
(LPTSTR)command.c_str(),
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
TRUE,
|
||||||
|
CREATE_NO_WINDOW, NULL,
|
||||||
|
NULL,
|
||||||
|
&si,
|
||||||
|
&pi
|
||||||
|
)) {
|
||||||
fprintf(
|
fprintf(
|
||||||
stderr,
|
stderr,
|
||||||
"%s CreateProcess failed! (%d).\n",
|
"%s CreateProcess failed! (%d).\n",
|
||||||
|
@ -350,7 +381,7 @@ bool VBOX_VM::is_registered() {
|
||||||
command = "showvminfo \"" + vm_name + "\" ";
|
command = "showvminfo \"" + vm_name + "\" ";
|
||||||
command += "--machinereadable ";
|
command += "--machinereadable ";
|
||||||
|
|
||||||
if (vbm_popen(command, output, "registration", false) == 0) {
|
if (vbm_popen(command, output, "registration", false, false) == 0) {
|
||||||
if (output.find("VBOX_E_OBJECT_NOT_FOUND") == string::npos) {
|
if (output.find("VBOX_E_OBJECT_NOT_FOUND") == string::npos) {
|
||||||
// Error message not found in text
|
// Error message not found in text
|
||||||
return true;
|
return true;
|
||||||
|
@ -368,7 +399,7 @@ bool VBOX_VM::is_hdd_registered() {
|
||||||
|
|
||||||
command = "showhdinfo \"" + virtual_machine_root_dir + "/" + image_filename + "\" ";
|
command = "showhdinfo \"" + virtual_machine_root_dir + "/" + image_filename + "\" ";
|
||||||
|
|
||||||
if (vbm_popen(command, output, "hdd registration", false) == 0) {
|
if (vbm_popen(command, output, "hdd registration", false, false) == 0) {
|
||||||
if ((output.find("VBOX_E_FILE_ERROR") == string::npos) && (output.find("VBOX_E_OBJECT_NOT_FOUND") == string::npos)) {
|
if ((output.find("VBOX_E_FILE_ERROR") == string::npos) && (output.find("VBOX_E_OBJECT_NOT_FOUND") == string::npos)) {
|
||||||
// Error message not found in text
|
// Error message not found in text
|
||||||
return true;
|
return true;
|
||||||
|
@ -377,7 +408,7 @@ bool VBOX_VM::is_hdd_registered() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VBOX_VM::poll() {
|
void VBOX_VM::poll(bool log_state) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
string command;
|
string command;
|
||||||
string output;
|
string output;
|
||||||
|
@ -388,7 +419,7 @@ void VBOX_VM::poll() {
|
||||||
command = "showvminfo \"" + vm_name + "\" ";
|
command = "showvminfo \"" + vm_name + "\" ";
|
||||||
command += "--machinereadable ";
|
command += "--machinereadable ";
|
||||||
|
|
||||||
if (vbm_popen(command, output, "VM state", false) == 0) {
|
if (vbm_popen(command, output, "VM state", false, false) == 0) {
|
||||||
vmstate_start = output.find("VMState=\"");
|
vmstate_start = output.find("VMState=\"");
|
||||||
if (vmstate_start != string::npos) {
|
if (vmstate_start != string::npos) {
|
||||||
vmstate_start += 9;
|
vmstate_start += 9;
|
||||||
|
@ -423,12 +454,14 @@ void VBOX_VM::poll() {
|
||||||
crashed = true;
|
crashed = true;
|
||||||
} else {
|
} else {
|
||||||
online = false;
|
online = false;
|
||||||
fprintf(
|
if (log_state) {
|
||||||
stderr,
|
fprintf(
|
||||||
"%s Virtual machine is no longer is a running state. It is in '%s'.\n",
|
stderr,
|
||||||
boinc_msg_prefix(buf, sizeof(buf)),
|
"%s Virtual machine is no longer is a running state. It is in '%s'.\n",
|
||||||
vmstate.c_str()
|
boinc_msg_prefix(buf, sizeof(buf)),
|
||||||
);
|
vmstate.c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1246,6 +1279,36 @@ int VBOX_VM::get_network_bytes_sent(double& sent) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VBOX_VM::get_system_log(string& log) {
|
||||||
|
string virtualbox_user_home;
|
||||||
|
string virtualbox_system_log;
|
||||||
|
int retval = 0;
|
||||||
|
|
||||||
|
// Where is VirtualBox storing its configuration files?
|
||||||
|
virtualbox_user_home = getenv("VBOX_USER_HOME");
|
||||||
|
if (virtualbox_user_home.empty()) {
|
||||||
|
// If the override environment variable isn't specified then
|
||||||
|
// it is based of the current users HOME directory.
|
||||||
|
#ifdef _WIN32
|
||||||
|
virtualbox_user_home = getenv("USERPROFILE");
|
||||||
|
#else
|
||||||
|
virtualbox_user_home = getenv("HOME");
|
||||||
|
#endif
|
||||||
|
virtualbox_user_home += "/.VirtualBox";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate and read log file
|
||||||
|
virtualbox_system_log = virtualbox_user_home + "/VBoxSVC.log";
|
||||||
|
if (boinc_file_exists(virtualbox_system_log.c_str())) {
|
||||||
|
// Keep only the last 16k if it is larger than that.
|
||||||
|
retval = read_file_string(virtualbox_system_log.c_str(), log, 16384, true);
|
||||||
|
} else {
|
||||||
|
retval = ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int VBOX_VM::get_vm_log(string& log) {
|
int VBOX_VM::get_vm_log(string& log) {
|
||||||
string command;
|
string command;
|
||||||
string output;
|
string output;
|
||||||
|
@ -1257,16 +1320,13 @@ int VBOX_VM::get_vm_log(string& log) {
|
||||||
retval = vbm_popen(command, output, "get vm log");
|
retval = vbm_popen(command, output, "get vm log");
|
||||||
if (retval) return retval;
|
if (retval) return retval;
|
||||||
|
|
||||||
#ifdef _WIN32
|
// Keep only the last 16k if it is larger than that.
|
||||||
// Remove \r from the log spew
|
size_t size = output.size();
|
||||||
for (string::iterator iter = output.begin(); iter != output.end(); ++iter) {
|
if (size > 16384) {
|
||||||
if (*iter == '\r') {
|
log = output.substr(size - 16384, size);
|
||||||
output.erase(iter);
|
} else {
|
||||||
}
|
log = output;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
log = output;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ struct VBOX_VM {
|
||||||
int pause();
|
int pause();
|
||||||
int resume();
|
int resume();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void poll();
|
void poll(bool log_state = true);
|
||||||
bool is_running();
|
bool is_running();
|
||||||
bool is_paused();
|
bool is_paused();
|
||||||
|
|
||||||
|
@ -94,6 +94,7 @@ struct VBOX_VM {
|
||||||
int get_process_id(int& process_id);
|
int get_process_id(int& process_id);
|
||||||
int get_network_bytes_sent(double& sent);
|
int get_network_bytes_sent(double& sent);
|
||||||
int get_network_bytes_received(double& received);
|
int get_network_bytes_received(double& received);
|
||||||
|
int get_system_log(std::string& log);
|
||||||
int get_vm_log(std::string& log);
|
int get_vm_log(std::string& log);
|
||||||
int read_floppy(std::string& data);
|
int read_floppy(std::string& data);
|
||||||
int write_floppy(std::string& data);
|
int write_floppy(std::string& data);
|
||||||
|
@ -103,10 +104,10 @@ struct VBOX_VM {
|
||||||
static int get_install_directory(std::string& dir);
|
static int get_install_directory(std::string& dir);
|
||||||
static int get_slot_directory(std::string& dir);
|
static int get_slot_directory(std::string& dir);
|
||||||
static int vbm_popen(
|
static int vbm_popen(
|
||||||
std::string& command, std::string& output, const char* item, bool log_error = true
|
std::string& command, std::string& output, const char* item, bool log_error = true, bool retry_failures = true
|
||||||
);
|
);
|
||||||
static int vbm_popen_raw(
|
static int vbm_popen_raw(
|
||||||
std::string& command, std::string& output, const char* item
|
std::string& command, std::string& output
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -220,6 +220,7 @@ int main(int argc, char** argv) {
|
||||||
int vm_pid=0;
|
int vm_pid=0;
|
||||||
int vm_max_cpus=0;
|
int vm_max_cpus=0;
|
||||||
std::string vm_log;
|
std::string vm_log;
|
||||||
|
std::string system_log;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
memset(&boinc_options, 0, sizeof(boinc_options));
|
memset(&boinc_options, 0, sizeof(boinc_options));
|
||||||
|
@ -384,6 +385,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
if (!vm.online) {
|
if (!vm.online) {
|
||||||
if (vm.crashed || (elapsed_time < vm.job_duration)) {
|
if (vm.crashed || (elapsed_time < vm.job_duration)) {
|
||||||
|
vm.get_system_log(system_log);
|
||||||
vm.get_vm_log(vm_log);
|
vm.get_vm_log(vm_log);
|
||||||
}
|
}
|
||||||
vm.cleanup();
|
vm.cleanup();
|
||||||
|
@ -440,11 +442,15 @@ int main(int argc, char** argv) {
|
||||||
stderr,
|
stderr,
|
||||||
"%s NOTE: This could be like a blue-screen event in Windows, the rest of the information in this file\n"
|
"%s NOTE: This could be like a blue-screen event in Windows, the rest of the information in this file\n"
|
||||||
"%s is diagnostic information generated by the hypervisor.\n"
|
"%s is diagnostic information generated by the hypervisor.\n"
|
||||||
|
"%s Hypervisor System Log:\n\n"
|
||||||
|
"%s\n"
|
||||||
"%s VM Execution Log:\n\n"
|
"%s VM Execution Log:\n\n"
|
||||||
"%s\n",
|
"%s\n",
|
||||||
boinc_msg_prefix(buf, sizeof(buf)),
|
boinc_msg_prefix(buf, sizeof(buf)),
|
||||||
boinc_msg_prefix(buf, sizeof(buf)),
|
boinc_msg_prefix(buf, sizeof(buf)),
|
||||||
boinc_msg_prefix(buf, sizeof(buf)),
|
boinc_msg_prefix(buf, sizeof(buf)),
|
||||||
|
system_log.c_str(),
|
||||||
|
boinc_msg_prefix(buf, sizeof(buf)),
|
||||||
vm_log.c_str()
|
vm_log.c_str()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue