lib/flapjack/data/notification.rb in flapjack-0.7.11 vs lib/flapjack/data/notification.rb in flapjack-0.7.12

- old
+ new

@@ -6,54 +6,145 @@ module Flapjack module Data class Notification - attr_accessor :event, :type, :max_notified_severity + attr_reader :event, :type, :max_notified_severity, :contacts, + :default_timezone def self.for_event(event, opts = {}) self.new(:event => event, :type => opts[:type], - :max_notified_severity => opts[:max_notified_severity]) + :max_notified_severity => opts[:max_notified_severity], + :contacts => opts[:contacts], + :default_timezone => opts[:default_timezone], + :logger => opts[:logger]) end - def messages(opts = {}) - contacts = opts[:contacts] - return [] if contacts.nil? + def messages + return [] if contacts.nil? || contacts.empty? + + event_id = event.id + event_state = event.state + + severity = if ([event_state, max_notified_severity] & ['critical', 'unknown']).any? + 'critical' + elsif [event_state, max_notified_severity].include?('warning') + 'warning' + else + 'ok' + end + + contents = {'event_id' => event_id, + 'state' => event_state, + 'summary' => event.summary, + 'details' => event.details, + 'time' => event.time, + 'duration' => event.duration || nil, + 'notification_type' => type, + 'max_notified_severity' => max_notified_severity } + @messages ||= contacts.collect {|contact| + contact_id = contact.id + rules = contact.notification_rules + media = contact.media - # TODO move the message filtering logic from executive into this - # class and apply here, don't generate message if it won't be sent + @logger.debug "considering messages for contact id #{contact_id} #{event_id} #{event_state} (media) #{media.inspect}" + rlen = rules.length + @logger.debug "found #{rlen} rule#{(rlen == 1) ? '' : 's'} for contact" - contact.media.each_pair.inject([]) { |ret, (k, v)| - m = Flapjack::Data::Message.for_contact(:contact => contact) - m.notification = self - m.medium = k - m.address = v + media_to_use = if rules.empty? + media + else + # matchers are rules of the contact that have matched the current event + # for time and entity + matchers = rules.select do |rule| + rule.match_entity?(event_id) && + rule_occurring_now?(rule, :contact => contact, :default_timezone => default_timezone) + end + + @logger.debug "#{matchers.length} matchers remain for this contact:" + matchers.each do |matcher| + @logger.debug "matcher: #{matcher.to_json}" + end + + # delete any matchers for all entities if there are more specific matchers + if matchers.any? {|matcher| matcher.is_specific? } + + @logger.debug("general removal: found #{matchers.length} entity specific matchers") + num_matchers = matchers.length + + matchers.reject! {|matcher| !matcher.is_specific? } + + if num_matchers != matchers.length + @logger.debug("notification: removal of general matchers when entity specific matchers are present: number of matchers changed from #{num_matchers} to #{matchers.length} for contact id: #{contact_id}") + end + end + + # delete media based on blackholes + next if matchers.any? {|matcher| matcher.blackhole?(event_state) } + + @logger.debug "notification: num matchers after removing blackhole matchers: #{matchers.size}" + + rule_media = matchers.collect{|matcher| + matcher.media_for_severity(severity) + }.flatten.uniq + + @logger.debug "notification: collected media_for_severity(#{severity}): #{rule_media}" + rule_media = rule_media.flatten.uniq.reject {|medium| + contact.drop_notifications?(:media => medium, + :check => event_id, + :state => event_state) + } + + @logger.debug "notification: media after contact_drop?: #{rule_media}" + + media.select {|medium, address| rule_media.include?(medium) } + end + + @logger.debug "notification: media_to_use: #{media_to_use}" + + media_to_use.each_pair.inject([]) { |ret, (k, v)| + m = Flapjack::Data::Message.for_contact(contact, + :notification_contents => contents, + :medium => k, :address => v) ret << m ret } - }.flatten + }.compact.flatten end - def contents - @contents ||= {'event_id' => event.id, - 'state' => event.state, - 'summary' => event.summary, - 'details' => event.details, - 'time' => event.time, - 'duration' => event.duration || nil, - 'notification_type' => type, - 'max_notified_severity' => max_notified_severity } - end - private def initialize(opts = {}) raise "Event not passed" unless event = opts[:event] @event = event @type = opts[:type] @max_notified_severity = opts[:max_notified_severity] + @contacts = opts[:contacts] + @default_timezone = opts[:default_timezone] + @logger = opts[:logger] + end + + # # time restrictions match? + # nil rule.time_restrictions matches + # times (start, end) within time restrictions will have any UTC offset removed and will be + # considered to be in the timezone of the contact + def rule_occurring_now?(rule, options = {}) + contact = options[:contact] + default_timezone = options[:default_timezone] + + return true if rule.time_restrictions.nil? or rule.time_restrictions.empty? + + timezone = contact.timezone(:default => default_timezone) + usertime = timezone.now + + rule.time_restrictions.any? do |tr| + # add contact's timezone to the time restriction schedule + schedule = Flapjack::Data::NotificationRule. + time_restriction_to_icecube_schedule(tr, timezone) + schedule && schedule.occurring_at?(usertime) + end end end end end