#!/usr/bin/env ruby require 'socket' require 'eventmachine' # the redis/synchrony gems need to be required in this particular order, see # the redis-rb README for details require 'hiredis' require 'em-synchrony' require 'redis/connection/synchrony' require 'redis' require 'chronic_duration' require 'blather/client/client' require 'em-synchrony/fiber_iterator' require 'yajl/json_gem' require 'flapjack/data/entity_check' require 'flapjack/pikelet' require 'flapjack/utility' require 'flapjack/version' module Flapjack class Jabber < Blather::Client include Flapjack::Pikelet include Flapjack::Utility log = Logger.new(STDOUT) # log.level = Logger::DEBUG log.level = Logger::INFO Blather.logger = log def initialize super @buffer = [] @hostname = Socket.gethostname 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: " + @flapjack_jid.to_s + ", port: " + @config['port'].to_s + ", server: " + @config['server'].to_s + ", password: " + @config['password'].to_s) register_handler :ready do |stanza| EM.next_tick do EM.synchrony do on_ready(stanza) end end end register_handler :message, :groupchat?, :body => /^flapjack:\s+/ do |stanza| EM.next_tick do EM.synchrony do on_groupchat(stanza) end end end register_handler :message, :chat? do |stanza| EM.next_tick do EM.synchrony do on_chat(stanza) end end end register_handler :disconnected do |stanza| ret = true EM.next_tick do EM.synchrony do ret = on_disconnect(stanza) end end ret end end # Join the MUC Chat room after connecting. def on_ready(stanza) return if should_quit? @redis_handler ||= build_redis_connection_pool @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}") presence = Blather::Stanza::Presence.new presence.from = @flapjack_jid presence.to = Blather::JID.new("#{room}/#{@config['alias']}") presence << "" write presence say(room, "flapjack jabber gateway started at #{Time.now}, hello!", :groupchat) end end return if @buffer.empty? while stanza = @buffer.shift @logger.debug("Sending a buffered jabber message to: #{stanza.to}, using: #{stanza.type}, message: #{stanza.body}") write(stanza) end end def interpreter(command) msg = nil action = nil entity_check = nil case when command =~ /^ACKID\s+(\d+)(?:\s*(.*?)(?:\s*duration.*?(\d+.*\w+.*))?)$/i; ackid = $1 comment = $2 duration_str = $3 error = nil dur = nil if comment.nil? || (comment.length == 0) error = "please provide a comment, eg \"flapjack: ACKID #{$1} AL looking\"" elsif duration_str # a fairly liberal match above, we'll let chronic_duration do the heavy lifting dur = ChronicDuration.parse(duration_str) end four_hours = 4 * 60 * 60 duration = (dur.nil? || (dur <= 0) || (dur > four_hours)) ? four_hours : dur event_id = @redis_handler.hget('unacknowledged_failures', ackid) if event_id.nil? error = "not found" else entity_check = Flapjack::Data::EntityCheck.for_event_id(event_id, :redis => @redis_handler) error = "unknown entity" if entity_check.nil? end if entity_check && entity_check.in_unscheduled_maintenance? error = "#{event_id} is already acknowledged" end if error msg = "ERROR - couldn't ACK #{ackid} - #{error}" else msg = "ACKing #{entity_check.check} on #{entity_check.entity_name} (#{ackid})" action = Proc.new { entity_check.create_acknowledgement('summary' => (comment || ''), 'acknowledgement_id' => ackid, 'duration' => duration) } end when command =~ /^help$/ msg = "commands: \n" msg += " ACKID [duration: