Skip to content
Snippets Groups Projects
Commit 2af807de authored by Tanner Prestegard's avatar Tanner Prestegard Committed by GraceDB
Browse files

Cleanup and bugfixes for email alerts

parent 4005f2b5
No related branches found
No related tags found
No related merge requests found
from __future__ import absolute_import
import json
import logging
import os
import socket
from subprocess import Popen, PIPE, STDOUT
import sys
from django.core.mail import EmailMessage
from django.conf import settings
from core.time_utils import gpsToUtc
from events.models import Event
from events.permission_utils import is_external
from search.query.labels import filter_for_labels
# Set up logger
log = logging.getLogger(__name__)
......@@ -39,73 +31,7 @@ def prepareSummary(event):
Component masses: %.2f, %.2f """ % (si.mass1, si.mass2)
return summary
# The serialized object passed in here will normally be an EventLog or EMBB log entry
def issueAlertForUpdate(event, description, doxmpp, filename="", serialized_object=None):
if doxmpp:
issueXMPPAlert(event, filename, "update", description, serialized_object)
# XXX No emails or phone calls for this. Argh.
# The only kind of serialized object relevant for a Label is an event.
def issueAlertForLabel(event, label, doxmpp, serialized_event=None, event_url=None):
if doxmpp:
issueXMPPAlert(event, "", "label", label, serialized_event)
# Email
profileRecips = []
phoneRecips = []
pipeline = event.pipeline
# Triggers on given label matching pipeline OR with no pipeline (wildcard type)
triggers = label.trigger_set.filter(pipelines=pipeline)
triggers = triggers | label.trigger_set.filter(pipelines=None)
for trigger in triggers:
if len(trigger.label_query) > 0:
# construct a queryset containing only this event
qs = Event.objects.filter(id=event.id)
qs = filter_for_labels(qs, trigger.label_query)
# If the label query cleans out our query set, we'll continue
# without adding the recipient.
if qs.count() == 0:
continue
for recip in trigger.contacts.all():
if recip.email:
profileRecips.append(recip.email)
if recip.phone:
phoneRecips.append(recip)
if event.search:
subject = "[gracedb] %s / %s / %s / %s" % (label.name, event.pipeline.name, event.search.name, event.graceid)
else:
subject = "[gracedb] %s / %s / %s" % (label.name, event.pipeline.name, event.graceid)
message = "A %s event with graceid %s was labeled with %s" % \
(event.pipeline.name, event.graceid, label.name)
if event_url:
message += '\n\n%s' % event_url
if event.group.name == "Test":
fromaddress = settings.ALERT_TEST_EMAIL_FROM
toaddresses = settings.ALERT_TEST_EMAIL_TO
bccaddresses = []
message += "\n\nWould have sent email to: %s" % str(profileRecips)
message += "\n\nWould have called/texted: {0}" \
.format(str([c.phone for c in phoneRecips]))
phoneRecips = []
else:
fromaddress = settings.ALERT_EMAIL_FROM
toaddresses = []
bccaddresses = profileRecips
if settings.SEND_EMAIL_ALERTS and (toaddresses or bccaddresses):
if not toaddresses:
toaddresses = ["(undisclosed recipients)"]
email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses)
email.send()
# Make phone calls.
if settings.SEND_PHONE_ALERTS and phoneRecips:
make_twilio_calls(event, phoneRecips, "label", label=label)
def issueEmailAlert(event, event_url):
def issue_email_alerts(event, event_url):
# Check settings switch for turning off email alerts
if not settings.SEND_EMAIL_ALERTS:
......@@ -162,112 +88,3 @@ Event Summary:
email = EmailMessage(subject, message, fromaddress, toaddresses, bccaddresses)
email.send()
def issuePhoneAlert(event):
# Check settings switch for turning off phone alerts
if not settings.SEND_PHONE_ALERTS:
return
# The right way of doing this is to make the email alerts filter-able
# by search. But this is a low priority dev task. For now, we simply
# short-circuit in case this is an MDC event.
if event.search and event.search.name == 'MDC':
return
# Gather recipients
phoneRecips = []
if event.group.name != 'Test':
pipeline = event.pipeline
triggers = pipeline.trigger_set.filter(labels=None)
for trigger in triggers:
for recip in trigger.contacts.all():
if ((event.far and event.far < trigger.farThresh)
or not trigger.farThresh):
if recip.phone:
phoneRecips.append(recip)
# Make phone calls.
if phoneRecips:
make_twilio_calls(event, phoneRecips, "create")
def issueXMPPAlert(event, location, alert_type="new", description="", serialized_object=None):
# Check settings switch for turning off XMPP alerts
if not settings.SEND_XMPP_ALERTS:
return
nodename = "%s_%s" % (event.group.name, event.pipeline.name)
nodename = nodename.lower()
nodenames = [ nodename, ]
if event.search:
nodename = nodename + "_%s" % event.search.name.lower()
nodenames.append(nodename)
log.debug('issueXMPPAlert: %s' % event.graceid)
# Create the output dictionary and serialize as JSON.
lva_data = {
'file': location,
'uid': event.graceid,
'alert_type': alert_type,
# The following string cast is necessary because sometimes
# description is a label object!
'description': str(description),
'labels': [label.name for label in event.labels.all()]
}
if serialized_object:
lva_data['object'] = serialized_object
msg = json.dumps(lva_data)
log.debug("issueXMPPAlert: writing message %s" % msg)
if settings.USE_LVALERT_OVERSEER:
manager = Manager()
for server in settings.ALERT_XMPP_SERVERS:
port = settings.LVALERT_OVERSEER_PORTS[server]
for nodename in nodenames:
if settings.USE_LVALERT_OVERSEER:
# Calculate unique message_id and log
message_id = sha1(nodename + msg).hexdigest()
log.info("issueXMPPAlert: sending %s,%s,%s to node %s" % (event.graceid, alert_type, message_id, nodename))
rdict = manager.dict()
msg_dict = {'node_name': nodename, 'message': msg, 'action': 'push'}
p = Process(target=send_to_overseer, args=(msg_dict, rdict, log, True, port))
p.start()
p.join()
if rdict.get('success', None):
continue
# If not success, we need to do this the old way.
log.info("issueXMPPAlert: failover to lvalert_send")
else:
# Not using LVAlert overseer, so just log the node and server
log.info("issueXMPPAlert: sending to node %s on %s" % (nodename, server))
# Set up environment for running lvalert_send script
env = os.environ.copy()
# Construct lvalert_send command
p = Popen(
["lvalert_send",
"--server=%s" % server,
"--file=-",
"--node=%s" % nodename,
],
stdin=PIPE,
stdout=PIPE,
stderr=PIPE,
env=env)
# Send lvalert message to subprocess
out, err = p.communicate(msg)
log.debug("issueXMPPAlert: lvalert_send: return code %s" % p.returncode)
if p.returncode > 0:
# XXX This should probably raise an exception.
log.error("issueXMPPAlert: ERROR: %s" % err)
......@@ -10,6 +10,7 @@ from django.conf import settings
from django.contrib.auth.models import Group
from django.core.mail import EmailMessage
from django.db.models import QuerySet, Q
from django.urls import reverse
from core.time_utils import gpsToUtc
from events.models import Event
......@@ -18,6 +19,7 @@ from events.shortcuts import is_event
from search.query.labels import filter_for_labels
from superevents.shortcuts import is_superevent
from userprofile.models import Contact
from .email import issue_email_alerts
from .phone import issue_phone_alerts
from .xmpp import issue_xmpp_alerts
......@@ -126,7 +128,10 @@ def issue_alerts(event_or_superevent, alert_type, serialized_object,
if event.offline:
return
# Compile phone and email recipients for alert
# Compile phone and email recipients for new or label alerts
if alert_type not in ["new", "label"]:
return
if alert_type == "new":
email_recips, phone_recips = get_alert_recips(event_or_superevent)
# Force label = None for new alerts
......@@ -136,7 +141,8 @@ def issue_alerts(event_or_superevent, alert_type, serialized_object,
get_alert_recips_for_label(event_or_superevent, label)
if settings.SEND_EMAIL_ALERTS:
issueEmailAlert(event_or_superevent, url)
url = reverse('view', args=[event_or_superevent.graceid])
issue_email_alerts(event_or_superevent, url)
if settings.SEND_PHONE_ALERTS and phone_recips:
issue_phone_alerts(event_or_superevent, phone_recips, label=label)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment