diff --git a/include/Image.h b/include/Image.h index ee1be2757c..b12f7eac9e 100644 --- a/include/Image.h +++ b/include/Image.h @@ -354,7 +354,7 @@ public: */ bool is_saving() { - return (static_cast(obj_template))->is_saving_hot(); + return (static_cast(obj_template))->is_saving(); } /** diff --git a/include/ImageTemplate.h b/include/ImageTemplate.h index 45348abe1b..6391161c67 100644 --- a/include/ImageTemplate.h +++ b/include/ImageTemplate.h @@ -59,7 +59,7 @@ public: Template::remove_all_except_restricted(restricted_attributes); }; - bool is_saving_hot() + bool is_saving() { bool save_as_hot; @@ -68,7 +68,7 @@ public: return save_as_hot; } - void set_saving_hot() + void set_saving() { replace("SAVE_AS_HOT", "YES"); } diff --git a/include/RequestManagerVirtualMachine.h b/include/RequestManagerVirtualMachine.h index 33f606d50e..44c6b974e6 100644 --- a/include/RequestManagerVirtualMachine.h +++ b/include/RequestManagerVirtualMachine.h @@ -170,15 +170,15 @@ public: /* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */ -class VirtualMachineDiskExport : public RequestManagerVirtualMachine +class VirtualMachineDiskSaveas : public RequestManagerVirtualMachine { public: - VirtualMachineDiskExport(): - RequestManagerVirtualMachine("VirtualMachineDiskExport", - "Exports a disk from virtual machine as a new image", - "A:siiss"){}; + VirtualMachineDiskSaveas(): + RequestManagerVirtualMachine("VirtualMachineDiskSaveas", + "Save a disk from virtual machine as a new image", + "A:siissi"){}; - ~VirtualMachineDiskExport(){}; + ~VirtualMachineDiskSaveas(){}; void request_execute(xmlrpc_c::paramList const& _paramList, RequestAttributes& att); diff --git a/include/VirtualMachine.h b/include/VirtualMachine.h index b0b9701002..2ca85bfa57 100644 --- a/include/VirtualMachine.h +++ b/include/VirtualMachine.h @@ -1270,38 +1270,39 @@ public: int generate_context(string &files, int &disk_id, string& token_password); // ------------------------------------------------------------------------- - // Export Disk related functions (save_as hot) + // "Save as" Disk related functions (save_as hot) // ------------------------------------------------------------------------- /** - * Mark the disk that is going to be exported (saved_as) + * Mark the disk that is going to be "save as" * @param disk_id of the VM + * @param snap_id of the disk to save, -1 to select the active snapshot * @param err_str describing the error * @return -1 if the image cannot saveas or image_id of current disk */ - int set_saveas_disk(int disk_id, string& err_str); + int set_saveas_disk(int disk_id, int snap_id, string& err_str); /** - * Set export attributes for the disk - * @param disk_id Index of the disk to export + * Set save attributes for the disk + * @param disk_id Index of the disk to save * @param source to save the disk * @param img_id ID of the image this disk will be saved to */ int set_saveas_disk(int disk_id, const string& source, int img_id); /** - * Sets the corresponding state to export the disk. - * @return 0 if the VM can be exported + * Sets the corresponding state to save the disk. + * @return 0 if the VM can be saved */ int set_saveas_state(); /** - * Clears the export state, moving the VM to the original state. - * @return 0 if the VM was in an export state + * Clears the save state, moving the VM to the original state. + * @return 0 if the VM was in an saveas state */ int clear_saveas_state(); /** - * Clears the export attributes of the disk being saved as + * Clears the SAVE_AS_* attributes of the disk being saved as * @return the ID of the image this disk will be saved to or -1 if it * is not found. */ @@ -1318,7 +1319,7 @@ public: * @return -1 if failure */ int get_saveas_disk(int& disk_id, string& source, int& image_id, - string& tm_mad, string& ds_id); + string& snap_id, string& tm_mad, string& ds_id); // ------------------------------------------------------------------------ // Authorization related functions diff --git a/src/cli/one_helper/onevm_helper.rb b/src/cli/one_helper/onevm_helper.rb index b2d080305b..22e4d6e3da 100644 --- a/src/cli/one_helper/onevm_helper.rb +++ b/src/cli/one_helper/onevm_helper.rb @@ -601,13 +601,8 @@ class OneVMHelper < OpenNebulaHelper::OneHelper d["CLONE"] end - column :"SAVE_AS", "", :size=>7 do |d| - d["SAVE_AS"] || "-" - end - - default :ID, :TARGET, :IMAGE, :TYPE, - :SAVE, :SAVE_AS + :SAVE end.show(vm_disks, {}) while vm.has_elements?("/VM/TEMPLATE/DISK") diff --git a/src/cli/onevm b/src/cli/onevm index e97023ea3b..42f0d093ae 100755 --- a/src/cli/onevm +++ b/src/cli/onevm @@ -298,15 +298,15 @@ cmd=CommandParser::CmdParser.new(ARGV) do end end - disk_export_desc = <<-EOT.unindent - Exports the specified VM disk to a new Image. The Image is + disk_saveas_desc = <<-EOT.unindent + Saves the specified VM disk as a new Image. The Image is created immediately, and the contents of the VM disk will be saved to it. States: ANY EOT - command :"disk-export", disk_export_desc, :vmid, :diskid, :img_name, + command :"disk-saveas", disk_saveas_desc, :vmid, :diskid, :img_name, :options=>[TYPE] do disk_id = args[1].to_i image_name = args[2] @@ -316,7 +316,7 @@ cmd=CommandParser::CmdParser.new(ARGV) do "the image #{image_name}" helper.perform_action(args[0],options,verbose) do |vm| - res = vm.disk_export(disk_id, image_name, image_type) + res = vm.disk_saveas(disk_id, image_name, image_type,-1) if !OpenNebula.is_error?(res) puts "Image ID: #{res}" diff --git a/src/cloud/ec2/lib/EC2QueryServer.rb b/src/cloud/ec2/lib/EC2QueryServer.rb index 5381e4443c..37b58bd15a 100644 --- a/src/cloud/ec2/lib/EC2QueryServer.rb +++ b/src/cloud/ec2/lib/EC2QueryServer.rb @@ -218,7 +218,7 @@ class EC2QueryServer < CloudServer return rc end - image_id = vm.disk_export(1, + image_id = vm.disk_saveas(1, params["Name"], OpenNebula::Image::IMAGE_TYPES[0]) diff --git a/src/cloud/ec2/lib/ebs.rb b/src/cloud/ec2/lib/ebs.rb index 9f6807ff87..eff3b3575e 100644 --- a/src/cloud/ec2/lib/ebs.rb +++ b/src/cloud/ec2/lib/ebs.rb @@ -302,7 +302,7 @@ module EBS disk_id = vm["TEMPLATE/DISK[IMAGE_ID=#{image_id}]/DISK_ID"] if !disk_id.nil? - snapshot_id = vm.disk_export(disk_id.to_i, + snapshot_id = vm.disk_saveas(disk_id.to_i, params["Description"]||ImageEC2.generate_uuid, OpenNebula::Image::IMAGE_TYPES[image["TYPE"].to_i]) diff --git a/src/image/ImageManagerDriver.cc b/src/image/ImageManagerDriver.cc index d2cda36e9d..6bb6fa1aac 100644 --- a/src/image/ImageManagerDriver.cc +++ b/src/image/ImageManagerDriver.cc @@ -473,12 +473,12 @@ error_img: goto error; error_save_get: - oss << "Image created for SAVE_AS, but the associated VM does not exist."; + oss << "Image created to save as a disk but VM does not exist."; goto error_save; error_save_state: vm->unlock(); - oss << "Image created for SAVE_AS, but VM is no longer running"; + oss << "Image created to save as disk but VM is no longer running"; error_save: image = ipool->get(id, true); diff --git a/src/lcm/LifeCycleStates.cc b/src/lcm/LifeCycleStates.cc index 2a36ead8f8..76954ab173 100644 --- a/src/lcm/LifeCycleStates.cc +++ b/src/lcm/LifeCycleStates.cc @@ -1609,8 +1609,9 @@ void LifeCycleManager::saveas_success_action(int vid) int image_id; int disk_id; string tm_mad; + string snap; string ds_id; - string source; + string src; VirtualMachine * vm = vmpool->get(vid,true); @@ -1619,7 +1620,7 @@ void LifeCycleManager::saveas_success_action(int vid) return; } - int rc = vm->get_saveas_disk(disk_id, source, image_id, tm_mad, ds_id); + int rc = vm->get_saveas_disk(disk_id, src, image_id, snap, tm_mad, ds_id); vm->clear_saveas_disk(); @@ -1665,8 +1666,9 @@ void LifeCycleManager::saveas_failure_action(int vid) int image_id; int disk_id; string tm_mad; + string snap; string ds_id; - string source; + string src; VirtualMachine * vm = vmpool->get(vid,true); @@ -1675,7 +1677,7 @@ void LifeCycleManager::saveas_failure_action(int vid) return; } - int rc = vm->get_saveas_disk(disk_id, source, image_id, tm_mad, ds_id); + int rc = vm->get_saveas_disk(disk_id, src, image_id, snap, tm_mad, ds_id); vm->clear_saveas_disk(); diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 71dfda1ca7..cb686f1f4e 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -43,7 +43,7 @@ module OpenNebula :attachnic => "vm.attachnic", :detachnic => "vm.detachnic", :recover => "vm.recover", - :diskexport => "vm.diskexport", + :disksaveas => "vm.disksaveas", :disksnapshotcreate => "vm.disksnapshotcreate", :disksnapshotrevert => "vm.disksnapshotrevert", :disksnapshotdelete => "vm.disksnapshotdelete" @@ -459,7 +459,7 @@ module OpenNebula migrate(host_id, true, enforce) end - # Set the specified vm's disk to be saved in a new image + # Set the specified vm's disk to be saved as a new image # when the VirtualMachine shutdowns # # @param disk_id [Integer] ID of the disk to be saved @@ -467,17 +467,20 @@ module OpenNebula # disk will be saved # @param image_type [String] Type of the new image. Set to empty string # to use the default type + # @param snap_id [Integer] ID of the snapshot to save, -1 to use the + # current disk image state # # @return [Integer, OpenNebula::Error] the new Image ID in case of # success, error otherwise - def disk_export(disk_id, image_name, image_type="") + def disk_saveas(disk_id, image_name, image_type="", snap_id=-1) return Error.new('ID not defined') if !@pe_id - rc = @client.call(VM_METHODS[:diskexport], + rc = @client.call(VM_METHODS[:disksaveas], @pe_id, disk_id, image_name, - image_type) + image_type, + snap_id) return rc end @@ -767,7 +770,7 @@ module OpenNebula image_id = disk["IMAGE_ID"] if !image_id.nil? && !image_id.empty? - rc = disk_export(disk_id.to_i,"#{name}-disk-#{disk_id}","") + rc = disk_saveas(disk_id.to_i,"#{name}-disk-#{disk_id}","",-1) return rc if OpenNebula.is_error?(rc) diff --git a/src/rm/RequestManager.cc b/src/rm/RequestManager.cc index 72a29c3d91..78ed77a113 100644 --- a/src/rm/RequestManager.cc +++ b/src/rm/RequestManager.cc @@ -302,7 +302,7 @@ void RequestManager::register_xml_methods() xmlrpc_c::methodPtr vm_snap_create(new VirtualMachineSnapshotCreate()); xmlrpc_c::methodPtr vm_snap_revert(new VirtualMachineSnapshotRevert()); xmlrpc_c::methodPtr vm_snap_delete(new VirtualMachineSnapshotDelete()); - xmlrpc_c::methodPtr vm_dexport(new VirtualMachineDiskExport()); + xmlrpc_c::methodPtr vm_dsaveas(new VirtualMachineDiskSaveas()); xmlrpc_c::methodPtr vm_dsnap_create(new VirtualMachineDiskSnapshotCreate()); xmlrpc_c::methodPtr vm_dsnap_revert(new VirtualMachineDiskSnapshotRevert()); xmlrpc_c::methodPtr vm_dsnap_delete(new VirtualMachineDiskSnapshotDelete()); @@ -463,7 +463,7 @@ void RequestManager::register_xml_methods() RequestManagerRegistry.addMethod("one.vm.snapshotcreate", vm_snap_create); RequestManagerRegistry.addMethod("one.vm.snapshotrevert", vm_snap_revert); RequestManagerRegistry.addMethod("one.vm.snapshotdelete", vm_snap_delete); - RequestManagerRegistry.addMethod("one.vm.diskexport", vm_dexport); + RequestManagerRegistry.addMethod("one.vm.disksaveas", vm_dsaveas); RequestManagerRegistry.addMethod("one.vm.disksnapshotcreate", vm_dsnap_create); RequestManagerRegistry.addMethod("one.vm.disksnapshotrevert", vm_dsnap_revert); RequestManagerRegistry.addMethod("one.vm.disksnapshotdelete", vm_dsnap_delete); diff --git a/src/rm/RequestManagerVirtualMachine.cc b/src/rm/RequestManagerVirtualMachine.cc index 6bb1d5cc3b..a2390fd4dc 100644 --- a/src/rm/RequestManagerVirtualMachine.cc +++ b/src/rm/RequestManagerVirtualMachine.cc @@ -1176,8 +1176,8 @@ void VirtualMachineMigrate::request_execute(xmlrpc_c::paramList const& paramList /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -void VirtualMachineDiskExport::request_execute(xmlrpc_c::paramList const& paramList, - RequestAttributes& att) +void VirtualMachineDiskSaveas::request_execute( + xmlrpc_c::paramList const& paramList, RequestAttributes& att) { Nebula& nd = Nebula::instance(); @@ -1188,6 +1188,7 @@ void VirtualMachineDiskExport::request_execute(xmlrpc_c::paramList const& paramL int disk_id = xmlrpc_c::value_int(paramList.getInt(2)); string img_name = xmlrpc_c::value_string(paramList.getString(3)); string img_type = xmlrpc_c::value_string(paramList.getString(4)); + int snap_id = xmlrpc_c::value_int(paramList.getInt(5)); VirtualMachinePool * vmpool = static_cast(pool); @@ -1224,7 +1225,7 @@ void VirtualMachineDiskExport::request_execute(xmlrpc_c::paramList const& paramL string error; // ------------------------------------------------------------------------- - // Prepare and check the VM/DISK to be export + // Prepare and check the VM/DISK to be saved as // ------------------------------------------------------------------------- if ((vm = get_vm(id, att)) == 0) { @@ -1236,7 +1237,7 @@ void VirtualMachineDiskExport::request_execute(xmlrpc_c::paramList const& paramL goto error_state; } - iid_orig = vm->set_saveas_disk(disk_id, error); + iid_orig = vm->set_saveas_disk(disk_id, snap_id, error); if (iid_orig == -1) { @@ -1317,7 +1318,7 @@ void VirtualMachineDiskExport::request_execute(xmlrpc_c::paramList const& paramL itemplate->add("SAVED_IMAGE_ID",iid_orig); itemplate->add("SAVED_DISK_ID",disk_id); itemplate->add("SAVED_VM_ID", id); - itemplate->set_saving_hot(); + itemplate->set_saving(); if (img_type.empty()) { @@ -1404,7 +1405,7 @@ error_state: vm->unlock(); failure_response(INTERNAL,request_error("VM has to be RUNNING, POWEROFF or " - "SUSPENDED to export disks.",""), att); + "SUSPENDED to save disks.",""), att); return; error_disk: diff --git a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb index b181f4ddd3..295b10e1ca 100644 --- a/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/VirtualMachineJSON.rb @@ -104,7 +104,7 @@ module OpenNebulaJSON end def save_as(params=Hash.new) - disk_export(params['disk_id'].to_i, params['image_name'], params['type']) + disk_saveas(params['disk_id'].to_i, params['image_name'], params['type']) end def snapshot_create(params=Hash.new) diff --git a/src/tm/TransferManager.cc b/src/tm/TransferManager.cc index a3dcbaea7d..80f479fbc1 100644 --- a/src/tm/TransferManager.cc +++ b/src/tm/TransferManager.cc @@ -2053,7 +2053,8 @@ void TransferManager::saveas_hot_action(int vid) { int disk_id; int image_id; - string source; + string src; + string snap_id; string tm_mad; string ds_id; @@ -2084,7 +2085,7 @@ void TransferManager::saveas_hot_action(int vid) goto error_common; } - if (vm->get_saveas_disk(disk_id, source, image_id, tm_mad, ds_id) != 0) + if (vm->get_saveas_disk(disk_id, src, image_id, snap_id, tm_mad, ds_id)!= 0) { vm->log("TM", Log::ERROR,"Could not get disk information to export it"); goto error_common; @@ -2097,7 +2098,7 @@ void TransferManager::saveas_hot_action(int vid) goto error_driver; } - xfr_name = vm->get_transfer_file() + ".saveas_hot"; + xfr_name = vm->get_transfer_file() + ".disk_saveas"; xfr.open(xfr_name.c_str(),ios::out | ios::trunc); if (xfr.fail() == true) @@ -2105,12 +2106,13 @@ void TransferManager::saveas_hot_action(int vid) goto error_file; } - //MVDS tm_mad hostname:remote_system_dir/disk.0 vmid dsid + //MVDS tm_mad hostname:remote_system_dir/disk.0 source snapid vmid dsid xfr << "CPDS " << tm_mad << " " << vm->get_hostname() << ":" << vm->get_remote_system_dir() << "/disk." << disk_id << " " - << source << " " + << src << " " + << snap_id << " " << vm->get_oid() << " " << ds_id << endl; diff --git a/src/vm/VirtualMachine.cc b/src/vm/VirtualMachine.cc index 848232838c..884600358d 100644 --- a/src/vm/VirtualMachine.cc +++ b/src/vm/VirtualMachine.cc @@ -2530,7 +2530,6 @@ int VirtualMachine::set_attach_nic(int nic_id) void VirtualMachine::release_disk_images() { int iid; - int save_as_id; int num_disks; int did = -1; @@ -2572,12 +2571,6 @@ void VirtualMachine::release_disk_images() imagem->release_image(oid, iid, img_error); } - - if ( disk->vector_value("SAVE_AS", save_as_id) == 0 ) - { - imagem->release_image(oid, save_as_id, img_error); - } - } } @@ -3216,25 +3209,49 @@ const VectorAttribute* VirtualMachine::get_disk(int disk_id) const /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ -int VirtualMachine::set_saveas_disk(int disk_id, string& err_str) +int VirtualMachine::set_saveas_disk(int disk_id, int snap_id, string& err_str) { int iid = -1; VectorAttribute * disk = get_disk(disk_id); - if ( disk == 0 ) + if (disk == 0) { err_str = "DISK does not exist."; return -1; } - if ( disk->vector_value("IMAGE_ID", iid) != 0 ) + if (disk->vector_value("IMAGE_ID", iid) != 0) { err_str = "DISK does not have a valid IMAGE_ID."; return -1; } + const Snapshots * snaps = get_disk_snapshots(disk_id, err_str); + + if (snaps == 0) + { + if (snap_id != -1) + { + err_str = "Snapshot does not exists."; + return -1; + } + } + else + { + if (snap_id == -1) + { + snap_id = snaps->get_active_id(); + } + else if (!snaps->exists(snap_id)) + { + err_str = "Snapshot does not exists."; + return -1; + } + } + disk->replace("HOTPLUG_SAVE_AS_ACTIVE", "YES"); + disk->replace("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id); return iid; } @@ -3268,6 +3285,8 @@ int VirtualMachine::set_saveas_disk(int disk_id, const string& source, int iid) int VirtualMachine::set_saveas_state() { + string s; + switch (state) { case ACTIVE: @@ -3277,22 +3296,24 @@ int VirtualMachine::set_saveas_state() } lcm_state = HOTPLUG_SAVEAS; - break; + break; case POWEROFF: state = ACTIVE; lcm_state = HOTPLUG_SAVEAS_POWEROFF; - break; + break; case SUSPENDED: state = ACTIVE; lcm_state = HOTPLUG_SAVEAS_SUSPENDED; - break; + break; default: return -1; } + log("VM", Log::INFO, "New state is " + lcm_state_to_str(s,lcm_state)); + return 0; } @@ -3301,20 +3322,25 @@ int VirtualMachine::set_saveas_state() int VirtualMachine::clear_saveas_state() { + string s; + switch (lcm_state) { case HOTPLUG_SAVEAS: lcm_state = RUNNING; + log("VM", Log::INFO, "New state is "+lcm_state_to_str(s,lcm_state)); break; case HOTPLUG_SAVEAS_POWEROFF: state = POWEROFF; lcm_state = LCM_INIT; + log("VM", Log::INFO, "New state is " + vm_state_to_str(s,state)); break; case HOTPLUG_SAVEAS_SUSPENDED: state = SUSPENDED; lcm_state = LCM_INIT; + log("VM", Log::INFO, "New state is " + vm_state_to_str(s,state)); break; default: @@ -3355,6 +3381,7 @@ int VirtualMachine::clear_saveas_disk() disk->remove("HOTPLUG_SAVE_AS_ACTIVE"); disk->remove("HOTPLUG_SAVE_AS"); disk->remove("HOTPLUG_SAVE_AS_SOURCE"); + disk->remove("HOTPLUG_SAVE_AS_SNAPSHOT_ID"); return image_id; } @@ -3368,7 +3395,7 @@ int VirtualMachine::clear_saveas_disk() /* -------------------------------------------------------------------------- */ int VirtualMachine::get_saveas_disk(int& disk_id, string& source, - int& image_id, string& tm_mad, string& ds_id) + int& image_id, string& snap_id, string& tm_mad, string& ds_id) { vector disks; VectorAttribute * disk; @@ -3391,6 +3418,7 @@ int VirtualMachine::get_saveas_disk(int& disk_id, string& source, { rc = disk->vector_value("HOTPLUG_SAVE_AS_SOURCE", source); rc += disk->vector_value("HOTPLUG_SAVE_AS", image_id); + rc += disk->vector_value("HOTPLUG_SAVE_AS_SNAPSHOT_ID", snap_id); rc += disk->vector_value("DISK_ID", disk_id); rc += disk->vector_value("DATASTORE_ID", ds_id); rc += disk->vector_value("TM_MAD", tm_mad);