diff --git a/checkin_notes b/checkin_notes index 9b30f638cd..ba4bccd80f 100644 --- a/checkin_notes +++ b/checkin_notes @@ -2705,3 +2705,11 @@ David 29 Apr 2011 lib/ gui_rpc_client.cpp + +Rom 29 Apr 2011 + - VBOX: Checkpoint, Re-implement the registering and un-registering of the + vm using the vboxmanage app. + + samples/vboxwrapper/ + vbox.cpp, .h + vm.cpp, .h diff --git a/samples/vboxwrapper/vbox.cpp b/samples/vboxwrapper/vbox.cpp index a5bd304f6a..cd2e871457 100644 --- a/samples/vboxwrapper/vbox.cpp +++ b/samples/vboxwrapper/vbox.cpp @@ -43,6 +43,7 @@ #include "procinfo.h" #include "boinc_api.h" #include "vbox.h" +#include "vm.h" // Execute the vbox manage application and copy the output to the @@ -61,9 +62,8 @@ int virtualbox_vbm_popen(std::string& arguments, std::string& output) { if (fp == NULL){ fprintf( stderr, - "%s vbm_popen popen failed! cmd = '%s', errno = %d\n", + "%s vbm_popen popen failed! errno = %d\n", boinc_msg_prefix(buf, sizeof(buf)), - command.c_str(), errno ); return VBOX_POPEN_ERROR; @@ -84,7 +84,7 @@ int virtualbox_vbm_popen(std::string& arguments, std::string& output) { // Returns the current directory in which the executable resides. // int virtualbox_generate_vm_root_dir( std::string& dir ) { - TCHAR root_dir[256]; + char root_dir[256]; #ifdef _WIN32 _getcwd(root_dir, (sizeof(root_dir)*sizeof(TCHAR))); @@ -127,6 +127,48 @@ int virtualbox_generate_vm_name( std::string& name ) { } +// Generate a deterministic yet unique UUID for a given medium (hard drive, +// cd drive, hard drive image) +// Rules: +// 1. Must be unique +// 2. Must identifity itself as being part of BOINC +// 3. Must be based on the slot directory id +// 4. Must be in the form of a GUID +// 00000000-0000-0000-0000-000000000000 +// +// Form/Meaning +// A B C D E +// 00000000-0000-0000-0000-000000000000 +// +// A = Drive ID +// B = Slot ID +// C = Standalone Flag +// D = Reserved +// E = 'BOINC' ASCII converted to Hex +// +int virtualbox_generate_medium_uuid( int drive_id, std::string& uuid ) { + APP_INIT_DATA aid; + char medium_uuid[256]; + + boinc_get_init_data_p( &aid ); + + sprintf( + medium_uuid, + _T("%08d-%04d-%04d-0000-00424F494E43"), + drive_id, + aid.slot, + boinc_is_standalone() + ); + + uuid = medium_uuid; + + if (!uuid.empty()) { + return 1; + } + return 0; +} + + bool virtualbox_vm_is_registered() { std::string command; std::string output; @@ -140,7 +182,23 @@ bool virtualbox_vm_is_registered() { return true; } } + return false; +} + +bool virtualbox_vm_is_hdd_uuid_registered() { + std::string command; + std::string output; + std::string virtual_hdd_uuid; + + virtualbox_generate_medium_uuid(0, virtual_hdd_uuid); + command = "showhdinfo " + virtual_hdd_uuid; + + if (VBOX_SUCCESS == virtualbox_vbm_popen(command, output)) { + if (output.find("VBOX_E_FILE_ERROR") != std::string::npos) { + return true; + } + } return false; } @@ -173,9 +231,13 @@ int virtualbox_register_vm() { std::string output; std::string virtual_machine_name; std::string virtual_machine_root_dir; + std::string virtual_hdd_uuid; + char buf[256]; + int retval; virtualbox_generate_vm_name(virtual_machine_name); virtualbox_generate_vm_root_dir(virtual_machine_root_dir); + virtualbox_generate_medium_uuid(0, virtual_hdd_uuid); fprintf( stderr, @@ -183,14 +245,247 @@ int virtualbox_register_vm() { boinc_msg_prefix(buf, sizeof(buf)) ); - //command = "startvm " + virtual_machine_name + " --type headless"; - //virtualbox_vbm_popen(command, output); + + // Create and register the VM + // + command = "createvm "; + command += "--name \"" + virtual_machine_name + "\" "; + command += "--basefolder \"" + virtual_machine_root_dir + "\" "; + command += "--settingsfile \"" + virtual_machine_root_dir + "/" + virtual_machine_name + "\" "; + command += "--ostype \"" + vm.vm_os_name + "\" "; + command += "--register"; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error registering virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Tweak the VM from it's default configuration + // + command = "modifyvm \"" + virtual_machine_name + "\" "; + command += "--memory " + vm.vm_memory_size + " "; + command += "--acpi on "; + command += "--ioapic on "; + command += "--boot1 disk "; + command += "--boot2 none "; + command += "--boot3 none "; + command += "--boot4 none "; + command += "--nic1 nat "; + command += "--natdnsproxy1 on "; + command += "--cableconnected1 off "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error modifing virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Add storage controller to VM + // + command = "storagectl \"" + virtual_machine_name + "\" "; + command += "--name \"IDE Controller\" "; + command += "--add ide "; + command += "--controller PIIX4 "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error adding storage controller to virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Adding virtual hard drive to Virtual Box Media Registry + // + command = "openmedium "; + command += "disk \"" + virtual_machine_root_dir + "/" + vm.vm_disk_image_name + "\" "; + command += "--uuid " + virtual_hdd_uuid + " "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error adding virtual disk drive to virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Adding virtual hard drive to VM + // + command = "storageattach \"" + virtual_machine_name + "\" "; + command += "--storagectl \"IDE Controller\" "; + command += "--port 0 "; + command += "--device 0 "; + command += "--type hdd "; + command += "--medium " + virtual_hdd_uuid + " "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error adding virtual disk drive to virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Enable the network adapter if a network connection is required. + // NOTE: Network access should never be allowed if the code running in a + // shared directory or the VM itself is NOT signed. Doing so opens up + // the network behind the firewall to attack. + // + if (vm.enable_network) { + command = "modifyvm \"" + virtual_machine_name + "\" "; + command += "--cableconnected1 on "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error enabling network access for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + } + + + // Enable the shared folder if a shared folder is specified. + // + if (vm.enable_shared_directory) { + command = "sharedfolder add \"" + virtual_machine_name + "\" "; + command += "--name \"" + vm.vm_shared_folder_name + "\" "; + command += "--hostpath \"" + virtual_machine_root_dir + "/" + vm.vm_shared_folder_dir_name + "\" "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error enabling shared directory for virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + } return VBOX_SUCCESS; } int virtualbox_deregister_vm() { + std::string command; + std::string output; + std::string virtual_machine_name; + std::string virtual_machine_root_dir; + std::string virtual_hdd_uuid; + char buf[256]; + int retval; + + virtualbox_generate_vm_name(virtual_machine_name); + virtualbox_generate_vm_root_dir(virtual_machine_root_dir); + virtualbox_generate_medium_uuid(0, virtual_hdd_uuid); + + fprintf( + stderr, + "%s Deregistering virtual machine.\n", + boinc_msg_prefix(buf, sizeof(buf)) + ); + + + // First step in deregistering a VM is to delete its storage controller + // + command = "storagectl \"" + virtual_machine_name + "\" "; + command += "--name \"IDE Controller\" "; + command += "--remove "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error removing storage controller from virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Next delete VM + // + command = "unregistervm \"" + virtual_machine_name + "\" "; + command += "--delete "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error removing virtual machine from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + + + // Lastly delete medium from Virtual Box Media Registry + // + command = "closemedium \"" + virtual_hdd_uuid + "\" "; + + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error removing virtual hdd from virtual box! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + return VBOX_SUCCESS; } @@ -204,10 +499,24 @@ int virtualbox_startvm() { std::string command; std::string output; std::string virtual_machine_name; + char buf[256]; + int retval; virtualbox_generate_vm_name(virtual_machine_name); command = "startvm " + virtual_machine_name + " --type headless"; - return virtualbox_vbm_popen(command, output); + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error starting virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + return VBOX_SUCCESS; } @@ -215,10 +524,24 @@ int virtualbox_stopvm() { std::string command; std::string output; std::string virtual_machine_name; + char buf[256]; + int retval; virtualbox_generate_vm_name(virtual_machine_name); command = "controlvm " + virtual_machine_name + " savestate"; - return virtualbox_vbm_popen(command, output); + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error stopping virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + return VBOX_SUCCESS; } @@ -226,10 +549,24 @@ int virtualbox_pausevm() { std::string command; std::string output; std::string virtual_machine_name; + char buf[256]; + int retval; virtualbox_generate_vm_name(virtual_machine_name); command = "controlvm " + virtual_machine_name + " pause"; - return virtualbox_vbm_popen(command, output); + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error pausing virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + return VBOX_SUCCESS; } @@ -237,10 +574,24 @@ int virtualbox_resumevm() { std::string command; std::string output; std::string virtual_machine_name; + char buf[256]; + int retval; virtualbox_generate_vm_name(virtual_machine_name); command = "controlvm " + virtual_machine_name + " resume"; - return virtualbox_vbm_popen(command, output); + retval = virtualbox_vbm_popen(command, output); + if (retval) { + fprintf( + stderr, + "%s Error resuming virtual machine! rc = 0x%x\nCommand:\n%s\nOutput:\n%s\n", + boinc_msg_prefix(buf, sizeof(buf)), + retval, + command.c_str(), + output.c_str() + ); + return retval; + } + return VBOX_SUCCESS; } diff --git a/samples/vboxwrapper/vbox.h b/samples/vboxwrapper/vbox.h index 7f9b35812d..e4549ef1bb 100644 --- a/samples/vboxwrapper/vbox.h +++ b/samples/vboxwrapper/vbox.h @@ -28,8 +28,10 @@ // Functions extern int virtualbox_generate_vm_root_dir( std::string& dir ); extern int virtualbox_generate_vm_name( std::string& name ); +extern int virtualbox_generate_medium_uuid( int drive_id, std::string& uuid ); extern bool virtualbox_vm_is_registered(); +extern bool virtualbox_vm_is_hdd_uuid_registered(); extern bool virtualbox_vm_is_running(); extern int virtualbox_initialize(); diff --git a/samples/vboxwrapper/vm.cpp b/samples/vboxwrapper/vm.cpp index 813e5fa982..ec46f54006 100644 --- a/samples/vboxwrapper/vm.cpp +++ b/samples/vboxwrapper/vm.cpp @@ -47,10 +47,8 @@ VM::VM() { stdout_filename.clear(); stderr_filename.clear(); vm_os_name.clear(); - vm_os_version.clear(); - vm_memory_size = 0; + vm_memory_size.clear(); vm_disk_image_name.clear(); - vm_disk_image_type.clear(); vm_shared_folder_name.clear(); vm_shared_folder_dir_name.clear(); suspended = false; @@ -79,10 +77,8 @@ int VM::parse(XML_PARSER& xp) { else if (xp.parse_string(tag, "stdout_filename", stdout_filename)) continue; else if (xp.parse_string(tag, "stderr_filename", stderr_filename)) continue; else if (xp.parse_string(tag, "vm_os_name", vm_os_name)) continue; - else if (xp.parse_string(tag, "vm_os_version", vm_os_version)) continue; - else if (xp.parse_int(tag, "vm_memory_size", vm_memory_size)) continue; + else if (xp.parse_string(tag, "vm_memory_size", vm_memory_size)) continue; else if (xp.parse_string(tag, "vm_disk_image_name", vm_disk_image_name)) continue; - else if (xp.parse_string(tag, "vm_disk_image_type", vm_disk_image_type)) continue; else if (xp.parse_string(tag, "vm_shared_folder_name", vm_shared_folder_name)) continue; else if (xp.parse_string(tag, "vm_shared_folder_dir_name", vm_shared_folder_dir_name)) continue; else if (xp.parse_bool(tag, "enable_network", enable_network)) continue; diff --git a/samples/vboxwrapper/vm.h b/samples/vboxwrapper/vm.h index 27da8ca747..3f08bd1300 100644 --- a/samples/vboxwrapper/vm.h +++ b/samples/vboxwrapper/vm.h @@ -31,14 +31,10 @@ public: std::string stderr_filename; // name of the OS the VM runs std::string vm_os_name; - // name of the version of the VM the OS runs - std::string vm_os_version; // size of the memory allocation for the VM - int vm_memory_size; + std::string vm_memory_size; // name of the virtual machine disk image file std::string vm_disk_image_name; - // name of the virtual machine disk image type - std::string vm_disk_image_type; // name of shared folder std::string vm_shared_folder_name; // shared folder directory name