[naily astute] Add remove_nodes methods.
This commit is contained in:
parent
002b087320
commit
aa64c2201f
@ -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}"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user