Deguice Watcher Actions and Transformations (elastic/elasticsearch#3818)

This change simplifies the creation of Actions and Transformations.
It moves all instantiation away from guice into straight forward
constructor based initialization.

Original commit: elastic/x-pack-elasticsearch@3c0bca2bea
This commit is contained in:
Simon Willnauer 2016-10-19 23:35:16 +02:00 committed by GitHub
parent a4c0c49b43
commit 8b6867b99b
25 changed files with 162 additions and 416 deletions

View File

@ -233,7 +233,6 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
extensionsService.getExtensions())); extensionsService.getExtensions()));
components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService, sslService)); components.addAll(monitoring.createComponents(internalClient, threadPool, clusterService, licenseService, sslService));
components.addAll(watcher.createComponents(getClock(), scriptService));
// watcher http stuff // watcher http stuff
Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>(); Map<String, HttpAuthFactory> httpAuthFactories = new HashMap<>();
@ -245,8 +244,13 @@ public class XPackPlugin extends Plugin implements ScriptPlugin, ActionPlugin, I
final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, sslService); final HttpClient httpClient = new HttpClient(settings, httpAuthRegistry, sslService);
components.add(httpClient); components.add(httpClient);
components.addAll(createNotificationComponents(clusterService.getClusterSettings(), httpClient, Collection<Object> notificationComponents = createNotificationComponents(clusterService.getClusterSettings(), httpClient,
httpTemplateParser, scriptService, httpAuthRegistry)); httpTemplateParser, scriptService, httpAuthRegistry);
components.addAll(notificationComponents);
components.addAll(watcher.createComponents(getClock(), scriptService, internalClient, searchRequestParsers, licenseState,
httpClient, components));
// just create the reloader as it will pull all of the loaded ssl configurations and start watching them // just create the reloader as it will pull all of the loaded ssl configurations and start watching them
new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService); new SSLConfigurationReloader(settings, env, sslService, resourceWatcherService);

View File

@ -20,18 +20,44 @@ import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.common.util.concurrent.EsExecutors;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.ActionPlugin;
import org.elasticsearch.plugins.ScriptPlugin; import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.rest.RestHandler; import org.elasticsearch.rest.RestHandler;
import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.ExecutorBuilder;
import org.elasticsearch.threadpool.FixedExecutorBuilder; import org.elasticsearch.threadpool.FixedExecutorBuilder;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.XPackSettings; import org.elasticsearch.xpack.XPackSettings;
import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.notification.email.EmailService;
import org.elasticsearch.xpack.notification.email.attachment.EmailAttachmentsParser;
import org.elasticsearch.xpack.notification.hipchat.HipChatService;
import org.elasticsearch.xpack.notification.pagerduty.PagerDutyService;
import org.elasticsearch.xpack.notification.slack.SlackService;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.support.clock.Clock; import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.watcher.actions.WatcherActionModule; import org.elasticsearch.xpack.watcher.actions.ActionFactory;
import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatActionFactory;
import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
import org.elasticsearch.xpack.watcher.actions.index.IndexActionFactory;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingActionFactory;
import org.elasticsearch.xpack.watcher.actions.pagerduty.PagerDutyAction;
import org.elasticsearch.xpack.watcher.actions.pagerduty.PagerDutyActionFactory;
import org.elasticsearch.xpack.watcher.actions.slack.SlackAction;
import org.elasticsearch.xpack.watcher.actions.slack.SlackActionFactory;
import org.elasticsearch.xpack.watcher.actions.webhook.WebhookAction;
import org.elasticsearch.xpack.watcher.actions.webhook.WebhookActionFactory;
import org.elasticsearch.xpack.watcher.client.WatcherClientModule; import org.elasticsearch.xpack.watcher.client.WatcherClientModule;
import org.elasticsearch.xpack.watcher.condition.AlwaysCondition; import org.elasticsearch.xpack.watcher.condition.AlwaysCondition;
import org.elasticsearch.xpack.watcher.condition.ArrayCompareCondition; import org.elasticsearch.xpack.watcher.condition.ArrayCompareCondition;
@ -58,7 +84,12 @@ import org.elasticsearch.xpack.watcher.rest.action.RestWatchServiceAction;
import org.elasticsearch.xpack.watcher.rest.action.RestWatcherStatsAction; import org.elasticsearch.xpack.watcher.rest.action.RestWatcherStatsAction;
import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry; import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry;
import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig; import org.elasticsearch.xpack.watcher.support.WatcherIndexTemplateRegistry.TemplateConfig;
import org.elasticsearch.xpack.watcher.transform.TransformModule; import org.elasticsearch.xpack.watcher.transform.TransformFactory;
import org.elasticsearch.xpack.watcher.transform.TransformRegistry;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransformFactory;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransformFactory;
import org.elasticsearch.xpack.watcher.transport.actions.ack.AckWatchAction; import org.elasticsearch.xpack.watcher.transport.actions.ack.AckWatchAction;
import org.elasticsearch.xpack.watcher.transport.actions.ack.TransportAckWatchAction; import org.elasticsearch.xpack.watcher.transport.actions.ack.TransportAckWatchAction;
import org.elasticsearch.xpack.watcher.transport.actions.activate.ActivateWatchAction; import org.elasticsearch.xpack.watcher.transport.actions.activate.ActivateWatchAction;
@ -90,6 +121,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
@ -124,7 +156,9 @@ public class Watcher implements ActionPlugin, ScriptPlugin {
validAutoCreateIndex(settings); validAutoCreateIndex(settings);
} }
public Collection<Object> createComponents(Clock clock, ScriptService scriptService) { public Collection<Object> createComponents(Clock clock, ScriptService scriptService, InternalClient internalClient,
SearchRequestParsers searchRequestParsers, XPackLicenseState licenseState,
HttpClient httpClient, Collection<Object> components) {
final Map<String, ConditionFactory> parsers = new HashMap<>(); final Map<String, ConditionFactory> parsers = new HashMap<>();
parsers.put(AlwaysCondition.TYPE, (c, id, p, upgrade) -> AlwaysCondition.parse(id, p)); parsers.put(AlwaysCondition.TYPE, (c, id, p, upgrade) -> AlwaysCondition.parse(id, p));
parsers.put(NeverCondition.TYPE, (c, id, p, upgrade) -> NeverCondition.parse(id, p)); parsers.put(NeverCondition.TYPE, (c, id, p, upgrade) -> NeverCondition.parse(id, p));
@ -133,7 +167,40 @@ public class Watcher implements ActionPlugin, ScriptPlugin {
String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings); String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
parsers.put(ScriptCondition.TYPE, (c, id, p, upgrade) -> ScriptCondition.parse(scriptService, id, p, upgrade, parsers.put(ScriptCondition.TYPE, (c, id, p, upgrade) -> ScriptCondition.parse(scriptService, id, p, upgrade,
defaultLegacyScriptLanguage)); defaultLegacyScriptLanguage));
return Collections.singleton(new ConditionRegistry(Collections.unmodifiableMap(parsers), clock));
final ConditionRegistry conditionRegistry = new ConditionRegistry(Collections.unmodifiableMap(parsers), clock);
final Map<String, TransformFactory> transformFactories = new HashMap<>();
transformFactories.put(ScriptTransform.TYPE, new ScriptTransformFactory(settings, scriptService));
transformFactories.put(SearchTransform.TYPE, new SearchTransformFactory(settings, internalClient, searchRequestParsers,
scriptService));
final TransformRegistry transformRegistry = new TransformRegistry(settings, Collections.unmodifiableMap(transformFactories));
final Map<String, ActionFactory> actionFactoryMap = new HashMap<>();
TextTemplateEngine templateEngine = getService(TextTemplateEngine.class, components);
actionFactoryMap.put(EmailAction.TYPE, new EmailActionFactory(settings, getService(EmailService.class, components), templateEngine,
getService(EmailAttachmentsParser.class, components)));
actionFactoryMap.put(WebhookAction.TYPE, new WebhookActionFactory(settings, httpClient,
getService(HttpRequestTemplate.Parser.class, components), templateEngine));
actionFactoryMap.put(IndexAction.TYPE, new IndexActionFactory(settings, internalClient));
actionFactoryMap.put(LoggingAction.TYPE, new LoggingActionFactory(settings, templateEngine));
actionFactoryMap.put(HipChatAction.TYPE, new HipChatActionFactory(settings, templateEngine,
getService(HipChatService.class, components)));
actionFactoryMap.put(SlackAction.TYPE, new SlackActionFactory(settings, templateEngine,
getService(SlackService.class, components)));
actionFactoryMap.put(PagerDutyAction.TYPE, new PagerDutyActionFactory(settings, templateEngine,
getService(PagerDutyService.class, components)));
final ActionRegistry registry = new ActionRegistry(actionFactoryMap, conditionRegistry, transformRegistry, clock, licenseState);
return Collections.singleton(registry);
}
private <T> T getService(Class<T> serviceClass, Collection<Object> services) {
List<Object> collect = services.stream().filter(o -> o.getClass() == serviceClass).collect(Collectors.toList());
if (collect.isEmpty()) {
throw new IllegalArgumentException("no service for class " + serviceClass.getName());
} else if (collect.size() > 1) {
throw new IllegalArgumentException("more than one service for class " + serviceClass.getName());
}
return (T) collect.get(0);
} }
public Collection<Module> nodeModules() { public Collection<Module> nodeModules() {
@ -142,11 +209,9 @@ public class Watcher implements ActionPlugin, ScriptPlugin {
if (enabled && transportClient == false) { if (enabled && transportClient == false) {
modules.add(new WatchModule()); modules.add(new WatchModule());
modules.add(new WatcherClientModule()); modules.add(new WatcherClientModule());
modules.add(new TransformModule());
modules.add(new TriggerModule(settings)); modules.add(new TriggerModule(settings));
modules.add(new ScheduleModule()); modules.add(new ScheduleModule());
modules.add(new InputModule()); modules.add(new InputModule());
modules.add(new WatcherActionModule());
modules.add(new HistoryModule()); modules.add(new HistoryModule());
modules.add(new ExecutionModule()); modules.add(new ExecutionModule());
} }
@ -295,6 +360,4 @@ public class Watcher implements ActionPlugin, ScriptPlugin {
" that any future history indices after 6 months with the pattern " + " that any future history indices after 6 months with the pattern " +
"[.watcher-history-YYYY.MM.dd] are allowed to be created", value); "[.watcher-history-YYYY.MM.dd] are allowed to be created", value);
} }
} }

