diff --git a/java/google/registry/env/production/default/WEB-INF/cron.xml b/java/google/registry/env/production/default/WEB-INF/cron.xml index 0a8081e60..d4f27477f 100644 --- a/java/google/registry/env/production/default/WEB-INF/cron.xml +++ b/java/google/registry/env/production/default/WEB-INF/cron.xml @@ -271,7 +271,7 @@ - Starts the beam/InvoicingPipeline Dataflow template, which creates the overall invoice and + Starts the beam/invoicing/InvoicingPipeline Dataflow template, which creates the overall invoice and detail report CSVs for last month, storing them in gs://[PROJECT-ID]-billing/invoices/yyyy-MM. Upon success, sends an e-mail copy of the invoice to billing personnel, and copies detail reports to the associated registrars' drive folders. @@ -285,4 +285,17 @@ 1 of month 17:00 backend + + + + + Starts the beam/spec11/Spec11Pipeline Dataflow template, which creates last month's Spec11 + report. This report is stored in gs://[PROJECT-ID]-reporting/icann/spec11/yyyy-MM. + Upon Dataflow job completion, sends an e-mail to all registrars with domain registrations + flagged by the SafeBrowsing API. + See GenerateSpec11ReportAction for more details. + + 2 of month 15:00 + backend + diff --git a/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java b/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java index cf851e1aa..d8866617f 100644 --- a/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java +++ b/java/google/registry/reporting/spec11/PublishSpec11ReportAction.java @@ -39,7 +39,7 @@ import org.joda.time.YearMonth; * pipeline accordingly. * *

