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

feature #863: added comments, simpler log messages. Now the main action info is the one returned to OpenNebula core

This commit is contained in:
Ruben S. Montero 2011-11-30 22:56:52 +01:00
parent b2c04d65cd
commit 5414c03028
2 changed files with 231 additions and 223 deletions

View File

@ -24,7 +24,7 @@ module DriverExecHelper
:failure => "FAILURE"
}
def failed?(rc_str)
def self.failed?(rc_str)
return rc_str == RESULT[:failure]
end

View File

@ -40,13 +40,20 @@ require 'pp'
class VmmAction
attr_reader :data
# Initialize a VmmAction object
# @param[OpenNebula::ExecDriver] Driver to be used for the actions
# @param[String] Id of the VM
# @param[String] name of the actions as described in the VMM protocol
# @param[xml_data] data sent from OpenNebula core
def initialize(driver, id, action, xml_data)
@vmm=driver
@id=id
@main_action=action
@xml_data=@vmm.decode(xml_data)
# Initialize object with xml data
@vmm = driver
@id = id
@data=Hash.new
@main_action = action
@xml_data = @vmm.decode(xml_data)
@data = Hash.new
get_data(:host)
get_data(:net_drv)
@ -76,6 +83,115 @@ class VmmAction
end
end
#Execute a set of steps defined with
# - :driver :vmm or :vnm to execute the step
# - :action for the step
# - :parameters command line paremeters for the action
# - :destination use next host
# - :fail_action steps to be executed if steps fail
# - :stdin for the action
# @param [Array] of steps
def run(steps, info_on_success = nil)
result = execute_steps(steps)
#Prepare the info for the OpenNebula core
if DriverExecHelper.failed?(result)
info = @data[:failed_info]
else
info = @data["#{@main_action.to_s}_info".to_sym]
end
@vmm.send_message(VirtualMachineDriver::ACTION[@main_action],
result, @id, info)
end
private
DRIVER_NAMES = {
:vmm => "virtualization driver"
:vnm => "network driver"
}
# Executes a set of steps. If one step fails any recover action is performed
# and the step execution breaks.
# @param [Array] array of steps to be executed
# @return [String, Hash] "SUCCESS/FAILURE" for the step set, and
# information associated to each step (by :<action>_info). In case of
# failure information is also in [:failed_info]
def execute_steps(steps)
steps.each do |step|
# Execute Step
case step[: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[:parameters]),
@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
result = DriverExecHelper.RESULT[:failure]
info = "No driver in #{step[:action]}"}
end
# Save the step info
@data["#{step[:action]}_info".to_sym] = info
# Roll back steps, store failed info and break steps
if DriverExecHelper.failed?(result)
execute_steps(@data[:fail_actions]) if @data[:fail_actions]
@data[:failed_info] = info
@vmm.log(@id,
"Failed to execute #{DRIVER_NAMES[step[:driver]]} " \
"operation: #{step[:action]}.")
break
else
@vmm.log(@id,
"Sussecfully execute #{DRIVER_NAMES[step[:driver]]} " \
"operation: #{step[:action]}.")
end
end
return result
end
# Prepare the parameters for the action step generating a blanck separated
# list of command arguments
# @param [Hash] an action step
def get_parameters(step_params)
parameters = step_params || []
parameters.map do |param|
if Symbol===param
@data[param].to_s
else
param
end
end.join(' ')
end
# Extracts data from the XML argument of the VMM action
# @param [Symbol] corresponding to a XML element
# @param [String] an xpath for the XML element
# @return [String] the element value
def get_data(name, xml_path=nil)
if xml_path
path=xml_path.to_s
@ -85,94 +201,6 @@ class VmmAction
@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
@ -180,7 +208,9 @@ end
class ExecDriver < VirtualMachineDriver
attr_reader :options
# SshDriver constructor
# Initializes the VMM driver
# @param [String] hypervisor name identifies the plugin
# @param [OpenNebulaDriver::options]
def initialize(hypervisor, options={})
@options={
:threaded => true
@ -191,20 +221,26 @@ class ExecDriver < VirtualMachineDriver
@hypervisor = hypervisor
end
# Creates an SshStream to execute commands on the target host
# @param[String] the hostname of the host
# @param[String] id of the VM to log messages
# @return [SshStreamCommand]
def get_ssh_stream(host, id)
SshStreamCommand.new(host,
@remote_scripts_base_path,
log_method(id))
end
#---------------------------------------------------------------------------
# Virtual Machine Manager Protocol Actions
#---------------------------------------------------------------------------
#
# DEPLOY action, sends the deployment file to remote host
#
def deploy(id, drv_message)
# ----------------------------------------------------------------------
# Initialization of deployment data
# ----------------------------------------------------------------------
action=VmmAction.new(self, id, :deploy, drv_message)
local_dfile=action.data[:local_dfile]
if !local_dfile || File.zero?(local_dfile)
@ -221,28 +257,33 @@ class ExecDriver < VirtualMachineDriver
dfile = action.data[:remote_dfile]
end
# ----------------------------------------------------------------------
# Deployment Steps
# ----------------------------------------------------------------------
action = VmmAction.new(self, id, :deploy, drv_message)
steps=[
# Execute pre-boot networking setup
{
:driver => :vnm,
:action => :pre,
:post_log => "Successfully executed network driver " <<
"#{action.data[:net_drv]} (pre-boot)"
:driver => :vnm,
:action => :pre
},
# Boot the Virtual Machine
{
:driver => :vmm,
:action => :deploy,
:parameters => [dfile, :host],
:stdin => domain,
:save_info => :deploy_id
},
:driver => :vmm,
:action => :deploy,
:parameters => [dfile, :host],
:stdin => domain
},
# Execute post-boot networking setup
{
:driver => :vnm,
:action => :post,
:fail_actions => [
:driver => :vnm,
:action => :post,
:fail_actions => [
{
:driver => :vmm,
:action => :cancel,
:parameters => [:deploy_id, :host]
:parameters => [:deploy_info, :host]
}
]
}
@ -251,187 +292,149 @@ class ExecDriver < VirtualMachineDriver
action.run(steps)
end
# Basic Domain Management Operations
#
# SHUTDOWN action, graceful shutdown and network clean up
#
def shutdown(id, drv_message)
action=VmmAction.new(self, id, :shutdown, drv_message)
action = VmmAction.new(self, id, :shutdown, drv_message)
steps=[
# Shutdown the Virtual Machine
{
:driver => :vmm,
:action => :shutdown,
:parameters => [:deploy_id, :host],
:post_log => "Successfully shut down VM with id: " <<
action.data[:deploy_id]
:parameters => [:deploy_id, :host]
},
# Execute networking clean up operations
{
:driver => :vnm,
:action => :clean,
:post_log => "Successfully executed network driver " <<
"#{action.data[:net_drv]} (clean-shutdown)"
:driver => :vnm,
:action => :clean
}
}
action.run(steps)
end
#
# CANCEL action, destroys a VM and network clean up
#
def cancel(id, drv_message)
action=VmmAction.new(self, id, :cancel, drv_message)
action = VmmAction.new(self, id, :cancel, drv_message)
steps=[
# Cancel the Virtual Machine
{
:driver => :vmm,
:action => :cancel,
:parameters => [:deploy_id, :host],
:post_log => "Successfully canceled VM with id: " <<
action.data[:deploy_id]
:parameters => [:deploy_id, :host]
},
# Execute networking clean up operations
{
:driver => :vnm,
:action => :clean,
:post_log => "Successfully executed network driver " <<
"#{action.data[:net_drv]} (clean-cancel)"
:driver => :vnm,
:action => :clean
}
]
action.run(steps)
end
#
# SAVE action, stops the VM and saves its state, network is cleaned up
#
def save(id, drv_message)
action=VmmAction.new(self, id, :save, drv_message)
action = VmmAction.new(self, id, :save, drv_message)
steps=[
# Save the Virtual Machine state
{
:driver => :vmm,
:action => :save,
:parameters => [:deploy_id, :checkpoint_file, :host],
:post_log => "Successfully saved VM with id: " <<
action.data[:deploy_id]
:parameters => [:deploy_id, :checkpoint_file, :host]
},
# Execute networking clean up operations
{
:driver => :vnm,
:action => :clean,
:post_log => "Successfully executed network driver " <<
"#{action.data[:net_drv]} (clean-save)"
:driver => :vnm,
:action => :clean
}
]
action.run(steps)
end
#
# RESTORE action, restore a VM from a previous state, and restores network
#
def restore(id, drv_message)
action=VmmAction.new(self, id, :restore, drv_message)
steps=[
# Execute pre-boot networking setup
{
:driver => :vnm,
:action => :pre,
:post_log => "Successfully executed network driver " <<
"#{action.data[:net_drv]} (pre-restore)"
:action => :pre
},
# Restore the Virtual Machine from checkpoint
{
:driver => :vmm,
:action => :restore,
:parameters => [:checkpoint_file, :host],
:save_info => :deploy_id,
:post_log => "Successfully restored VM with id: " <<
action.data[:deploy_id]
:parameters => [:checkpoint_file, :host]
},
# Execute post-boot networking setup
{
:driver => :vnm,
:action => :post,
:fail_actions => [
: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)"
}
]
action.run(steps)
end
#
# MIGRATE (live) action, migrates a VM to another host creating network
#
def migrate(id, drv_message)
data = decode(drv_message)
net_drv = data.elements['NET_DRV'].text
host = data.elements['HOST'].text
deploy_id = data.elements['DEPLOY_ID'].text
dest_host = data.elements['MIGR_HOST'].text
dest_driver = data.elements['MIGR_NET_DRV'].text
action=VmmAction.new(self, id, :migrate, drv_message)
ssh_src = SshStreamCommand.new(host,
@remote_scripts_base_path,
log_method(id))
steps=[
# Execute pre-boot networking setup on migrating host
{
:driver => :vnm,
:action => :pre,
:destination => true
},
# Migrate the Virtual Machine
{
:driver => :vmm,
:action => :migrate,
:parameters => [:deploy_id, :migr_host, :host]
},
# Execute networking clean up operations
{
:driver => :vnm,
:action => :clean
},
# Execute post-boot networking setup on migrating host
{
:driver => :vnm,
:action => :post,
:destination => :true
#TODO :fail_action what to do here? cancel VM?
},
]
ssh_dst = SshStreamCommand.new(dest_host,
@remote_scripts_base_path,
log_method(id))
vnm_src = VirtualNetworkDriver.new(net_drv,
:local_actions => @options[:local_actions],
:message => data,
:ssh_stream => ssh_src)
vnm_dst = VirtualNetworkDriver.new(dest_driver,
:local_actions => @options[:local_actions],
:message => data,
:ssh_stream => ssh_dst)
# ----------------------------------------------------------------------
# Execute pre-boot action of the network driver
# ----------------------------------------------------------------------
result, info = vnm_dst.do_action(id, :pre)
if failed?(result)
send_message(ACTION[:migrate], result, id,info)
return
end
log(id, "Successfully executed network driver #{net_drv} (pre-migrate)")
result, info = do_action("#{deploy_id} #{dest_host} #{host}", id, host,
:migrate,
:save,
:ssh_stream => ssh_src,
:respond => false)
if failed?(result)
send_message(ACTION[:migrate], result, id, info)
return
end
log(id, "Successfully migrated VM with id: #{deploy_id}")
# ----------------------------------------------------------------------
# Execute post-migrate action of the network driver
# ----------------------------------------------------------------------
result, info = vnm_dst.do_action(id, :post)
if failed?(result)
log(id, "Failed to executed network driver #{dest_driver} (post-migrate)")
log(id, "Canceling VM with id: #{deploy_id}")
do_action("#{deploy_id} #{host}", id, dest_host, :cancel,
:ssh_stream => ssh_dst,
: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, deploy_id)
action.run(steps)
end
#
# POLL action, gets information of a VM
#
def poll(id, drv_message)
data = decode(drv_message)
host = data.elements['HOST'].text
@ -441,7 +444,12 @@ class ExecDriver < VirtualMachineDriver
end
end
# SshDriver Main program
################################################################################
#
# Virtual Machine Manager Execution Driver - Main Program
#
################################################################################
opts = GetoptLong.new(
[ '--retries', '-r', GetoptLong::OPTIONAL_ARGUMENT ],
[ '--threads', '-t', GetoptLong::OPTIONAL_ARGUMENT ],