#!/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|
EventMachine::Synchrony.next_tick do
on_ready(stanza)
end
end
register_handler :message, :groupchat?, :body => /^flapjack:\s+/ do |stanza|
EventMachine::Synchrony.next_tick do
on_groupchat(stanza)
end
end
register_handler :message, :chat? do |stanza|
EventMachine::Synchrony.next_tick do
on_chat(stanza)
end
end
register_handler :disconnected do |stanza|
ret = true
EventMachine::Synchrony.next_tick do
ret = on_disconnect(stanza)
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)) ? 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: