|
4 | 4 | from django.core.mail import send_mail
|
5 | 5 | from django.core.urlresolvers import reverse
|
6 | 6 | from django.template import Context, Template
|
| 7 | +from django.db import models |
| 8 | +from django.db.models import get_models |
7 | 9 |
|
8 | 10 | from twilio.rest import TwilioRestClient
|
9 | 11 | from twilio import twiml
|
| 12 | + |
10 | 13 | import requests
|
11 | 14 | import logging
|
| 15 | +import re |
| 16 | + |
| 17 | +from polymorphic import PolymorphicModel |
12 | 18 |
|
13 | 19 | logger = logging.getLogger(__name__)
|
14 | 20 |
|
15 |
| -email_template = """Service {{ service.name }} {{ scheme }}://{{ host }}{% url 'service' pk=service.id %} {% if service.overall_status != service.PASSING_STATUS %}alerting with status: {{ service.overall_status }}{% else %}is back to normal{% endif %}. |
16 |
| -{% if service.overall_status != service.PASSING_STATUS %} |
17 |
| -CHECKS FAILING:{% for check in service.all_failing_checks %} |
18 |
| - FAILING - {{ check.name }} - Type: {{ check.check_category }} - Importance: {{ check.get_importance_display }}{% endfor %} |
19 |
| -{% if service.all_passing_checks %} |
20 |
| -Passing checks:{% for check in service.all_passing_checks %} |
21 |
| - PASSING - {{ check.name }} - Type: {{ check.check_category }} - Importance: {{ check.get_importance_display }}{% endfor %} |
22 |
| -{% endif %} |
23 |
| -{% endif %} |
24 |
| -""" |
| 21 | +class AlertPlugin(PolymorphicModel): |
| 22 | + title = models.CharField(max_length=30, unique=True, editable=False) |
| 23 | + enabled = models.BooleanField(default=True) |
25 | 24 |
|
26 |
| -hipchat_template = "Service {{ service.name }} {% if service.overall_status == service.PASSING_STATUS %}is back to normal{% else %}reporting {{ service.overall_status }} status{% endif %}: {{ scheme }}://{{ host }}{% url 'service' pk=service.id %}. {% if service.overall_status != service.PASSING_STATUS %}Checks failing:{% for check in service.all_failing_checks %}{% if check.check_category == 'Jenkins check' %}{% if check.last_result.error %} {{ check.name }} ({{ check.last_result.error|safe }}) {{jenkins_api}}job/{{ check.name }}/{{ check.last_result.job_number }}/console{% else %} {{ check.name }} {{jenkins_api}}/job/{{ check.name }}/{{check.last_result.job_number}}/console {% endif %}{% else %} {{ check.name }} {% if check.last_result.error %} ({{ check.last_result.error|safe }}){% endif %}{% endif %}{% endfor %}{% endif %}{% if alert %}{% for alias in users %} @{{ alias }}{% endfor %}{% endif %}" |
| 25 | + author = None |
27 | 26 |
|
28 |
| -sms_template = "Service {{ service.name }} {% if service.overall_status == service.PASSING_STATUS %}is back to normal{% else %}reporting {{ service.overall_status }} status{% endif %}: {{ scheme }}://{{ host }}{% url 'service' pk=service.id %}" |
| 27 | + def __unicode__(self): |
| 28 | + return u'%s' % (self.title) |
29 | 29 |
|
30 |
| -telephone_template = "This is an urgent message from Arachnys monitoring. Service \"{{ service.name }}\" is erroring. Please check Cabot urgently." |
| 30 | + def send_alert(service, users, duty_officers): |
| 31 | + """ |
| 32 | + Implement a send_alert function here that shall be called. |
| 33 | + """ |
| 34 | + return True |
31 | 35 |
|
| 36 | +class AlertPluginUserData(PolymorphicModel): |
| 37 | + title = models.CharField(max_length=30, editable=False) |
| 38 | + user = models.ForeignKey('UserProfile', editable=False) |
| 39 | + |
| 40 | + class Meta: |
| 41 | + unique_together = ('title', 'user',) |
| 42 | + |
| 43 | + def __unicode__(self): |
| 44 | + return u'%s' % (self.title) |
32 | 45 |
|
33 | 46 | def send_alert(service, duty_officers=None):
|
34 | 47 | users = service.users_to_notify.filter(is_active=True)
|
35 |
| - if service.email_alert: |
36 |
| - send_email_alert(service, users, duty_officers) |
37 |
| - if service.hipchat_alert: |
38 |
| - send_hipchat_alert(service, users, duty_officers) |
39 |
| - if service.sms_alert: |
40 |
| - send_sms_alert(service, users, duty_officers) |
41 |
| - if service.telephone_alert: |
42 |
| - send_telephone_alert(service, users, duty_officers) |
43 |
| - |
44 |
| - |
45 |
| -def send_email_alert(service, users, duty_officers): |
46 |
| - emails = [u.email for u in users if u.email] |
47 |
| - if not emails: |
48 |
| - return |
49 |
| - c = Context({ |
50 |
| - 'service': service, |
51 |
| - 'host': settings.WWW_HTTP_HOST, |
52 |
| - 'scheme': settings.WWW_SCHEME |
53 |
| - }) |
54 |
| - if service.overall_status != service.PASSING_STATUS: |
55 |
| - if service.overall_status == service.CRITICAL_STATUS: |
56 |
| - emails += [u.email for u in duty_officers] |
57 |
| - subject = '%s status for service: %s' % ( |
58 |
| - service.overall_status, service.name) |
59 |
| - else: |
60 |
| - subject = 'Service back to normal: %s' % (service.name,) |
61 |
| - t = Template(email_template) |
62 |
| - send_mail( |
63 |
| - subject=subject, |
64 |
| - message=t.render(c), |
65 |
| - from_email='Cabot <%s>' % settings.CABOT_FROM_EMAIL, |
66 |
| - recipient_list=emails, |
67 |
| - ) |
68 |
| - |
69 |
| - |
70 |
| -def send_hipchat_alert(service, users, duty_officers): |
71 |
| - alert = True |
72 |
| - hipchat_aliases = [u.profile.hipchat_alias for u in users if hasattr( |
73 |
| - u, 'profile') and u.profile.hipchat_alias] |
74 |
| - if service.overall_status == service.WARNING_STATUS: |
75 |
| - alert = False # Don't alert at all for WARNING |
76 |
| - if service.overall_status == service.ERROR_STATUS: |
77 |
| - if service.old_overall_status in (service.ERROR_STATUS, service.ERROR_STATUS): |
78 |
| - alert = False # Don't alert repeatedly for ERROR |
79 |
| - if service.overall_status == service.PASSING_STATUS: |
80 |
| - color = 'green' |
81 |
| - if service.old_overall_status == service.WARNING_STATUS: |
82 |
| - alert = False # Don't alert for recovery from WARNING status |
83 |
| - else: |
84 |
| - color = 'red' |
85 |
| - if service.overall_status == service.CRITICAL_STATUS: |
86 |
| - hipchat_aliases += [u.profile.hipchat_alias for u in duty_officers if hasattr( |
87 |
| - u, 'profile') and u.profile.hipchat_alias] |
88 |
| - c = Context({ |
89 |
| - 'service': service, |
90 |
| - 'users': hipchat_aliases, |
91 |
| - 'host': settings.WWW_HTTP_HOST, |
92 |
| - 'scheme': settings.WWW_SCHEME, |
93 |
| - 'alert': alert, |
94 |
| - 'jenkins_api': settings.JENKINS_API, |
95 |
| - }) |
96 |
| - message = Template(hipchat_template).render(c) |
97 |
| - _send_hipchat_alert(message, color=color, sender='Cabot/%s' % service.name) |
98 |
| - |
99 |
| - |
100 |
| -def _send_hipchat_alert(message, color='green', sender='Cabot'): |
101 |
| - room = settings.HIPCHAT_ALERT_ROOM |
102 |
| - api_key = settings.HIPCHAT_API_KEY |
103 |
| - url = settings.HIPCHAT_URL |
104 |
| - resp = requests.post(url + '?auth_token=' + api_key, data={ |
105 |
| - 'room_id': room, |
106 |
| - 'from': sender[:15], |
107 |
| - 'message': message, |
108 |
| - 'notify': 1, |
109 |
| - 'color': color, |
110 |
| - 'message_format': 'text', |
111 |
| - }) |
112 |
| - |
113 |
| - |
114 |
| -def send_sms_alert(service, users, duty_officers): |
115 |
| - client = TwilioRestClient( |
116 |
| - settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) |
117 |
| - mobiles = [u.profile.prefixed_mobile_number for u in users if hasattr( |
118 |
| - u, 'profile') and u.profile.mobile_number] |
119 |
| - if service.is_critical: |
120 |
| - mobiles += [u.profile.prefixed_mobile_number for u in duty_officers if hasattr( |
121 |
| - u, 'profile') and u.profile.mobile_number] |
122 |
| - c = Context({ |
123 |
| - 'service': service, |
124 |
| - 'host': settings.WWW_HTTP_HOST, |
125 |
| - 'scheme': settings.WWW_SCHEME, |
126 |
| - }) |
127 |
| - message = Template(sms_template).render(c) |
128 |
| - mobiles = list(set(mobiles)) |
129 |
| - for mobile in mobiles: |
130 |
| - try: |
131 |
| - client.sms.messages.create( |
132 |
| - to=mobile, |
133 |
| - from_=settings.TWILIO_OUTGOING_NUMBER, |
134 |
| - body=message, |
135 |
| - ) |
136 |
| - except Exception, e: |
137 |
| - logger.exception('Error sending twilio sms: %s' % e) |
138 |
| - |
139 |
| - |
140 |
| -def send_telephone_alert(service, users, duty_officers): |
141 |
| - # No need to call to say things are resolved |
142 |
| - if service.overall_status != service.CRITICAL_STATUS: |
143 |
| - return |
144 |
| - client = TwilioRestClient( |
145 |
| - settings.TWILIO_ACCOUNT_SID, settings.TWILIO_AUTH_TOKEN) |
146 |
| - mobiles = [u.profile.prefixed_mobile_number for u in duty_officers if hasattr( |
147 |
| - u, 'profile') and u.profile.mobile_number] |
148 |
| - url = 'http://%s%s' % (settings.WWW_HTTP_HOST, |
149 |
| - reverse('twiml-callback', kwargs={'service_id': service.id})) |
150 |
| - for mobile in mobiles: |
151 |
| - try: |
152 |
| - client.calls.create( |
153 |
| - to=mobile, |
154 |
| - from_=settings.TWILIO_OUTGOING_NUMBER, |
155 |
| - url=url, |
156 |
| - method='GET', |
157 |
| - ) |
158 |
| - except Exception, e: |
159 |
| - logger.exception('Error making twilio phone call: %s' % e) |
160 |
| - |
| 48 | + for alert in service.alerts.all(): |
| 49 | + alert.send_alert(service, users, duty_officers) |
161 | 50 |
|
162 |
| -def telephone_alert_twiml_callback(service): |
163 |
| - c = Context({'service': service}) |
164 |
| - t = Template(telephone_template).render(c) |
165 |
| - r = twiml.Response() |
166 |
| - r.say(t, voice='woman') |
167 |
| - r.hangup() |
168 |
| - return r |
| 51 | +def update_alert_plugins(): |
| 52 | + for plugin_subclass in AlertPlugin.__subclasses__(): |
| 53 | + plugin = plugin_subclass.objects.get_or_create(title=plugin_subclass.name) |
| 54 | + return AlertPlugin.objects.all() |
0 commit comments