From 2af807de18a76ae4e0de47def93efc876d0c5c1f Mon Sep 17 00:00:00 2001 From: Tanner Prestegard <tanner.prestegard@ligo.org> Date: Tue, 11 Dec 2018 09:39:01 -0600 Subject: [PATCH] Cleanup and bugfixes for email alerts --- gracedb/alerts/email.py | 185 +--------------------------------------- gracedb/alerts/main.py | 10 ++- 2 files changed, 9 insertions(+), 186 deletions(-) diff --git a/gracedb/alerts/email.py b/gracedb/alerts/email.py index f39999acb..f2ffc108d 100644 --- a/gracedb/alerts/email.py +++ b/gracedb/alerts/email.py @@ -1,18 +1,10 @@ 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) - diff --git a/gracedb/alerts/main.py b/gracedb/alerts/main.py index 5d7d04cdc..5aa68e42d 100644 --- a/gracedb/alerts/main.py +++ b/gracedb/alerts/main.py @@ -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) -- GitLab