View File

@ -13,7 +13,7 @@ import java.io.IOException;
/** /**
* Parses xcontent to a concrete action of the same type. * Parses xcontent to a concrete action of the same type.
*/ */
public abstract class ActionFactory<A extends Action, E extends ExecutableAction<A>> { public abstract class ActionFactory {
protected final Logger actionLogger; protected final Logger actionLogger;
@ -21,20 +21,8 @@ public abstract class ActionFactory<A extends Action, E extends ExecutableAction
this.actionLogger = actionLogger; this.actionLogger = actionLogger;
} }
/**
* @return The type of the action
*/
public abstract String type();
public abstract A parseAction(String watchId, String actionId, XContentParser parser) throws IOException;
public abstract E createExecutable(A action);
/** /**
* Parses the given xcontent and creates a concrete action * Parses the given xcontent and creates a concrete action
*/ */
public E parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException { public abstract ExecutableAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException;
A action = parseAction(watchId, actionId, parser);
return createExecutable(action);
}
} }

View File

@ -6,7 +6,6 @@
package org.elasticsearch.xpack.watcher.actions; package org.elasticsearch.xpack.watcher.actions;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.support.clock.Clock; import org.elasticsearch.xpack.support.clock.Clock;
@ -27,7 +26,6 @@ public class ActionRegistry {
private final Clock clock; private final Clock clock;
private final XPackLicenseState licenseState; private final XPackLicenseState licenseState;
@Inject
public ActionRegistry(Map<String, ActionFactory> parsers, public ActionRegistry(Map<String, ActionFactory> parsers,
ConditionRegistry conditionRegistry, TransformRegistry transformRegistry, ConditionRegistry conditionRegistry, TransformRegistry transformRegistry,
Clock clock, Clock clock,
@ -60,11 +58,17 @@ public class ActionRegistry {
throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error); throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error);
} }
} else if (token == XContentParser.Token.START_OBJECT && id != null) { } else if (token == XContentParser.Token.START_OBJECT && id != null) {
actions.add(ActionWrapper.parse(watchId, id, parser, this, conditionRegistry, transformRegistry, clock, actions.add(ActionWrapper.parse(watchId, id, parser, this, clock, licenseState, upgradeActionSource));
licenseState, upgradeActionSource));
} }
} }
return actions; return actions;
} }
public TransformRegistry getTransformRegistry() {
return transformRegistry;
}
public ConditionRegistry getConditionRegistry() {
return conditionRegistry;
}
} }

View File

