aboutsummaryrefslogtreecommitdiff
path: root/lib/mauve/alert_changed.rb
blob: 692508585cd825166ccf720ee27b5f8c9932c69b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# encoding: UTF-8
require 'mauve/datamapper'
require 'log4r'

module Mauve
  #
  # Class to record changes to alerts.  Also responsible for keeping records for reminders.
  #
  class AlertChanged
    include DataMapper::Resource
    
    # so .first always returns the most recent update
    default_scope(:default).update(:order => [:at.desc, :id.desc])
    
    property :id, Serial
    property :alert_id, Integer, :required  => true
    property :person, String, :required  => true
    property :at, EpochTime, :required => true
    property :was_relevant, Boolean, :required => true, :default => true
    property :level, String, :required  => true
    property :update_type, String, :required  => true
    property :remind_at, EpochTime, :required => false
    
    belongs_to :alert

    before :valid?, :do_set_timestamps

    protected

    def do_set_timestamps(context = :default)
      self.at = Time.now if self.dirty?
    end

    public

    # @return [String]
    def to_s
      "#<AlertChanged #{id}: alert_id #{alert_id}, for #{person}, update_type #{update_type}>"
    end

    # @deprecated I don't think was_relevant is used any more.
    #
    def was_relevant=(value)
      attribute_set(:was_relevant, value)
    end

    # The time this object was last updated
    # 
    # @return [Time]
    def updated_at
      self.at
    end
    
    # Set the time this object was last updated
    #
    # @param [Time] t
    # @return [Time]
    def updated_at=(t)
      self.at = t
    end

    # @return [Log4r::Logger]
    def logger
     Log4r::Logger.new self.class.to_s
    end

    # Sends a reminder about this alert state change, or forget about it if
    # the alert has been acknowledged
    #
    # @return [Boolean] indicating successful update of the AlertChanged object
    def remind
      unless alert.is_a?(Alert)
        logger.info "#{self.inspect} lost alert #{alert_id}.  Killing self."
        destroy
        return false
      end
      
      if !alert_group 
        logger.info("No alert group matches any more.  Clearing reminder for #{self.alert}.")
        self.remind_at = nil
        return save
      end

      if alert.acknowledged? or alert.cleared?
        logger.info("Alert already acknowledged/cleared.  Clearing reminder due for #{self.alert}.")
        self.remind_at = nil
        return save
      end

      #
      # Postpone reminders from previous runs, if needed.
      #
      if Server.instance.in_initial_sleep? and
          self.at < Server.instance.started_at

        self.remind_at = Server.instance.started_at + Server.instance.initial_sleep
        logger.info("Postponing reminder for #{self.alert} until #{self.remind_at} since this reminder was updated in a prior run of Mauve.")
        return save
      end

      #
      # Bail out if notifications for this alert have been suppressed.
      #
      if alert.suppressed?
        #
        # Skip reminders if the alert is suppressed.
        #
        logger.info("Notifications suppressed until #{alert.suppress_until} for #{alert.inspect}")
      else
        #
        # Push this notifitcation onto the queue.
        #
        Server.notification_push([alert, self.remind_at])
      end

      #
      # Need to make sure this reminder is cleared.
      #
      self.remind_at = nil

      #
      # Now save.
      #
      return self.save
    end
    
    # The time this AlertChanged should next be polled at, or nil.  Mimics
    # interaface from Alert.
    #
    # @return [Time, NilClass]
    def due_at 
      remind_at ? remind_at : nil
    end
    
    # Sends a reminder, if needed. Mimics interaface from Alert.
    #
    # @return [Boolean] showing polling was successful
    def poll # mimic interface from Alert
      logger.debug("Polling #{self.to_s}")

      if remind_at.is_a?(Time) and remind_at <= Time.now
        remind 
      else
        true
      end
    end

    # The AlertGroup for this object
    #
    # @return [Mauve::AlertGroup]
    def alert_group
      alert.alert_group
    end
    
    class << self
      # Finds the next reminder due, or nil if nothing due.
      #
      # @return [Mauve::AlertChanged, NilClass]
      def next_reminder
        first(:remind_at.not => nil, :order => [:remind_at])
      end
      
      # Finds the next event due.  Mimics interface from Alert.
      #
      # @return [Mauve::AlertChanged, NilClass]
      def find_next_with_event 
        next_reminder
      end

      # @deprecated  I don't think this is used any more.
      #
      # @return [Array]
      def all_overdue(at = Time.now)
        all(:remind_at.not => nil, :remind_at.lt => at, :order => [:remind_at]).to_a
      end
    end
  end
end