1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-03-22 18:50:08 +03:00

feature #863: added a configurable action system and changed some actions to use it

This commit is contained in:
Javi Fontan 2011-11-29 19:43:13 +01:00
parent 09fe832399
commit ab10f16d50

View File

@ -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