@ -20,13 +20,11 @@ import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.xpack.support.clock.Clock; import org.elasticsearch.xpack.support.clock.Clock;
import org.elasticsearch.xpack.watcher.actions.throttler.ActionThrottler; import org.elasticsearch.xpack.watcher.actions.throttler.ActionThrottler;
import org.elasticsearch.xpack.watcher.actions.throttler.Throttler; import org.elasticsearch.xpack.watcher.actions.throttler.Throttler;
import org.elasticsearch.xpack.watcher.condition.ConditionRegistry;
import org.elasticsearch.xpack.watcher.condition.Condition; import org.elasticsearch.xpack.watcher.condition.Condition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils; import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
import org.elasticsearch.xpack.watcher.transform.Transform; import org.elasticsearch.xpack.watcher.transform.Transform;
import org.elasticsearch.xpack.watcher.transform.TransformRegistry;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.watcher.watch.Watch; import org.elasticsearch.xpack.watcher.watch.Watch;
@ -195,9 +193,8 @@ public class ActionWrapper implements ToXContent {
return builder.endObject(); return builder.endObject();
} }
static ActionWrapper parse(String watchId, String actionId, XContentParser parser, static ActionWrapper parse(String watchId, String actionId, XContentParser parser, ActionRegistry actionRegistry, Clock clock,
ActionRegistry actionRegistry, ConditionRegistry conditionRegistry, TransformRegistry transformRegistry, XPackLicenseState licenseState, boolean upgradeActionSource) throws IOException {
Clock clock, XPackLicenseState licenseState, boolean upgradeActionSource) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT; assert parser.currentToken() == XContentParser.Token.START_OBJECT;
@ -213,9 +210,9 @@ public class ActionWrapper implements ToXContent {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else { } else {
if (ParseFieldMatcher.STRICT.match(currentFieldName, Watch.Field.CONDITION)) { if (ParseFieldMatcher.STRICT.match(currentFieldName, Watch.Field.CONDITION)) {
condition = conditionRegistry.parseExecutable(watchId, parser, upgradeActionSource); condition = actionRegistry.getConditionRegistry().parseExecutable(watchId, parser, upgradeActionSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Transform.Field.TRANSFORM)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Transform.Field.TRANSFORM)) {
transform = transformRegistry.parse(watchId, parser, upgradeActionSource); transform = actionRegistry.getTransformRegistry().parse(watchId, parser, upgradeActionSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD)) {
throttlePeriod = timeValueMillis(parser.longValue()); throttlePeriod = timeValueMillis(parser.longValue());
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD_HUMAN)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD_HUMAN)) {

View File

@ -1,57 +0,0 @@
/*
* 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.xpack.watcher.actions;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.MapBinder;
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatAction;
import org.elasticsearch.xpack.watcher.actions.hipchat.HipChatActionFactory;
import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
import org.elasticsearch.xpack.watcher.actions.index.IndexActionFactory;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingAction;
import org.elasticsearch.xpack.watcher.actions.logging.LoggingActionFactory;
import org.elasticsearch.xpack.watcher.actions.pagerduty.PagerDutyAction;
import org.elasticsearch.xpack.watcher.actions.pagerduty.PagerDutyActionFactory;
import org.elasticsearch.xpack.watcher.actions.slack.SlackAction;
import org.elasticsearch.xpack.watcher.actions.slack.SlackActionFactory;
import org.elasticsearch.xpack.watcher.actions.webhook.WebhookAction;
import org.elasticsearch.xpack.watcher.actions.webhook.WebhookActionFactory;
import java.util.HashMap;
import java.util.Map;
public class WatcherActionModule extends AbstractModule {
private final Map<String, Class<? extends ActionFactory>> parsers = new HashMap<>();
public WatcherActionModule() {
registerAction(EmailAction.TYPE, EmailActionFactory.class);
registerAction(WebhookAction.TYPE, WebhookActionFactory.class);
registerAction(IndexAction.TYPE, IndexActionFactory.class);
registerAction(LoggingAction.TYPE, LoggingActionFactory.class);
registerAction(HipChatAction.TYPE, HipChatActionFactory.class);
registerAction(SlackAction.TYPE, SlackActionFactory.class);
registerAction(PagerDutyAction.TYPE, PagerDutyActionFactory.class);
}
public void registerAction(String type, Class<? extends ActionFactory> parserType) {
parsers.put(type, parserType);
}
@Override
protected void configure() {
MapBinder<String, ActionFactory> parsersBinder = MapBinder.newMapBinder(binder(), String.class, ActionFactory.class);
for (Map.Entry<String, Class<? extends ActionFactory>> entry : parsers.entrySet()) {
bind(entry.getValue()).asEagerSingleton();
parsersBinder.addBinding(entry.getKey()).to(entry.getValue());
}
bind(ActionRegistry.class).asEagerSingleton();
}
}

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.email; package org.elasticsearch.xpack.watcher.actions.email;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -17,14 +16,13 @@ import org.elasticsearch.xpack.notification.email.attachment.EmailAttachmentsPar
import java.io.IOException; import java.io.IOException;
public class EmailActionFactory extends ActionFactory<EmailAction, ExecutableEmailAction> { public class EmailActionFactory extends ActionFactory {
private final EmailService emailService; private final EmailService emailService;
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
private final HtmlSanitizer htmlSanitizer; private final HtmlSanitizer htmlSanitizer;
private final EmailAttachmentsParser emailAttachmentsParser; private final EmailAttachmentsParser emailAttachmentsParser;
@Inject
public EmailActionFactory(Settings settings, EmailService emailService, TextTemplateEngine templateEngine, public EmailActionFactory(Settings settings, EmailService emailService, TextTemplateEngine templateEngine,
EmailAttachmentsParser emailAttachmentsParser) { EmailAttachmentsParser emailAttachmentsParser) {
super(Loggers.getLogger(ExecutableEmailAction.class, settings)); super(Loggers.getLogger(ExecutableEmailAction.class, settings));
@ -35,18 +33,9 @@ public class EmailActionFactory extends ActionFactory<EmailAction, ExecutableEma
} }
@Override @Override
public String type() { public ExecutableEmailAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return EmailAction.TYPE; return new ExecutableEmailAction(EmailAction.parse(watchId, actionId, parser, emailAttachmentsParser),
actionLogger, emailService, templateEngine, htmlSanitizer, emailAttachmentsParser.getParsers());
} }
@Override
public EmailAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
return EmailAction.parse(watchId, actionId, parser, emailAttachmentsParser);
}
@Override
public ExecutableEmailAction createExecutable(EmailAction action) {
return new ExecutableEmailAction(action, actionLogger, emailService, templateEngine, htmlSanitizer,
emailAttachmentsParser.getParsers());
}
} }

View File

@ -5,8 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.hipchat; package org.elasticsearch.xpack.watcher.actions.hipchat;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -17,12 +15,11 @@ import org.elasticsearch.xpack.notification.hipchat.HipChatService;
import java.io.IOException; import java.io.IOException;
public class HipChatActionFactory extends ActionFactory<HipChatAction, ExecutableHipChatAction> { public class HipChatActionFactory extends ActionFactory {
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
private final HipChatService hipchatService; private final HipChatService hipchatService;
@Inject
public HipChatActionFactory(Settings settings, TextTemplateEngine templateEngine, HipChatService hipchatService) { public HipChatActionFactory(Settings settings, TextTemplateEngine templateEngine, HipChatService hipchatService) {
super(Loggers.getLogger(ExecutableHipChatAction.class, settings)); super(Loggers.getLogger(ExecutableHipChatAction.class, settings));
this.templateEngine = templateEngine; this.templateEngine = templateEngine;
@ -30,25 +27,10 @@ public class HipChatActionFactory extends ActionFactory<HipChatAction, Executabl
} }
@Override @Override
public String type() { public ExecutableHipChatAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return HipChatAction.TYPE;
}
@Override
public HipChatAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
HipChatAction action = HipChatAction.parse(watchId, actionId, parser); HipChatAction action = HipChatAction.parse(watchId, actionId, parser);
HipChatAccount account = hipchatService.getAccount(action.account); HipChatAccount account = hipchatService.getAccount(action.account);
if (account == null) {
throw new ElasticsearchParseException("could not parse [hipchat] action [{}]. unknown hipchat account [{}]", watchId,
action.account);
}
account.validateParsedTemplate(watchId, actionId, action.message); account.validateParsedTemplate(watchId, actionId, action.message);
return action;
}
@Override
public ExecutableHipChatAction createExecutable(HipChatAction action) {
return new ExecutableHipChatAction(action, actionLogger, hipchatService, templateEngine); return new ExecutableHipChatAction(action, actionLogger, hipchatService, templateEngine);
} }
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.index; package org.elasticsearch.xpack.watcher.actions.index;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
@ -16,12 +15,11 @@ import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import java.io.IOException; import java.io.IOException;
public class IndexActionFactory extends ActionFactory<IndexAction, ExecutableIndexAction> { public class IndexActionFactory extends ActionFactory {
private final WatcherClientProxy client; private final WatcherClientProxy client;
private final TimeValue defaultTimeout; private final TimeValue defaultTimeout;
@Inject
public IndexActionFactory(Settings settings, InternalClient client) { public IndexActionFactory(Settings settings, InternalClient client) {
this(settings, new WatcherClientProxy(settings, client)); this(settings, new WatcherClientProxy(settings, client));
} }
@ -33,17 +31,7 @@ public class IndexActionFactory extends ActionFactory<IndexAction, ExecutableInd
} }
@Override @Override
public String type() { public ExecutableIndexAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return IndexAction.TYPE; return new ExecutableIndexAction(IndexAction.parse(watchId, actionId, parser), actionLogger, client, defaultTimeout);
}
@Override
public IndexAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
return IndexAction.parse(watchId, actionId, parser);
}
@Override
public ExecutableIndexAction createExecutable(IndexAction action) {
return new ExecutableIndexAction(action, actionLogger, client, defaultTimeout);
} }
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.logging; package org.elasticsearch.xpack.watcher.actions.logging;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -14,12 +13,11 @@ import org.elasticsearch.xpack.watcher.actions.ActionFactory;
import java.io.IOException; import java.io.IOException;
public class LoggingActionFactory extends ActionFactory<LoggingAction, ExecutableLoggingAction> { public class LoggingActionFactory extends ActionFactory {
private final Settings settings; private final Settings settings;
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
@Inject
public LoggingActionFactory(Settings settings, TextTemplateEngine templateEngine) { public LoggingActionFactory(Settings settings, TextTemplateEngine templateEngine) {
super(Loggers.getLogger(ExecutableLoggingAction.class, settings)); super(Loggers.getLogger(ExecutableLoggingAction.class, settings));
this.settings = settings; this.settings = settings;
@ -27,17 +25,9 @@ public class LoggingActionFactory extends ActionFactory<LoggingAction, Executabl
} }
@Override @Override
public String type() { public ExecutableLoggingAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return LoggingAction.TYPE; LoggingAction action = LoggingAction.parse(watchId, actionId, parser);
}
@Override
public LoggingAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
return LoggingAction.parse(watchId, actionId, parser);
}
@Override
public ExecutableLoggingAction createExecutable(LoggingAction action) {
return new ExecutableLoggingAction(action, actionLogger, settings, templateEngine); return new ExecutableLoggingAction(action, actionLogger, settings, templateEngine);
} }
} }

View File

@ -5,25 +5,21 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.pagerduty; package org.elasticsearch.xpack.watcher.actions.pagerduty;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.common.text.TextTemplateEngine; import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.actions.ActionFactory; import org.elasticsearch.xpack.watcher.actions.ActionFactory;
import org.elasticsearch.xpack.watcher.actions.hipchat.ExecutableHipChatAction; import org.elasticsearch.xpack.watcher.actions.hipchat.ExecutableHipChatAction;
import org.elasticsearch.xpack.notification.pagerduty.PagerDutyAccount;
import org.elasticsearch.xpack.notification.pagerduty.PagerDutyService; import org.elasticsearch.xpack.notification.pagerduty.PagerDutyService;
import java.io.IOException; import java.io.IOException;
public class PagerDutyActionFactory extends ActionFactory<PagerDutyAction, ExecutablePagerDutyAction> { public class PagerDutyActionFactory extends ActionFactory {
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
private final PagerDutyService pagerDutyService; private final PagerDutyService pagerDutyService;
@Inject
public PagerDutyActionFactory(Settings settings, TextTemplateEngine templateEngine, PagerDutyService pagerDutyService) { public PagerDutyActionFactory(Settings settings, TextTemplateEngine templateEngine, PagerDutyService pagerDutyService) {
super(Loggers.getLogger(ExecutableHipChatAction.class, settings)); super(Loggers.getLogger(ExecutableHipChatAction.class, settings));
this.templateEngine = templateEngine; this.templateEngine = templateEngine;
@ -31,24 +27,9 @@ public class PagerDutyActionFactory extends ActionFactory<PagerDutyAction, Execu
} }
@Override @Override
public String type() { public ExecutablePagerDutyAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return PagerDutyAction.TYPE;
}
@Override
public PagerDutyAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
PagerDutyAction action = PagerDutyAction.parse(watchId, actionId, parser); PagerDutyAction action = PagerDutyAction.parse(watchId, actionId, parser);
PagerDutyAccount account = pagerDutyService.getAccount(action.event.account); pagerDutyService.getAccount(action.event.account);
if (account == null) {
throw new ElasticsearchParseException("could not parse [pagerduty] action [{}/{}]. unknown pager duty account [{}]", watchId,
account, action.event.account);
}
return action;
}
@Override
public ExecutablePagerDutyAction createExecutable(PagerDutyAction action) {
return new ExecutablePagerDutyAction(action, actionLogger, pagerDutyService, templateEngine); return new ExecutablePagerDutyAction(action, actionLogger, pagerDutyService, templateEngine);
} }
} }

View File

@ -5,24 +5,20 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.slack; package org.elasticsearch.xpack.watcher.actions.slack;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.common.text.TextTemplateEngine; import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.actions.ActionFactory; import org.elasticsearch.xpack.watcher.actions.ActionFactory;
import org.elasticsearch.xpack.watcher.actions.hipchat.ExecutableHipChatAction; import org.elasticsearch.xpack.watcher.actions.hipchat.ExecutableHipChatAction;
import org.elasticsearch.xpack.notification.slack.SlackAccount;
import org.elasticsearch.xpack.notification.slack.SlackService; import org.elasticsearch.xpack.notification.slack.SlackService;
import java.io.IOException; import java.io.IOException;
public class SlackActionFactory extends ActionFactory<SlackAction, ExecutableSlackAction> { public class SlackActionFactory extends ActionFactory {
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
private final SlackService slackService; private final SlackService slackService;
@Inject
public SlackActionFactory(Settings settings, TextTemplateEngine templateEngine, SlackService slackService) { public SlackActionFactory(Settings settings, TextTemplateEngine templateEngine, SlackService slackService) {
super(Loggers.getLogger(ExecutableHipChatAction.class, settings)); super(Loggers.getLogger(ExecutableHipChatAction.class, settings));
this.templateEngine = templateEngine; this.templateEngine = templateEngine;
@ -30,23 +26,9 @@ public class SlackActionFactory extends ActionFactory<SlackAction, ExecutableSla
} }
@Override @Override
public String type() { public ExecutableSlackAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return SlackAction.TYPE;
}
@Override
public SlackAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
SlackAction action = SlackAction.parse(watchId, actionId, parser); SlackAction action = SlackAction.parse(watchId, actionId, parser);
SlackAccount account = slackService.getAccount(action.account); slackService.getAccount(action.account); // for validation -- throws exception if account not present
if (account == null) {
throw new ElasticsearchParseException("could not parse [slack] action [{}]. unknown slack account [{}]", watchId,
action.account);
}
return action;
}
@Override
public ExecutableSlackAction createExecutable(SlackAction action) {
return new ExecutableSlackAction(action, actionLogger, slackService, templateEngine); return new ExecutableSlackAction(action, actionLogger, slackService, templateEngine);
} }
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.webhook; package org.elasticsearch.xpack.watcher.actions.webhook;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -16,13 +15,12 @@ import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
import java.io.IOException; import java.io.IOException;
public class WebhookActionFactory extends ActionFactory<WebhookAction, ExecutableWebhookAction> { public class WebhookActionFactory extends ActionFactory {
private final HttpClient httpClient; private final HttpClient httpClient;
private final HttpRequestTemplate.Parser requestTemplateParser; private final HttpRequestTemplate.Parser requestTemplateParser;
private final TextTemplateEngine templateEngine; private final TextTemplateEngine templateEngine;
@Inject
public WebhookActionFactory(Settings settings, HttpClient httpClient, HttpRequestTemplate.Parser requestTemplateParser, public WebhookActionFactory(Settings settings, HttpClient httpClient, HttpRequestTemplate.Parser requestTemplateParser,
TextTemplateEngine templateEngine) { TextTemplateEngine templateEngine) {
@ -33,17 +31,9 @@ public class WebhookActionFactory extends ActionFactory<WebhookAction, Executabl
} }
@Override @Override
public String type() { public ExecutableWebhookAction parseExecutable(String watchId, String actionId, XContentParser parser) throws IOException {
return WebhookAction.TYPE; return new ExecutableWebhookAction(WebhookAction.parse(watchId, actionId, parser, requestTemplateParser),
} actionLogger, httpClient, templateEngine);
@Override
public WebhookAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
return WebhookAction.parse(watchId, actionId, parser, requestTemplateParser);
}
@Override
public ExecutableWebhookAction createExecutable(WebhookAction action) {
return new ExecutableWebhookAction(action, actionLogger, httpClient, templateEngine);
} }
} }

View File

@ -1,43 +0,0 @@
/*
* 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.xpack.watcher.transform;
import org.elasticsearch.common.inject.AbstractModule;
import org.elasticsearch.common.inject.multibindings.MapBinder;
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform;
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransformFactory;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransformFactory;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransformFactory;
import java.util.HashMap;
import java.util.Map;
public class TransformModule extends AbstractModule {
private Map<String, Class<? extends TransformFactory>> factories = new HashMap<>();
public void registerTransform(String payloadType, Class<? extends TransformFactory> parserType) {
factories.put(payloadType, parserType);
}
@Override
protected void configure() {
MapBinder<String, TransformFactory> mbinder = MapBinder.newMapBinder(binder(), String.class, TransformFactory.class);
bind(SearchTransformFactory.class).asEagerSingleton();
mbinder.addBinding(SearchTransform.TYPE).to(SearchTransformFactory.class);
bind(ScriptTransformFactory.class).asEagerSingleton();
mbinder.addBinding(ScriptTransform.TYPE).to(ScriptTransformFactory.class);
for (Map.Entry<String, Class<? extends TransformFactory>> entry : factories.entrySet()) {
bind(entry.getValue()).asEagerSingleton();
mbinder.addBinding(entry.getKey()).to(entry.getValue());
}
}
}

View File

@ -6,7 +6,6 @@
package org.elasticsearch.xpack.watcher.transform; package org.elasticsearch.xpack.watcher.transform;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform; import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform;
@ -21,7 +20,6 @@ public class TransformRegistry {
private final Map<String, TransformFactory> factories; private final Map<String, TransformFactory> factories;
@Inject
public TransformRegistry(Settings settings, Map<String, TransformFactory> factories) { public TransformRegistry(Settings settings, Map<String, TransformFactory> factories) {
Map<String, TransformFactory> map = new HashMap<>(factories); Map<String, TransformFactory> map = new HashMap<>(factories);
map.put(ChainTransform.TYPE, new ChainTransformFactory(settings, this)); map.put(ChainTransform.TYPE, new ChainTransformFactory(settings, this));
@ -46,7 +44,7 @@ public class TransformRegistry {
return transform; return transform;
} }
public ExecutableTransform parse(String watchId, String type, XContentParser parser, private ExecutableTransform parse(String watchId, String type, XContentParser parser,
boolean upgradeTransformSource) throws IOException { boolean upgradeTransformSource) throws IOException {
TransformFactory factory = factories.get(type); TransformFactory factory = factories.get(type);
if (factory == null) { if (factory == null) {

View File

@ -68,7 +68,7 @@ public class ChainTransform implements Transform {
return builder.endArray(); return builder.endArray();
} }
public static ChainTransform parse(String watchId, XContentParser parser, TransformRegistry transformRegistry, static ChainTransform parse(String watchId, XContentParser parser, TransformRegistry transformRegistry,
boolean upgradeSource) throws IOException { boolean upgradeSource) throws IOException {
XContentParser.Token token = parser.currentToken(); XContentParser.Token token = parser.currentToken();
if (token != XContentParser.Token.START_ARRAY) { if (token != XContentParser.Token.START_ARRAY) {

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.transform.script; package org.elasticsearch.xpack.watcher.transform.script;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -20,7 +19,6 @@ public class ScriptTransformFactory extends TransformFactory<ScriptTransform, Sc
private final Settings settings; private final Settings settings;
private final ScriptService scriptService; private final ScriptService scriptService;
@Inject
public ScriptTransformFactory(Settings settings, ScriptService scriptService) { public ScriptTransformFactory(Settings settings, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableScriptTransform.class, settings)); super(Loggers.getLogger(ExecutableScriptTransform.class, settings));
this.settings = settings; this.settings = settings;

View File

@ -30,11 +30,11 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
private final ParseFieldMatcher parseFieldMatcher; private final ParseFieldMatcher parseFieldMatcher;
private final WatcherSearchTemplateService searchTemplateService; private final WatcherSearchTemplateService searchTemplateService;
@Inject
public SearchTransformFactory(Settings settings, InternalClient client, public SearchTransformFactory(Settings settings, InternalClient client,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) { SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
this(settings, new WatcherClientProxy(settings, client), searchRequestParsers, scriptService); this(settings, new WatcherClientProxy(settings, client), searchRequestParsers, scriptService);
} }
public SearchTransformFactory(Settings settings, WatcherClientProxy client, public SearchTransformFactory(Settings settings, WatcherClientProxy client,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) { SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableSearchTransform.class, settings)); super(Loggers.getLogger(ExecutableSearchTransform.class, settings));

View File

@ -26,7 +26,6 @@ import org.elasticsearch.xpack.watcher.Watcher;
import org.elasticsearch.xpack.watcher.actions.ActionRegistry; import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
import org.elasticsearch.xpack.watcher.actions.ActionStatus; import org.elasticsearch.xpack.watcher.actions.ActionStatus;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.condition.ConditionRegistry;
import org.elasticsearch.xpack.watcher.condition.Condition; import org.elasticsearch.xpack.watcher.condition.Condition;
import org.elasticsearch.xpack.watcher.condition.AlwaysCondition; import org.elasticsearch.xpack.watcher.condition.AlwaysCondition;
import org.elasticsearch.xpack.watcher.input.ExecutableInput; import org.elasticsearch.xpack.watcher.input.ExecutableInput;
@ -36,7 +35,6 @@ import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.support.xcontent.WatcherParams; import org.elasticsearch.xpack.watcher.support.xcontent.WatcherParams;
import org.elasticsearch.xpack.watcher.support.xcontent.WatcherXContentParser; import org.elasticsearch.xpack.watcher.support.xcontent.WatcherXContentParser;
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
import org.elasticsearch.xpack.watcher.transform.TransformRegistry;
import org.elasticsearch.xpack.watcher.trigger.Trigger; import org.elasticsearch.xpack.watcher.trigger.Trigger;
import org.elasticsearch.xpack.watcher.trigger.TriggerEngine; import org.elasticsearch.xpack.watcher.trigger.TriggerEngine;
import org.elasticsearch.xpack.watcher.trigger.TriggerService; import org.elasticsearch.xpack.watcher.trigger.TriggerService;
@ -209,9 +207,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
public static class Parser extends AbstractComponent { public static class Parser extends AbstractComponent {
private final ConditionRegistry conditionRegistry;
private final TriggerService triggerService; private final TriggerService triggerService;
private final TransformRegistry transformRegistry;
private final ActionRegistry actionRegistry; private final ActionRegistry actionRegistry;
private final InputRegistry inputRegistry; private final InputRegistry inputRegistry;
private final CryptoService cryptoService; private final CryptoService cryptoService;
@ -221,13 +217,10 @@ public class Watch implements TriggerEngine.Job, ToXContent {
private final Clock clock; private final Clock clock;
@Inject @Inject
public Parser(Settings settings, ConditionRegistry conditionRegistry, TriggerService triggerService, public Parser(Settings settings, TriggerService triggerService, ActionRegistry actionRegistry, InputRegistry inputRegistry,
TransformRegistry transformRegistry, ActionRegistry actionRegistry, @Nullable CryptoService cryptoService, Clock clock) {
InputRegistry inputRegistry, @Nullable CryptoService cryptoService, Clock clock) {
super(settings); super(settings);
this.conditionRegistry = conditionRegistry;
this.transformRegistry = transformRegistry;
this.triggerService = triggerService; this.triggerService = triggerService;
this.actionRegistry = actionRegistry; this.actionRegistry = actionRegistry;
this.inputRegistry = inputRegistry; this.inputRegistry = inputRegistry;
@ -309,9 +302,9 @@ public class Watch implements TriggerEngine.Job, ToXContent {
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.INPUT)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.INPUT)) {
input = inputRegistry.parse(id, parser, upgradeWatchSource); input = inputRegistry.parse(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.CONDITION)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.CONDITION)) {
condition = conditionRegistry.parseExecutable(id, parser, upgradeWatchSource); condition = actionRegistry.getConditionRegistry().parseExecutable(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRANSFORM)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRANSFORM)) {
transform = transformRegistry.parse(id, parser, upgradeWatchSource); transform = actionRegistry.getTransformRegistry().parse(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD)) {
throttlePeriod = timeValueMillis(parser.longValue()); throttlePeriod = timeValueMillis(parser.longValue());
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD_HUMAN)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD_HUMAN)) {

View File

@ -13,6 +13,7 @@ import org.elasticsearch.xpack.watcher.test.TimeWarpedWatcher;
import java.io.IOException; import java.io.IOException;
public class TimeWarpedXPackPlugin extends XPackPlugin { public class TimeWarpedXPackPlugin extends XPackPlugin {
private final ClockMock clock = new ClockMock();
public TimeWarpedXPackPlugin(Settings settings) throws IOException { public TimeWarpedXPackPlugin(Settings settings) throws IOException {
super(settings); super(settings);
@ -21,6 +22,6 @@ public class TimeWarpedXPackPlugin extends XPackPlugin {
@Override @Override
protected Clock getClock() { protected Clock getClock() {
return new ClockMock(); return clock;
} }
} }

View File

@ -5,26 +5,14 @@
*/ */
package org.elasticsearch.xpack.watcher.actions; package org.elasticsearch.xpack.watcher.actions;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.xpack.watcher.actions.index.IndexAction;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.get.GetWatchResponse;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
import org.elasticsearch.xpack.watcher.watch.Payload;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery; import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder; import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
@ -38,14 +26,6 @@ public class ActionErrorIntegrationTests extends AbstractWatcherIntegrationTestC
return true; // to have control over the execution return true; // to have control over the execution
} }
@Override
protected List<Class<? extends Plugin>> pluginTypes() {
List<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.pluginTypes());
types.add(ErrorActionPlugin.class);
return Collections.unmodifiableList(types);
}
/** /**
* This test makes sure that when an action encounters an error it should * This test makes sure that when an action encounters an error it should
* not be subject to throttling. Also, the ack status of the action in the * not be subject to throttling. Also, the ack status of the action in the
@ -53,13 +33,16 @@ public class ActionErrorIntegrationTests extends AbstractWatcherIntegrationTestC
* fails. * fails.
*/ */
public void testErrorInAction() throws Exception { public void testErrorInAction() throws Exception {
createIndex("foo");
client().admin().indices().prepareUpdateSettings("foo").setSettings(Settings.builder().put("index.blocks.write", true)).get();
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder() PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id").setSource(watchBuilder()
.trigger(schedule(interval("10m"))) .trigger(schedule(interval("10m")))
// adding an action that throws an error and is associated with a 60 minute throttle period // adding an action that throws an error and is associated with a 60 minute throttle period
// with such a period, on successful execution we other executions of the watch will be // with such a period, on successful execution we other executions of the watch will be
// throttled within the hour... but on failed execution there should be no throttling // throttled within the hour... but on failed execution there should be no throttling
.addAction("_action", TimeValue.timeValueMinutes(60), new ErrorAction.Builder())) .addAction("_action", TimeValue.timeValueMinutes(60), IndexAction.builder("foo", "bar")))
.get(); .get();
assertThat(putWatchResponse.isCreated(), is(true)); assertThat(putWatchResponse.isCreated(), is(true));
@ -104,83 +87,4 @@ public class ActionErrorIntegrationTests extends AbstractWatcherIntegrationTestC
XContentSource watch = getWatchResponse.getSource(); XContentSource watch = getWatchResponse.getSource();
watch.getValue("status.actions._action.ack.awaits_successful_execution"); watch.getValue("status.actions._action.ack.awaits_successful_execution");
} }
public static class ErrorActionPlugin extends Plugin {
public void onModule(WatcherActionModule module) {
module.registerAction(ErrorAction.TYPE, ErrorAction.Factory.class);
}
}
public static class ErrorAction implements Action {
static final String TYPE = "error";
@Override
public String type() {
return TYPE;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
}
public static class Result extends Action.Result {
public Result() {
super(TYPE, Status.FAILURE);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject().endObject();
}
}
public static class Executable extends ExecutableAction<ErrorAction> {
public Executable(ErrorAction action, Logger logger) {
super(action, logger);
}
@Override
public Action.Result execute(String actionId, WatchExecutionContext context, Payload payload) throws Exception {
throw new RuntimeException("dummy error");
}
}
public static class Factory extends ActionFactory<ErrorAction, Executable> {
@Inject
public Factory(Settings settings) {
super(Loggers.getLogger(Executable.class, settings));
}
@Override
public String type() {
return TYPE;
}
@Override
public ErrorAction parseAction(String watchId, String actionId, XContentParser parser) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
assert parser.nextToken() == XContentParser.Token.END_OBJECT;
return new ErrorAction();
}
@Override
public Executable createExecutable(ErrorAction action) {
return new Executable(action, actionLogger);
}
}
public static class Builder implements Action.Builder<ErrorAction> {
@Override
public ErrorAction build() {
return new ErrorAction();
}
}
}
} }

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.actions.hipchat; package org.elasticsearch.xpack.watcher.actions.hipchat;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -16,6 +17,8 @@ import org.elasticsearch.xpack.notification.hipchat.HipChatAccount;
import org.elasticsearch.xpack.notification.hipchat.HipChatService; import org.elasticsearch.xpack.notification.hipchat.HipChatService;
import org.junit.Before; import org.junit.Before;
import java.util.Collections;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.hipchatAction; import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.hipchatAction;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -43,24 +46,20 @@ public class HipChatActionFactoryTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
parser.nextToken(); parser.nextToken();
HipChatAction parsedAction = factory.parseAction("_w1", "_a1", parser); ExecutableHipChatAction parsedAction = factory.parseExecutable("_w1", "_a1", parser);
assertThat(parsedAction, is(action)); assertThat(parsedAction.action(), is(action));
verify(account, times(1)).validateParsedTemplate("_w1", "_a1", action.message); verify(account, times(1)).validateParsedTemplate("_w1", "_a1", action.message);
} }
public void testParseActionUnknownAccount() throws Exception { public void testParseActionUnknownAccount() throws Exception {
when(hipchatService.getAccount("_unknown")).thenReturn(null); hipchatService = new HipChatService(Settings.EMPTY, null, new ClusterSettings(Settings.EMPTY,
Collections.singleton(HipChatService.HIPCHAT_ACCOUNT_SETTING)));
factory = new HipChatActionFactory(Settings.EMPTY, mock(TextTemplateEngine.class), hipchatService);
HipChatAction action = hipchatAction("_unknown", "_body").build(); HipChatAction action = hipchatAction("_unknown", "_body").build();
XContentBuilder jsonBuilder = jsonBuilder().value(action); XContentBuilder jsonBuilder = jsonBuilder().value(action);
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
parser.nextToken(); parser.nextToken();
try { expectThrows(IllegalArgumentException.class, () -> factory.parseExecutable("_w1", "_a1", parser));
factory.parseAction("_w1", "_a1", parser);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), is("could not parse [hipchat] action [_w1]. unknown hipchat account [_unknown]"));
}
} }
} }

