diff --git a/server/src/main/java/org/elasticsearch/script/ParameterMap.java b/server/src/main/java/org/elasticsearch/script/ParameterMap.java index b4fd24b059bd8..b59d057d66e62 100644 --- a/server/src/main/java/org/elasticsearch/script/ParameterMap.java +++ b/server/src/main/java/org/elasticsearch/script/ParameterMap.java @@ -19,11 +19,12 @@ package org.elasticsearch.script; +import org.apache.logging.log4j.LogManager; +import org.elasticsearch.common.logging.DeprecationLogger; + import java.util.Collection; import java.util.Map; import java.util.Set; -import org.apache.logging.log4j.LogManager; -import org.elasticsearch.common.logging.DeprecationLogger; public final class ParameterMap implements Map { @@ -34,7 +35,7 @@ public final class ParameterMap implements Map { private final Map deprecations; - ParameterMap(Map params, Map deprecations) { + public ParameterMap(Map params, Map deprecations) { this.params = params; this.deprecations = deprecations; } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java index ab00187634865..eaf64e6ef8f19 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/Watcher.java @@ -48,7 +48,6 @@ import org.elasticsearch.plugins.ScriptPlugin; import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestHandler; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.SearchScript; @@ -106,6 +105,7 @@ import org.elasticsearch.xpack.watcher.condition.InternalAlwaysCondition; import org.elasticsearch.xpack.watcher.condition.NeverCondition; import org.elasticsearch.xpack.watcher.condition.ScriptCondition; +import org.elasticsearch.xpack.watcher.condition.WatcherConditionScript; import org.elasticsearch.xpack.watcher.execution.AsyncTriggerEventConsumer; import org.elasticsearch.xpack.watcher.execution.ExecutionService; import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor; @@ -152,6 +152,7 @@ import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService; import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform; import org.elasticsearch.xpack.watcher.transform.script.ScriptTransformFactory; +import org.elasticsearch.xpack.watcher.transform.script.WatcherTransformScript; import org.elasticsearch.xpack.watcher.transform.search.SearchTransform; import org.elasticsearch.xpack.watcher.transform.search.SearchTransformFactory; import org.elasticsearch.xpack.watcher.transport.actions.ack.TransportAckWatchAction; @@ -225,9 +226,6 @@ public class Watcher extends Plugin implements ActionPlugin, ScriptPlugin, Reloa public static final ScriptContext SCRIPT_SEARCH_CONTEXT = new ScriptContext<>("xpack", SearchScript.Factory.class); - // TODO: remove this context when each xpack script use case has their own contexts - public static final ScriptContext SCRIPT_EXECUTABLE_CONTEXT - = new ScriptContext<>("xpack_executable", ExecutableScript.Factory.class); public static final ScriptContext SCRIPT_TEMPLATE_CONTEXT = new ScriptContext<>("xpack_template", TemplateScript.Factory.class); @@ -673,7 +671,8 @@ public List getBootstrapChecks() { @Override public List> getContexts() { - return Arrays.asList(Watcher.SCRIPT_SEARCH_CONTEXT, Watcher.SCRIPT_EXECUTABLE_CONTEXT, Watcher.SCRIPT_TEMPLATE_CONTEXT); + return Arrays.asList(Watcher.SCRIPT_SEARCH_CONTEXT, WatcherTransformScript.CONTEXT, + WatcherConditionScript.CONTEXT, Watcher.SCRIPT_TEMPLATE_CONTEXT); } @Override diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/email/ExecutableEmailAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/email/ExecutableEmailAction.java index f737d89c1286d..fcc4eb0e9422b 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/email/ExecutableEmailAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/email/ExecutableEmailAction.java @@ -41,7 +41,7 @@ public ExecutableEmailAction(EmailAction action, Logger logger, EmailService ema } public Action.Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws Exception { - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); Map attachments = new HashMap<>(); DataAttachment dataAttachment = action.getDataAttachment(); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/hipchat/ExecutableHipChatAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/hipchat/ExecutableHipChatAction.java index 5772d1ffa6f1f..176de8b945df2 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/hipchat/ExecutableHipChatAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/hipchat/ExecutableHipChatAction.java @@ -39,7 +39,7 @@ public Action.Result execute(final String actionId, WatchExecutionContext ctx, P // watch/action were created. account.validateParsedTemplate(ctx.id().watchId(), actionId, action.message); - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); HipChatMessage message = account.render(ctx.id().watchId(), actionId, templateEngine, action.message, model); if (ctx.simulateAction(actionId)) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/jira/ExecutableJiraAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/jira/ExecutableJiraAction.java index acb0c8ce59142..89f9af8e1d529 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/jira/ExecutableJiraAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/jira/ExecutableJiraAction.java @@ -42,7 +42,7 @@ public Action.Result execute(final String actionId, WatchExecutionContext ctx, P throw new IllegalStateException("account [" + action.account + "] was not found. perhaps it was deleted"); } - final Function render = s -> engine.render(new TextTemplate(s), Variables.createCtxModel(ctx, payload)); + final Function render = s -> engine.render(new TextTemplate(s), Variables.createCtxParamsMap(ctx, payload)); Map fields = new HashMap<>(); // Apply action fields diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/logging/ExecutableLoggingAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/logging/ExecutableLoggingAction.java index b1cb723949d8e..83fdb4e7c1fef 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/logging/ExecutableLoggingAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/logging/ExecutableLoggingAction.java @@ -40,7 +40,7 @@ Logger textLogger() { @Override public Action.Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws Exception { - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); String loggedText = templateEngine.render(action.text, model); if (ctx.simulateAction(actionId)) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/pagerduty/ExecutablePagerDutyAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/pagerduty/ExecutablePagerDutyAction.java index 59381dc33362c..0c995ce94ef10 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/pagerduty/ExecutablePagerDutyAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/pagerduty/ExecutablePagerDutyAction.java @@ -40,7 +40,7 @@ public Action.Result execute(final String actionId, WatchExecutionContext ctx, P throw new IllegalStateException("account [" + action.event.account + "] was not found. perhaps it was deleted"); } - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); IncidentEvent event = action.event.render(ctx.watch().id(), actionId, templateEngine, model, account.getDefaults()); if (ctx.simulateAction(actionId)) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/slack/ExecutableSlackAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/slack/ExecutableSlackAction.java index 9ab4a028ca13d..b904b05ada703 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/slack/ExecutableSlackAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/slack/ExecutableSlackAction.java @@ -40,7 +40,7 @@ public Action.Result execute(final String actionId, WatchExecutionContext ctx, P throw new IllegalStateException("account [" + action.account + "] was not found. perhaps it was deleted"); } - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); SlackMessage message = action.message.render(ctx.id().watchId(), actionId, templateEngine, model, account.getMessageDefaults()); if (ctx.simulateAction(actionId)) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/webhook/ExecutableWebhookAction.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/webhook/ExecutableWebhookAction.java index 7313d529b4aea..ec1f5774b13f3 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/webhook/ExecutableWebhookAction.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/webhook/ExecutableWebhookAction.java @@ -31,7 +31,7 @@ public ExecutableWebhookAction(WebhookAction action, Logger logger, HttpClient h @Override public Action.Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws Exception { - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); HttpRequest request = action.requestTemplate.render(templateEngine, model); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/AbstractCompareCondition.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/AbstractCompareCondition.java index 555f9d465458a..81e3eb464e69b 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/AbstractCompareCondition.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/AbstractCompareCondition.java @@ -36,7 +36,7 @@ protected AbstractCompareCondition(String type, Clock clock) { @Override public final Result execute(WatchExecutionContext ctx) { Map resolvedValues = new HashMap<>(); - Map model = Variables.createCtxModel(ctx, ctx.payload()); + Map model = Variables.createCtxParamsMap(ctx, ctx.payload()); return doExecute(model, resolvedValues); } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ScriptCondition.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ScriptCondition.java index b65eca086c46c..19307569ce06b 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ScriptCondition.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ScriptCondition.java @@ -8,19 +8,15 @@ import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptService; import org.elasticsearch.xpack.core.watcher.condition.ExecutableCondition; import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; -import org.elasticsearch.xpack.watcher.Watcher; import org.elasticsearch.xpack.watcher.support.Variables; import java.io.IOException; import java.util.Map; -import static org.elasticsearch.xpack.core.watcher.support.Exceptions.illegalState; - /** * This class executes a script against the ctx payload and returns a boolean */ @@ -30,16 +26,16 @@ public final class ScriptCondition implements ExecutableCondition { private static final Result UNMET = new Result(null, TYPE, false); private final Script script; - private final ExecutableScript.Factory scriptFactory; + private final WatcherConditionScript.Factory scriptFactory; public ScriptCondition(Script script) { this.script = script; - scriptFactory = null; + this.scriptFactory = null; } - ScriptCondition(Script script, ExecutableScript.Factory scriptFactory) { + ScriptCondition(Script script, ScriptService scriptService) { this.script = script; - this.scriptFactory = scriptFactory; + this.scriptFactory = scriptService.compile(script, WatcherConditionScript.CONTEXT); } public Script getScript() { @@ -49,7 +45,7 @@ public Script getScript() { public static ScriptCondition parse(ScriptService scriptService, String watchId, XContentParser parser) throws IOException { try { Script script = Script.parse(parser); - return new ScriptCondition(script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + return new ScriptCondition(script, scriptService); } catch (ElasticsearchParseException pe) { throw new ElasticsearchParseException("could not parse [{}] condition for watch [{}]. failed to parse script", pe, TYPE, watchId); @@ -62,17 +58,12 @@ public Result execute(WatchExecutionContext ctx) { } public Result doExecute(WatchExecutionContext ctx) { - Map parameters = Variables.createCtxModel(ctx, ctx.payload()); + Map parameters = Variables.createCtxParamsMap(ctx, ctx.payload()); if (script.getParams() != null && !script.getParams().isEmpty()) { parameters.putAll(script.getParams()); } - ExecutableScript executable = scriptFactory.newInstance(parameters); - Object value = executable.run(); - if (value instanceof Boolean) { - return (Boolean) value ? MET : UNMET; - } - throw illegalState("condition [{}] must return a boolean value (true|false) but instead returned [{}]", type(), ctx.watch().id(), - script, value); + WatcherConditionScript conditionScript = scriptFactory.newInstance(script.getParams(), ctx); + return conditionScript.execute() ? MET : UNMET; } @Override diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/WatcherConditionScript.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/WatcherConditionScript.java new file mode 100644 index 0000000000000..1148cc6a58eb5 --- /dev/null +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/WatcherConditionScript.java @@ -0,0 +1,62 @@ +/* + * 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.condition; + +import org.elasticsearch.script.ParameterMap; +import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; +import org.elasticsearch.xpack.watcher.support.Variables; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A script to determine whether a watch should be run. + */ +public abstract class WatcherConditionScript { + public static final String[] PARAMETERS = {}; + + private static final Map DEPRECATIONS; + + static { + Map deprecations = new HashMap<>(); + deprecations.put( + "ctx", + "Accessing variable [ctx] via [params.ctx] from within a watcher_condition script " + + "is deprecated in favor of directly accessing [ctx]." + ); + DEPRECATIONS = Collections.unmodifiableMap(deprecations); + } + + private final Map params; + // TODO: ctx should have its members extracted into execute parameters, but it needs to be a member for bwc access in params + private final Map ctx; + + public WatcherConditionScript(Map params, WatchExecutionContext watcherContext) { + Map paramsWithCtx = new HashMap<>(params); + Map ctx = Variables.createCtx(watcherContext, watcherContext.payload()); + paramsWithCtx.put("ctx", ctx); + this.params = new ParameterMap(Collections.unmodifiableMap(paramsWithCtx), DEPRECATIONS); + this.ctx = ctx; + } + + public abstract boolean execute(); + + public Map getParams() { + return params; + } + + public Map getCtx() { + return ctx; + } + + public interface Factory { + WatcherConditionScript newInstance(Map params, WatchExecutionContext watcherContext); + } + + public static ScriptContext CONTEXT = new ScriptContext<>("watcher_condition", Factory.class); +} diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/http/ExecutableHttpInput.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/http/ExecutableHttpInput.java index 1bc7ab309f0aa..5d738772f21cb 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/http/ExecutableHttpInput.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/http/ExecutableHttpInput.java @@ -44,7 +44,7 @@ public ExecutableHttpInput(HttpInput input, Logger logger, HttpClient client, Te public HttpInput.Result execute(WatchExecutionContext ctx, Payload payload) { HttpRequest request = null; try { - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); request = input.getRequest().render(templateEngine, model); return doExecute(ctx, request); } catch (Exception e) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/DataAttachmentParser.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/DataAttachmentParser.java index 9164e1db7ea1b..34730c88ce01b 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/DataAttachmentParser.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/DataAttachmentParser.java @@ -57,7 +57,7 @@ public DataAttachment parse(String id, XContentParser parser) throws IOException @Override public Attachment toAttachment(WatchExecutionContext ctx, Payload payload, DataAttachment attachment) throws IOException { - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); return attachment.getDataAttachment().create(attachment.id(), model); } } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/HttpEmailAttachementParser.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/HttpEmailAttachementParser.java index 7c5d68a126b2c..076c57c832fb4 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/HttpEmailAttachementParser.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/HttpEmailAttachementParser.java @@ -79,7 +79,7 @@ public HttpRequestAttachment parse(String id, XContentParser parser) throws IOEx @Override public Attachment toAttachment(WatchExecutionContext context, Payload payload, HttpRequestAttachment attachment) throws IOException { - Map model = Variables.createCtxModel(context, payload); + Map model = Variables.createCtxParamsMap(context, payload); HttpRequest httpRequest = attachment.getRequestTemplate().render(templateEngine, model); HttpResponse response = httpClient.execute(httpRequest); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParser.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParser.java index 28a8c194b579f..f6026c0efce3b 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParser.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/notification/email/attachment/ReportingAttachmentParser.java @@ -91,7 +91,7 @@ public ReportingAttachment parse(String id, XContentParser parser) throws IOExce @Override public Attachment toAttachment(WatchExecutionContext context, Payload payload, ReportingAttachment attachment) throws IOException { - Map model = Variables.createCtxModel(context, payload); + Map model = Variables.createCtxParamsMap(context, payload); String initialUrl = templateEngine.render(new TextTemplate(attachment.url()), model); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/Variables.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/Variables.java index 858f6707f29a9..cf3c9f8103924 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/Variables.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/Variables.java @@ -22,7 +22,15 @@ public final class Variables { public static final String METADATA = "metadata"; public static final String VARS = "vars"; - public static Map createCtxModel(WatchExecutionContext ctx, Payload payload) { + /** Creates a ctx map and puts it into the returned map as "ctx". */ + public static Map createCtxParamsMap(WatchExecutionContext ctx, Payload payload) { + Map model = new HashMap<>(); + model.put(CTX, createCtx(ctx, payload)); + return model; + } + + /** Creates a ctx map. */ + public static Map createCtx(WatchExecutionContext ctx, Payload payload) { Map ctxModel = new HashMap<>(); ctxModel.put(ID, ctx.id().value()); ctxModel.put(WATCH_ID, ctx.id().watchId()); @@ -33,10 +41,6 @@ public static Map createCtxModel(WatchExecutionContext ctx, Payl } ctxModel.put(METADATA, ctx.watch().metadata()); ctxModel.put(VARS, ctx.vars()); - Map model = new HashMap<>(); - model.put(CTX, ctxModel); - return model; + return ctxModel; } - - } diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java index 9df4f5f8b5234..2208aab428a39 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java @@ -45,7 +45,7 @@ public WatcherSearchTemplateService(Settings settings, ScriptService scriptServi public String renderTemplate(Script source, WatchExecutionContext ctx, Payload payload) throws IOException { // Due the inconsistency with templates in ES 1.x, we maintain our own template format. // This template format we use now, will become the template structure in ES 2.0 - Map watcherContextParams = Variables.createCtxModel(ctx, payload); + Map watcherContextParams = Variables.createCtxParamsMap(ctx, payload); // Here we convert watcher template into a ES core templates. Due to the different format we use, we // convert to the template format used in ES core if (source.getParams() != null) { diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/ExecutableScriptTransform.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/ExecutableScriptTransform.java index e2b1cf882cc47..20cd8e7b6efd7 100644 --- a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/ExecutableScriptTransform.java +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/ExecutableScriptTransform.java @@ -8,19 +8,16 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.util.Supplier; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptService; import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.core.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.core.watcher.watch.Payload; -import org.elasticsearch.xpack.watcher.Watcher; import java.io.IOException; import java.util.HashMap; import java.util.Map; -import static org.elasticsearch.xpack.watcher.support.Variables.createCtxModel; import static org.elasticsearch.xpack.watcher.transform.script.ScriptTransform.TYPE; public class ExecutableScriptTransform extends ExecutableTransform { @@ -32,7 +29,7 @@ public ExecutableScriptTransform(ScriptTransform transform, Logger logger, Scrip this.scriptService = scriptService; Script script = transform.getScript(); // try to compile so we catch syntax errors early - scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT); + scriptService.compile(script, WatcherTransformScript.CONTEXT); } @Override @@ -47,14 +44,9 @@ public ScriptTransform.Result execute(WatchExecutionContext ctx, Payload payload ScriptTransform.Result doExecute(WatchExecutionContext ctx, Payload payload) throws IOException { Script script = transform.getScript(); - Map model = new HashMap<>(); - if (script.getParams() != null) { - model.putAll(script.getParams()); - } - model.putAll(createCtxModel(ctx, payload)); - ExecutableScript.Factory factory = scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT); - ExecutableScript executable = factory.newInstance(model); - Object value = executable.run(); + WatcherTransformScript.Factory factory = scriptService.compile(script, WatcherTransformScript.CONTEXT); + WatcherTransformScript transformScript = factory.newInstance(script.getParams(), ctx, payload); + Object value = transformScript.execute(); // TODO: deprecate one of these styles (returning a map or returning an opaque value below) if (value instanceof Map) { return new ScriptTransform.Result(new Payload.Simple((Map) value)); diff --git a/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/WatcherTransformScript.java b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/WatcherTransformScript.java new file mode 100644 index 0000000000000..6d84c32578bc0 --- /dev/null +++ b/x-pack/plugin/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/script/WatcherTransformScript.java @@ -0,0 +1,63 @@ +/* + * 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.script; + +import org.elasticsearch.script.ParameterMap; +import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; +import org.elasticsearch.xpack.core.watcher.watch.Payload; +import org.elasticsearch.xpack.watcher.support.Variables; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * A script to transform the results of a watch execution. + */ +public abstract class WatcherTransformScript { + public static final String[] PARAMETERS = {}; + + private static final Map DEPRECATIONS; + + static { + Map deprecations = new HashMap<>(); + deprecations.put( + "ctx", + "Accessing variable [ctx] via [params.ctx] from within a watcher_transform script " + + "is deprecated in favor of directly accessing [ctx]." + ); + DEPRECATIONS = Collections.unmodifiableMap(deprecations); + } + + private final Map params; + // TODO: ctx should have its members extracted into execute parameters, but it needs to be a member bwc access in params + private final Map ctx; + + public WatcherTransformScript(Map params, WatchExecutionContext watcherContext, Payload payload) { + Map paramsWithCtx = new HashMap<>(params); + Map ctx = Variables.createCtx(watcherContext, payload); + paramsWithCtx.put("ctx", ctx); + this.params = new ParameterMap(Collections.unmodifiableMap(paramsWithCtx), DEPRECATIONS); + this.ctx = ctx; + } + + public abstract Object execute(); + + public Map getParams() { + return params; + } + + public Map getCtx() { + return ctx; + } + + public interface Factory { + WatcherTransformScript newInstance(Map params, WatchExecutionContext watcherContext, Payload payload); + } + + public static ScriptContext CONTEXT = new ScriptContext<>("watcher_transform", Factory.class); +} diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/AlwaysConditionTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/AlwaysConditionTests.java index c29452302c0ab..20bf83ef4ed77 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/AlwaysConditionTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/AlwaysConditionTests.java @@ -12,7 +12,6 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.watcher.condition.ExecutableCondition; -import org.elasticsearch.xpack.watcher.Watcher; import java.time.Clock; @@ -56,7 +55,7 @@ public static ExecutableCondition randomCondition(ScriptService scriptService) { switch (type) { case ScriptCondition.TYPE: Script mockScript = mockScript("_script"); - return new ScriptCondition(mockScript, scriptService.compile(mockScript, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + return new ScriptCondition(mockScript, scriptService); case CompareCondition.TYPE: return new CompareCondition("_path", randomFrom(CompareCondition.Op.values()), randomFrom(5, "3"), Clock.systemUTC()); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/ScriptConditionTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/ScriptConditionTests.java index 9fd0ace3b321b..fc6161cb9279c 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/ScriptConditionTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/ScriptConditionTests.java @@ -13,15 +13,12 @@ import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.MetaData; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.script.GeneralScriptException; -import org.elasticsearch.script.MockScriptEngine; import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.ScriptMetaData; import org.elasticsearch.script.ScriptService; @@ -30,9 +27,12 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.watcher.condition.ExecutableCondition; import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; +import org.elasticsearch.xpack.core.watcher.execution.Wid; +import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent; import org.elasticsearch.xpack.core.watcher.watch.Payload; -import org.elasticsearch.xpack.watcher.Watcher; +import org.elasticsearch.xpack.core.watcher.watch.Watch; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; +import org.elasticsearch.xpack.watcher.test.WatcherMockScriptPlugin; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.junit.Before; @@ -51,6 +51,8 @@ import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ScriptConditionTests extends ESTestCase { @@ -77,15 +79,13 @@ public void init() throws IOException { return total > 1; }); - scripts.put("ctx.payload.hits.total > threshold", vars -> { + scripts.put("ctx.payload.hits.total > params.threshold", vars -> { int total = (int) XContentMapValues.extractValue("ctx.payload.hits.total", vars); - int threshold = (int) XContentMapValues.extractValue("threshold", vars); + int threshold = (int) XContentMapValues.extractValue("params.threshold", vars); return total > threshold; }); - ScriptEngine engine = new MockScriptEngine(MockScriptEngine.NAME, scripts, Collections.emptyMap()); - scriptService = new ScriptService(Settings.EMPTY, Collections.singletonMap(engine.getType(), engine), - Collections.singletonMap(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + scriptService = WatcherMockScriptPlugin.newMockScriptService(scripts); ClusterState.Builder clusterState = new ClusterState.Builder(new ClusterName("_name")); clusterState.metaData(MetaData.builder().putCustom(ScriptMetaData.TYPE, new ScriptMetaData.Builder(null).build())); @@ -94,8 +94,7 @@ public void init() throws IOException { } public void testExecute() throws Exception { - Script script = mockScript("ctx.payload.hits.total > 1"); - ScriptCondition condition = new ScriptCondition(script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + ScriptCondition condition = new ScriptCondition(mockScript("ctx.payload.hits.total > 1"), scriptService); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); @@ -103,8 +102,9 @@ public void testExecute() throws Exception { } public void testExecuteMergedParams() throws Exception { - Script script = new Script(ScriptType.INLINE, "mockscript", "ctx.payload.hits.total > threshold", singletonMap("threshold", 1)); - ScriptCondition executable = new ScriptCondition(script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + Script script = new Script(ScriptType.INLINE, "mockscript", + "ctx.payload.hits.total > params.threshold", singletonMap("threshold", 1)); + ScriptCondition executable = new ScriptCondition(script, scriptService); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); @@ -182,9 +182,8 @@ public void testScriptConditionParser_badLang() throws Exception { } public void testScriptConditionThrowException() throws Exception { - Script script = mockScript("null.foo"); ScriptCondition condition = new ScriptCondition( - script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + mockScript("null.foo"), scriptService); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); @@ -192,20 +191,9 @@ public void testScriptConditionThrowException() throws Exception { assertThat(exception.getMessage(), containsString("Error evaluating null.foo")); } - public void testScriptConditionReturnObjectThrowsException() throws Exception { - Script script = mockScript("return new Object()"); - ScriptCondition condition = new ScriptCondition(script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); - SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY); - WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); - Exception exception = expectThrows(IllegalStateException.class, () -> condition.execute(ctx)); - assertThat(exception.getMessage(), - containsString("condition [script] must return a boolean value (true|false) but instead returned [_name]")); - } - public void testScriptConditionAccessCtx() throws Exception { - Script script = mockScript("ctx.trigger.scheduled_time.getMillis() < new Date().time"); - ScriptCondition condition = new ScriptCondition(script, scriptService.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)); + ScriptCondition condition = new ScriptCondition(mockScript("ctx.trigger.scheduled_time.getMillis() < new Date().time"), + scriptService); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 0, 500L, ShardSearchFailure.EMPTY_ARRAY, SearchResponse.Clusters.EMPTY); WatchExecutionContext ctx = mockExecutionContext("_name", new DateTime(DateTimeZone.UTC), new Payload.XContent(response)); @@ -213,6 +201,23 @@ public void testScriptConditionAccessCtx() throws Exception { assertThat(condition.execute(ctx).met(), is(true)); } + public void testParamsCtxDeprecated() throws Exception { + WatchExecutionContext watcherContext = mock(WatchExecutionContext.class); + when(watcherContext.id()).thenReturn(mock(Wid.class)); + when(watcherContext.watch()).thenReturn(mock(Watch.class)); + when(watcherContext.triggerEvent()).thenReturn(mock(TriggerEvent.class)); + WatcherConditionScript watcherScript = new WatcherConditionScript(Collections.emptyMap(), watcherContext) { + @Override + public boolean execute() { + assertThat(getParams().get("ctx"), is(getCtx())); + return true; + } + }; + watcherScript.execute(); + assertWarnings("Accessing variable [ctx] via [params.ctx] from within a watcher_condition script " + + "is deprecated in favor of directly accessing [ctx]."); + } + private static XContentBuilder createConditionContent(String script, String scriptLang, ScriptType scriptType) throws IOException { XContentBuilder builder = jsonBuilder(); if (scriptType == null) { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/history/HistoryActionConditionTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/history/HistoryActionConditionTests.java index 9093a6f86ae56..78fc9c290eddb 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/history/HistoryActionConditionTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/history/HistoryActionConditionTests.java @@ -24,6 +24,7 @@ import org.elasticsearch.xpack.watcher.condition.NeverCondition; import org.elasticsearch.xpack.watcher.condition.ScriptCondition; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; +import org.elasticsearch.xpack.watcher.test.WatcherMockScriptPlugin; import java.util.ArrayList; import java.util.Arrays; @@ -66,7 +67,7 @@ protected List> pluginTypes() { return types; } - public static class CustomScriptPlugin extends MockScriptPlugin { + public static class CustomScriptPlugin extends WatcherMockScriptPlugin { @Override protected Map, Object>> pluginScripts() { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/transform/TransformInputTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/transform/TransformInputTests.java index a3d4d68d4c127..0ac5932586e61 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/transform/TransformInputTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/transform/TransformInputTests.java @@ -13,8 +13,6 @@ import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.script.MockScriptEngine; import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptContext; -import org.elasticsearch.script.ScriptEngine; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptType; import org.elasticsearch.test.ESTestCase; @@ -25,7 +23,7 @@ import org.elasticsearch.xpack.core.watcher.transform.TransformFactory; import org.elasticsearch.xpack.core.watcher.transform.TransformRegistry; import org.elasticsearch.xpack.core.watcher.watch.Payload; -import org.elasticsearch.xpack.watcher.Watcher; +import org.elasticsearch.xpack.watcher.test.WatcherMockScriptPlugin; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.transform.script.ExecutableScriptTransform; import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform; @@ -33,7 +31,6 @@ import org.junit.Before; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; @@ -46,14 +43,7 @@ public class TransformInputTests extends ESTestCase { @Before public void setupScriptService() { - Map engines = new HashMap<>(); - engines.put(MockScriptEngine.NAME, - new MockScriptEngine(MockScriptEngine.NAME, Collections.singletonMap("1", s -> "2"), Collections.emptyMap())); - Map> contexts = new HashMap<>(); - contexts.put(Watcher.SCRIPT_TEMPLATE_CONTEXT.name, Watcher.SCRIPT_TEMPLATE_CONTEXT); - contexts.put(Watcher.SCRIPT_SEARCH_CONTEXT.name, Watcher.SCRIPT_SEARCH_CONTEXT); - contexts.put(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT); - scriptService = new ScriptService(Settings.EMPTY, engines, contexts); + scriptService = WatcherMockScriptPlugin.newMockScriptService(Collections.singletonMap("1", s -> "2")); } public void testExecute() { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/VariablesTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/VariablesTests.java index 74396a3290644..4ab5b7b7b87aa 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/VariablesTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/VariablesTests.java @@ -40,7 +40,7 @@ public void testCreateCtxModel() throws Exception { .metadata(metatdata) .buildMock(); - Map model = Variables.createCtxModel(ctx, payload); + Map model = Variables.createCtxParamsMap(ctx, payload); assertThat(model, notNullValue()); assertThat(model.size(), is(1)); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/WatcherMockScriptPlugin.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/WatcherMockScriptPlugin.java new file mode 100644 index 0000000000000..2908dbaa6cc14 --- /dev/null +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/WatcherMockScriptPlugin.java @@ -0,0 +1,74 @@ +/* + * 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.test; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.script.MockScriptEngine; +import org.elasticsearch.script.MockScriptPlugin; +import org.elasticsearch.script.ScriptContext; +import org.elasticsearch.script.ScriptEngine; +import org.elasticsearch.script.ScriptService; +import org.elasticsearch.xpack.watcher.Watcher; +import org.elasticsearch.xpack.watcher.condition.WatcherConditionScript; +import org.elasticsearch.xpack.watcher.transform.script.WatcherTransformScript; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * Provides a mock script engine with mock versions of watcher scripts. + */ +public abstract class WatcherMockScriptPlugin extends MockScriptPlugin { + public static final Map, MockScriptEngine.ContextCompiler> CONTEXT_COMPILERS; + static { + Map, MockScriptEngine.ContextCompiler> compilers = new HashMap<>(); + compilers.put(WatcherConditionScript.CONTEXT, (script, options) -> + (WatcherConditionScript.Factory) (params, watcherContext) -> + new WatcherConditionScript(params, watcherContext) { + @Override + public boolean execute() { + Map vars = new HashMap<>(); + vars.put("params", getParams()); + vars.put("ctx", getCtx()); + return (boolean) script.apply(vars); + } + }); + compilers.put(WatcherTransformScript.CONTEXT, (script, options) -> + (WatcherTransformScript.Factory) (params, watcherContext, payload) -> + new WatcherTransformScript(params, watcherContext, payload) { + @Override + public Object execute() { + Map vars = new HashMap<>(); + vars.put("params", getParams()); + vars.put("ctx", getCtx()); + return script.apply(vars); + } + }); + CONTEXT_COMPILERS = Collections.unmodifiableMap(compilers); + } + + public static final List> CONTEXTS = Collections.unmodifiableList(Arrays.asList( + WatcherConditionScript.CONTEXT, WatcherTransformScript.CONTEXT, Watcher.SCRIPT_TEMPLATE_CONTEXT, Watcher.SCRIPT_SEARCH_CONTEXT + )); + + @Override + protected Map, MockScriptEngine.ContextCompiler> pluginContextCompilers() { + return CONTEXT_COMPILERS; + } + + public static ScriptService newMockScriptService(Map, Object>> scripts) { + Map engines = new HashMap<>(); + engines.put(MockScriptEngine.NAME, + new MockScriptEngine(MockScriptEngine.NAME, scripts, CONTEXT_COMPILERS)); + Map> contexts = CONTEXTS.stream().collect(Collectors.toMap(o -> o.name, Function.identity())); + return new ScriptService(Settings.EMPTY, engines, contexts); + } +} diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/ExecutionVarsIntegrationTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/ExecutionVarsIntegrationTests.java index 0b3c0fc28ec05..90b14233b8d27 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/ExecutionVarsIntegrationTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/ExecutionVarsIntegrationTests.java @@ -9,13 +9,13 @@ import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.protocol.xpack.watcher.PutWatchResponse; -import org.elasticsearch.script.MockScriptPlugin; import org.elasticsearch.xpack.core.watcher.client.WatcherClient; import org.elasticsearch.xpack.core.watcher.support.xcontent.ObjectPath; import org.elasticsearch.xpack.core.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.core.watcher.transport.actions.execute.ExecuteWatchResponse; import org.elasticsearch.xpack.watcher.condition.ScriptCondition; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; +import org.elasticsearch.xpack.watcher.test.WatcherMockScriptPlugin; import org.hamcrest.Matcher; import java.util.HashMap; @@ -46,7 +46,7 @@ protected List> pluginTypes() { return types; } - public static class CustomScriptPlugin extends MockScriptPlugin { + public static class CustomScriptPlugin extends WatcherMockScriptPlugin { @Override @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java index 6d7f4bef213f7..b66a70c23afa4 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java @@ -42,6 +42,7 @@ import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; +import org.elasticsearch.xpack.watcher.transform.script.WatcherTransformScript; import org.junit.Before; import org.mockito.ArgumentCaptor; @@ -76,7 +77,7 @@ public void setup() { Map> contexts = new HashMap<>(); contexts.put(Watcher.SCRIPT_TEMPLATE_CONTEXT.name, Watcher.SCRIPT_TEMPLATE_CONTEXT); contexts.put(Watcher.SCRIPT_SEARCH_CONTEXT.name, Watcher.SCRIPT_SEARCH_CONTEXT); - contexts.put(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT); + contexts.put(WatcherTransformScript.CONTEXT.name, WatcherTransformScript.CONTEXT); scriptService = new ScriptService(Settings.EMPTY, engines, contexts); ThreadPool threadPool = mock(ThreadPool.class); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/TransformIntegrationTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/TransformIntegrationTests.java index d629c54934fc1..044c3d3061ee0 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/TransformIntegrationTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/TransformIntegrationTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.xpack.watcher.condition.InternalAlwaysCondition; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; +import org.elasticsearch.xpack.watcher.test.WatcherMockScriptPlugin; import java.io.IOException; import java.io.UncheckedIOException; @@ -78,7 +79,7 @@ protected Path nodeConfigPath(int nodeOrdinal) { return config; } - public static class CustomScriptPlugin extends MockScriptPlugin { + public static class CustomScriptPlugin extends WatcherMockScriptPlugin { @Override protected Map, Object>> pluginScripts() { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java index bc79561f726c9..752b753f028ff 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java @@ -8,7 +8,6 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptContext; import org.elasticsearch.script.ScriptException; @@ -17,10 +16,12 @@ import org.elasticsearch.script.ScriptType; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.watcher.execution.WatchExecutionContext; +import org.elasticsearch.xpack.core.watcher.execution.Wid; import org.elasticsearch.xpack.core.watcher.transform.Transform; +import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent; import org.elasticsearch.xpack.core.watcher.watch.Payload; +import org.elasticsearch.xpack.core.watcher.watch.Watch; import org.elasticsearch.xpack.watcher.Watcher; -import org.elasticsearch.xpack.watcher.support.Variables; import java.util.Collections; import java.util.HashMap; @@ -49,21 +50,19 @@ public void testExecuteMapValue() throws Exception { ScriptType type = randomFrom(ScriptType.values()); Map params = Collections.emptyMap(); Script script = new Script(type, type == ScriptType.STORED ? null : "_lang", "_script", params); - ExecutableScript.Factory factory = mock(ExecutableScript.Factory.class); - when(service.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)).thenReturn(factory); + WatcherTransformScript.Factory factory = mock(WatcherTransformScript.Factory.class); + when(service.compile(script, WatcherTransformScript.CONTEXT)).thenReturn(factory); ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service); WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY); Payload payload = new Payload.Simple("key", "value"); - Map model = Variables.createCtxModel(ctx, payload); - Map transformed = singletonMap("key", "value"); - ExecutableScript executable = mock(ExecutableScript.class); - when(executable.run()).thenReturn(transformed); - when(factory.newInstance(model)).thenReturn(executable); + WatcherTransformScript executable = mock(WatcherTransformScript.class); + when(executable.execute()).thenReturn(transformed); + when(factory.newInstance(params, ctx, payload)).thenReturn(executable); Transform.Result result = transform.execute(ctx, payload); assertThat(result, notNullValue()); @@ -77,19 +76,17 @@ public void testExecuteMapValueFailure() throws Exception { ScriptType type = randomFrom(ScriptType.values()); Map params = Collections.emptyMap(); Script script = new Script(type, type == ScriptType.STORED ? null : "_lang", "_script", params); - ExecutableScript.Factory factory = mock(ExecutableScript.Factory.class); - when(service.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)).thenReturn(factory); + WatcherTransformScript.Factory factory = mock(WatcherTransformScript.Factory.class); + when(service.compile(script, WatcherTransformScript.CONTEXT)).thenReturn(factory); ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service); WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY); Payload payload = new Payload.Simple("key", "value"); - Map model = Variables.createCtxModel(ctx, payload); - - ExecutableScript executable = mock(ExecutableScript.class); - when(executable.run()).thenThrow(new RuntimeException("_error")); - when(factory.newInstance(model)).thenReturn(executable); + WatcherTransformScript executable = mock(WatcherTransformScript.class); + when(executable.execute()).thenThrow(new RuntimeException("_error")); + when(factory.newInstance(params, ctx, payload)).thenReturn(executable); Transform.Result result = transform.execute(ctx, payload); assertThat(result, notNullValue()); @@ -103,20 +100,18 @@ public void testExecuteNonMapValue() throws Exception { ScriptType type = randomFrom(ScriptType.values()); Map params = Collections.emptyMap(); Script script = new Script(type, type == ScriptType.STORED ? null : "_lang", "_script", params); - ExecutableScript.Factory factory = mock(ExecutableScript.Factory.class); - when(service.compile(script, Watcher.SCRIPT_EXECUTABLE_CONTEXT)).thenReturn(factory); + WatcherTransformScript.Factory factory = mock(WatcherTransformScript.Factory.class); + when(service.compile(script, WatcherTransformScript.CONTEXT)).thenReturn(factory); ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service); WatchExecutionContext ctx = mockExecutionContext("_name", Payload.EMPTY); Payload payload = new Payload.Simple("key", "value"); - Map model = Variables.createCtxModel(ctx, payload); - - ExecutableScript executable = mock(ExecutableScript.class); + WatcherTransformScript executable = mock(WatcherTransformScript.class); Object value = randomFrom("value", 1, new String[] { "value" }, Collections.singletonList("value"), singleton("value")); - when(executable.run()).thenReturn(value); - when(factory.newInstance(model)).thenReturn(executable); + when(executable.execute()).thenReturn(value); + when(factory.newInstance(params, ctx, payload)).thenReturn(executable); Transform.Result result = transform.execute(ctx, payload); assertThat(result, notNullValue()); @@ -158,7 +153,7 @@ public void testScriptConditionParserBadScript() throws Exception { String errorMessage = "expected error message"; ScriptException scriptException = new ScriptException(errorMessage, new RuntimeException("foo"), Collections.emptyList(), "whatever", "whatever"); - when(scriptService.compile(anyObject(), eq(Watcher.SCRIPT_EXECUTABLE_CONTEXT))).thenThrow(scriptException); + when(scriptService.compile(anyObject(), eq(WatcherTransformScript.CONTEXT))).thenThrow(scriptException); ScriptTransformFactory transformFactory = new ScriptTransformFactory(Settings.builder().build(), scriptService); @@ -191,6 +186,23 @@ public void testScriptConditionParserBadLang() throws Exception { assertThat(e.getMessage(), containsString("script_lang not supported [not_a_valid_lang]")); } + public void testParamsCtxDeprecated() throws Exception { + WatchExecutionContext watcherContext = mock(WatchExecutionContext.class); + when(watcherContext.id()).thenReturn(mock(Wid.class)); + when(watcherContext.watch()).thenReturn(mock(Watch.class)); + when(watcherContext.triggerEvent()).thenReturn(mock(TriggerEvent.class)); + Payload payload = mock(Payload.class); + WatcherTransformScript watcherScript = new WatcherTransformScript(Collections.emptyMap(), watcherContext, payload) { + @Override + public Object execute() { + return getParams().get("ctx"); + } + }; + assertThat(watcherScript.execute(), is(watcherScript.getCtx())); + assertWarnings("Accessing variable [ctx] via [params.ctx] from within a watcher_transform script " + + "is deprecated in favor of directly accessing [ctx]."); + } + static String scriptTypeField(ScriptType type) { switch (type) { case INLINE: return "source"; @@ -205,7 +217,7 @@ public static ScriptService createScriptService() throws Exception { .put("path.home", createTempDir()) .build(); Map contexts = new HashMap<>(ScriptModule.CORE_CONTEXTS); - contexts.put(Watcher.SCRIPT_EXECUTABLE_CONTEXT.name, Watcher.SCRIPT_EXECUTABLE_CONTEXT); + contexts.put(WatcherTransformScript.CONTEXT.name, WatcherTransformScript.CONTEXT); contexts.put(Watcher.SCRIPT_TEMPLATE_CONTEXT.name, Watcher.SCRIPT_TEMPLATE_CONTEXT); return new ScriptService(settings, Collections.emptyMap(), Collections.emptyMap()); }