# -*- ruby -*- #encoding: utf-8 require 'time' require 'tty/table' require 'arborist/cli' unless defined?( Arborist::CLI ) require 'arborist/client' # Command to fetch down/acked/disabled nodes for quick display. module Arborist::CLI::Summary extend Arborist::CLI::Subcommand using Arborist::TimeRefinements BANNER = [ ' _ _ _', ' __ _ _ _| |__ ___ _ _(_)__| |', '/ _` | \'_| \'_ \\/ _ \\ \'_| (_-< _|', '\\__,_|_| |_.__/\\___/_| |_/__/\\__| %s, %s nodes', ] desc 'Summarize known problems' command :summary do |cmd| cmd.flag [:s, :sort], type: String, desc: "Sort output by this node key", arg_name: 'sort', default_value: 'status_changed' cmd.action do |globals, options, args| client = Arborist::Client.new status = client.status nodes = client.fetch down = get_status( nodes, 'down' ) warning = get_status( nodes, 'warn' ) acked = get_status( nodes, 'acked' ) disabled = get_status( nodes, 'disabled' ) quieted = get_status( nodes, 'quieted' ) problems = ! ( down.size + acked.size + disabled.size + warning.size ).zero? prompt.say "Connected to: %s" % [ highlight_string(client.tree_api_url) ] prompt.say "Status as of: %s" % [ hl.on_blue.bright_white(Time.now.to_s) ] (0..2).each do |i| prompt.say "%s" % [ hl.bold.bright_green( BANNER[i] ) ] end prompt.say hl.bold.bright_green( BANNER.last ) % [ highlight_string(status['server_version']), highlight_string(status['nodecount']) ] puts if problems output_problems( disabled, acked, down, quieted, warning, options[:sort] ) else prompt.say success_string( "No problems found!" ) end end end ############### module_function ############### ### Since we fetch all nodes instead of doing separate ### API searches, quickly return nodes of a given +status+. def get_status( nodes, status ) return nodes.select{|n| n['status'] == status} end ### Output all problems. ### def output_problems( disabled, acked, down, quieted, warning, sort ) unless disabled.size.zero? prompt.say hl.headline( "Disabled Nodes" ) display_table( *format_acked(disabled, sort) ) puts end unless acked.size.zero? prompt.say hl.headline( "Acknowledged Outages" ) display_table( *format_acked(acked, sort) ) puts end unless warning.size.zero? prompt.say hl.headline( "Warnings" ) header = [ highlight_string( 'identifier' ), highlight_string( 'type' ), highlight_string( 'when' ), highlight_string( 'warnings' ) ] display_table( header, format_warn(warning, sort) ) puts end unless down.size.zero? prompt.say hl.headline( "Current Outages" ) header = [ highlight_string( 'identifier' ), highlight_string( 'type' ), highlight_string( 'when' ), highlight_string( 'errors' ) ] display_table( header, format_down(down, sort) ) prompt.say "%d nodes have been %s as a result of the above problems." % [ quieted.size, hl.quieted( 'quieted' ) ] puts end end ### Prepare an array of acked/disabled nodes. def format_acked( nodes, sort_key ) header = [ highlight_string( 'identifier' ), highlight_string( 'type' ), highlight_string( 'when' ), highlight_string( 'who' ), highlight_string( 'message' ) ] rows = nodes.sort_by{|n| n[sort_key] }.each_with_object([]) do |node, acc| acc << [ hl.disabled( node['identifier'] ), node[ 'type' ], Time.parse( node[ 'status_changed' ] ).as_delta, node[ 'ack' ][ 'sender' ], node[ 'ack' ][ 'message' ] ] end return header, rows end ### Prepare an array of down nodes. def format_down( nodes, sort_key ) return nodes.sort_by{|n| n[sort_key] }.each_with_object([]) do |node, acc| errors = node[ 'errors' ].map{|err| "%s: %s" % [ err.first, err.last ]} acc << [ hl.down( node['identifier'] ), node[ 'type' ], Time.parse( node[ 'status_changed' ] ).as_delta, errors.join( "\n" ) ] end end ### Prepare an array of nodes in a warning state. def format_warn( nodes, sort_key ) return nodes.sort_by{|n| n[sort_key] }.each_with_object([]) do |node, acc| warnings = node[ 'warnings' ].map{|err| "%s: %s" % [ err.first, err.last ]} acc << [ hl.warn( node['identifier'] ), node[ 'type' ], Time.parse( node[ 'status_changed' ] ).as_delta, warnings.join( "\n" ) ] end end end # module Arborist::CLI::Summary