View File

@ -5,7 +5,7 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.pagerduty; package org.elasticsearch.xpack.watcher.actions.pagerduty;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -16,6 +16,8 @@ import org.elasticsearch.xpack.notification.pagerduty.PagerDutyAccount;
import org.elasticsearch.xpack.notification.pagerduty.PagerDutyService; import org.elasticsearch.xpack.notification.pagerduty.PagerDutyService;
import org.junit.Before; import org.junit.Before;
import java.util.Collections;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.triggerPagerDutyAction; import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.triggerPagerDutyAction;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -43,20 +45,18 @@ public class PagerDutyActionFactoryTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
parser.nextToken(); parser.nextToken();
PagerDutyAction parsedAction = factory.parseAction("_w1", "_a1", parser); PagerDutyAction parsedAction = PagerDutyAction.parse("_w1", "_a1", parser);
assertThat(parsedAction, is(action)); assertThat(parsedAction, is(action));
} }
public void testParseActionUnknownAccount() throws Exception { public void testParseActionUnknownAccount() throws Exception {
try { factory = new PagerDutyActionFactory(Settings.EMPTY, mock(TextTemplateEngine.class), new PagerDutyService(Settings.EMPTY, null,
when(service.getAccount("_unknown")).thenReturn(null); new ClusterSettings(Settings.EMPTY, Collections.singleton(PagerDutyService.PAGERDUTY_ACCOUNT_SETTING))));
PagerDutyAction action = triggerPagerDutyAction("_unknown", "_body").build();
PagerDutyAction action = triggerPagerDutyAction("_unknown", "_body").build(); XContentBuilder jsonBuilder = jsonBuilder().value(action);
XContentBuilder jsonBuilder = jsonBuilder().value(action); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); parser.nextToken();
parser.nextToken(); expectThrows(IllegalArgumentException.class, () ->
factory.parseAction("_w1", "_a1", parser); factory.parseExecutable("_w1", "_a1", parser));
fail("Expected ElasticsearchParseException due to unknown account");
} catch (ElasticsearchParseException e) {}
} }
} }

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.actions.slack; package org.elasticsearch.xpack.watcher.actions.slack;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -16,6 +17,8 @@ import org.elasticsearch.xpack.notification.slack.SlackAccount;
import org.elasticsearch.xpack.notification.slack.SlackService; import org.elasticsearch.xpack.notification.slack.SlackService;
import org.junit.Before; import org.junit.Before;
import java.util.Collections;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.slackAction; import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.slackAction;
import static org.elasticsearch.xpack.notification.slack.message.SlackMessageTests.createRandomTemplate; import static org.elasticsearch.xpack.notification.slack.message.SlackMessageTests.createRandomTemplate;
@ -42,22 +45,18 @@ public class SlackActionFactoryTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
parser.nextToken(); parser.nextToken();
SlackAction parsedAction = factory.parseAction("_w1", "_a1", parser); SlackAction parsedAction = SlackAction.parse("_w1", "_a1", parser);
assertThat(parsedAction, is(action)); assertThat(parsedAction, is(action));
} }
public void testParseActionUnknownAccount() throws Exception { public void testParseActionUnknownAccount() throws Exception {
when(service.getAccount("_unknown")).thenReturn(null); SlackService service = new SlackService(Settings.EMPTY, null, new ClusterSettings(Settings.EMPTY,
Collections.singleton(SlackService.SLACK_ACCOUNT_SETTING)));
factory = new SlackActionFactory(Settings.EMPTY, mock(TextTemplateEngine.class), service);
SlackAction action = slackAction("_unknown", createRandomTemplate()).build(); SlackAction action = slackAction("_unknown", createRandomTemplate()).build();
XContentBuilder jsonBuilder = jsonBuilder().value(action); XContentBuilder jsonBuilder = jsonBuilder().value(action);
XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
parser.nextToken(); parser.nextToken();
try { expectThrows(IllegalArgumentException.class, () -> factory.parseExecutable("_w1", "_a1", parser));
factory.parseAction("_w1", "_a1", parser);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), is("could not parse [slack] action [_w1]. unknown slack account [_unknown]"));
}
} }
} }

