lib/flapjack/jabber.rb in flapjack-0.6.39 vs lib/flapjack/jabber.rb in flapjack-0.6.40

- old
+ new

@@ -16,33 +16,46 @@ require 'em-synchrony/fiber_iterator' require 'yajl/json_gem' require 'flapjack/data/entity_check' require 'flapjack/pikelet' +require 'flapjack/redis_pool' require 'flapjack/utility' require 'flapjack/version' module Flapjack class Jabber < Blather::Client - include Flapjack::Pikelet + include Flapjack::GenericPikelet include Flapjack::Utility log = Logger.new(STDOUT) # log.level = Logger::DEBUG log.level = Logger::INFO Blather.logger = log - def initialize - super + alias_method :generic_bootstrap, :bootstrap + alias_method :generic_cleanup, :cleanup + + def bootstrap(opts = {}) + generic_bootstrap(opts) + + @redis_config = opts[:redis_config] + @redis = Flapjack::RedisPool.new(:config => @redis_config, :size => 1) + @buffer = [] @hostname = Socket.gethostname end + def cleanup + @redis.empty! if @redis + @redis_handler.empty! if @redis_handler + generic_cleanup + end + def setup - @redis = build_redis_connection_pool @flapjack_jid = Blather::JID.new((@config['jabberid'] || 'flapjack') + '/' + @hostname) super(@flapjack_jid, @config['password'], @config['server'], @config['port'].to_i) logger.debug("Building jabber connection with jabberid: " + @@ -77,12 +90,12 @@ end end # Join the MUC Chat room after connecting. def on_ready(stanza) - return if should_quit? - @redis_handler ||= build_redis_connection_pool + return if should_quit? && @shutting_down + @redis_handler ||= Flapjack::RedisPool.new(:config => @redis_config, :size => 1) @connected_at = Time.now.to_i logger.info("Jabber Connected") if @config['rooms'] && @config['rooms'].length > 0 @config['rooms'].each do |room| logger.info("Joining room #{room}") @@ -148,10 +161,12 @@ end when command =~ /^help$/ msg = "commands: \n" msg += " ACKID <id> <comment> [duration: <time spec>] \n" + msg += " find entities matching /pattern/ \n" + msg += " test notifications for <entity>[:<check>] \n" msg += " identify \n" msg += " help \n" when command =~ /^identify$/ t = Process.times @@ -160,21 +175,58 @@ msg += "Boot time: #{boot_time}\n" msg += "User CPU Time: #{t.utime}\n" msg += "System CPU Time: #{t.stime}\n" msg += `uname -a`.chomp + "\n" + when command =~ /^test notifications for\s+([a-z0-9-]+)(:(.+))?$/i + entity_name = $1 + check_name = $3 ? $3 : 'test' + + msg = "so you want me to test notifications for entity: #{entity_name}, check: #{check_name} eh? ... well OK!" + + entity = Flapjack::Data::Entity.find_by_name(entity_name, :redis => @redis_handler) + if entity + summary = "Testing notifications to all contacts interested in entity: #{entity.name}, check: #{check_name}" + + entity_check = Flapjack::Data::EntityCheck.for_entity(entity, check_name, :redis => @redis_handler) + puts entity_check.inspect + entity_check.test_notifications('summary' => summary) + + else + msg = "yeah, no i can't see #{entity_name} in my systems" + end + + when command =~ /^(find )?entities matching\s+\/(.*)\/.*$/i + pattern = $2.chomp.strip + entity_list = Flapjack::Data::Entity.find_all_name_matching(pattern, :redis => @redis_handler) + max_showable = 30 + number_found = entity_list.length + entity_list = entity_list[0..(max_showable - 1)] if number_found > max_showable + + case + when number_found == 0 + msg = "found no entities matching /#{pattern}/" + when number_found == 1 + msg = "found #{number_found} entity matching /#{pattern}/ ... \n" + when number_found > max_showable + msg = "showing first #{max_showable} of #{number_found} entities found matching /#{pattern}/\n" + else + msg = "found #{number_found} entities matching /#{pattern}/ ... \n" + end + msg += entity_list.join(', ') unless entity_list.empty? + when command =~ /^(.*)/ words = $1 msg = "what do you mean, '#{words}'? Type 'help' for a list of acceptable commands." end {:msg => msg, :action => action} end def on_groupchat(stanza) - return if should_quit? + return if should_quit? && @shutting_down logger.debug("groupchat message received: #{stanza.inspect}") if stanza.body =~ /^flapjack:\s+(.*)/ command = $1 end @@ -189,11 +241,11 @@ action.call if action end end def on_chat(stanza) - return if should_quit? + return if should_quit? && @shutting_down logger.debug("chat message received: #{stanza.inspect}") if stanza.body =~ /^flapjack:\s+(.*)/ command = $1 else @@ -211,11 +263,11 @@ end end # returning true to prevent the reactor loop from stopping def on_disconnect(stanza) - return true if should_quit? + return true if should_quit? && @shutting_down logger.warn("jabbers disconnected! reconnecting in 1 second ...") EventMachine::Timer.new(1) do connect # Blather::Client.connect end true @@ -254,24 +306,25 @@ # simplified to use a single queue only as it makes the shutdown logic easier queue = @config['queue'] events = {} - until should_quit? + until should_quit? && @shutting_down # FIXME: should also check if presence has been established in any group chat rooms that are # configured before starting to process events, otherwise the first few may get lost (send # before joining the group chat rooms) if connected? logger.debug("jabber is connected so commencing blpop on #{queue}") events[queue] = @redis.blpop(queue, 0) event = Yajl::Parser.parse(events[queue][1]) - type = event['notification_type'] + type = event['notification_type'] || 'unknown' logger.debug('jabber notification event received') logger.debug(event.inspect) if 'shutdown'.eql?(type) if should_quit? + @shutting_down = true EventMachine::Synchrony.next_tick do # get delays without the next_tick close # Blather::Client.close end end @@ -282,19 +335,35 @@ duration = event['duration'] ? time_period_in_words(event['duration']) : '4 hours' address = event['address'] logger.debug("processing jabber notification address: #{address}, event: #{entity}:#{check}, state: #{state}, summary: #{summary}") - ack_str = event['event_count'] && !state.eql?('ok') && !'acknowledgement'.eql?(type) ? + ack_str = + event['event_count'] && + !state.eql?('ok') && + !'acknowledgement'.eql?(type) && + !'test'.eql?(type) ? "::: flapjack: ACKID #{event['event_count']} " : '' - maint_str = (type && 'acknowledgement'.eql?(type)) ? - "has been acknowledged, unscheduled maintenance created for #{duration}" : + type = 'unknown' unless type + + maint_str = case type + when 'acknowledgement' + "has been acknowledged, unscheduled maintenance created for #{duration}" + when 'test' + '' + else "is #{state.upcase}" + end - msg = "#{type.upcase} #{ack_str}::: \"#{check}\" on #{entity} #{maint_str} ::: #{summary}" + # FIXME - should probably put all the message composition stuff in one place so + # the logic isn't duplicated in each notification channel. + # TODO - templatise the messages so they can be customised without changing core code + headline = "test".eql?(type.downcase) ? "TEST NOTIFICATION" : type.upcase + msg = "#{headline} #{ack_str}::: \"#{check}\" on #{entity} #{maint_str} ::: #{summary}" + chat_type = :chat chat_type = :groupchat if @config['rooms'] && @config['rooms'].include?(address) EventMachine::Synchrony.next_tick do say(Blather::JID.new(address), msg, chat_type) end @@ -305,12 +374,9 @@ end end count_timer.cancel keepalive_timer.cancel - - @redis.empty! if @redis - @redis_handler.empty! if @redis_handler end end end