redis-trib: All output wrapped by a specific function.

This is needed in order to colorize it as next step.
We use conventions in output messages such as

>>> This is an action
*** This is a warning
[ERR] This is an error
[OK] That's fine

And so forth, so that a color will be associated checking the first
three chars.
This commit is contained in:
antirez 2013-03-22 17:39:43 +01:00
parent be7bdd376e
commit c195289e5e

View File

@ -27,8 +27,7 @@ require 'redis'
ClusterHashSlots = 16384 ClusterHashSlots = 16384
def xputs(s) def xputs(s)
printf s puts s
STDOUT.flush
end end
class ClusterNode class ClusterNode
@ -67,23 +66,23 @@ class ClusterNode
def connect(o={}) def connect(o={})
return if @r return if @r
xputs "Connecting to node #{self}: " print "Connecting to node #{self}: "
STDOUT.flush
begin begin
@r = Redis.new(:host => @info[:host], :port => @info[:port]) @r = Redis.new(:host => @info[:host], :port => @info[:port])
@r.ping @r.ping
rescue rescue
puts "ERROR" xputs "[ERR] Sorry, can't connect to node #{self}"
puts "Sorry, can't connect to node #{self}"
exit 1 if o[:abort] exit 1 if o[:abort]
@r = nil @r = nil
end end
puts "OK" xputs "OK"
end end
def assert_cluster def assert_cluster
info = @r.info info = @r.info
if !info["cluster_enabled"] || info["cluster_enabled"].to_i == 0 if !info["cluster_enabled"] || info["cluster_enabled"].to_i == 0
puts "Error: Node #{self} is not configured as a cluster node." xputs "[ERR] Node #{self} is not configured as a cluster node."
exit 1 exit 1
end end
end end
@ -91,7 +90,7 @@ class ClusterNode
def assert_empty def assert_empty
if !(@r.cluster("info").split("\r\n").index("cluster_known_nodes:1")) || if !(@r.cluster("info").split("\r\n").index("cluster_known_nodes:1")) ||
(@r.info['db0']) (@r.info['db0'])
puts "Error: Node #{self} is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0." xputs "[ERR] Node #{self} is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0."
exit 1 exit 1
end end
end end
@ -241,7 +240,7 @@ class RedisTrib
def check_arity(req_args, num_args) def check_arity(req_args, num_args)
if ((req_args > 0 and num_args != req_args) || if ((req_args > 0 and num_args != req_args) ||
(req_args < 0 and num_args < req_args.abs)) (req_args < 0 and num_args < req_args.abs))
puts "Wrong number of arguments for specified sub command" xputs "[ERR] Wrong number of arguments for specified sub command"
exit 1 exit 1
end end
end end
@ -252,7 +251,7 @@ class RedisTrib
def cluster_error(msg) def cluster_error(msg)
@errors << msg @errors << msg
puts msg xputs msg
end end
def get_node_by_name(name) def get_node_by_name(name)
@ -263,7 +262,7 @@ class RedisTrib
end end
def check_cluster def check_cluster
puts ">>> Performing Cluster Check (using node #{@nodes[0]})" xputs ">>> Performing Cluster Check (using node #{@nodes[0]})"
show_nodes show_nodes
check_config_consistency check_config_consistency
check_open_slots check_open_slots
@ -281,10 +280,10 @@ class RedisTrib
end end
def check_slots_coverage def check_slots_coverage
puts ">>> Check slots coverage..." xputs ">>> Check slots coverage..."
slots = covered_slots slots = covered_slots
if slots.length == ClusterHashSlots if slots.length == ClusterHashSlots
puts "[OK] All #{ClusterHashSlots} slots covered." xputs "[OK] All #{ClusterHashSlots} slots covered."
else else
cluster_error \ cluster_error \
"[ERR] Not all #{ClusterHashSlots} slots are covered by nodes." "[ERR] Not all #{ClusterHashSlots} slots are covered by nodes."
@ -293,7 +292,7 @@ class RedisTrib
end end
def check_open_slots def check_open_slots
puts ">>> Check for open slots..." xputs ">>> Check for open slots..."
open_slots = [] open_slots = []
@nodes.each{|n| @nodes.each{|n|
if n.info[:migrating].size > 0 if n.info[:migrating].size > 0
@ -308,7 +307,7 @@ class RedisTrib
} }
open_slots.uniq! open_slots.uniq!
if open_slots.length > 0 if open_slots.length > 0
puts "[WARNING] The following slots are open: #{open_slots.join(",")}" xputs "[WARNING] The following slots are open: #{open_slots.join(",")}"
end end
if @fix if @fix
open_slots.each{|slot| fix_open_slot slot} open_slots.each{|slot| fix_open_slot slot}
@ -325,8 +324,8 @@ class RedisTrib
def fix_slots_coverage def fix_slots_coverage
not_covered = (0...ClusterHashSlots).to_a - covered_slots.keys not_covered = (0...ClusterHashSlots).to_a - covered_slots.keys
puts "\nFixing slots coverage..." xputs ">>> Fixing slots coverage..."
puts "List of not covered slots: " + not_covered.join(",") xputs "List of not covered slots: " + not_covered.join(",")
# For every slot, take action depending on the actual condition: # For every slot, take action depending on the actual condition:
# 1) No node has keys for this slot. # 1) No node has keys for this slot.
@ -336,7 +335,7 @@ class RedisTrib
not_covered.each{|slot| not_covered.each{|slot|
nodes = nodes_with_keys_in_slot(slot) nodes = nodes_with_keys_in_slot(slot)
slots[slot] = nodes slots[slot] = nodes
puts "Slot #{slot} has keys in #{nodes.length} nodes: #{nodes.join}" xputs "Slot #{slot} has keys in #{nodes.length} nodes: #{nodes.join}"
} }
none = slots.select {|k,v| v.length == 0} none = slots.select {|k,v| v.length == 0}
@ -345,34 +344,34 @@ class RedisTrib
# Handle case "1": keys in no node. # Handle case "1": keys in no node.
if none.length > 0 if none.length > 0
puts "The folowing uncovered slots have no keys across the cluster:" xputs "The folowing uncovered slots have no keys across the cluster:"
puts none.keys.join(",") xputs none.keys.join(",")
yes_or_die "Fix these slots by covering with a random node?" yes_or_die "Fix these slots by covering with a random node?"
none.each{|slot,nodes| none.each{|slot,nodes|
node = @nodes.sample node = @nodes.sample
puts "Covering slot #{slot} with #{node}" xputs ">>> Covering slot #{slot} with #{node}"
node.r.cluster("addslots",slot) node.r.cluster("addslots",slot)
} }
end end
# Handle case "2": keys only in one node. # Handle case "2": keys only in one node.
if single.length > 0 if single.length > 0
puts "The folowing uncovered slots have keys in just one node:" xputs "The folowing uncovered slots have keys in just one node:"
puts single.keys.join(",") puts single.keys.join(",")
yes_or_die "Fix these slots by covering with those nodes?" yes_or_die "Fix these slots by covering with those nodes?"
single.each{|slot,nodes| single.each{|slot,nodes|
puts "Covering slot #{slot} with #{nodes[0]}" xputs ">>> Covering slot #{slot} with #{nodes[0]}"
nodes[0].r.cluster("addslots",slot) nodes[0].r.cluster("addslots",slot)
} }
end end
# Handle case "3": keys in multiple nodes. # Handle case "3": keys in multiple nodes.
if multi.length > 0 if multi.length > 0
puts "The folowing uncovered slots have keys in multiple nodes:" xputs "The folowing uncovered slots have keys in multiple nodes:"
puts multi.keys.join(",") xputs multi.keys.join(",")
yes_or_die "Fix these slots by moving keys into a single node?" yes_or_die "Fix these slots by moving keys into a single node?"
multi.each{|slot,nodes| multi.each{|slot,nodes|
puts "Covering slot #{slot} moving keys to #{nodes[0]}" xputs ">>> Covering slot #{slot} moving keys to #{nodes[0]}"
# TODO # TODO
# 1) Set all nodes as "MIGRATING" for this slot, so that we # 1) Set all nodes as "MIGRATING" for this slot, so that we
# can access keys in the hash slot using ASKING. # can access keys in the hash slot using ASKING.
@ -397,10 +396,10 @@ class RedisTrib
elsif n.info[:importing][slot] elsif n.info[:importing][slot]
importing << n importing << n
elsif n.r.cluster("countkeysinslot",slot) > 0 elsif n.r.cluster("countkeysinslot",slot) > 0
puts "Found keys about slot #{slot} in node #{n}!" xputs "*** Found keys about slot #{slot} in node #{n}!"
end end
} }
puts "Fixing open slot 0:" puts ">>> Fixing open slot #{slot}"
puts "Set as migrating in: #{migrating.join(",")}" puts "Set as migrating in: #{migrating.join(",")}"
puts "Set as importing in: #{importing.join(",")}" puts "Set as importing in: #{importing.join(",")}"
@ -409,7 +408,7 @@ class RedisTrib
if migrating.length == 1 && importing.length == 1 if migrating.length == 1 && importing.length == 1
move_slot(migrating[0],importing[0],slot,:verbose=>true) move_slot(migrating[0],importing[0],slot,:verbose=>true)
else else
puts "Sorry, Redis-trib can't fix this slot yet (work in progress)" xputs "[ERR] Sorry, Redis-trib can't fix this slot yet (work in progress)"
end end
end end
@ -420,9 +419,9 @@ class RedisTrib
signatures << n.get_config_signature signatures << n.get_config_signature
} }
if signatures.uniq.length != 1 if signatures.uniq.length != 1
puts "[ERR] Nodes don't agree about configuration!" cluster_error "[ERR] Nodes don't agree about configuration!"
else else
puts "[OK] All nodes agree about slots configuration." xputs "[OK] All nodes agree about slots configuration."
end end
end end
@ -446,7 +445,7 @@ class RedisTrib
def show_nodes def show_nodes
@nodes.each{|n| @nodes.each{|n|
puts n.info_string xputs n.info_string
} }
end end
@ -467,7 +466,7 @@ class RedisTrib
print "#{msg} (type 'yes' to accept): " print "#{msg} (type 'yes' to accept): "
STDOUT.flush STDOUT.flush
if !(STDIN.gets.chomp.downcase == "yes") if !(STDIN.gets.chomp.downcase == "yes")
puts "Aborting..." xputs "*** Aborting..."
exit 1 exit 1
end end
end end
@ -571,7 +570,7 @@ class RedisTrib
load_cluster_info_from_node(ARGV[1]) load_cluster_info_from_node(ARGV[1])
check_cluster check_cluster
if @errors.length != 0 if @errors.length != 0
puts "\n--- Please fix your cluster problems before resharding ---" puts "*** Please fix your cluster problems before resharding"
exit 1 exit 1
end end
numslots = 0 numslots = 0
@ -584,14 +583,14 @@ class RedisTrib
print "What is the receiving node ID? " print "What is the receiving node ID? "
target = get_node_by_name(STDIN.gets.chop) target = get_node_by_name(STDIN.gets.chop)
if !target || target.has_flag?("slave") if !target || target.has_flag?("slave")
puts "The specified node is not known or not a master, please retry." xputs "*** The specified node is not known or not a master, please retry."
target = nil target = nil
end end
end end
sources = [] sources = []
puts "Please enter all the source node IDs." xputs "Please enter all the source node IDs."
puts " Type 'all' to use all the nodes as source nodes for the hash slots." xputs " Type 'all' to use all the nodes as source nodes for the hash slots."
puts " Type 'done' once you entered all the source nodes IDs." xputs " Type 'done' once you entered all the source nodes IDs."
while true while true
print "Source node ##{sources.length+1}:" print "Source node ##{sources.length+1}:"
line = STDIN.gets.chop line = STDIN.gets.chop
@ -611,9 +610,9 @@ class RedisTrib
} }
break break
elsif !src || src.has_flag?("slave") elsif !src || src.has_flag?("slave")
puts "The specified node is not known or is not a master, please retry." xputs "*** The specified node is not known or is not a master, please retry."
elsif src.info[:name] == target.info[:name] elsif src.info[:name] == target.info[:name]
puts "It is not possible to use the target node as source node." xputs "*** It is not possible to use the target node as source node."
else else
sources << src sources << src
end end
@ -635,7 +634,7 @@ class RedisTrib
end end
def create_cluster_cmd def create_cluster_cmd
puts "Creating cluster" xputs ">>> Creating cluster"
ARGV[1..-1].each{|n| ARGV[1..-1].each{|n|
node = ClusterNode.new(n) node = ClusterNode.new(n)
node.connect(:abort => true) node.connect(:abort => true)
@ -644,19 +643,19 @@ class RedisTrib
node.assert_empty node.assert_empty
add_node(node) add_node(node)
} }
puts "Performing hash slots allocation on #{@nodes.length} nodes..." xputs ">>> Performing hash slots allocation on #{@nodes.length} nodes..."
alloc_slots alloc_slots
show_nodes show_nodes
yes_or_die "Can I set the above configuration?" yes_or_die "Can I set the above configuration?"
flush_nodes_config flush_nodes_config
puts "** Nodes configuration updated" xputs ">>> Nodes configuration updated"
puts "** Sending CLUSTER MEET messages to join the cluster" xputs ">>> Sending CLUSTER MEET messages to join the cluster"
join_cluster join_cluster
check_cluster check_cluster
end end
def addnode_cluster_cmd def addnode_cluster_cmd
puts "Adding node #{ARGV[1]} to cluster #{ARGV[2]}" xputs ">>> Adding node #{ARGV[1]} to cluster #{ARGV[2]}"
# Check the existing cluster # Check the existing cluster
load_cluster_info_from_node(ARGV[2]) load_cluster_info_from_node(ARGV[2])
@ -671,7 +670,7 @@ class RedisTrib
first = @nodes.first.info first = @nodes.first.info
# Send CLUSTER MEET command to the new node # Send CLUSTER MEET command to the new node
puts "Send CLUSTER MEET to node #{new} to make it join the cluster." xputs ">>> Send CLUSTER MEET to node #{new} to make it join the cluster."
new.r.cluster("meet",first[:host],first[:port]) new.r.cluster("meet",first[:host],first[:port])
end end