diff --git a/src/main/java/org/elasticsearch/alerts/actions/ActionModule.java b/src/main/java/org/elasticsearch/alerts/actions/ActionModule.java index 673fd13f4ed..0da3d6dcedd 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/ActionModule.java +++ b/src/main/java/org/elasticsearch/alerts/actions/ActionModule.java @@ -6,6 +6,7 @@ package org.elasticsearch.alerts.actions; import org.elasticsearch.alerts.actions.email.EmailAction; +import org.elasticsearch.alerts.actions.email.EmailSettingsService; import org.elasticsearch.alerts.actions.index.IndexAction; import org.elasticsearch.alerts.actions.webhook.HttpClient; import org.elasticsearch.alerts.actions.webhook.WebhookAction; @@ -46,6 +47,7 @@ public class ActionModule extends AbstractModule { bind(ActionRegistry.class).asEagerSingleton(); bind(HttpClient.class).asEagerSingleton(); + bind(EmailSettingsService.class).asEagerSingleton(); } diff --git a/src/main/java/org/elasticsearch/alerts/actions/email/EmailAction.java b/src/main/java/org/elasticsearch/alerts/actions/email/EmailAction.java index 1064ae7f952..7840cba5dc8 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/email/EmailAction.java +++ b/src/main/java/org/elasticsearch/alerts/actions/email/EmailAction.java @@ -9,8 +9,6 @@ import org.elasticsearch.alerts.Alert; import org.elasticsearch.alerts.actions.Action; import org.elasticsearch.alerts.actions.ActionException; import org.elasticsearch.alerts.support.StringTemplateUtils; -import org.elasticsearch.cluster.settings.DynamicSettings; -import org.elasticsearch.cluster.settings.Validator; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; @@ -19,7 +17,6 @@ import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.node.settings.NodeSettingsService; import org.elasticsearch.script.ScriptService; import javax.mail.*; @@ -31,16 +28,10 @@ import java.util.*; /** */ -public class EmailAction extends Action implements NodeSettingsService.Listener { +public class EmailAction extends Action { public static final String TYPE = "email"; - static final String PORT_SETTING = "alerts.action.email.server.port"; - static final String SERVER_SETTING = "alerts.action.email.server.name"; - static final String FROM_SETTING = "alerts.action.email.from.address"; - static final String USERNAME_SETTING = "alerts.action.email.from.username"; - static final String PASSWORD_SETTING = "alerts.action.email.from.password"; - private final List
emailAddresses; //Optional, can be null, will use defaults from emailSettings (EmailServiceConfig) @@ -48,9 +39,6 @@ public class EmailAction extends Action implements NodeSetti private final StringTemplateUtils.Template subjectTemplate; private final StringTemplateUtils.Template messageTemplate; - private static final String DEFAULT_SERVER = "smtp.gmail.com"; - private static final int DEFAULT_PORT = 578; - private static final StringTemplateUtils.Template DEFAULT_SUBJECT_TEMPLATE = new StringTemplateUtils.Template( "Elasticsearch Alert {{alert_name}} triggered", null, "mustache", ScriptService.ScriptType.INLINE); @@ -59,24 +47,22 @@ public class EmailAction extends Action implements NodeSetti private final StringTemplateUtils templateUtils; - private volatile EmailServiceConfig emailSettings = new EmailServiceConfig(DEFAULT_SERVER, DEFAULT_PORT, null, null, null); + private final EmailSettingsService emailSettingsService; - - protected EmailAction(ESLogger logger, Settings settings, NodeSettingsService nodeSettingsService, + protected EmailAction(ESLogger logger, EmailSettingsService emailSettingsService, StringTemplateUtils templateUtils, @Nullable StringTemplateUtils.Template subjectTemplate, @Nullable StringTemplateUtils.Template messageTemplate, @Nullable String fromAddress, List
emailAddresses) { super(logger); this.templateUtils = templateUtils; + this.emailSettingsService = emailSettingsService; + this.emailAddresses = new ArrayList<>(); this.emailAddresses.addAll(emailAddresses); this.subjectTemplate = subjectTemplate; this.messageTemplate = messageTemplate; this.fromAddress = fromAddress; - - nodeSettingsService.addListener(this); - updateSettings(settings); } @Override @@ -87,19 +73,21 @@ public class EmailAction extends Action implements NodeSetti @Override public Result execute(Alert alert, Map data) throws IOException { + final EmailSettingsService.EmailServiceConfig emailSettings = emailSettingsService.emailServiceConfig(); + Properties props = new Properties(); props.put("mail.smtp.auth", "true"); props.put("mail.smtp.starttls.enable", "true"); - props.put("mail.smtp.host", emailSettings.host); - props.put("mail.smtp.port", emailSettings.port); + props.put("mail.smtp.host", emailSettings.host()); + props.put("mail.smtp.port", emailSettings.port()); final Session session; - if (emailSettings.password != null) { + if (emailSettings.password() != null) { final String username; - if (emailSettings.username != null) { - username = emailSettings.username; + if (emailSettings.username() != null) { + username = emailSettings.username(); } else { - username = emailSettings.defaultFromAddress; + username = emailSettings.defaultFromAddress(); } if (username == null) { @@ -109,7 +97,7 @@ public class EmailAction extends Action implements NodeSetti session = Session.getInstance(props, new javax.mail.Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, emailSettings.password); + return new PasswordAuthentication(username, emailSettings.password()); } }); } else { @@ -119,7 +107,7 @@ public class EmailAction extends Action implements NodeSetti try { Message email = new MimeMessage(session); - String fromAddressToUse = emailSettings.defaultFromAddress; + String fromAddressToUse = emailSettings.defaultFromAddress(); if (fromAddress != null) { fromAddressToUse = fromAddress; } @@ -179,11 +167,6 @@ public class EmailAction extends Action implements NodeSetti } - @Override - public void onRefreshSettings(Settings settings) { - updateSettings(settings); - } - public static class Parser extends AbstractComponent implements Action.Parser { public static final ParseField FROM_FIELD = new ParseField("from"); @@ -191,20 +174,14 @@ public class EmailAction extends Action implements NodeSetti public static final ParseField MESSAGE_TEMPLATE_FIELD = new ParseField("message_template"); public static final ParseField SUBJECT_TEMPLATE_FIELD = new ParseField("subject_template"); - private final NodeSettingsService nodeSettingsService; private final StringTemplateUtils templateUtils; + private final EmailSettingsService emailSettingsService; @Inject - public Parser(Settings settings, DynamicSettings dynamicSettings, NodeSettingsService nodeSettingsService, StringTemplateUtils templateUtils) { + public Parser(Settings settings, EmailSettingsService emailSettingsService, StringTemplateUtils templateUtils) { super(settings); - this.nodeSettingsService = nodeSettingsService; this.templateUtils = templateUtils; - - dynamicSettings.addDynamicSetting(PORT_SETTING, Validator.POSITIVE_INTEGER); - dynamicSettings.addDynamicSetting(SERVER_SETTING); - dynamicSettings.addDynamicSetting(FROM_SETTING); - dynamicSettings.addDynamicSetting(USERNAME_SETTING); - dynamicSettings.addDynamicSetting(PASSWORD_SETTING); + this.emailSettingsService = emailSettingsService; } @Override @@ -256,8 +233,8 @@ public class EmailAction extends Action implements NodeSetti throw new ActionException("could not parse email action. [addresses] was not found or was empty"); } - return new EmailAction(logger, settings, nodeSettingsService, - templateUtils, subjectTemplate, messageTemplate, fromAddress, addresses); + return new EmailAction(logger, emailSettingsService, templateUtils, subjectTemplate, + messageTemplate, fromAddress, addresses); } } @@ -306,66 +283,4 @@ public class EmailAction extends Action implements NodeSetti } } - - - // This is useful to change all settings at the same time. Otherwise we may change the username then email gets send - // and then change the password and then the email sending fails. - // - // Also this reduces the number of volatile writes - private class EmailServiceConfig { - - private String host; - private int port; - private String username; - private String password; - - private String defaultFromAddress; - - private EmailServiceConfig(String host, int port, String userName, String password, String defaultFromAddress) { - this.host = host; - this.port = port; - this.username = userName; - this.password = password; - this.defaultFromAddress = defaultFromAddress; - - } - } - - private void updateSettings(Settings settings) { - boolean changed = false; - String host = emailSettings.host; - String newHost = settings.get(SERVER_SETTING); - if (newHost != null && !newHost.equals(host)) { - host = newHost; - changed = true; - } - int port = emailSettings.port; - int newPort = settings.getAsInt(PORT_SETTING, -1); - if (newPort != -1) { - port = newPort; - changed = true; - } - String fromAddress = emailSettings.defaultFromAddress; - String newFromAddress = settings.get(FROM_SETTING); - if (newFromAddress != null && !newFromAddress.equals(fromAddress)) { - fromAddress = newFromAddress; - changed = true; - } - String userName = emailSettings.username; - String newUserName = settings.get(USERNAME_SETTING); - if (newUserName != null && !newUserName.equals(userName)) { - userName = newFromAddress; - changed = true; - } - String password = emailSettings.password; - String newPassword = settings.get(PASSWORD_SETTING); - if (newPassword != null && !newPassword.equals(password)) { - password = newPassword; - changed = true; - } - if (changed) { - emailSettings = new EmailServiceConfig(host, port, fromAddress, userName, password); - } - } - } diff --git a/src/main/java/org/elasticsearch/alerts/actions/email/EmailSettingsService.java b/src/main/java/org/elasticsearch/alerts/actions/email/EmailSettingsService.java new file mode 100644 index 00000000000..947578d14ab --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/actions/email/EmailSettingsService.java @@ -0,0 +1,141 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.alerts.actions.email; + +import org.elasticsearch.cluster.settings.DynamicSettings; +import org.elasticsearch.cluster.settings.Validator; +import org.elasticsearch.common.component.AbstractComponent; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.node.settings.NodeSettingsService; + +/** + */ +public class EmailSettingsService extends AbstractComponent implements NodeSettingsService.Listener { + + static final String PORT_SETTING = "alerts.action.email.server.port"; + static final String SERVER_SETTING = "alerts.action.email.server.name"; + static final String FROM_SETTING = "alerts.action.email.from.address"; + static final String USERNAME_SETTING = "alerts.action.email.from.username"; + static final String PASSWORD_SETTING = "alerts.action.email.from.password"; + + private static final String DEFAULT_SERVER = "smtp.gmail.com"; + private static final int DEFAULT_PORT = 578; + + private volatile EmailServiceConfig emailServiceConfig = new EmailServiceConfig(DEFAULT_SERVER, DEFAULT_PORT, null, null, null); + + @Inject + public EmailSettingsService(Settings settings, DynamicSettings dynamicSettings, NodeSettingsService nodeSettingsService) { + super(settings); + //TODO Add validators for hosts and email addresses + dynamicSettings.addDynamicSetting(PORT_SETTING, Validator.POSITIVE_INTEGER); + dynamicSettings.addDynamicSetting(SERVER_SETTING); + dynamicSettings.addDynamicSetting(FROM_SETTING); + dynamicSettings.addDynamicSetting(USERNAME_SETTING); + dynamicSettings.addDynamicSetting(PASSWORD_SETTING); + + nodeSettingsService.addListener(this); + + updateSettings(settings); + + } + + public EmailServiceConfig emailServiceConfig() { + return emailServiceConfig; + } + + // This is useful to change all settings at the same time. Otherwise we may change the username then email gets send + // and then change the password and then the email sending fails. + // + // Also this reduces the number of volatile writes + static class EmailServiceConfig { + + private String host; + private int port; + private String username; + private String password; + private String defaultFromAddress; + + public String host() { + return host; + } + + public int port() { + return port; + } + + public String username() { + return username; + } + + public String password() { + return password; + } + + public String defaultFromAddress() { + return defaultFromAddress; + } + + private EmailServiceConfig(String host, int port, String userName, String password, String defaultFromAddress) { + this.host = host; + this.port = port; + this.username = userName; + this.password = password; + this.defaultFromAddress = defaultFromAddress; + + } + } + + @Override + public void onRefreshSettings(Settings settings) { + updateSettings(settings); + } + + private void updateSettings(Settings settings) { + boolean changed = false; + String host = emailServiceConfig.host; + String newHost = settings.get(SERVER_SETTING); + if (newHost != null && !newHost.equals(host)) { + logger.info("host changed from [{}] to [{}]", host, newHost); + host = newHost; + changed = true; + } + int port = emailServiceConfig.port; + int newPort = settings.getAsInt(PORT_SETTING, -1); + if (newPort != -1) { + logger.info("port changed from [{}] to [{}]", port, newPort); + port = newPort; + changed = true; + } + String fromAddress = emailServiceConfig.defaultFromAddress; + String newFromAddress = settings.get(FROM_SETTING); + if (newFromAddress != null && !newFromAddress.equals(fromAddress)) { + logger.info("from changed from [{}] to [{}]", fromAddress, newFromAddress); + fromAddress = newFromAddress; + changed = true; + } + String userName = emailServiceConfig.username; + String newUserName = settings.get(USERNAME_SETTING); + if (newUserName != null && !newUserName.equals(userName)) { + logger.info("username changed from [{}] to [{}]", userName, newUserName); + userName = newFromAddress; + changed = true; + } + String password = emailServiceConfig.password; + String newPassword = settings.get(PASSWORD_SETTING); + if (newPassword != null && !newPassword.equals(password)) { + logger.info("password changed"); + password = newPassword; + changed = true; + } + if (changed) { + logger.info("one or more settings have changed, updating the email service config"); + emailServiceConfig = new EmailServiceConfig(host, port, fromAddress, userName, password); + } + } + + +}