class Flapjack::Gateways::Jabber::Interpreter
Constants
- CHECK_MATCH_FRAGMENT
Attributes
siblings[RW]
Public Class Methods
new(opts = {})
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 127 def initialize(opts = {}) @lock = opts[:lock] @stop_cond = opts[:stop_condition] @config = opts[:config] @boot_time = opts[:boot_time] @should_quit = false @messages = [] end
Public Instance Methods
derive_check_ids_for(pattern, tag_name, check_name, options = {}) { |ids, "matching /#{strip}/", num_checks| ... }
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 203 def derive_check_ids_for(pattern, tag_name, check_name, options = {}) lock_klasses = options[:lock_klasses] || [] deriver = if !pattern.nil? && !pattern.strip.empty? proc { checks = begin Flapjack::Data::Check.intersect(:name => Regexp.new(pattern.strip)) rescue RegexpError nil end if checks.nil? "Error parsing /#{pattern.strip}/" else num_checks = checks.count if num_checks == 0 "No checks match /#{pattern.strip}/" else checks = checks.sort(:name, :limit => options[:limit]) if options[:limit] yield(checks.ids, "matching /#{pattern.strip}/", num_checks) if block_given? end end } elsif !tag_name.nil? && !tag_name.strip.empty? lock_klasses.unshift(Flapjack::Data::Tag) proc { tag = Flapjack::Data::Tag.intersect(:name => tag_name.strip).all.first if tag.nil? "No tag '#{tag_name.strip}'" else checks = tag.checks num_checks = checks.count if num_checks == 0 "No checks with tag '#{tag_name.strip}'" else checks = checks.sort(:name, :limit => options[:limit]) if options[:limit] yield(checks.ids, "with tag '#{tag_name}'", num_checks) if block_given? end end } elsif !check_name.nil? && !check_name.strip.empty? proc { checks = Flapjack::Data::Check.intersect(:name => check_name.strip) if checks.empty? "No check exists with name '#{check_name.strip}'" else num_checks = checks.count checks = checks.sort(:name, :limit => options[:limit]) if options[:limit] yield(checks.ids, "with name '#{check_name.strip}'", num_checks) if block_given? end } end return if deriver.nil? if lock_klasses.empty? Flapjack::Data::Check.lock(&deriver) else Flapjack::Data::Check.lock(*lock_klasses, &deriver) end end
get_check_details(check, at_time)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 168 def get_check_details(check, at_time) start_range = Zermelo::Filters::IndexRange.new(nil, at_time, :by_score => true) end_range = Zermelo::Filters::IndexRange.new(at_time, nil, :by_score => true) sched = check.scheduled_maintenances.intersect(:start_time => start_range, :end_time => end_range).all.max_by(&:end_time) unsched = check.unscheduled_maintenances.intersect(:start_time => start_range, :end_time => end_range).all.max_by(&:end_time) out = '' if sched.nil? && unsched.nil? out += "Not in scheduled or unscheduled maintenance.\n" else if sched.nil? out += "Not in scheduled maintenance.\n" else remain = time_period_in_words( (sched.end_time - at_time).ceil ) # TODO a simpler time format? out += "In scheduled maintenance: #{sched.start_time} -> #{sched.end_time} (#{remain} remaining)\n" end if unsched.nil? out += "Not in unscheduled maintenance.\n" else remain = time_period_in_words( (unsched.end_time - at_time).ceil ) # TODO a simpler time format? out += "In unscheduled maintenance: #{unsched.start_time} -> #{unsched.end_time} (#{remain} remaining)\n" end end out end
interpret(room, nick, time, command)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 269 def interpret(room, nick, time, command) msg = nil action = nil check = nil begin case command when /^help\s*$/ msg = "commands: \n" + " find (number) checks matching /pattern/\n" + " find (number) checks with tag <tag>\n" + " state of <check>\n" + " state of checks matching /pattern/\n" + " state of checks with tag <tag>\n" + " tell me about <check>\n" + " tell me about (number) checks matching /pattern/\n" + " tell me about (number) checks with tag <tag>\n" + " ACKID <id>[ duration: <time spec>][ comment: <comment>]\n" + " ack <check>[ duration: <time spec>][ comment: <comment>]\n" + " ack checks matching /pattern/[ duration: <time spec>][ comment: <comment>]\n" + " ack checks with tag <tag>[ duration: <time spec>][ comment: <comment>]\n" + " maint <check>[ (start-at|start-in): <time spec>][ duration: <time spec>][ comment: <comment>]\n" + " maint checks matching /pattern/[ (start-at|start-in): <time spec>][ duration: <time spec>][ comment: <comment>]\n" + " maint checks with tag <tag>[ (start-at|start-in): <time spec>][ duration: <time spec>][ comment: <comment>]\n" + " test notifications for <check>\n" + " test notifications for checks matching /pattern/\n" + " test notifications for checks with tag <tag>\n" + " identify\n" + " help\n" when /^identify\s*$/ t = Process.times fqdn = `/bin/hostname -f`.chomp pid = Process.pid msg = "Flapjack #{Flapjack::VERSION} process #{pid} on #{fqdn} \n" + "Identifiers: #{@bot.identifiers.join(', ')}\n" + "Boot time: #{@boot_time}\n" + "User CPU Time: #{t.utime}\n" + "System CPU Time: #{t.stime}\n" + `uname -a`.chomp + "\n" when /^find\s+(\d+\s+)?checks\s+(?:matching\s+\/(.+)\/|with\s+tag\s+(.+))\s*$/im limit_checks = Regexp.last_match(1).nil? ? 30 : Regexp.last_match(1).strip.to_i pattern = Regexp.last_match(2) tag = Regexp.last_match(3) msg = derive_check_ids_for(pattern, tag, nil, :limit => limit_checks) do |check_ids, descriptor, num_checks| resp = "Checks #{descriptor}:\n" checks = Flapjack::Data::Check.find_by_ids(*check_ids) resp += "Showing first #{limit_checks} results of #{num_checks}:\n" if num_checks > limit_checks resp += checks.map {|chk| cond = chk.condition "#{chk.name} is #{cond.nil? ? '[none]' : cond.upcase}" }.join(', ') resp end when /^state\s+of\s+#{CHECK_MATCH_FRAGMENT}\s*$/im pattern = Regexp.last_match(1) tag = Regexp.last_match(2) check_name = Regexp.last_match(3) msg = derive_check_ids_for(pattern, tag, check_name) do |check_ids, descriptor| "State of checks #{descriptor}:\n" + Flapjack::Data::Check.intersect(:id => check_ids).collect {|chk| cond = chk.condition "#{chk.name} - #{cond.nil? ? '[none]' : cond.upcase}" }.join("\n") end when /^tell\s+me\s+about\s(\d+\s+)?+#{CHECK_MATCH_FRAGMENT}\s*$/im limit_checks = Regexp.last_match(1).nil? ? 30 : Regexp.last_match(1).strip.to_i pattern = Regexp.last_match(2) tag = Regexp.last_match(3) check_name = Regexp.last_match(4) msg = derive_check_ids_for(pattern, tag, check_name, :limit => limit_checks, :lock_klasses => [Flapjack::Data::ScheduledMaintenance, Flapjack::Data::UnscheduledMaintenance]) do |check_ids, descriptor, num_checks| current_time = Time.now resp = "Details of checks #{descriptor}\n" resp += "Showing first #{limit_checks} results of #{num_checks}:\n" if num_checks > limit_checks resp += Flapjack::Data::Check.intersect(:id => check_ids).collect {|chk| get_check_details(chk, current_time) }.join("") end when /^ACKID\s+([0-9A-F]+)(?:\s*(.*?)(?:\s*duration:.*?(\w+.*))?)$/im ackid = Regexp.last_match(1) comment = Regexp.last_match(2) duration_str = Regexp.last_match(3) error = nil dur = nil if comment.nil? || (comment.length == 0) error = "please provide a comment, eg \"#{@bot.alias}: ACKID #{Regexp.last_match(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 check = Flapjack::Data::Check.intersect(:ack_hash => ackid).all.first if check.nil? msg = "ERROR - couldn't ACK #{ackid} - not found" else check_name = check.name details = "#{check_name} (#{ackid})" if check.in_unscheduled_maintenance? msg = "Changing ACK for #{details}" else msg = "ACKing #{details}" end action = Proc.new { Flapjack::Data::Event.create_acknowledgements( @config['processor_queue'] || 'events', [check], :summary => (comment || ''), :acknowledgement_id => ackid, :duration => duration, ) } end when /^ack\s+#{CHECK_MATCH_FRAGMENT}(?:\s+(.*?)(?:\s*duration:.*?(\w+.*))?)?\s*$/im pattern = Regexp.last_match(1) tag = Regexp.last_match(2) check_name = Regexp.last_match(3) comment = Regexp.last_match(4) ? Regexp.last_match(4).strip : nil duration_str = Regexp.last_match(5) ? Regexp.last_match(5).strip : '1 hour' duration = ChronicDuration.parse(duration_str) msg = derive_check_ids_for(pattern, tag, check_name, :lock_klasses => [Flapjack::Data::UnscheduledMaintenance]) do |check_ids, descriptor| failing_checks = Flapjack::Data::Check. intersect(:id => check_ids, :failing => true) if failing_checks.empty? "No failing checks #{descriptor}" else summary = "#{nick}: #{comment.blank? ? 'Set via chatbot' : comment}" action = Proc.new { Flapjack::Data::Event.create_acknowledgements( @config['processor_queue'] || 'events', failing_checks, :summary => summary, :duration => duration ) } "Ack list:\n" + failing_checks.map(&:name).join("\n") end end when /^maint\s+#{CHECK_MATCH_FRAGMENT}\s+(?:start-in:.*?(\w+.*?)|start-at:.*?(\w+.*?))?(?:\s+duration:.*?(\w+.*?))?(?:\s+comment:.*?(\w+.*?))?\s*$/im pattern = Regexp.last_match(1) tag = Regexp.last_match(2) check_name = Regexp.last_match(3) start_in = Regexp.last_match(4) ? Regexp.last_match(4).strip : nil start_at = Regexp.last_match(5) ? Regexp.last_match(5).strip : nil duration_str = Regexp.last_match(6) ? Regexp.last_match(6).strip : '1 hour' duration = ChronicDuration.parse(duration_str) comment = Regexp.last_match(7) ? Regexp.last_match(7).strip : 'Test maintenance' started = case when start_in Time.now.to_i + ChronicDuration.parse(start_in) when start_at Chronic.parse(start_at).to_i else Time.now.to_i end msg = derive_check_ids_for(pattern, tag, check_name, :lock_klasses => [Flapjack::Data::ScheduledMaintenance]) do |check_ids, descriptor| checks = Flapjack::Data::Check.find_by_ids(*check_ids) checks.each do |chk| sched_maint = Flapjack::Data::ScheduledMaintenance.new( :start_time => started, :end_time => started + duration, :summary => comment ) sched_maint.save chk.scheduled_maintenances << sched_maint end "Scheduled maintenance for #{duration/60} minutes starting at #{Time.at(started)} on:\n" + checks.collect {|c| "#{c.name}" }.join("\n") end when /^test\s+notifications\s+for\s+#{CHECK_MATCH_FRAGMENT}\s*$/im pattern = Regexp.last_match(1) tag = Regexp.last_match(2) check_name = Regexp.last_match(3) msg = derive_check_ids_for(pattern, tag, check_name) do |check_ids, descriptor| summary = "Testing notifications to all contacts interested in checks #{descriptor}" checks = Flapjack::Data::Check.find_by_ids(*check_ids) action = Proc.new { Flapjack::Data::Event.test_notifications(@config['processor_queue'] || 'events', checks, :summary => summary) } "Testing notifications for check#{(checks.size > 1) ? 's' : ''} #{descriptor}" end when /^(.*)/ words = Regexp.last_match(1) msg = "what do you mean, '#{words}'? Type 'help' for a list of acceptable commands." end rescue => e Flapjack.logger.error { "Exception when interpreting command '#{command}' - #{e.class}, #{e.message}" } Flapjack.logger.debug { e.backtrace.join("\n") } msg = "Oops, something went wrong processing that command (#{e.class}, #{e.message})" end @bot ||= @siblings && @siblings.detect {|sib| sib.respond_to?(:announce) } if @bot && (room || nick) if room Flapjack.logger.info "sending to room #{room}: #{msg}" @bot.announce(room, msg) else Flapjack.logger.info "sending to user #{nick}: #{msg}" @bot.say(nick, msg) end else Flapjack.logger.warn "jabber bot not running, won't send #{msg} to #{room || nick}" end action.call if action end
receive_message(room, nick, time, msg)
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 161 def receive_message(room, nick, time, msg) @lock.synchronize do @messages += [{:room => room, :nick => nick, :time => time, :message => msg}] @stop_cond.signal end end
start()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 139 def start Zermelo.redis = Flapjack.redis @lock.synchronize do @bot = self.siblings ? self.siblings.detect {|sib| sib.respond_to?(:announce)} : nil until @messages.empty? && @should_quit while msg = @messages.pop Flapjack.logger.info "interpreter received #{msg.inspect}" interpret(msg[:room], msg[:nick], msg[:time], msg[:message]) end @stop_cond.wait_while { @messages.empty? && !@should_quit } end end Flapjack.redis.quit end
stop_type()
click to toggle source
# File lib/flapjack/gateways/jabber.rb, line 157 def stop_type :signal end