From ab10f16d507f5d0e1db22c5c999a90851768e6c6 Mon Sep 17 00:00:00 2001 From: Javi Fontan Date: Tue, 29 Nov 2011 19:43:13 +0100 Subject: [PATCH] feature #863: added a configurable action system and changed some actions to use it --- src/vmm_mad/exec/one_vmm_exec.rb | 501 ++++++++++++++++--------------- 1 file changed, 264 insertions(+), 237 deletions(-) diff --git a/src/vmm_mad/exec/one_vmm_exec.rb b/src/vmm_mad/exec/one_vmm_exec.rb index 6e73a14d09..6a6b021e73 100755 --- a/src/vmm_mad/exec/one_vmm_exec.rb +++ b/src/vmm_mad/exec/one_vmm_exec.rb @@ -37,8 +37,148 @@ require 'ssh_stream' require 'pp' +class VmmAction + attr_reader :data + + def initialize(driver, id, action, xml_data) + @vmm=driver + @id=id + @main_action=action + @xml_data=@vmm.decode(xml_data) + + @data=Hash.new + + get_data(:host) + get_data(:net_drv) + get_data(:deploy_id) + get_data(:checkpoint_file) + + get_data(:local_dfile, :LOCAL_DEPLOYMENT_FILE) + get_data(:remote_dfile, :REMOTE_DEPLOYMENT_FILE) + + # For migration + get_data(:dest_host, :MIGR_HOST) + get_data(:dest_driver, :MIGR_NET_DRV) + + # Initialize streams and vnm + @ssh_src = @vmm.get_ssh_stream(@data[:host], @id) + @vnm_src = VirtualNetworkDriver.new(@data[:net_drv], + :local_actions => @vmm.options[:local_actions], + :message => @xml_data, + :ssh_stream => @ssh_src) + + if @data[:dest_host] and !@data[:dest_host].empty? + @ssh_dst = @vmm.get_ssh_stream(@data[:dest_host], @id) + @vnm_dst = VirtualNetworkDriver.new(@data[:dest_driver], + :local_actions => @vmm.options[:local_actions], + :message => @xml_data, + :ssh_stream => @ssh_dst) + end + end + + def get_data(name, xml_path=nil) + if xml_path + path=xml_path.to_s + else + path=name.to_s.upcase + end + + @data[name]=@xml_data.elements[path].text + end + +=begin + { + :driver => :vmm, + :action => :deploy, + :parameters => [:host, :deploy_id], + :destination => false + :save_info => :deploy_id, + :fail_actions => [], + :pre_log => "", + :post_log => "", + :stdin => nil + } +=end + + def execute_steps(steps) + result=false + info='Action #{step[:action]} not found' + + steps.each do |step| + + driver=step[:driver] || :vmm + + @vmm.log(@id, @data[:pre_log]) if @data[:pre_log] + + case driver + when :vmm + if step[:destination] + host = @data[:dest_host] + ssh = @ssh_dst + else + host = @data[:host] + ssh = @ssh_src + end + + result, info=@vmm.do_action(get_parameters(step), @id, host, + step[:action], + :ssh_stream => ssh, + :respond => false, + :stdin => step[:stdin]) + + when :vnm + if step[:destination] + vnm=@vnm_dst + else + vnm=@vnm_src + end + + result, info=vnm.do_action(@id, step[:action]) + else + end + + # Save the info variable if asked for + if @data[:save_info] + @data[@data[:save_info]]=info + end + + if @vmm.failed?(result) + if @data[:fail_actions] + execute_steps(@data[:fail_actions]) + end + + break + end + + @vmm.log(@id, @data[:post_log]) if @data[:post_log] + end + + return result, info + end + + def run(steps) + result, info=execute_steps(steps) + + @vmm.send_message(VirtualMachineDriver::ACTION[@main_action], + result, @id, info) + end + + def get_parameters(step) + parameters=step[:parameters] || [] + parameters.map do |param| + if Symbol===param + @data[param].to_s + else + param + end + end.join(' ') + end +end + + # The main class for the Sh driver class ExecDriver < VirtualMachineDriver + attr_reader :options # SshDriver constructor def initialize(hypervisor, options={}) @@ -51,19 +191,21 @@ class ExecDriver < VirtualMachineDriver @hypervisor = hypervisor end + def get_ssh_stream(host, id) + SshStreamCommand.new(host, + @remote_scripts_base_path, + log_method(id)) + end + # DEPLOY action, sends the deployment file to remote host def deploy(id, drv_message) # ---------------------------------------------------------------------- # Initialization of deployment data # ---------------------------------------------------------------------- - data = decode(drv_message) + action=VmmAction.new(self, id, :deploy, drv_message) - local_dfile = data.elements['LOCAL_DEPLOYMENT_FILE'].text - remote_dfile = data.elements['REMOTE_DEPLOYMENT_FILE'].text - - host = data.elements['HOST'].text - net_drv = data.elements['NET_DRV'].text + local_dfile=action.data[:local_dfile] if !local_dfile || File.zero?(local_dfile) send_message(ACTION[:deploy],RESULT[:failure],id, @@ -74,263 +216,146 @@ class ExecDriver < VirtualMachineDriver domain = File.read(local_dfile) if action_is_local?(:deploy) - dfile = local_dfile + dfile = action.data[:local_dfile] else - dfile = remote_dfile + dfile = action.data[:remote_dfile] end - ssh = SshStreamCommand.new(host, - @remote_scripts_base_path, - log_method(id)) + steps=[ + { + :driver => :vnm, + :action => :pre, + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (pre-boot)" + }, + { + :driver => :vmm, + :action => :deploy, + :parameters => [dfile, :host], + :stdin => domain, + :save_info => :deploy_id + }, + { + :driver => :vnm, + :action => :post, + :fail_actions => [ + { + :driver => :vmm, + :action => :cancel, + :parameters => [:deploy_id, :host] + } + ] + } + ] - vnm = VirtualNetworkDriver.new(net_drv, - :local_actions => @options[:local_actions], - :message => data, - :ssh_stream => ssh) - - # ---------------------------------------------------------------------- - # Execute pre-boot action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :pre) - - if failed?(result) - send_message(ACTION[:deploy], result, id,info) - return - end - - log(id, "Successfully executed network driver #{net_drv} (pre-boot)") - - # ---------------------------------------------------------------------- - # Boot the VM - # ---------------------------------------------------------------------- - - result, info = do_action("#{dfile} #{host}", id, host, :deploy, - :stdin => domain, - :ssh_stream => ssh, - :respond => false) - if failed?(result) - send_message(ACTION[:deploy], result, id, info) - return - end - - deploy_id = info - - log(id, "Successfully booted VM with id: #{deploy_id}") - - # ---------------------------------------------------------------------- - # Execute post-boot action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :post) - - if failed?(result) - log(id, "Failed to executed network driver #{net_drv} (post-boot)") - log(id, "Canceling VM with id: #{deploy_id}") - - do_action("#{deploy_id} #{host}", id, host, :cancel, - :ssh_stream => ssh, - :respond => false) - - send_message(ACTION[:deploy], result, id, info) - return - end - - log(id, "Successfully executed network driver #{net_drv} (post-boot)") - - send_message(ACTION[:deploy], RESULT[:success], id, deploy_id) + action.run(steps) end # Basic Domain Management Operations def shutdown(id, drv_message) - data = decode(drv_message) - host = data.elements['HOST'].text - net_drv = data.elements['NET_DRV'].text - deploy_id = data.elements['DEPLOY_ID'].text + action=VmmAction.new(self, id, :shutdown, drv_message) - ssh = SshStreamCommand.new(host, - @remote_scripts_base_path, - log_method(id)) + steps=[ + { + :driver => :vmm, + :action => :shutdown, + :parameters => [:deploy_id, :host], + :post_log => "Successfully shut down VM with id: " << + action.data[:deploy_id] + }, + { + :driver => :vnm, + :action => :clean, + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (clean-shutdown)" + } + } - vnm = VirtualNetworkDriver.new(net_drv, - :local_actions => @options[:local_actions], - :message => data, - :ssh_stream => ssh) - - result, info = do_action("#{deploy_id} #{host}", id, host, :shutdown, - :ssh_stream => ssh, - :respond => false) - - if failed?(result) - send_message(ACTION[:shutdown], result, id,info) - return - end - - log(id, "Successfully shut down VM with id: #{deploy_id}") - - # ---------------------------------------------------------------------- - # Execute clean action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :clean) - - if failed?(result) - send_message(ACTION[:shutdown], result, id,info) - return - end - - log(id, "Successfully executed network driver #{net_drv}" << - " (clean-shutdown)") + action.run(steps) end def cancel(id, drv_message) - data = decode(drv_message) - host = data.elements['HOST'].text - net_drv = data.elements['NET_DRV'].text - deploy_id = data.elements['DEPLOY_ID'].text + action=VmmAction.new(self, id, :cancel, drv_message) - ssh = SshStreamCommand.new(host, - @remote_scripts_base_path, - log_method(id)) + steps=[ + { + :driver => :vmm, + :action => :cancel, + :parameters => [:deploy_id, :host], + :post_log => "Successfully canceled VM with id: " << + action.data[:deploy_id] + }, + { + :driver => :vnm, + :action => :clean, + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (clean-cancel)" + } + ] - vnm = VirtualNetworkDriver.new(net_drv, - :local_actions => @options[:local_actions], - :message => data, - :ssh_stream => ssh) - - result, info = do_action("#{deploy_id} #{host}", id, host, :cancel, - :ssh_stream => ssh, - :respond => false) - - if failed?(result) - send_message(ACTION[:cancel], result, id,info) - return - end - - log(id, "Successfully canceled VM with id: #{deploy_id}") - - # ---------------------------------------------------------------------- - # Execute clean action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :clean) - - if failed?(result) - send_message(ACTION[:cancel], result, id,info) - return - end - - log(id, "Successfully executed network driver #{net_drv}" << - " (clean-cancel)") - - send_message(ACTION[:shutdown], RESULT[:success], id, deploy_id) + action.run(steps) end def save(id, drv_message) - data = decode(drv_message) - host = data.elements['HOST'].text - net_drv = data.elements['NET_DRV'].text - deploy_id = data.elements['DEPLOY_ID'].text - file = data.elements['CHECKPOINT_FILE'].text + action=VmmAction.new(self, id, :save, drv_message) - ssh = SshStreamCommand.new(host, - @remote_scripts_base_path, - log_method(id)) + steps=[ + { + :driver => :vmm, + :action => :save, + :parameters => [:deploy_id, :checkpoint_file, :host], + :post_log => "Successfully saved VM with id: " << + action.data[:deploy_id] + }, + { + :driver => :vnm, + :action => :clean, + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (clean-save)" + } + ] - vnm = VirtualNetworkDriver.new(net_drv, - :local_actions => @options[:local_actions], - :message => data, - :ssh_stream => ssh) - - result, info = do_action("#{deploy_id} #{file} #{host}", id, host, - :save, - :ssh_stream => ssh, - :respond => false) - - if failed?(result) - send_message(ACTION[:save], result, id,info) - return - end - - log(id, "Successfully saved VM with id: #{deploy_id}") - - # ---------------------------------------------------------------------- - # Execute clean action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :clean) - - if failed?(result) - send_message(ACTION[:save], result, id,info) - return - end - - log(id, "Successfully executed network driver #{net_drv}" << - " (clean-save)") - - send_message(ACTION[:save], RESULT[:success], id, domain_id) + action.run(steps) end def restore(id, drv_message) - data = decode(drv_message) - host = data.elements['HOST'].text - file = data.elements['CHECKPOINT_FILE'].text + action=VmmAction.new(self, id, :restore, drv_message) - ssh = SshStreamCommand.new(host, - @remote_scripts_base_path, - log_method(id)) + steps=[ + { + :driver => :vnm, + :action => :pre, + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (pre-restore)" + }, + { + :driver => :vmm, + :action => :restore, + :parameters => [:checkpoint_file, :host], + :save_info => :deploy_id, + :post_log => "Successfully restored VM with id: " << + action.data[:deploy_id] + }, + { + :driver => :vnm, + :action => :post, + :fail_actions => [ + { + :pre_log => "Failed to execute network driver" << + "#{action.data[:net_drv]} (post-restore). " << + "Cancelling VM with id: #{action.data[:deploy_id]}" + :driver => :vmm, + :action => :cancel, + :parameters => [:deploy_id, :host] + } + ], + :post_log => "Successfully executed network driver " << + "#{action.data[:net_drv]} (post-restore)" + } + ] - vnm = VirtualNetworkDriver.new(net_drv, - :local_actions => @options[:local_actions], - :message => data, - :ssh_stream => ssh) - - # ---------------------------------------------------------------------- - # Execute pre-boot action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :pre) - - if failed?(result) - send_message(ACTION[:restore], result, id,info) - return - end - - log(id, "Successfully executed network driver #{net_drv} (pre-restore)") - - result, info = do_action("#{file} #{host}", id, host, :restore, - :save, - :ssh_stream => ssh, - :respond => false) - if failed?(result) - send_message(ACTION[:restore], result, id, info) - return - end - - log(id, "Successfully restored VM with id: #{info}") - - # ---------------------------------------------------------------------- - # Execute post-restore action of the network driver - # ---------------------------------------------------------------------- - - result, info = vnm.do_action(id, :post) - - if failed?(result) - log(id, "Failed to executed network driver #{net_drv} (post-restore)") - log(id, "Canceling VM with id: #{domain_id}") - - do_action("#{domain_id} #{host}", id, host, :cancel, - :ssh_stream => ssh, - :respond => false) - - send_message(ACTION[:restore], result, id, info) - return - end - - log(id, "Successfully executed network driver #{net_drv} (post-restore)") - - send_message(ACTION[:restore], RESULT[:success], id, domain_id) + action.run(steps) end def migrate(id, drv_message) @@ -455,3 +480,5 @@ exec_driver = ExecDriver.new(hypervisor, :local_actions => local_actions) exec_driver.start_driver + +