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:
parent
b2c04d65cd
commit
5414c03028
@ -24,7 +24,7 @@ module DriverExecHelper
|
||||
:failure => "FAILURE"
|
||||
}
|
||||
|
||||
def failed?(rc_str)
|
||||
def self.failed?(rc_str)
|
||||
return rc_str == RESULT[:failure]
|
||||
end
|
||||
|
||||
|
@ -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 ],
|
||||
|
Loading…
x
Reference in New Issue
Block a user