From b74f1e6cb2db33bd6ca45c2cb9854cc5ac17c64f Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Fri, 2 Sep 2016 21:43:05 +0200 Subject: [PATCH] watcher: Add limited capability to upgrade the source of a watcher upon startup. This particular change focuses on upgrading the source of a watch when it comes to scripts that have no language specified explicitly. The default language in version 5 changed to painless from whatever is specified in `script.default_lang` setting (this defaulted to groovy). In order to make sure that scripts in watcher remain to work we should rewrite the search source upon startup and set the legacy default language explicitly. The legacy script language is now controlled by `script.legacy.default_lang` setting and that defaults to groovy. Changing the source upon startup should do the trick and only change the source of watches with scripts that don't have an explicit language set. For new watches the default language used in scripts is painless and because we now always serialize the language explicitly in scripts these watches won't be changed on startup. The upgrade logic added here tries to upgrade scripts in the following places in a watch: * script condition * script transform * any script defined inside of a search input Original commit: elastic/x-pack-elasticsearch@4d578819eb4580d6ee84fd85a23f7457541b3794 --- .../xpack/common/text/TextTemplate.java | 6 +- .../xpack/watcher/actions/ActionRegistry.java | 5 +- .../xpack/watcher/actions/ActionWrapper.java | 6 +- .../watcher/condition/ConditionFactory.java | 8 +- .../watcher/condition/ConditionRegistry.java | 14 ++- .../always/AlwaysConditionFactory.java | 2 +- .../compare/CompareConditionFactory.java | 2 +- .../array/ArrayCompareConditionFactory.java | 2 +- .../never/NeverConditionFactory.java | 2 +- .../condition/script/ScriptCondition.java | 10 +- .../script/ScriptConditionFactory.java | 11 +- .../xpack/watcher/input/InputFactory.java | 12 ++- .../xpack/watcher/input/InputRegistry.java | 13 ++- .../input/chain/ChainInputFactory.java | 3 +- .../watcher/input/http/HttpInputFactory.java | 2 +- .../watcher/input/none/NoneInputFactory.java | 2 +- .../watcher/input/search/SearchInput.java | 16 +-- .../input/search/SearchInputFactory.java | 17 ++- .../input/simple/SimpleInputFactory.java | 2 +- .../search/WatcherSearchTemplateRequest.java | 36 +++++-- .../search/WatcherSearchTemplateService.java | 3 +- .../watcher/transform/TransformFactory.java | 12 ++- .../watcher/transform/TransformRegistry.java | 13 +-- .../transform/chain/ChainTransform.java | 5 +- .../chain/ChainTransformFactory.java | 4 +- .../transform/script/ScriptTransform.java | 10 +- .../script/ScriptTransformFactory.java | 11 +- .../transform/search/SearchTransform.java | 19 ++-- .../search/SearchTransformFactory.java | 14 +-- .../xpack/watcher/watch/Watch.java | 25 +++-- .../xpack/watcher/watch/WatchStore.java | 4 +- .../always/AlwaysConditionTests.java | 4 +- .../compare/CompareConditionTests.java | 8 +- .../array/ArrayCompareConditionTests.java | 14 +-- .../condition/never/NeverConditionTests.java | 4 +- .../script/ScriptConditionTests.java | 11 +- .../watcher/input/chain/ChainInputTests.java | 2 +- .../watcher/input/http/HttpInputTests.java | 4 +- .../input/simple/SimpleInputTests.java | 4 +- .../watcher/support/WatcherUtilsTests.java | 6 +- .../WatcherSearchTemplateRequestTests.java | 60 ++++++++++- .../test/integration/SearchInputTests.java | 3 +- .../integration/SearchTransformTests.java | 2 +- .../WatcherBackwardsCompatibilityTests.java | 36 ++++++- .../transform/chain/ChainTransformTests.java | 6 +- .../script/ScriptTransformTests.java | 8 +- .../xpack/watcher/watch/WatchStoreTests.java | 14 ++- .../xpack/watcher/watch/WatchTests.java | 98 ++++++++++++++++-- .../resources/bwc_indices/bwc_index_2_3_5.zip | Bin 7851 -> 7916 bytes 49 files changed, 416 insertions(+), 159 deletions(-) diff --git a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/text/TextTemplate.java b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/text/TextTemplate.java index a3c31fac856..83ce0db34e6 100644 --- a/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/text/TextTemplate.java +++ b/elasticsearch/x-pack/src/main/java/org/elasticsearch/xpack/common/text/TextTemplate.java @@ -27,6 +27,8 @@ import java.util.Objects; */ public class TextTemplate implements ToXContent { + public static final String DEFAULT_TEMPLATE_LANG = "mustache"; + private final Script script; private final String inlineTemplate; @@ -37,7 +39,7 @@ public class TextTemplate implements ToXContent { public TextTemplate(String template, @Nullable XContentType contentType, ScriptType type, @Nullable Map params) { - this.script = new Script(template, type, "mustache", params, contentType); + this.script = new Script(template, type, DEFAULT_TEMPLATE_LANG, params, contentType); this.inlineTemplate = null; } @@ -95,7 +97,7 @@ public class TextTemplate implements ToXContent { if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { return new TextTemplate(parser.text()); } else { - return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, "mustache")); + return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, DEFAULT_TEMPLATE_LANG)); } } } diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionRegistry.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionRegistry.java index 0579ac92ead..9a93cf7c561 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionRegistry.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionRegistry.java @@ -45,7 +45,7 @@ public class ActionRegistry { return parsers.get(type); } - public ExecutableActions parseActions(String watchId, XContentParser parser) throws IOException { + public ExecutableActions parseActions(String watchId, XContentParser parser, boolean upgradeActionSource) throws IOException { if (parser.currentToken() != XContentParser.Token.START_OBJECT) { throw new ElasticsearchParseException("could not parse actions for watch [{}]. expected an object but found [{}] instead", watchId, parser.currentToken()); @@ -62,7 +62,8 @@ public class ActionRegistry { throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error); } } else if (token == XContentParser.Token.START_OBJECT && id != null) { - actions.add(ActionWrapper.parse(watchId, id, parser, this, conditionRegistry, transformRegistry, clock, licenseState)); + actions.add(ActionWrapper.parse(watchId, id, parser, this, conditionRegistry, transformRegistry, clock, + licenseState, upgradeActionSource)); } } return new ExecutableActions(actions); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionWrapper.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionWrapper.java index 219684a8b71..e8fc9024cb8 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionWrapper.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/actions/ActionWrapper.java @@ -201,7 +201,7 @@ public class ActionWrapper implements ToXContent { static ActionWrapper parse(String watchId, String actionId, XContentParser parser, ActionRegistry actionRegistry, ConditionRegistry conditionRegistry, TransformRegistry transformRegistry, - Clock clock, XPackLicenseState licenseState) throws IOException { + Clock clock, XPackLicenseState licenseState, boolean upgradeActionSource) throws IOException { assert parser.currentToken() == XContentParser.Token.START_OBJECT; @@ -217,9 +217,9 @@ public class ActionWrapper implements ToXContent { currentFieldName = parser.currentName(); } else { if (ParseFieldMatcher.STRICT.match(currentFieldName, Watch.Field.CONDITION)) { - condition = conditionRegistry.parseExecutable(watchId, parser); + condition = conditionRegistry.parseExecutable(watchId, parser, upgradeActionSource); } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Transform.Field.TRANSFORM)) { - transform = transformRegistry.parse(watchId, parser); + transform = transformRegistry.parse(watchId, parser, upgradeActionSource); } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD)) { throttlePeriod = timeValueMillis(parser.longValue()); } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD_HUMAN)) { diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ConditionFactory.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ConditionFactory.java index 3de9db7ff69..980c541b928 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ConditionFactory.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/ConditionFactory.java @@ -28,8 +28,14 @@ public abstract class ConditionFactory + * + * @param watchId The id of the watch + * @param parser The parsing that contains the condition content + * @param upgradeConditionSource Whether to upgrade the source related to condition if in legacy format + * Note: depending on the version, only conditions implementations that have a + * known legacy format will support this option, otherwise this is a noop. */ - public ExecutableCondition parseExecutable(String watchId, XContentParser parser) throws IOException { - Condition condition = parseCondition(watchId, parser); + public ExecutableCondition parseExecutable(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException { + Condition condition = parseCondition(watchId, parser, upgradeConditionSource); return factories.get(condition.type()).createExecutable(condition); } @@ -56,7 +62,7 @@ public class ConditionRegistry { * } * */ - public Condition parseCondition(String watchId, XContentParser parser) throws IOException { + public Condition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException { Condition condition = null; ConditionFactory factory = null; @@ -74,7 +80,7 @@ public class ConditionRegistry { throw new ElasticsearchParseException("could not parse condition for watch [{}]. unknown condition type [{}]", watchId, type); } - condition = factory.parseCondition(watchId, parser); + condition = factory.parseCondition(watchId, parser, upgradeConditionSource); } } if (condition == null) { diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/always/AlwaysConditionFactory.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/always/AlwaysConditionFactory.java index 73001a21839..c2da3cb1e1e 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/always/AlwaysConditionFactory.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/condition/always/AlwaysConditionFactory.java @@ -32,7 +32,7 @@ public class AlwaysConditionFactory extends ConditionFactory { + private final Settings settings; private final ScriptService scriptService; @Inject public ScriptConditionFactory(Settings settings, ScriptService service) { super(Loggers.getLogger(ExecutableScriptCondition.class, settings)); + this.settings = settings; scriptService = service; } @@ -33,8 +33,9 @@ public class ScriptConditionFactory extends ConditionFactory extract = null; TimeValue timeout = null; @@ -124,7 +125,8 @@ public class SearchInput implements Input { currentFieldName = parser.currentName(); } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) { try { - request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE); + request = WatcherSearchTemplateRequest.fromXContent(inputLogger, parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, + upgradeInputSource, defaultLegacyScriptLanguage, parseFieldMatcher, searchRequestParsers); } catch (ElasticsearchParseException srpe) { throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE, watchId, currentFieldName); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/search/SearchInputFactory.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/search/SearchInputFactory.java index f521b3b773e..dcadcfc66d9 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/search/SearchInputFactory.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/input/search/SearchInputFactory.java @@ -11,12 +11,9 @@ import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.index.query.QueryParseContext; -import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.script.ScriptService; +import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.search.SearchRequestParsers; -import org.elasticsearch.search.aggregations.AggregatorParsers; -import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.watcher.input.InputFactory; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; @@ -25,11 +22,9 @@ import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateServi import java.io.IOException; -/** - * - */ public class SearchInputFactory extends InputFactory { + private final Settings settings; private final WatcherClientProxy client; private final TimeValue defaultTimeout; private final SearchRequestParsers searchRequestParsers; @@ -45,6 +40,7 @@ public class SearchInputFactory extends InputFactory indices = new ArrayList<>(); List types = new ArrayList<>(); IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS; @@ -200,6 +209,19 @@ public class WatcherSearchTemplateRequest implements ToXContent { try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { builder.copyCurrentStructure(parser); searchSource = builder.bytes(); + if (upgradeSearchSource) { + XContentParser searchSourceParser = XContentHelper.createParser(searchSource); + QueryParseContext context = new QueryParseContext(defaultLegacyScriptLanguage, + searchRequestParsers.queryParsers, searchSourceParser, parseFieldMatcher); + try (XContentBuilder upgradeBuilder = XContentBuilder.builder(parser.contentType().xContent())) { + SearchSourceBuilder sourceBuilder = SearchSourceBuilder.fromXContent(context, + searchRequestParsers.aggParsers, searchRequestParsers.suggesters); + upgradeBuilder.value(sourceBuilder); + searchSource = upgradeBuilder.bytes(); + } catch (Exception e) { + logger.warn("Unable to upgrade search source: [" + searchSource.utf8ToString() + "]", e); + } + } } } else if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_OPTIONS_FIELD)) { boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen(); @@ -248,7 +270,7 @@ public class WatcherSearchTemplateRequest implements ToXContent { indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed, DEFAULT_INDICES_OPTIONS); } else if (ParseFieldMatcher.STRICT.match(currentFieldName, TEMPLATE_FIELD)) { - template = Script.parse(parser, ParseFieldMatcher.STRICT, DEFAULT_LANG); + template = Script.parse(parser, ParseFieldMatcher.STRICT, TextTemplate.DEFAULT_TEMPLATE_LANG); } else { throw new ElasticsearchParseException("could not read search request. unexpected object field [" + currentFieldName + "]"); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java index 3250f702ef5..224a948bebc 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateService.java @@ -56,7 +56,8 @@ public class WatcherSearchTemplateService extends AbstractComponent { if (source.getParams() != null) { watcherContextParams.putAll(source.getParams()); } - Script template = new Script(source.getScript(), source.getType(), source.getLang(), watcherContextParams, + // Templates are always of lang mustache: + Script template = new Script(source.getScript(), source.getType(), "mustache", watcherContextParams, source.getContentType()); CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT, Collections.emptyMap()); return (BytesReference) scriptService.executable(compiledScript, template.getParams()).run(); diff --git a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/TransformFactory.java b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/TransformFactory.java index 0e38bb7bd11..b8b2a41f8d3 100644 --- a/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/TransformFactory.java +++ b/elasticsearch/x-pack/watcher/src/main/java/org/elasticsearch/xpack/watcher/transform/TransformFactory.java @@ -28,16 +28,22 @@ public abstract class TransformFactory { + private final Settings settings; private final ScriptService scriptService; @Inject public ScriptTransformFactory(Settings settings, ScriptService scriptService) { super(Loggers.getLogger(ExecutableScriptTransform.class, settings)); + this.settings = settings; this.scriptService = scriptService; } @@ -33,8 +33,9 @@ public class ScriptTransformFactory extends TransformFactory { + private final Settings settings; protected final WatcherClientProxy client; private final TimeValue defaultTimeout; private final SearchRequestParsers searchRequestParsers; @@ -40,6 +38,7 @@ public class SearchTransformFactory extends TransformFactory conditionParser.createExecutable(scriptCondition)); } @@ -182,7 +181,7 @@ public class ScriptConditionTests extends ESTestCase { XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", ScriptType.INLINE); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); parser.nextToken(); - ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser); + ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser, false); GeneralScriptException exception = expectThrows(GeneralScriptException.class, () -> conditionParser.createExecutable(scriptCondition)); assertThat(exception.getMessage(), containsString("script_lang not supported [not_a_valid_lang]]")); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/chain/ChainInputTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/chain/ChainInputTests.java index b135abe8dd1..1efb0e27a49 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/chain/ChainInputTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/chain/ChainInputTests.java @@ -83,7 +83,7 @@ public class ChainInputTests extends ESTestCase { // first pass JSON and check for correct inputs XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); parser.nextToken(); - ChainInput chainInput = chainInputFactory.parseInput("test", parser); + ChainInput chainInput = chainInputFactory.parseInput("test", parser, false); assertThat(chainInput.getInputs(), hasSize(2)); assertThat(chainInput.getInputs().get(0).v1(), is("first")); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/http/HttpInputTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/http/HttpInputTests.java index 9af85ea6286..668270898f1 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/http/HttpInputTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/http/HttpInputTests.java @@ -188,7 +188,7 @@ public class HttpInputTests extends ESTestCase { BytesReference source = jsonBuilder().value(inputBuilder.build()).bytes(); XContentParser parser = XContentHelper.createParser(source); parser.nextToken(); - HttpInput result = httpParser.parseInput("_id", parser); + HttpInput result = httpParser.parseInput("_id", parser, false); assertThat(result.type(), equalTo(HttpInput.TYPE)); assertThat(result.getRequest().scheme(), equalTo(scheme != null ? scheme : Scheme.HTTP)); // http is the default @@ -226,7 +226,7 @@ public class HttpInputTests extends ESTestCase { XContentParser parser = XContentHelper.createParser(builder.bytes()); parser.nextToken(); try { - httpParser.parseInput("_id", parser); + httpParser.parseInput("_id", parser, false); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { assertThat(e.getMessage(), is("unsupported http method [_METHOD]")); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/simple/SimpleInputTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/simple/SimpleInputTests.java index 91894a3fdc2..d9ab8dec906 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/simple/SimpleInputTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/input/simple/SimpleInputTests.java @@ -48,7 +48,7 @@ public class SimpleInputTests extends ESTestCase { InputFactory parser = new SimpleInputFactory(Settings.builder().build()); XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); xContentParser.nextToken(); - ExecutableInput input = parser.parseExecutable("_id", xContentParser); + ExecutableInput input = parser.parseExecutable("_id", xContentParser, false); assertEquals(input.type(), SimpleInput.TYPE); @@ -65,7 +65,7 @@ public class SimpleInputTests extends ESTestCase { XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); xContentParser.nextToken(); try { - parser.parseInput("_id", xContentParser); + parser.parseInput("_id", xContentParser, false); fail("[simple] input parse should fail with an InputException for an empty json object"); } catch (ElasticsearchParseException e) { assertThat(e.getMessage(), containsString("expected an object but found [VALUE_STRING] instead")); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/WatcherUtilsTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/WatcherUtilsTests.java index 04611dcea70..64617575d66 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/WatcherUtilsTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/WatcherUtilsTests.java @@ -124,7 +124,8 @@ public class WatcherUtilsTests extends ESTestCase { request.toXContent(builder, ToXContent.EMPTY_PARAMS); XContentParser parser = XContentHelper.createParser(builder.bytes()); assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE); + WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(logger, parser, DEFAULT_SEARCH_TYPE, + false, null, null, null); assertThat(result.getIndices(), arrayContainingInAnyOrder(expectedIndices != null ? expectedIndices : new String[0])); assertThat(result.getTypes(), arrayContainingInAnyOrder(expectedTypes != null ? expectedTypes : new String[0])); @@ -213,7 +214,8 @@ public class WatcherUtilsTests extends ESTestCase { XContentParser parser = XContentHelper.createParser(builder.bytes()); assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); - WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE); + WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(logger, parser, DEFAULT_SEARCH_TYPE, + false, null, null, null); assertThat(result.getIndices(), arrayContainingInAnyOrder(indices)); assertThat(result.getTypes(), arrayContainingInAnyOrder(types)); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateRequestTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateRequestTests.java index 5efa5996d0b..4005a93f8bc 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateRequestTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/support/search/WatcherSearchTemplateRequestTests.java @@ -6,15 +6,23 @@ package org.elasticsearch.xpack.watcher.support.search; import org.elasticsearch.action.search.SearchType; +import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.support.XContentMapValues; +import org.elasticsearch.search.SearchModule; +import org.elasticsearch.search.SearchRequestParsers; import org.elasticsearch.test.ESTestCase; import java.io.IOException; +import java.util.Collections; import java.util.Map; import static java.util.Collections.singletonMap; +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.equalTo; public class WatcherSearchTemplateRequestTests extends ESTestCase { @@ -33,7 +41,8 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase { try (XContentParser parser = XContentHelper.createParser(new BytesArray(source))) { parser.nextToken(); - WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, randomFrom(SearchType.values())); + WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent( + logger, parser, randomFrom(SearchType.values()), false, null, null, null); assertNotNull(result.getTemplate()); assertThat(result.getTemplate().getScript(), equalTo(expectedScript)); assertThat(result.getTemplate().getLang(), equalTo(expectedLang)); @@ -42,4 +51,53 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase { fail("Failed to parse watch search request: " + e.getMessage()); } } + + public void testUpgradeSearchSource() throws IOException { + XContentBuilder contentBuilder = jsonBuilder(); + contentBuilder.startObject(); + contentBuilder.startObject("body"); + + contentBuilder.startObject("query"); + contentBuilder.startObject("script"); + contentBuilder.startObject("script"); + contentBuilder.field("inline", "return true"); + contentBuilder.endObject(); + contentBuilder.endObject(); + contentBuilder.endObject(); + + contentBuilder.startObject("aggregations"); + contentBuilder.startObject("avg_grade"); + contentBuilder.startObject("avg"); + contentBuilder.startObject("script"); + contentBuilder.field("inline", "1 + 1"); + contentBuilder.endObject(); + contentBuilder.endObject(); + contentBuilder.endObject(); + contentBuilder.startObject("another_avg"); + contentBuilder.startObject("avg"); + contentBuilder.startObject("script"); + contentBuilder.field("inline", "1 + 2"); + contentBuilder.field("lang", "javascript"); + contentBuilder.endObject(); + contentBuilder.endObject(); + contentBuilder.endObject(); + contentBuilder.endObject(); + + contentBuilder.endObject(); + contentBuilder.endObject(); + XContentParser parser = XContentHelper.createParser(contentBuilder.bytes()); + parser.nextToken(); + + SearchRequestParsers searchRequestParsers = new SearchModule(Settings.EMPTY, false, Collections.emptyList()) + .getSearchRequestParsers(); + WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent( + logger, parser, SearchType.DEFAULT, true, "your_legacy_lang", ParseFieldMatcher.STRICT, searchRequestParsers); + Map parsedResult = XContentHelper.convertToMap(result.getSearchSource(), true).v2(); + // after upgrading the language must be equal to legacy language, because no language was defined explicitly in these scripts: + assertThat(XContentMapValues.extractValue("query.script.script.lang", parsedResult), equalTo("your_legacy_lang")); + assertThat(XContentMapValues.extractValue("aggregations.avg_grade.avg.script.lang", parsedResult), equalTo("your_legacy_lang")); + // after upgrading the language must remain javascript here, because that has been explicitly defined in the script: + assertThat(XContentMapValues.extractValue("aggregations.another_avg.avg.script.lang", parsedResult), equalTo("javascript")); + } + } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java index e95db798ee1..46c689240b7 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchInputTests.java @@ -22,7 +22,6 @@ import org.elasticsearch.search.SearchRequestParsers; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase.ClusterScope; -import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.watcher.actions.ExecutableActions; import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition; import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext; @@ -152,7 +151,7 @@ public class SearchInputTests extends ESIntegTestCase { SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), searchParsers, scriptService()); - SearchInput searchInput = factory.parseInput("_id", parser); + SearchInput searchInput = factory.parseInput("_id", parser, false); assertEquals(SearchInput.TYPE, searchInput.type()); assertThat(searchInput.getTimeout(), equalTo(timeout)); } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchTransformTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchTransformTests.java index d664daa1614..0a43d05fa66 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchTransformTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/SearchTransformTests.java @@ -217,7 +217,7 @@ public class SearchTransformTests extends ESIntegTestCase { SearchRequestParsers searchRequestParsers = internalCluster().getInstance(SearchRequestParsers.class); SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()), searchRequestParsers, scriptService()); - ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser); + ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser, false); assertThat(executable, notNullValue()); assertThat(executable.type(), is(SearchTransform.TYPE)); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/WatcherBackwardsCompatibilityTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/WatcherBackwardsCompatibilityTests.java index 00c54c27e76..4dc2c4b4cad 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/WatcherBackwardsCompatibilityTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/test/integration/WatcherBackwardsCompatibilityTests.java @@ -12,6 +12,8 @@ import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.env.Environment; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.script.MockScriptPlugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; @@ -21,7 +23,10 @@ import org.elasticsearch.xpack.watcher.watch.WatchStore; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.function.Function; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -44,6 +49,13 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati return false; } + @Override + protected List> pluginTypes() { + List> plugins = super.pluginTypes(); + plugins.add(FoolMeScriptLang.class); + return plugins; + } + public void testWatchLoadedSuccessfullyAfterUpgrade() throws Exception { // setup node Path dataDir = createTempDir(); @@ -86,10 +98,32 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati assertThat(getWatchResponse.isFound(), is(true)); Map watchSourceAsMap = getWatchResponse.getSource().getAsMap(); assertThat(ObjectPath.eval("trigger.schedule.interval", watchSourceAsMap), equalTo("99w")); - assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.1.range.date.lte", watchSourceAsMap), + assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.1.range.date.to", watchSourceAsMap), equalTo("{{ctx.trigger.scheduled_time}}")); assertThat(ObjectPath.eval("actions.log_error.logging.text", watchSourceAsMap), equalTo("Found {{ctx.payload.hits.total}} errors in the logs")); + + // Check that all scripts have been upgraded, so that the language has been set to groovy (legacy language default): + assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.2.script.script.lang", watchSourceAsMap), + equalTo("groovy")); + assertThat(ObjectPath.eval("input.search.request.body.aggregations.avg_grade.avg.script.lang", watchSourceAsMap), + equalTo("groovy")); + assertThat(ObjectPath.eval("condition.script.lang", watchSourceAsMap), equalTo("groovy")); + } + + // Fool the script service that this is the groovy script language, so that we can just load the watch upon startup + // and verify that the lang options on scripts have been set. + public static class FoolMeScriptLang extends MockScriptPlugin{ + + @Override + protected Map, Object>> pluginScripts() { + return Collections.singletonMap("ctx.payload.hits.total > 0", (vars) -> true); + } + + @Override + public String pluginScriptLang() { + return "groovy"; + } } } diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/chain/ChainTransformTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/chain/ChainTransformTests.java index 382fd4a6f15..560a8585bc8 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/chain/ChainTransformTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/chain/ChainTransformTests.java @@ -126,7 +126,7 @@ public class ChainTransformTests extends ESTestCase { XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); parser.nextToken(); - ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser); + ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser, false); assertThat(executable, notNullValue()); assertThat(executable.transform().getTransforms(), notNullValue()); assertThat(executable.transform().getTransforms(), hasSize(4)); @@ -204,7 +204,7 @@ public class ChainTransformTests extends ESTestCase { } @Override - public Transform parseTransform(String watchId, XContentParser parser) throws IOException { + public Transform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException { if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { return new Transform(parser.text()); } @@ -273,7 +273,7 @@ public class ChainTransformTests extends ESTestCase { } @Override - public Transform parseTransform(String watchId, XContentParser parser) throws IOException { + public Transform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException { assert parser.currentToken() == XContentParser.Token.START_OBJECT; XContentParser.Token token = parser.nextToken(); assert token == XContentParser.Token.END_OBJECT; diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java index f9203f4bf27..6433d0f5278 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/transform/script/ScriptTransformTests.java @@ -152,7 +152,7 @@ public class ScriptTransformTests extends ESTestCase { XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); parser.nextToken(); - ExecutableScriptTransform transform = new ScriptTransformFactory(Settings.EMPTY, service).parseExecutable("_id", parser); + ExecutableScriptTransform transform = new ScriptTransformFactory(Settings.EMPTY, service).parseExecutable("_id", parser, false); Script script = new Script("_script", type, "_lang", singletonMap("key", "value")); assertThat(transform.transform().getScript(), equalTo(script)); } @@ -163,7 +163,7 @@ public class ScriptTransformTests extends ESTestCase { XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); parser.nextToken(); - ExecutableScriptTransform transform = new ScriptTransformFactory(Settings.EMPTY, service).parseExecutable("_id", parser); + ExecutableScriptTransform transform = new ScriptTransformFactory(Settings.EMPTY, service).parseExecutable("_id", parser, false); assertThat(transform.transform().getScript(), equalTo(new Script("_script"))); } @@ -189,7 +189,7 @@ public class ScriptTransformTests extends ESTestCase { XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); parser.nextToken(); - ScriptTransform scriptTransform = transformFactory.parseTransform("_watch", parser); + ScriptTransform scriptTransform = transformFactory.parseTransform("_watch", parser, false); try { transformFactory.createExecutable(scriptTransform); fail("expected a transform validation exception trying to create an executable with a bad or missing script"); @@ -212,7 +212,7 @@ public class ScriptTransformTests extends ESTestCase { XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); parser.nextToken(); - ScriptTransform scriptCondition = transformFactory.parseTransform("_watch", parser); + ScriptTransform scriptCondition = transformFactory.parseTransform("_watch", parser, false); try { transformFactory.createExecutable(scriptCondition); fail("expected a transform validation exception trying to create an executable with an invalid language"); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchStoreTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchStoreTests.java index 44221316b23..06ab49cd227 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchStoreTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchStoreTests.java @@ -67,8 +67,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; -/** - */ public class WatchStoreTests extends ESTestCase { private WatchStore watchStore; private WatcherClientProxy clientProxy; @@ -221,10 +219,10 @@ public class WatchStoreTests extends ESTestCase { when(watch3.status()).thenReturn(status); Watch watch4 = mock(Watch.class); when(watch4.status()).thenReturn(status); - when(parser.parse("_id1", true, source)).thenReturn(watch1); - when(parser.parse("_id2", true, source)).thenReturn(watch2); - when(parser.parse("_id3", true, source)).thenReturn(watch3); - when(parser.parse("_id4", true, source)).thenReturn(watch4); + when(parser.parse("_id1", true, source, true)).thenReturn(watch1); + when(parser.parse("_id2", true, source, true)).thenReturn(watch2); + when(parser.parse("_id3", true, source, true)).thenReturn(watch3); + when(parser.parse("_id4", true, source, true)).thenReturn(watch4); when(clientProxy.clearScroll(anyString())).thenReturn(new ClearScrollResponse(true, 0)); @@ -303,7 +301,7 @@ public class WatchStoreTests extends ESTestCase { }; when(watch.transform()).thenReturn(randomFrom(testTransform, null)); - when(parser.parse("_id" + i, true, source)).thenReturn(watch); + when(parser.parse("_id" + i, true, source, true)).thenReturn(watch); } SearchResponse searchResponse = mockSearchResponse(1, 1, hitCount, hits.toArray(new InternalSearchHit[] {})); @@ -365,7 +363,7 @@ public class WatchStoreTests extends ESTestCase { Watch watch = mock(Watch.class); WatchStatus status = mock(WatchStatus.class); when(watch.status()).thenReturn(status); - when(parser.parse("_id1", true, source)).thenReturn(watch); + when(parser.parse("_id1", true, source, true)).thenReturn(watch); when(clientProxy.clearScroll(anyString())).thenReturn(new ClearScrollResponse(true, 0)); diff --git a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java index b778264365a..11106d22a04 100644 --- a/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java +++ b/elasticsearch/x-pack/watcher/src/test/java/org/elasticsearch/xpack/watcher/watch/WatchTests.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.watcher.watch; import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; @@ -15,10 +16,12 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryParser; +import org.elasticsearch.index.query.ScriptQueryBuilder; import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.script.Script; import org.elasticsearch.script.ScriptService; +import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.search.SearchRequestParsers; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.common.http.HttpClient; @@ -81,6 +84,7 @@ import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInputFactory; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; +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.ExecutableTransform; @@ -181,7 +185,7 @@ public class WatchTests extends ESTestCase { TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); ExecutableInput input = randomInput(); - InputRegistry inputRegistry = registry(input); + InputRegistry inputRegistry = registry(input.type()); ExecutableCondition condition = randomCondition(); ConditionRegistry conditionRegistry = conditionRegistry(); @@ -230,7 +234,7 @@ public class WatchTests extends ESTestCase { TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); ConditionRegistry conditionRegistry = conditionRegistry(); ExecutableInput input = randomInput(); - InputRegistry inputRegistry = registry(input); + InputRegistry inputRegistry = registry(input.type()); TransformRegistry transformRegistry = transformRegistry(); @@ -259,7 +263,7 @@ public class WatchTests extends ESTestCase { TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); ConditionRegistry conditionRegistry = conditionRegistry(); - InputRegistry inputRegistry = registry(new ExecutableNoneInput(logger)); + InputRegistry inputRegistry = registry(new ExecutableNoneInput(logger).type()); TransformRegistry transformRegistry = transformRegistry(); ExecutableActions actions = new ExecutableActions(Collections.emptyList()); ActionRegistry actionRegistry = registry(actions, conditionRegistry, transformRegistry); @@ -282,6 +286,84 @@ public class WatchTests extends ESTestCase { assertThat(watch.actions().count(), is(0)); } + public void testParseWatch_verifyScriptLangDefault() throws Exception { + ScheduleRegistry scheduleRegistry = registry(new IntervalSchedule(new IntervalSchedule.Interval(1, + IntervalSchedule.Interval.Unit.SECONDS))); + TriggerEngine triggerEngine = new ParseOnlyScheduleTriggerEngine(Settings.EMPTY, scheduleRegistry, SystemClock.INSTANCE); + TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); + + ConditionRegistry conditionRegistry = conditionRegistry(); + InputRegistry inputRegistry = registry(SearchInput.TYPE); + TransformRegistry transformRegistry = transformRegistry(); + ExecutableActions actions = new ExecutableActions(Collections.emptyList()); + ActionRegistry actionRegistry = registry(actions, conditionRegistry, transformRegistry); + Watch.Parser watchParser = new Watch.Parser(settings, conditionRegistry, triggerService, transformRegistry, actionRegistry, + inputRegistry, null, SystemClock.INSTANCE); + + IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); + QueryParser queryParser1 = MatchAllQueryBuilder::fromXContent; + queryRegistry.register(queryParser1, MatchAllQueryBuilder.NAME); + QueryParser queryParser2 = ScriptQueryBuilder::fromXContent; + queryRegistry.register(queryParser2, ScriptQueryBuilder.NAME); + SearchRequestParsers searchParsers = new SearchRequestParsers(queryRegistry, null, null); + WatcherSearchTemplateService searchTemplateService = new WatcherSearchTemplateService(settings, scriptService, searchParsers); + + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject(); + + builder.startObject("trigger"); + builder.startObject("schedule"); + builder.field("interval", "99w"); + builder.endObject(); + builder.endObject(); + + builder.startObject("input"); + builder.startObject("search"); + builder.startObject("request"); + builder.startObject("body"); + builder.startObject("query"); + builder.startObject("script"); + if (randomBoolean()) { + builder.field("script", "return true"); + } else { + builder.startObject("script"); + builder.field("inline", "return true"); + builder.endObject(); + } + builder.endObject(); + builder.endObject(); + builder.endObject(); + builder.endObject(); + builder.endObject(); + builder.endObject(); + + builder.startObject("condition"); + if (randomBoolean()) { + builder.field("script", "return true"); + } else { + builder.startObject("script"); + builder.field("inline", "return true"); + builder.endObject(); + } + builder.endObject(); + + builder.endObject(); + + // parse in default mode: + Watch watch = watchParser.parse("_id", false, builder.bytes()); + assertThat(((ScriptCondition) watch.condition().condition()).getScript().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); + WatcherSearchTemplateRequest request = ((SearchInput) watch.input().input()).getRequest(); + SearchRequest searchRequest = searchTemplateService.toSearchRequest(request); + assertThat(((ScriptQueryBuilder) searchRequest.source().query()).script().getLang(), equalTo(Script.DEFAULT_SCRIPT_LANG)); + + // parse in legacy mode: + watch = watchParser.parse("_id", false, builder.bytes(), true); + assertThat(((ScriptCondition) watch.condition().condition()).getScript().getLang(), equalTo("groovy")); + request = ((SearchInput) watch.input().input()).getRequest(); + searchRequest = searchTemplateService.toSearchRequest(request); + assertThat(((ScriptQueryBuilder) searchRequest.source().query()).script().getLang(), equalTo("groovy")); + } + private static Schedule randomSchedule() { String type = randomFrom(CronSchedule.TYPE, HourlySchedule.TYPE, DailySchedule.TYPE, WeeklySchedule.TYPE, MonthlySchedule.TYPE, YearlySchedule.TYPE, IntervalSchedule.TYPE); @@ -346,13 +428,15 @@ public class WatchTests extends ESTestCase { } } - private InputRegistry registry(ExecutableInput input) { + private InputRegistry registry(String inputType) { Map parsers = new HashMap<>(); - switch (input.type()) { + switch (inputType) { case SearchInput.TYPE: IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); - QueryParser queryParser = MatchAllQueryBuilder::fromXContent; - queryRegistry.register(queryParser, MatchAllQueryBuilder.NAME); + QueryParser queryParser1 = MatchAllQueryBuilder::fromXContent; + queryRegistry.register(queryParser1, MatchAllQueryBuilder.NAME); + QueryParser queryParser2 = ScriptQueryBuilder::fromXContent; + queryRegistry.register(queryParser2, ScriptQueryBuilder.NAME); SearchRequestParsers searchParsers = new SearchRequestParsers(queryRegistry, null, null); parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, searchParsers, scriptService)); return new InputRegistry(Settings.EMPTY, parsers); diff --git a/elasticsearch/x-pack/watcher/src/test/resources/bwc_indices/bwc_index_2_3_5.zip b/elasticsearch/x-pack/watcher/src/test/resources/bwc_indices/bwc_index_2_3_5.zip index 1e0bf8f00d2790930039e52e4f36f0c1fafbc670..5d074c0ab5da1b342131863fd693eb9637a21e78 100644 GIT binary patch delta 4665 zcmai1cUV)|(+(wt-a-pSYUrVaKqyj#D7^_H9TX4{q<1v*F2zfiCcOxVpwdKe!3Cvv z7Xm1tAc{(H1r>h@sJrg>$Cu}s`{X%i=H7Sa%$awl{^Z+}8B!D@e#3w)jEg)}IMa|9 zn(jSpdAx$4=prtq3qye)OU+aW7UGhwmP>Q5Gz0|lW(0u{Aa1~pogI%w`3G2-Q-LT* z$|MO4p#hOm?va5&lyDFT)Np>@j7yQj2<124ts#vzoZy7TFgVI=8LmY37J4QQ`?>|K zW_zZ%RpKV1b7h>EW1?b(0wy*nb~Tl+#xL$F! zvQoHpPJLxjU6EvkLf!p2mFxkTq#NReG=shk@!06Ucr(K6GSfH`5|=u!hJ<{c)xGrE z?`_L<5pvxmcf+C{cv<{Tj`eAryQ_ua6j{Pc&Fwi*6+WqLGFkx)nW?Uegspb3)jZ9t zxtu3{Hkd4*+X(SE(75Ye@c_ffP5pzy{X!EVI|YnJ;^Zl~IV?JO0S%xlPhD_12=&p? z>P*zD7V~0RJMY4^;di(-QRMPkTlCp2T*lcq6S+mRC+(QIk`-%Za9f)ruVkKoN&8wV z%3o~Qnu9N?Ht>ifzwlmg-RtulIVHs{Pd|eH5?Mo9oby7EpO;%TO*7-S!&D&H^@Pyt z!hMkNtlih;E)VaQI+jkpD01$5S18r7cn!%2NqLsJSh5-mSpgI5C1gh6@Q0B{mTorM zSNb6`7%8PYtSNMKi|QO1+$N?j3oy|bD1}C@csjoC+*|bG@;S+|4;u@)b#Ogab>)6j zI*hgEhmJ86!4!qX2Mx2pe3r6#XsBu}I9gSz4i6e=JvZl)!FpM$#>1M>#$My}`6nJu z66!&B>(^`UJp~lraGZ|&Y$_V1XF7jQS+|@z$~rREC|j$3`tWN<^z;JQcGm{KDmY`T zG>zwso71W->0onNO^S*IVT3xk7FL3=k1e7RIuBH9Z~1+0I1|qX^=bfO#l${@@$rQB zJ12<-N$7N3b4Z)_r62SL%Q7%IKy+URM(cp&B{ z><>OUIl#Jpr$+15bWLltQE8AVYcQp>jKzZ!+Hb7KRi$gXHV5&%c267_D(h(ZzCNa& zLqAm2g!DL_vC(voOEeZl-+G$QWL3$X-#6ndWIfvCxDn>;VO|!hHV|H8cIoXP>&F$m z>FcK3`4Kwt+eUffIZhSZ4m=NZJg+*unVZ_=Ti`cm+ZZa#WDP-?^SWP^x?6Pl%QX*N z)u3im?x!BJY+zuosh|)C?Q*ArQ@v~PxlBJa*%eKh*~q<-dPgVoPmj3zAcvBW8UL4e z{+^^m@{#ZQoD*^_(-zrYVtb(dDXeYR3Qy<@!%y2sTbG??!2Df_xEyJ(Xud2BRc-bO zG&U<5H;-B#yYUIrtF*&%`($%`wjD!i`N;UD?LFn*8tGX=i-Kkg*7tFEr%l!xQ{k*v zVe1x{FkEO^$8vF<>RR;MniXk&4+p6>X}QHU?HHfki%c74EseY^nFPZR>m$&_E_~ti zyZ3$Jmiwc1yfud=kG4YSWJ5#(UwzI$ud%-k!o#n1Q&PC8?lV=g-5u@Bi_vZ$&zEy_gY0Z~Fe@1obr~>8ZN#lrah|U z3K6=cFQ(>T+>j(%?s%9{j{#D)7=e$e6szRU2tE&^abJvGCp>{5DN{U-oo|k*HoXMcs|gAQMxjW91m0LZa-g5v-XZP1$q4&PgkLp0e6THkJL-};?5VAy|? z7ZZuR`s3{VoQdzcN)$;Tii#I_&jAJOIUxq}{||+=JSr9(v9`T&{>IZt>bAOeI6UjA zSxPc`XD17O8%|3XpdkRp<+mr{viULr6qPJ|r)gNUn*sC>ey4C@z@JJHTIqL;pGc@o zHsQj$)iT>M1w=gjM79(mViIC@K%*|Yx*QQ|F;ST)Kso~}AVQ76AAFx{pS*v^L&mPI zkkh_Tp(rW_CoNSOO-8<38UVwqPSFA(6c4lR!fQfUvgo6qaYe4~0JmORmIm-9N9eku zwDZQP^uj?>!!guyftv1W8TxvB+&P>ky~1utR*k;rUZo0#n*L%_CZA|b_PwC;$VZWP zIj0u&Z<8N+!cJmy7>ER0L=azaff5ADf&B*C|2NolG@N*Qk^490uUuf!+gUNvz7ey6 z#e;1!wB1>!Zs?(|*Jx*5L3Xa}-PmjFRJqyb#|~zMqC^cDU_#W26~!4f85tQGr`|+S z=-6gp`AmhDd-%y~p&DW>X^Me1A{%j;Z;L|T4=XNpg{q%bUoUD_I#UHH(kW3$5uTLI zLdP;KUkt%l@9P|%^D+6{{dG~ee#0*BqWdWkNsamQ{w(~JD2 z*}(P*Pw*o|*P+VPlaT@MvINd1r?e8;wcMmFlW=uvrX@4ICMG1i>dmk|yjo}Iq?YPd z%TT_;B<*y!vwNyF_jkUj)+{z=kvKKkxhZbyGij~(R$i|Z-plV3`%Bg%wm+X0>F5X# z+cch!KnKjKG+aHcxRxE7G7;**`VL(%)OHTLoL47dERVG6$Hu;bP+uw#o)3`BhX|iT znVR~^3kx-vJ)1Gm(vFBl&4xg%V=TP+g>2({Ou9POCk-via$Kyn|Plx#3PxWAaL-mrUUw^xqu^)N5OY*!IvN~6_Oymub{6=|o= zN0!vB^LE6vK6x!XWTrJawsL#gctE}JPsRC^NAW=`UwWS#sWml}fAfuqc_T=rdLknJ z@kKe+x2q2?QTyQEMX7H+q+cTltew2)oFQ zLIx<>r`}y9bbDm;D%KSBPd7SH3fTvm;8|zOn zXYpc>C`Bn4<2PI;r?g~>W&=L)ud<1^>5TLutNRJ=EcZa|9`Os2wqTpS^++1l+l-$u z+Iy~dd@BW7_NJN`^}mrXi7`(mPX+oi*HbWlTYocsOE%8ovEiq3Q+eK@`mQqhY)*_`Z|1twe~(}A_5V^`$gW?#30nkkue9#c6LGY zHQyV7&vHpFlP2;{{@4sR`H{NZ3_$HwM}VK2@@^8 zT;lv)&KJR;#K;fQS~i-V!i z_S5CIqqXl>>t7r!20yx4T%9VK5Nr-##_@4$wnqB_;I zF1Yw^Lvi5u>hbi=S#Rxy&F^HS68leGI%_^+#z!oro;hlHq{-;1QNG2oo{SR$g*3nmIk{;H>P;jk zVrMOq00x{e)97imPLfbkzxX1Fok|WG%`A35P zT0Ac6$I&AalrDIn4qrp8@ykS!AdwMp$Vf$Z@hEmA;v&Tk&cu(e`cLf8oPd=TXQ>8H zqE%!blV~5@dnmCgNIAjS-Ot0mu67VF3UWV4hx8z2cXHsuuUKENR{xos<64!tpLHgW z5|URCubpS54QbD@giyw>Rnh#xT1jzTN>6fdX!K&Mqjckte%h!3lP|5l+_O6dd-Ck` zy42FL(-?8OiDBhZ*?sU(`=7Jj17JV{#s#b~VJXtRNMkL6f<(F}nU#N$?$5QG%xcV7 zRDh@VrC+WQ-2*n6aWGOCHeR<|09Y2yBRkSYBnvwuF(&`8IkB4ns#z5N-C>X>W`GQ? z$oSu0qD2S(itHE?n>%sR1`63EDTt#sAj`&mWb}p&O&XnnW&}6gZ!J$CqC2uWd2=fqKvLPvB8 z_Os6czHqA2{pfCp>ZHzwO@l#?jPXf7^HsY;E!(-gK=a`%0E)qOS+gczZqX*IYQ#V z!VdWdC*OY$mG74gDFx<9He5gx5ADyBJ<2))4;MKG{$mTu>>uD1;3D;(qm%@!dFja& P*#Hk-6-YE25f12oBci^% delta 4508 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