[naily astute] Add remove_nodes methods.

This commit is contained in:
Andrey Danin 2012-11-07 21:19:37 +04:00
parent 002b087320
commit aa64c2201f
5 changed files with 114 additions and 34 deletions

View File

@ -30,6 +30,12 @@ module Astute
return
end
def remove_nodes(reporter, task_id, nodes)
context = Context.new(task_id, reporter)
result = simple_remove_nodes(context, nodes)
return result
end
def verify_networks(reporter, task_id, nodes, networks)
context = Context.new(task_id, reporter)
result = @check_network.call(context, nodes, networks)
@ -40,6 +46,41 @@ module Astute
end
private
def simple_remove_nodes(ctx, nodes)
if nodes.empty?
Astute.logger.info "#{ctx.task_id}: Nodes to remove are not provided. Do nothing."
return {'nodes' => nodes}
end
uids = nodes.map {|n| n['uid']}
Astute.logger.info "#{ctx.task_id}: Starting removing of nodes: #{uids.inspect}"
remover = MClient.new(ctx, "erase_node", uids, check_result=false)
result = remover.erase_node(:reboot => true)
Astute.logger.debug "#{ctx.task_id}: Data resieved from nodes: #{result.inspect}"
inaccessible_uids = uids - result.map {|n| n.results[:sender]}
error_nodes = []
erased_nodes = []
result.each do |n|
if n.results[:statuscode] != 0
error_nodes << {'uid' => n.results[:sender],
'error' => "RPC agent 'erase_node' failed. Result: #{n.results.inspect}"}
elsif not n.results[:data][:rebooted]
error_nodes << {'uid' => n.results[:sender],
'error' => "RPC method 'erase_node' failed with message: #{n.results[:data][:error_msg]}"}
else
erased_nodes << {'uid' => n.results[:sender]}
end
end
error_nodes.concat(inaccessible_uids.map {|n| {'uid' => n, 'error' => "Node not answered by RPC."}})
if error_nodes.empty?
answer = {'nodes' => erased_nodes}
else
answer = {'status' => 'error', 'nodes' => erased_nodes, 'error_nodes' => error_nodes}
Astute.logger.error "#{ctx.task_id}: Removing of nodes #{uids.inspect} ends with errors: #{error_nodes.inspect}"
end
Astute.logger.info "#{ctx.task_id}: Finished removing of nodes: #{uids.inspect}"
return answer
end
def deploy_piece(ctx, nodes)
nodes_roles = nodes.map { |n| { n['uid'] => n['role'] } }
Astute.logger.info "#{ctx.task_id}: Starting deployment of nodes => roles: #{nodes_roles.inspect}"

View File

@ -6,7 +6,7 @@ metadata :name => "Erase node bootloader",
:url => "http://mirantis.com",
:timeout => 40
action "erase_node", :description => "Zeroing of raw disk" do
action "erase_node", :description => "Zeroing of boot device" do
display :always
end

View File

@ -5,36 +5,7 @@ module MCollective
module Agent
class Erase_node<RPC::Agent
action "erase_node" do
validate :file, String
if File.exist?(request[:file])
if request.data.key?(:get_data) and request.data[:get_data] != ''
header = get_data(request[:file], 512)
reply[:erased_data] = Base64.encode64(header)
end
request_reboot = request.data.key?(:reboot) and request.data[:reboot] != ''
if request.data.key?(:dry_run) and request.data[:dry_run] != ''
reply[:status] = true
reply[:dry_run] = true
if request_reboot
reply[:reboot] = true
end
else
begin
erase_data(request[:file], 512)
reply[:status] = true
if request_reboot
reboot
reply[:reboot] = true
end
rescue Exception => e
reply[:status] = false
reply[:error_msg] = e.message
end
end
else
reply[:status] = false
reply[:error_msg] = "File \"#{request[:file]}\" not exist."
end
erase_node
end
action "reboot_node" do
@ -43,8 +14,69 @@ module MCollective
private
def erase_node
request_reboot = request.data[:reboot]
dry_run = request.data[:dry_run]
error_msg = []
reply[:status] = 0 # Shell exitcode behaviour
begin
boot_device = get_boot_device
erase_data(boot_device, 512) unless dry_run
reply[:erased] = true
rescue Exception => e
reply[:erased] = false
reply[:status] += 1
msg = "MBR can't be erased. Reason: #{e.message};"
Log.error(msg)
error_msg << msg
end
begin
reboot if not dry_run and request_reboot
reply[:rebooted] = true
rescue Exception => e
reply[:rebooted] = false
reply[:status] += 1
msg = "Can't reboot node. Reason: #{e.message};"
Log.error(msg)
error_msg << "Can't reboot node. Reason: #{e.message};"
end
unless error_msg.empty?
reply[:error_msg] = error_msg.join(' ')
end
end
def get_boot_device
dev_map = '/boot/grub/device.map'
grub_conf = '/boot/grub/grub.conf'
# Look boot device at GRUB device.map file
if File.file?(dev_map) and File.readable?(dev_map)
open(dev_map).readlines.each do |l|
line = l.strip
unless line.start_with?('#')
grub_dev, kernel_dev = line.split(%r{[ |\t]+})
return kernel_dev if grub_dev == '(hd0)'
end
end
end
# Look boot device at GRUB config autogenerated file
if File.file?(grub_conf) and File.readable?(grub_conf)
open(grub_conf).readlines.each do |l|
line = l.strip
if line.start_with?('#boot=')
grub_dev, kernel_dev = line.split('=')
return kernel_dev
end
end
end
# If nothing found
raise 'Boot device not found.'
end
def reboot
cmd = "/bin/sleep 5; /sbin/shutdown -r"
cmd = "/bin/sleep 5; /sbin/shutdown -r now"
pid = fork { system(cmd) }
Process.detach(pid)
end

View File

@ -45,6 +45,13 @@ module Naily
report_result(result, reporter)
end
def remove_nodes(data)
reporter = Naily::Reporter.new(@producer, data['respond_to'], data['args']['task_uuid'])
nodes = data['args']['nodes']
result = @orchestrator.remove_nodes(reporter, data['args']['task_uuid'], nodes)
report_result(result, reporter)
end
private
def report_result(result, reporter)
result = {} unless result.instance_of?(Hash)

View File

@ -38,7 +38,7 @@ module Naily
unless @delegate.respond_to?(data['method'])
Naily.logger.error "Unsupported RPC call #{data['method']}"
if data['respond_to']
reporter = Naily::Reporter.new(@publisher, data['respond_to'], data['args']['task_uuid'])
reporter = Naily::Reporter.new(@producer, data['respond_to'], data['args']['task_uuid'])
reporter.report({'status' => 'error', 'error' => "Unsupported method '#{data['method']}' called."})
end
return
@ -51,7 +51,7 @@ module Naily
rescue Exception => e
Naily.logger.error "Error running RPC method #{data['method']}: #{e.message}, trace: #{e.backtrace.inspect}"
if data['respond_to']
reporter = Naily::Reporter.new(@publisher, data['respond_to'], data['args']['task_uuid'])
reporter = Naily::Reporter.new(@producer, data['respond_to'], data['args']['task_uuid'])
reporter.report({'status' => 'error', 'error' => "Error occured while running method '#{data['method']}'. See logs of Naily for details."})
end
return