View File

@ -201,8 +201,7 @@ public class WatchTests extends ESTestCase {
BytesReference bytes = XContentFactory.jsonBuilder().value(watch).bytes(); BytesReference bytes = XContentFactory.jsonBuilder().value(watch).bytes();
logger.info("{}", bytes.utf8ToString()); logger.info("{}", bytes.utf8ToString());
Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, Watch.Parser watchParser = new Watch.Parser(settings, triggerService, actionRegistry, inputRegistry, null, clock);
inputRegistry, null, clock);
Watch parsedWatch = watchParser.parse("_name", includeStatus, bytes); Watch parsedWatch = watchParser.parse("_name", includeStatus, bytes);
@ -238,8 +237,7 @@ public class WatchTests extends ESTestCase {
.startObject() .startObject()
.startArray("actions").endArray() .startArray("actions").endArray()
.endObject(); .endObject();
Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, Watch.Parser watchParser = new Watch.Parser(settings, triggerService, actionRegistry, inputRegistry, null, clock);
inputRegistry, null, clock);
try { try {
watchParser.parse("failure", false, jsonBuilder.bytes()); watchParser.parse("failure", false, jsonBuilder.bytes());
fail("This watch should fail to parse as actions is an array"); fail("This watch should fail to parse as actions is an array");
@ -265,8 +263,7 @@ public class WatchTests extends ESTestCase {
.field(ScheduleTrigger.TYPE, schedule(schedule).build()) .field(ScheduleTrigger.TYPE, schedule(schedule).build())
.endObject(); .endObject();
builder.endObject(); builder.endObject();
Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, Watch.Parser watchParser = new Watch.Parser(settings, triggerService, actionRegistry, inputRegistry, null, SystemClock.INSTANCE);
inputRegistry, null, SystemClock.INSTANCE);
Watch watch = watchParser.parse("failure", false, builder.bytes()); Watch watch = watchParser.parse("failure", false, builder.bytes());
assertThat(watch, notNullValue()); assertThat(watch, notNullValue());
assertThat(watch.trigger(), instanceOf(ScheduleTrigger.class)); assertThat(watch.trigger(), instanceOf(ScheduleTrigger.class));
@ -287,8 +284,7 @@ public class WatchTests extends ESTestCase {
InputRegistry inputRegistry = registry(SearchInput.TYPE); InputRegistry inputRegistry = registry(SearchInput.TYPE);
TransformRegistry transformRegistry = transformRegistry(); TransformRegistry transformRegistry = transformRegistry();
ActionRegistry actionRegistry = registry(Collections.emptyList(), conditionRegistry, transformRegistry); ActionRegistry actionRegistry = registry(Collections.emptyList(), conditionRegistry, transformRegistry);
Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, Watch.Parser watchParser = new Watch.Parser(settings, triggerService, actionRegistry, inputRegistry, null, SystemClock.INSTANCE);
inputRegistry, null, SystemClock.INSTANCE);
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser1 = MatchAllQueryBuilder::fromXContent; QueryParser<MatchAllQueryBuilder> queryParser1 = MatchAllQueryBuilder::fromXContent;