diff --git a/src/tm_mad/vcenter/cpds b/src/tm_mad/vcenter/cpds index e29474ab14..b1885efb8c 100755 --- a/src/tm_mad/vcenter/cpds +++ b/src/tm_mad/vcenter/cpds @@ -70,7 +70,7 @@ begin vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vmid) if vm.has_snapshots? - STDERR.puts "'disk-saveas' operation is not supported for VMs with system snapshots." + raise "'disk-saveas' operation is not supported for VMs with system snapshots." exit 1 end diff --git a/src/tm_mad/vcenter/delete b/src/tm_mad/vcenter/delete index a0f017d440..fb015ce0c4 100755 --- a/src/tm_mad/vcenter/delete +++ b/src/tm_mad/vcenter/delete @@ -93,9 +93,9 @@ begin else @error_message = "Error unregistering vm #{vmid} (#{vm_ref})." vm.poweroff_hard if vm.is_powered_on? - vm.remove_all_snapshots if vm.has_snapshots? if vm.instantiated_as_persistent? + vm.remove_all_snapshots if vm.has_snapshots? vm.convert_to_template else vm.destroy diff --git a/src/tm_mad/vcenter/mvds b/src/tm_mad/vcenter/mvds index d4cc5b8e74..a39f7616cb 100755 --- a/src/tm_mad/vcenter/mvds +++ b/src/tm_mad/vcenter/mvds @@ -61,11 +61,13 @@ disk_id = img_path.split(".")[-1] begin vi_client = VCenterDriver::VIClient.new_from_host(host_id) vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vmid) - disk = vm.disk(disk_id) vmperst = vm.instantiated_as_persistent? + vm.remove_all_snapshots if vm.has_snapshots? + disk = vm.disk(disk_id) + # Don't detach persistent disks if the VM has snapshots - if disk && disk.exists? && !vm.has_snapshots? + if disk && disk.exists? vm.one_item = one_vm # Do not detach persistent unmanaged disk, we need them for mark as a template diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb index e3af24a07c..b2643133ca 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/datastore.rb @@ -385,13 +385,15 @@ class Datastore < Storage target_ds_vc = VCenterDriver::Datastore.new_from_ref(target_ds_ref, vi_client) dest_name = target_ds_vc['name'] - dest_path = "[#{dest_name}] #{dest_path}" + target_ds_vc.create_directory(File.dirname(dest_path)) + + dpath_ds = "[#{dest_name}] #{dest_path}" orig_path = "[#{self['name']}] #{disk.path}" move_params = { sourceName: orig_path, sourceDatacenter: get_dc.item, - destName: dest_path, + destName: dpath_ds, force: true } diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb index b037e29fac..679997b987 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/virtual_machine.rb @@ -267,7 +267,13 @@ class VirtualMachine < VCenterDriver::Template config = {} if action == :delete - config[:key] = "opennebula.disk.#{@id}" + if managed? + key = "opennebula.mdisk.#{@id}" + else + key = "opennebula.disk.#{@id}" + end + + config[:key] = key config[:value] = "" elsif action == :resize if new_size @@ -544,13 +550,14 @@ class VirtualMachine < VCenterDriver::Template @vi_client.vim.serviceContent.about.instanceUuid end - def get_unmanaged_keys + def get_disk_keys unmanaged_keys = {} @item.config.extraConfig.each do |val| - if val[:key].include?("opennebula.disk") - unmanaged_keys[val[:key]] = val[:value] - end + u = val[:key].include?("opennebula.disk") + m = val[:key].include?("opennebula.mdisk") + unmanaged_keys[val[:key]] = val[:value] if u || m end + return unmanaged_keys end @@ -988,13 +995,25 @@ class VirtualMachine < VCenterDriver::Template # # @return [vCenter_disk] the proper disk def query_disk(one_disk, keys, vc_disks) - index = one_disk['DISK_ID'] - cloned = one_disk["CLONE"].nil? || one_disk["CLONE"] == "YES" + index = one_disk['DISK_ID'] + cloned = one_disk["CLONE"].nil? || one_disk["CLONE"] == "YES" + unmanaged = "opennebula.disk.#{index}" + managed = "opennebula.mdisk.#{index}" - if keys["opennebula.disk.#{index}"] - key = keys["opennebula.disk.#{index}"].to_i + if keys[managed] + key = keys[managed].to_i + elsif keys[unmanaged] + key = keys[unmanaged].to_i + end + + if key query = vc_disks.select {|dev| key == dev[:key]} else + if has_snapshots? + error = 'disk metadata is corrupted and you have snapshots' + raise error + end + path = !cloned ? one_disk['SOURCE'] : disk_real_path(one_disk, index) query = vc_disks.select {|dev| path == dev[:path_wo_ds]} end @@ -1062,7 +1081,7 @@ class VirtualMachine < VCenterDriver::Template def info_disks @disks = {} - keys = get_unmanaged_keys + keys = get_disk_keys vc_disks = get_vcenter_disks one_disks = get_one_disks @@ -1135,7 +1154,7 @@ class VirtualMachine < VCenterDriver::Template raise "disk #{index} not found" unless one_disk - keys = opts[:keys].nil? ? get_unmanaged_keys : opts[:keys] + keys = opts[:keys].nil? ? get_disk_keys : opts[:keys] vc_disks = opts[:disks].nil? ? get_vcenter_disks : opts[:disks] vc_disk = query_disk(one_disk, keys, vc_disks) @@ -1418,7 +1437,6 @@ class VirtualMachine < VCenterDriver::Template boot_opts = set_boot_order(deploy[:boot]) end - # changes from sync_disks device_change += disks[:deviceChange] if disks[:deviceChange] extraconfig += disks[:extraConfig] if disks[:extraConfig] @@ -1749,10 +1767,12 @@ class VirtualMachine < VCenterDriver::Template # try to get specs for new attached disks # using disk_each method with :no_exists? condition def attach_disks_specs() - attach_disk_array = [] - attach_spod_array = [] + attach_disk_array = [] + extraconfig = [] + attach_spod_array = [] attach_spod_disk_info = {} + pos = {:ide => 0, :scsi => 0} disks_each(:no_exists?) do |disk| k = disk.one_item['TYPE'] == 'CDROM' ? :ide : :scsi @@ -1763,14 +1783,23 @@ class VirtualMachine < VCenterDriver::Template unit_ctrl = "#{spec[:device].controllerKey}-#{spec[:device].unitNumber}" attach_spod_disk_info[unit_ctrl] = disk.id else - attach_disk_array << calculate_add_disk_spec(disk.one_item, pos[k]) + aspec = calculate_add_disk_spec(disk.one_item, pos[k]) + extra_key = "opennebula.mdisk.#{disk.one_item["DISK_ID"]}" + extra_value = "#{aspec[:device].key}" + + attach_disk_array << aspec + extraconfig << {key: extra_key, value: extra_value } end pos[k]+=1 end - return attach_disk_array, attach_spod_array, attach_spod_disk_info + { disks: attach_disk_array, + spods: attach_spod_array, + spod_info: attach_spod_disk_info, + extraconfig: extraconfig + } end # try to get specs for detached disks @@ -1778,10 +1807,10 @@ class VirtualMachine < VCenterDriver::Template def detach_disks_specs() detach_disk_array = [] extra_config = [] - keys = get_unmanaged_keys.invert + keys = get_disk_keys.invert ipool = VCenterDriver::VIHelper.one_pool(OpenNebula::ImagePool) disks_each(:detached?) do |d| - key = d.key + key = d.key.to_s source = VCenterDriver::FileHelper.escape_path(d.path) persistent = VCenterDriver::VIHelper.find_persistent_image_by_source(source, ipool) @@ -1811,7 +1840,6 @@ class VirtualMachine < VCenterDriver::Template spec_hash = {} device_change = [] - extra_config = [] if option == :all detach_op = {} @@ -1820,13 +1848,16 @@ class VirtualMachine < VCenterDriver::Template @item.ReconfigVM_Task(:spec => detach_op).wait_for_completion if perform end - device_change, device_change_spod, device_change_spod_ids = attach_disks_specs + a_specs = attach_disks_specs - if !device_change_spod.empty? - spec_hash[:extraConfig] = create_storagedrs_disks(device_change_spod, device_change_spod_ids) + if !a_specs[:spods].empty? + spec_hash[:extraConfig] = create_storagedrs_disks(a_specs[:spods], a_specs[:spod_info]) end - spec_hash[:deviceChange] = device_change unless device_change.empty? + if !a_specs[:disks].empty? + spec_hash[:deviceChange] = a_specs[:disks] + spec_hash[:extraConfig] = a_specs[:extraconfig] + end return spec_hash unless execute @@ -1837,18 +1868,14 @@ class VirtualMachine < VCenterDriver::Template end # Attach DISK to VM (hotplug) - def attach_disk - spec_hash = {} - disk = nil + def attach_disk(disk) + spec_hash = {} device_change = [] # Extract unmanaged_keys - unmanaged_keys = get_unmanaged_keys + unmanaged_keys = get_disk_keys vc_disks = get_vcenter_disks - # Extract disk from driver action - disk = one_item.retrieve_xmlelements("TEMPLATE/DISK[ATTACH='YES']").first - # Check if we're dealing with a StoragePod SYSTEM ds storpod = disk["VCENTER_DS_REF"].start_with?('group-') @@ -1856,10 +1883,15 @@ class VirtualMachine < VCenterDriver::Template raise "DISK is already connected to VM" if disk_attached_to_vm(disk, unmanaged_keys, vc_disks) # Generate vCenter spec and reconfigure VM - device_change << calculate_add_disk_spec(disk) + add_spec = calculate_add_disk_spec(disk) + device_change << add_spec raise "Could not generate DISK spec" if device_change.empty? + extra_key = "opennebula.mdisk.#{disk["DISK_ID"]}" + extra_value = "#{add_spec[:device].key}" + spec_hash[:deviceChange] = device_change + spec_hash[:extraConfig] = [{key: extra_key, value: extra_value }] spec = RbVmomi::VIM.VirtualMachineConfigSpec(spec_hash) begin @@ -1961,7 +1993,7 @@ class VirtualMachine < VCenterDriver::Template return unless disk.exists? spec_hash = {} - spec_hash[:extraConfig] = [disk.config(:delete)] unless disk.managed? + spec_hash[:extraConfig] = [disk.config(:delete)] spec_hash[:deviceChange] = [{ :operation => :remove, :device => disk.device @@ -2016,6 +2048,34 @@ class VirtualMachine < VCenterDriver::Template return device_found end + def get_key(type) + @used_keys = [] unless @used_keys + + if type == "CDROM" + bound = "is_cdrom?" + key = 3000 + else + bound = "is_disk?" + key = 2000 + end + + used = @used_keys + @item.config.hardware.device.each do |dev| + used << dev.key + next unless send(bound, dev) + key = dev.key + end + + loop do + break if !used.include?(key) + key+=1 + end + + @used_keys << key + + key + end + def calculate_add_disk_spec(disk, position=0) img_name_escaped = VCenterDriver::FileHelper.get_img_name( disk, @@ -2049,7 +2109,7 @@ class VirtualMachine < VCenterDriver::Template device = RbVmomi::VIM::VirtualCdrom( :backing => vmdk_backing, - :key => -1, + :key => get_key(type), :controllerKey => controller.key, :unitNumber => unit_number, @@ -2067,7 +2127,6 @@ class VirtualMachine < VCenterDriver::Template else # TYPE is regular disk (not CDROM) - controller, unit_number = find_free_controller(position) storpod = disk["VCENTER_DS_REF"].start_with?('group-') @@ -2090,7 +2149,7 @@ class VirtualMachine < VCenterDriver::Template :backing => vmdk_backing, :capacityInKB => size_kb, :controllerKey => controller.key, - :key => (-1 - position), + :key => get_key(type), :unitNumber => unit_number ) @@ -2512,8 +2571,9 @@ class VirtualMachine < VCenterDriver::Template @item.PowerOffVM_Task.wait_for_completion end - def remove_all_snapshots - @item.RemoveAllSnapshots_Task.wait_for_completion + def remove_all_snapshots(consolidate = true) + @item.RemoveAllSnapshots_Task({consolidate: consolidate}).wait_for_completion + info_disks end def vm_tools? @@ -2930,10 +2990,6 @@ class VirtualMachine < VCenterDriver::Template vc_vm = VCenterDriver::VirtualMachine.new_without_id(vi_client, vm['/VM/DEPLOY_ID']) vc_vm.vm_id = vm_id - error = !vc_vm.disks_each(:managed?).empty? && !ds.nil? - # We know this comes from a migration from poweroff state (not a poweroff migration) - # since all the other cases are treated in vmm drivers: save, migrate and shutdown - raise 'datastore migration from poweroff state with managed disks is not supported' if error ccr_ref = dst_host['/HOST/TEMPLATE/VCENTER_CCR_REF'] vc_host = VCenterDriver::ClusterComputeResource.new_from_ref(ccr_ref, vi_client) diff --git a/src/vmm_mad/remotes/lib/vcenter_driver/vm_template.rb b/src/vmm_mad/remotes/lib/vcenter_driver/vm_template.rb index dbdbfced1d..1031f9ccb1 100644 --- a/src/vmm_mad/remotes/lib/vcenter_driver/vm_template.rb +++ b/src/vmm_mad/remotes/lib/vcenter_driver/vm_template.rb @@ -790,6 +790,10 @@ class Template !(device.class.ancestors.index(RbVmomi::VIM::VirtualDisk)).nil? end + def is_cdrom?(device) + device.backing.is_a? RbVmomi::VIM::VirtualCdromIsoBackingInfo + end + # Checks if a RbVmomi::VIM::VirtualDevice is a network interface def is_nic?(device) !device.class.ancestors.index(RbVmomi::VIM::VirtualEthernetCard).nil? diff --git a/src/vmm_mad/remotes/vcenter/attach_disk b/src/vmm_mad/remotes/vcenter/attach_disk index e7d481e53b..269c88346f 100755 --- a/src/vmm_mad/remotes/vcenter/attach_disk +++ b/src/vmm_mad/remotes/vcenter/attach_disk @@ -46,9 +46,10 @@ begin # Setting one_item with info with the vm_xml including DISK to be added one_item = drv_action.retrieve_xmlelements('VM').first + disk = one_item.retrieve_xmlelements("TEMPLATE/DISK[ATTACH='YES']").first vm = VCenterDriver::VirtualMachine.new_one(vi_client, vm_ref, one_item) - vm.attach_disk + vm.attach_disk(disk) rescue StandardError => e message = "Attach image for VM #{vm_ref} on vCenter cluster" \ "#{vc_cluster_name} failed due to \"#{e.message}\"\n" diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 1595620cbb..d9f9f96c2a 100755 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -48,16 +48,6 @@ begin vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vm_id) - if (%{'SAVE_MIGRATE'}).include?(lcm_state_str) - dst_ds = drv_action['VM/HISTORY_RECORDS/HISTORY/DS_ID'] - src_ds = drv_action['DATASTORE/ID'] - - new_ds = dst_ds != src_ds - - error = !vm.disks_each(:managed?).empty? && new_ds - raise 'cold datastore migration in poweroff hard with managed disk(s) is not supported' if error - end - vm.poweroff_hard rescue StandardError => e message = "Cancel VM #{vm_ref} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/migrate b/src/vmm_mad/remotes/vcenter/migrate index 2c01e95421..40b33882f8 100755 --- a/src/vmm_mad/remotes/vcenter/migrate +++ b/src/vmm_mad/remotes/vcenter/migrate @@ -29,7 +29,6 @@ $LOAD_PATH << File.dirname(__FILE__) require 'vcenter_driver' -vm_ref = ARGV[0] vm_id = ARGV[-2] src_host = ARGV[-3] dst_host = ARGV[-4] @@ -41,12 +40,7 @@ dst_ds = drv_action['VM/HISTORY_RECORDS/HISTORY/DS_ID'] src_ds = drv_action['DATASTORE/ID'] begin - vi_client = VCenterDriver::VIClient.new_from_host(src_host) - vm = VCenterDriver::VirtualMachine.new(vi_client, vm_ref, vm_id) - new_ds = dst_ds != src_ds - - error = !vm.disks_each(:managed?).empty? && new_ds - raise 'live datastore migration with managed disk is not supported' if error + new_ds = dst_ds != src_ds if new_ds VCenterDriver::VirtualMachine diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 7bbb13712f..b6e0b8b497 100755 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -55,19 +55,7 @@ begin vm = VCenterDriver::VirtualMachine.new_without_id(vi_client, vm_ref) - if (%{'SAVE_MIGRATE'}).include?(lcm_state_str) - vm.vm_id = vm_id - dst_ds = drv_action['VM/HISTORY_RECORDS/HISTORY/DS_ID'] - src_ds = drv_action['DATASTORE/ID'] - - new_ds = dst_ds != src_ds - - error = !vm.disks_each(:managed?).empty? && new_ds - raise 'cold datastore migration with managed disk(s) is not supported' if error - end - vm.suspend - rescue StandardError => e message = "Save of VM #{vm_ref} on vCenter cluster "\ "#{vc_cluster_name} failed due to "\ diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index 810795f9dc..817dac29d4 100755 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -62,19 +62,6 @@ begin vm = VCenterDriver::VirtualMachine.new_without_id(vi_client, vm_ref) - - if (%{'SAVE_MIGRATE'}).include?(lcm_state_str) - vm.vm_id = vm_id - dst_ds = drv_action['VM/HISTORY_RECORDS/HISTORY/DS_ID'] - src_ds = drv_action['DATASTORE/ID'] - - new_ds = dst_ds != src_ds - - error = !vm.disks_each(:managed?).empty? && new_ds - raise 'cold datastore migration in poweroff with managed disk(s) is not supported' if error - end - - vm.shutdown # Undeploy, Poweroff or Terminate rescue StandardError => e message = "Shutdown of VM #{vm_ref} on vCenter cluster "\