forked from spladug/harold
-
Notifications
You must be signed in to change notification settings - Fork 0
/
alerts.py
180 lines (141 loc) · 5.24 KB
/
alerts.py
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
179
180
import datetime
import functools
from email.mime.text import MIMEText
from twisted.internet import reactor
from http import ProtectedResource
from conf import PluginConfig, Option, tup
from utils import pretty_time_span
import watchdog
def make_short_name(jid):
short_name = jid.split('@')[0]
return short_name
class AlertsConfig(PluginConfig):
recipients = Option(tup, default=[])
refractory_period = Option(int, default=300)
max_mute_duration = Option(int, default=3600)
class BroadcastAlertListener(ProtectedResource):
isLeaf = True
def __init__(self, http, alerter):
ProtectedResource.__init__(self, http)
self.alerter = alerter
def _handle_request(self, request):
tag = request.args['tag'][0]
message = request.args['message'][0]
self.alerter.alert(tag, message)
class Alert(object):
pass
class Alerter(object):
def __init__(self, config, jabber_bot, smtp):
self.config = config
self.alerts = {}
self.jabber_bot = jabber_bot
self.smtp = smtp
senders = {
'smtp': self._send_smtp,
'jabber': self._send_jabber,
}
self.recipients = []
for recipient in self.config.recipients:
medium, id = recipient.split(':', 1)
sender = functools.partial(senders[medium], id)
self.recipients.append(sender)
def _send_smtp(self, recipient, message):
email = MIMEText(message)
self.smtp.sendmail(
self.smtp.username,
[recipient],
email
)
def _send_jabber(self, recipient, message):
self.jabber_bot.sendMessage(recipient, message)
def broadcast(self, message):
for recipient in self.recipients:
recipient(message)
def alert(self, tag, message):
alert = self._register_alert(tag)
if not alert.muted:
self.broadcast("<%s> %s" % (tag, message))
def _register_alert(self, tag):
alert = self.alerts.get(tag)
if not alert:
alert = Alert()
alert.first_seen = datetime.datetime.now()
alert.count = 0
alert.muted = False
alert.expirator = None
self.alerts[tag] = alert
if alert.expirator:
alert.expirator.cancel()
alert.count += 1
alert.last_seen = datetime.datetime.now()
alert.expirator = reactor.callLater(
self.config.refractory_period,
self._deregister_alert,
tag
)
return alert
def _deregister_alert(self, tag):
alert = self.alerts[tag]
if alert.muted:
alert.mute_expirator.cancel()
del self.alerts[tag]
def _register_mute(self, tag, sender):
alert = self.alerts[tag]
alert.muted = make_short_name(sender)
alert.mute_expirator = reactor.callLater(
self.config.max_mute_duration,
self._deregister_mute,
tag
)
def _deregister_mute(self, tag):
alert = self.alerts[tag]
alert.muted = False
def broadcast_from(self, sender, message):
short_name = make_short_name(sender)
self.broadcast("<%s> %s" % (short_name, message))
def wall(self, bot, sender, *message):
"Broadcast a message to all other alert-recipients."
self.broadcast_from(sender, ' '.join(message))
def ack(self, bot, sender, tag):
"""Acknowledge an alert and silence this occurence of it.
An occurence of the alert is defined as all instances of
this alert until a period of time (default of 5 minutes)
passes with no occurence of alerts with this tag.
"""
alert = self.alerts.get(tag)
if not alert:
bot.sendMessage(sender,
"No live alerts with tag \"%s\"." % tag)
elif alert.muted:
bot.sendMessage(sender, "\"%s\" is already acknowledged."
% tag)
else:
self.broadcast_from(sender, "acknowledged %s" % tag)
self._register_mute(tag, sender)
def status(self, bot, sender):
"Show status of all live alerts."
if not self.alerts:
bot.sendMessage(sender, "No live alerts. :)")
return
now = datetime.datetime.now()
with bot.message(sender) as m:
print >>m, "Live alerts:"
for tag, alert in self.alerts.iteritems():
print >>m, "<%s>%s seen %dx. started %s ago. last seen %s ago." % (
tag,
" ack'd by %s." % alert.muted if alert.muted else "",
alert.count,
pretty_time_span(now - alert.first_seen),
pretty_time_span(now - alert.last_seen),
)
def make_plugin(config, http, jabber, smtp):
alerts_config = AlertsConfig(config)
alerter = Alerter(alerts_config, jabber.bot, smtp)
# create the http resource
http.root.putChild("alert", BroadcastAlertListener(http, alerter))
# add commands
jabber.register_command(alerter.wall)
jabber.register_command(alerter.ack)
jabber.register_command(alerter.status)
# create the watchdog
watchdog.initialize(http, jabber, alerter)