This calls {@link Spec11EmailUtils#emailSpec11Reports()} on success or {@link - * Spec11EmailUtils#sendFailureAlertEmail(String)} on failure. + * Spec11EmailUtils#sendAlertEmail(String, String)} on failure. */ @Action(path = PublishSpec11ReportAction.PATH, method = POST, auth = Auth.AUTH_INTERNAL_OR_ADMIN) public class PublishSpec11ReportAction implements Runnable { @@ -88,7 +88,8 @@ public class PublishSpec11ReportAction implements Runnable { case JOB_FAILED: logger.atSevere().log("Dataflow job %s finished unsuccessfully.", jobId); response.setStatus(SC_NO_CONTENT); - emailUtils.sendFailureAlertEmail( + emailUtils.sendAlertEmail( + String.format("Spec11 Dataflow Pipeline Failure %s", yearMonth.toString()), String.format( "Spec11 %s job %s ended in status failure.", yearMonth.toString(), jobId)); break; @@ -99,7 +100,8 @@ public class PublishSpec11ReportAction implements Runnable { } } catch (IOException e) { logger.atSevere().withCause(e).log("Failed to publish Spec11 reports."); - emailUtils.sendFailureAlertEmail( + emailUtils.sendAlertEmail( + String.format("Spec11 Publish Failure %s", yearMonth.toString()), String.format( "Spec11 %s publish action failed due to %s", yearMonth.toString(), e.getMessage())); response.setStatus(SC_INTERNAL_SERVER_ERROR); diff --git a/java/google/registry/reporting/spec11/Spec11EmailUtils.java b/java/google/registry/reporting/spec11/Spec11EmailUtils.java index a9abfbe5d..310afbd46 100644 --- a/java/google/registry/reporting/spec11/Spec11EmailUtils.java +++ b/java/google/registry/reporting/spec11/Spec11EmailUtils.java @@ -97,12 +97,16 @@ public class Spec11EmailUtils { MessagingException.class); } catch (Throwable e) { // Send an alert with the root cause, unwrapping the retrier's RuntimeException - sendFailureAlertEmail( + sendAlertEmail( + String.format("Spec11 Emailing Failure %s", yearMonth.toString()), String.format( "Emailing spec11 reports failed due to %s", getRootCause(e).getMessage())); throw new RuntimeException("Emailing spec11 report failed", e); } + sendAlertEmail( + String.format("Spec11 Pipeline Success %s", yearMonth.toString()), + "Spec11 reporting completed successfully."); } private void emailRegistrar(String line) throws MessagingException, JSONException { @@ -110,10 +114,9 @@ public class Spec11EmailUtils { JSONObject reportJSON = new JSONObject(line); String registrarEmail = reportJSON.getString(Spec11Pipeline.REGISTRAR_EMAIL_FIELD); JSONArray threatMatches = reportJSON.getJSONArray(Spec11Pipeline.THREAT_MATCHES_FIELD); - // TODO(b/112354588): Reword this e-mail according to business team's opinions. StringBuilder body = new StringBuilder("Hello registrar partner,\n") - .append("The SafeBrowsing API has detected problems with the following domains:\n"); + .append("We have detected problems with the following domains:\n"); for (int i = 0; i < threatMatches.length(); i++) { ThreatMatch threatMatch = ThreatMatch.fromJSON(threatMatches.getJSONObject(i)); body.append( @@ -124,23 +127,22 @@ public class Spec11EmailUtils { .append("Regards,\nGoogle Registry\n"); Message msg = emailService.createMessage(); msg.setSubject( - String.format("Spec11 Monthly Threat Detector [%s]", yearMonth.toString())); + String.format("Google Registry Monthly Threat Detector [%s]", yearMonth.toString())); msg.setText(body.toString()); msg.setFrom(new InternetAddress(alertSenderAddress)); msg.setRecipient(RecipientType.TO, new InternetAddress(registrarEmail)); emailService.sendMessage(msg); - } - /** Sends an e-mail to the provided alert e-mail address indicating a spec11 failure. */ - void sendFailureAlertEmail(String body) { + /** Sends an e-mail indicating the state of the spec11 pipeline, with a given subject and body. */ + void sendAlertEmail(String subject, String body) { try { retrier.callWithRetry( () -> { Message msg = emailService.createMessage(); msg.setFrom(new InternetAddress(alertSenderAddress)); msg.addRecipient(RecipientType.TO, new InternetAddress(alertRecipientAddress)); - msg.setSubject(String.format("Spec11 Pipeline Alert: %s", yearMonth.toString())); + msg.setSubject(subject); msg.setText(body); emailService.sendMessage(msg); return null; diff --git a/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java b/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java index 7f444136f..ce28bac42 100644 --- a/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java +++ b/javatests/google/registry/reporting/spec11/PublishSpec11ReportActionTest.java @@ -83,7 +83,10 @@ public class PublishSpec11ReportActionTest { expectedJob.setCurrentState("JOB_STATE_FAILED"); publishAction.run(); assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT); - verify(emailUtils).sendFailureAlertEmail("Spec11 2018-06 job 12345 ended in status failure."); + verify(emailUtils) + .sendAlertEmail( + "Spec11 Dataflow Pipeline Failure 2018-06", + "Spec11 2018-06 job 12345 ended in status failure."); } @Test @@ -102,6 +105,8 @@ public class PublishSpec11ReportActionTest { assertThat(response.getContentType()).isEqualTo(MediaType.PLAIN_TEXT_UTF_8); assertThat(response.getPayload()).isEqualTo("Template launch failed: expected"); verify(emailUtils) - .sendFailureAlertEmail("Spec11 2018-06 publish action failed due to expected"); + .sendAlertEmail( + "Spec11 Publish Failure 2018-06", + "Spec11 2018-06 publish action failed due to expected"); } } diff --git a/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java b/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java index 99eddfb03..ce43ad2ae 100644 --- a/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java +++ b/javatests/google/registry/reporting/spec11/Spec11EmailUtilsTest.java @@ -93,15 +93,15 @@ public class Spec11EmailUtilsTest { public void testSuccess_emailSpec11Reports() throws MessagingException, IOException { emailUtils.emailSpec11Reports(); // We inspect individual parameters because Message doesn't implement equals(). - verify(emailService, times(2)).sendMessage(gotMessage.capture()); + verify(emailService, times(3)).sendMessage(gotMessage.capture()); List capturedMessages = gotMessage.getAllValues(); validateMessage( capturedMessages.get(0), "my-sender@test.com", "a@fake.com", - "Spec11 Monthly Threat Detector [2018-06]", + "Google Registry Monthly Threat Detector [2018-06]", "Hello registrar partner,\n" - + "The SafeBrowsing API has detected problems with the following domains:\n" + + "We have detected problems with the following domains:\n" + "a.com - MALWARE\n" + "At the moment, no action is required. This is purely informatory." + "Regards,\nGoogle Registry\n"); @@ -109,13 +109,19 @@ public class Spec11EmailUtilsTest { capturedMessages.get(1), "my-sender@test.com", "b@fake.com", - "Spec11 Monthly Threat Detector [2018-06]", + "Google Registry Monthly Threat Detector [2018-06]", "Hello registrar partner,\n" - + "The SafeBrowsing API has detected problems with the following domains:\n" + + "We have detected problems with the following domains:\n" + "b.com - MALWARE\n" + "c.com - MALWARE\n" + "At the moment, no action is required. This is purely informatory." + "Regards,\nGoogle Registry\n"); + validateMessage( + capturedMessages.get(2), + "my-sender@test.com", + "my-receiver@test.com", + "Spec11 Pipeline Success 2018-06", + "Spec11 reporting completed successfully."); } @Test @@ -157,13 +163,13 @@ public class Spec11EmailUtilsTest { gotMessage.getValue(), "my-sender@test.com", "my-receiver@test.com", - "Spec11 Pipeline Alert: 2018-06", + "Spec11 Emailing Failure 2018-06", "Emailing spec11 reports failed due to expected"); } @Test public void testSuccess_sendAlertEmail() throws MessagingException, IOException { - emailUtils.sendFailureAlertEmail("Alert!"); + emailUtils.sendAlertEmail("Spec11 Pipeline Alert: 2018-06", "Alert!"); verify(emailService).sendMessage(gotMessage.capture()); validateMessage( gotMessage.getValue(),