From f82099014aad379c90e01911bcf637f8ac77b562 Mon Sep 17 00:00:00 2001 From: Tino Vazquez Date: Wed, 24 Sep 2014 17:16:38 +0200 Subject: [PATCH] feature #2911: Add correct actions for vCenter, solve many bugs --- src/oca/ruby/opennebula/virtual_machine.rb | 11 +- src/vmm_mad/exec/one_vmm_sh | 2 +- src/vmm_mad/remotes/vcenter/cancel | 10 +- src/vmm_mad/remotes/vcenter/deploy | 18 +- src/vmm_mad/remotes/vcenter/reboot | 4 +- src/vmm_mad/remotes/vcenter/reset | 6 +- src/vmm_mad/remotes/vcenter/restore | 4 +- src/vmm_mad/remotes/vcenter/revert_snapshot | 8 +- src/vmm_mad/remotes/vcenter/save | 11 +- src/vmm_mad/remotes/vcenter/shutdown | 15 +- src/vmm_mad/remotes/vcenter/snapshot_create | 4 +- src/vmm_mad/remotes/vcenter/snapshot_delete | 8 +- src/vmm_mad/remotes/vcenter/vcenter_driver.rb | 198 +++++++++++------- 13 files changed, 196 insertions(+), 103 deletions(-) diff --git a/src/oca/ruby/opennebula/virtual_machine.rb b/src/oca/ruby/opennebula/virtual_machine.rb index 5d78a62903..2ad51e0a1c 100644 --- a/src/oca/ruby/opennebula/virtual_machine.rb +++ b/src/oca/ruby/opennebula/virtual_machine.rb @@ -224,7 +224,11 @@ module OpenNebula def deploy(host_id, enforce=false, ds_id=-1) enforce ||= false ds_id ||= -1 - return call(VM_METHODS[:deploy], @pe_id, host_id.to_i, enforce, ds_id.to_i) + return call(VM_METHODS[:deploy], + @pe_id, + host_id.to_i, + enforce, + ds_id.to_i) end # Shutdowns an already deployed VM @@ -587,6 +591,11 @@ module OpenNebula self['GID'].to_i end + # Returns the deploy_id of the VirtualMachine (numeric value) + def deploy_id + self['DEPLOY_ID'] + end + private def action(name) return Error.new('ID not defined') if !@pe_id diff --git a/src/vmm_mad/exec/one_vmm_sh b/src/vmm_mad/exec/one_vmm_sh index f87e3dc19f..fcdfebed68 100755 --- a/src/vmm_mad/exec/one_vmm_sh +++ b/src/vmm_mad/exec/one_vmm_sh @@ -25,6 +25,6 @@ fi LOCAL_ACTIONS="deploy,shutdown,reboot,cancel,save,restore,migrate,poll,pre" LOCAL_ACTIONS="${LOCAL_ACTIONS},post,clean" LOCAL_ACTIONS="${LOCAL_ACTIONS},snapshotcreate,snapshotrevert,snapshotdelete" -LOCAL_ACTIONS="${LOCAL_ACTIONS},attach_nic,detach_nic" +LOCAL_ACTIONS="${LOCAL_ACTIONS},attach_nic,detach_nic,reset" exec $MAD_LOCATION/one_vmm_exec -l $LOCAL_ACTIONS $* diff --git a/src/vmm_mad/remotes/vcenter/cancel b/src/vmm_mad/remotes/vcenter/cancel index 72cf74a372..d41f78ef26 100644 --- a/src/vmm_mad/remotes/vcenter/cancel +++ b/src/vmm_mad/remotes/vcenter/cancel @@ -31,11 +31,17 @@ require 'vcenter_driver' deploy_id = ARGV[0] host = ARGV[1] +vm_id = ARGV[-2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str begin - puts VCenterDriver::VCenterVm.cancel(deploy_id, host) - exit 0 + puts VCenterDriver::VCenterVm.cancel(deploy_id, host, lcm_state) rescue Exception => e STDERR.puts "Cancel of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/deploy b/src/vmm_mad/remotes/vcenter/deploy index 5282118339..c0c3834491 100644 --- a/src/vmm_mad/remotes/vcenter/deploy +++ b/src/vmm_mad/remotes/vcenter/deploy @@ -28,16 +28,26 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' dfile = ARGV[0] host = ARGV[1] -id = ARGV[2] +vm_id = ARGV[2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str +deploy_id = vm.deploy_id begin - puts VCenterDriver::VCenterVm.deploy File.read(dfile) - exit 0 + puts VCenterDriver::VCenterVm.deploy(File.read(dfile), + lcm_state, + deploy_id, + host) rescue Exception => e - STDERR.puts "Deploy of VM #{id} on host #{host} with #{dfile} failed " + + STDERR.puts "Deploy of VM #{vm_id} on host #{host} with #{dfile} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/reboot b/src/vmm_mad/remotes/vcenter/reboot index b03df8406c..7b6d79ad81 100644 --- a/src/vmm_mad/remotes/vcenter/reboot +++ b/src/vmm_mad/remotes/vcenter/reboot @@ -33,9 +33,9 @@ deploy_id = ARGV[0] host = ARGV[1] begin - puts VCenterDriver::VCenterVm.reboot(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.reboot(deploy_id, host) rescue Exception => e STDERR.puts "Guest reboot of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/reset b/src/vmm_mad/remotes/vcenter/reset index 8e59a9a5a4..0cc9ba4376 100644 --- a/src/vmm_mad/remotes/vcenter/reset +++ b/src/vmm_mad/remotes/vcenter/reset @@ -27,15 +27,15 @@ end $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) -require 'vmware_driver' +require 'vcenter_driver' deploy_id = ARGV[0] host = ARGV[1] begin - puts VCenterDriver::VCenterVm.reset(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.reset(deploy_id, host) rescue Exception => e STDERR.puts "Reset of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/restore b/src/vmm_mad/remotes/vcenter/restore index 4623dfb6ca..fa0191ffe4 100644 --- a/src/vmm_mad/remotes/vcenter/restore +++ b/src/vmm_mad/remotes/vcenter/restore @@ -33,9 +33,9 @@ host = ARGV[-1] deploy_id = ARGV[2] begin - puts VCenterDriver::VCenterVm.resume(deploy_id, host) - exit 0 + VCenterDriver::VCenterVm.resume(deploy_id, host) rescue Exception => e STDERR.puts "Restore of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/revert_snapshot b/src/vmm_mad/remotes/vcenter/revert_snapshot index 5a2ba4c4de..fa96fc4e6e 100644 --- a/src/vmm_mad/remotes/vcenter/revert_snapshot +++ b/src/vmm_mad/remotes/vcenter/revert_snapshot @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.revert_snapshot(deploy_id, - host, - snapshot_name) - exit 0 + VCenterDriver::VCenterVm.revert_snapshot(deploy_id, + host, + snapshot_name) rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} could not be " + "reverted due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/save b/src/vmm_mad/remotes/vcenter/save index 8ffc2adb72..251c5b2b6a 100644 --- a/src/vmm_mad/remotes/vcenter/save +++ b/src/vmm_mad/remotes/vcenter/save @@ -28,15 +28,22 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' deploy_id = ARGV[0] file = ARGV[1] host = ARGV[2] +vm_id = ARGV[-2] + +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info + +lcm_state = vm.lcm_state_str begin - puts VCenterDriver::VCenterVm.save(deploy_id, host) - exit 0 + puts VCenterDriver::VCenterVm.save(deploy_id, host, lcm_state) rescue Exception => e STDERR.puts "Save of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/shutdown b/src/vmm_mad/remotes/vcenter/shutdown index fd986aff83..565bcd7d3c 100644 --- a/src/vmm_mad/remotes/vcenter/shutdown +++ b/src/vmm_mad/remotes/vcenter/shutdown @@ -28,10 +28,21 @@ $: << RUBY_LIB_LOCATION $: << File.dirname(__FILE__) require 'vcenter_driver' +require 'opennebula' deploy_id = ARGV[0] host = ARGV[1] +vm_id = ARGV[-2] -vmware_drv = VMwareDriver.new(host) +vm = OpenNebula::VirtualMachine.new_with_id(vm_id, OpenNebula::Client.new) +vm.info -vmware_drv.shutdown(deploy_id) +lcm_state = vm.lcm_state_str + +begin + VCenterDriver::VCenterVm.shutdown(deploy_id, host, lcm_state) +rescue Exception => e + STDERR.puts "Shutdown of VM #{deploy_id} on host #{host} failed " + + "due to \"#{e.message}\"" + exit -1 +end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_create b/src/vmm_mad/remotes/vcenter/snapshot_create index 2860826b5c..cc89040dc0 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_create +++ b/src/vmm_mad/remotes/vcenter/snapshot_create @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.create_snapshot(deploy_id, + VCenterDriver::VCenterVm.create_snapshot(deploy_id, host, snapshot_name) - exit 0 rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/snapshot_delete b/src/vmm_mad/remotes/vcenter/snapshot_delete index cf81e3fabe..68e45639bb 100644 --- a/src/vmm_mad/remotes/vcenter/snapshot_delete +++ b/src/vmm_mad/remotes/vcenter/snapshot_delete @@ -34,11 +34,11 @@ snapshot_name = ARGV[1] host = ARGV[3] begin - puts VCenterDriver::VCenterVm.delete_snapshot(deploy_id, - host, - snapshot_name) - exit 0 + VCenterDriver::VCenterVm.delete_snapshot(deploy_id, + host, + snapshot_name) rescue Exception => e STDERR.puts "Snapshot of VM #{deploy_id} on host #{host} failed " + "due to \"#{e.message}\"" + exit -1 end diff --git a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb index 6d5edfe6f2..8f4c0a373b 100644 --- a/src/vmm_mad/remotes/vcenter/vcenter_driver.rb +++ b/src/vmm_mad/remotes/vcenter/vcenter_driver.rb @@ -419,63 +419,16 @@ class VCenterVm # Deploys a VM # @xml_text XML repsentation of the VM ############################################################################ - def self.deploy(xml_text) - - xml = REXML::Document.new xml_text - - pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") - - raise "Cannot find VCenter element in VM template." if pcs.nil? - - template = pcs.find { |t| - type = t.elements["TYPE"] - !type.nil? && type.text.downcase == "vcenter" - } - - raise "Cannot find VCenter element in VM template." if template.nil? - - uuid = template.elements["VM_TEMPLATE"] - - raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? - - uuid = uuid.text - - vmid = xml.root.elements["/VM/ID"].text - - hid = xml.root.elements["//HISTORY_RECORDS/HISTORY/HID"] - - raise "Cannot find host id in deployment file history." if hid.nil? - - connection = VIClient.new(hid) - - vc_template = connection.find_vm_template(uuid) - - relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( - :diskMoveType => :moveChildMostDiskBacking, - :pool => connection.resource_pool) - - clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( - :location => relocate_spec, - :powerOn => true, - :template => false) - - rc = vc_template.CloneVM_Task( - :folder => vc_template.parent, - :name => "one-#{vmid}", - :spec => clone_spec).wait_for_completion - - vm_uuid = rc.config.uuid - - vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] - - if vnc_port - spec = RbVmomi::VIM.VirtualMachineConfigSpec(:extraConfig => - [{:key=>"remotedisplay.vnc.enabled", :value=>"TRUE"}, - {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}]) - rc.ReconfigVM_Task(:spec => spec).wait_for_completion + def self.deploy(xml_text, lcm_state, deploy_id, hostname) + if lcm_state == "BOOT" + return clone_vm(xml_text) + else + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) + vm.PowerOnVM_Task.wait_for_completion + return vm.config.uuid end - - return vm_uuid end ############################################################################ @@ -483,14 +436,21 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.cancel(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) + def self.cancel(deploy_id, hostname, lcm_state) + case lcm_state + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + shutdown(deploy_id, hostname, lcm_state) + when "CANCEL" + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) - vm = connection.find_vm_template(deploy_id) - - vm.PowerOffVM_Task.wait_for_completion - vm.Destroy_Task.wait_for_completion + begin + vm.PowerOffVM_Task.wait_for_completion + rescue + end + vm.Destroy_Task.wait_for_completion + end end ############################################################################ @@ -498,13 +458,17 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.save(deploy_id, hostname) - hid = VIClient::translate_hostname(hostname) - connection = VIClient.new(hid) + def self.save(deploy_id, hostname, lcm_state) + case lcm_state + when "SAVE_MIGRATE" + raise "Migration between vCenters cluster not supported" + when "SAVE_SUSPEND", "SAVE_STOP" + hid = VIClient::translate_hostname(hostname) + connection = VIClient.new(hid) + vm = connection.find_vm_template(deploy_id) - vm = connection.find_vm_template(deploy_id) - - vm.SuspendVM_Task.wait_for_completion + vm.SuspendVM_Task.wait_for_completion + end end ############################################################################ @@ -515,7 +479,6 @@ class VCenterVm def self.resume(deploy_id, hostname) hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) - vm = connection.find_vm_template(deploy_id) vm.PowerOnVM_Task.wait_for_completion @@ -554,14 +517,27 @@ class VCenterVm # @param deploy_id vcenter identifier of the VM # @param hostname name of the host (equals the vCenter cluster) ############################################################################ - def self.shutdown(deploy_id, hostname) + def self.shutdown(deploy_id, hostname, lcm_state) hid = VIClient::translate_hostname(hostname) connection = VIClient.new(hid) vm = connection.find_vm_template(deploy_id) - vm.ShutdownGuest.wait_for_completion - vm.UnregisterVM.wait_for_completion + case lcm_state + when "SHUTDOWN" + begin + vm.ShutdownGuest.wait_for_completion + rescue + end + vm.PowerOffVM_Task.wait_for_completion + vm.Destroy_Task.wait_for_completion + when "SHUTDOWN_POWEROFF", "SHUTDOWN_UNDEPLOY" + begin + vm.ShutdownGuest.wait_for_completion + rescue + end + vm.PowerOffVM_Task.wait_for_completion + end end ############################################################################ @@ -696,7 +672,11 @@ class VCenterVm " TYPE =\"vcenter\",\n"\ " VM_TEMPLATE =\"#{@vm.config.uuid}\"\n"\ "]\n"\ - "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" + "GRAPHICS = [\n"\ + " TYPE =\"vnc\",\n"\ + " LISTEN =\"0.0.0.0\"\n"\ + "]\n"\ + "SCHED_REQUIREMENTS=\"NAME=\\\"#{@vm.runtime.host.parent.name}\\\"\"\n" end private @@ -714,5 +694,75 @@ private 'd' end end + + ######################################################################## + # Clone a vCenter VM Template and leaves it powered on + ######################################################################## + def self.clone_vm(xml_text) + + xml = REXML::Document.new xml_text + + pcs = xml.root.get_elements("//USER_TEMPLATE/PUBLIC_CLOUD") + + raise "Cannot find VCenter element in VM template." if pcs.nil? + + template = pcs.find { |t| + type = t.elements["TYPE"] + !type.nil? && type.text.downcase == "vcenter" + } + + raise "Cannot find VCenter element in VM template." if template.nil? + + uuid = template.elements["VM_TEMPLATE"] + + raise "Cannot find VM_TEMPLATE in VCenter element." if uuid.nil? + + uuid = uuid.text + + vmid = xml.root.elements["/VM/ID"].text + + hid = xml.root.elements["//HISTORY_RECORDS/HISTORY/HID"] + + raise "Cannot find host id in deployment file history." if hid.nil? + + connection = VIClient.new(hid) + + vc_template = connection.find_vm_template(uuid) + + relocate_spec = RbVmomi::VIM.VirtualMachineRelocateSpec( + :diskMoveType => :moveChildMostDiskBacking, + :pool => connection.resource_pool) + + clone_spec = RbVmomi::VIM.VirtualMachineCloneSpec( + :location => relocate_spec, + :powerOn => true, + :template => false) + + rc = vc_template.CloneVM_Task( + :folder => vc_template.parent, + :name => "one-#{vmid}", + :spec => clone_spec).wait_for_completion + + vm_uuid = rc.config.uuid + + vnc_port = xml.root.elements["/VM/TEMPLATE/GRAPHICS/PORT"] + vnc_listen = xml.root.elements["/VM/TEMPLATE/GRAPHICS/LISTEN"] + + if !vnc_listen + vnc_listen = "0.0.0.0" + else + vnc_listen = vnc_listen.text + end + + if vnc_port + spec = RbVmomi::VIM.VirtualMachineConfigSpec(:extraConfig => + [{:key=>"remotedisplay.vnc.enabled", :value=>"TRUE"}, + {:key=>"remotedisplay.vnc.port", :value=>vnc_port.text}, + {:key=>"remotedisplay.vnc.ip", :value=>vnc_listen}]) + rc.ReconfigVM_Task(:spec => spec).wait_for_completion + end + + return vm_uuid + end end end \ No newline at end of file