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@4d578819eb
This commit is contained in:
Martijn van Groningen 2016-09-02 21:43:05 +02:00
parent 4bf685cd31
commit b74f1e6cb2
49 changed files with 416 additions and 159 deletions

View File

@ -27,6 +27,8 @@ import java.util.Objects;
*/ */
public class TextTemplate implements ToXContent { public class TextTemplate implements ToXContent {
public static final String DEFAULT_TEMPLATE_LANG = "mustache";
private final Script script; private final Script script;
private final String inlineTemplate; private final String inlineTemplate;
@ -37,7 +39,7 @@ public class TextTemplate implements ToXContent {
public TextTemplate(String template, @Nullable XContentType contentType, ScriptType type, public TextTemplate(String template, @Nullable XContentType contentType, ScriptType type,
@Nullable Map<String, Object> params) { @Nullable Map<String, Object> params) {
this.script = new Script(template, type, "mustache", params, contentType); this.script = new Script(template, type, DEFAULT_TEMPLATE_LANG, params, contentType);
this.inlineTemplate = null; this.inlineTemplate = null;
} }
@ -95,7 +97,7 @@ public class TextTemplate implements ToXContent {
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) { if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
return new TextTemplate(parser.text()); return new TextTemplate(parser.text());
} else { } else {
return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, "mustache")); return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, DEFAULT_TEMPLATE_LANG));
} }
} }
} }

View File

@ -45,7 +45,7 @@ public class ActionRegistry {
return parsers.get(type); 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) { if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
throw new ElasticsearchParseException("could not parse actions for watch [{}]. expected an object but found [{}] instead", throw new ElasticsearchParseException("could not parse actions for watch [{}]. expected an object but found [{}] instead",
watchId, parser.currentToken()); watchId, parser.currentToken());
@ -62,7 +62,8 @@ public class ActionRegistry {
throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error); throw new ElasticsearchParseException("could not parse action [{}] for watch [{}]. {}", id, watchId, error);
} }
} else if (token == XContentParser.Token.START_OBJECT && id != null) { } else if (token == XContentParser.Token.START_OBJECT && id != null) {
actions.add(ActionWrapper.parse(watchId, id, parser, this, conditionRegistry, transformRegistry, clock, licenseState)); actions.add(ActionWrapper.parse(watchId, id, parser, this, conditionRegistry, transformRegistry, clock,
licenseState, upgradeActionSource));
} }
} }
return new ExecutableActions(actions); return new ExecutableActions(actions);

View File

@ -201,7 +201,7 @@ public class ActionWrapper implements ToXContent {
static ActionWrapper parse(String watchId, String actionId, XContentParser parser, static ActionWrapper parse(String watchId, String actionId, XContentParser parser,
ActionRegistry actionRegistry, ConditionRegistry conditionRegistry, TransformRegistry transformRegistry, 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; assert parser.currentToken() == XContentParser.Token.START_OBJECT;
@ -217,9 +217,9 @@ public class ActionWrapper implements ToXContent {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else { } else {
if (ParseFieldMatcher.STRICT.match(currentFieldName, Watch.Field.CONDITION)) { if (ParseFieldMatcher.STRICT.match(currentFieldName, Watch.Field.CONDITION)) {
condition = conditionRegistry.parseExecutable(watchId, parser); condition = conditionRegistry.parseExecutable(watchId, parser, upgradeActionSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Transform.Field.TRANSFORM)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Transform.Field.TRANSFORM)) {
transform = transformRegistry.parse(watchId, parser); transform = transformRegistry.parse(watchId, parser, upgradeActionSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD)) {
throttlePeriod = timeValueMillis(parser.longValue()); throttlePeriod = timeValueMillis(parser.longValue());
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD_HUMAN)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Throttler.Field.THROTTLE_PERIOD_HUMAN)) {

View File

@ -28,8 +28,14 @@ public abstract class ConditionFactory<C extends Condition, R extends Condition.
/** /**
* Parses the given xcontent and creates a concrete condition * Parses the given xcontent and creates a concrete condition
*
* @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 abstract C parseCondition(String watchId, XContentParser parser) throws IOException; public abstract C parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException;
/** /**
* Creates an {@link ExecutableCondition executable condition} for the given condition. * Creates an {@link ExecutableCondition executable condition} for the given condition.

View File

@ -40,9 +40,15 @@ public class ConditionRegistry {
* } * }
* } * }
* </code></pre> * </code></pre>
*
* @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 { public ExecutableCondition parseExecutable(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
Condition condition = parseCondition(watchId, parser); Condition condition = parseCondition(watchId, parser, upgradeConditionSource);
return factories.get(condition.type()).createExecutable(condition); return factories.get(condition.type()).createExecutable(condition);
} }
@ -56,7 +62,7 @@ public class ConditionRegistry {
* } * }
* </code></pre> * </code></pre>
*/ */
public Condition parseCondition(String watchId, XContentParser parser) throws IOException { public Condition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
Condition condition = null; Condition condition = null;
ConditionFactory factory = null; ConditionFactory factory = null;
@ -74,7 +80,7 @@ public class ConditionRegistry {
throw new ElasticsearchParseException("could not parse condition for watch [{}]. unknown condition type [{}]", throw new ElasticsearchParseException("could not parse condition for watch [{}]. unknown condition type [{}]",
watchId, type); watchId, type);
} }
condition = factory.parseCondition(watchId, parser); condition = factory.parseCondition(watchId, parser, upgradeConditionSource);
} }
} }
if (condition == null) { if (condition == null) {

View File

@ -32,7 +32,7 @@ public class AlwaysConditionFactory extends ConditionFactory<AlwaysCondition, Al
} }
@Override @Override
public AlwaysCondition parseCondition(String watchId, XContentParser parser) throws IOException { public AlwaysCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
return AlwaysCondition.parse(watchId, parser); return AlwaysCondition.parse(watchId, parser);
} }

View File

@ -33,7 +33,7 @@ public class CompareConditionFactory extends ConditionFactory<CompareCondition,
} }
@Override @Override
public CompareCondition parseCondition(String watchId, XContentParser parser) throws IOException { public CompareCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
return CompareCondition.parse(watchId, parser); return CompareCondition.parse(watchId, parser);
} }

View File

@ -31,7 +31,7 @@ public class ArrayCompareConditionFactory extends ConditionFactory<ArrayCompareC
} }
@Override @Override
public ArrayCompareCondition parseCondition(String watchId, XContentParser parser) throws IOException { public ArrayCompareCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
return ArrayCompareCondition.parse(watchId, parser); return ArrayCompareCondition.parse(watchId, parser);
} }

View File

@ -32,7 +32,7 @@ public class NeverConditionFactory extends ConditionFactory<NeverCondition, Neve
} }
@Override @Override
public NeverCondition parseCondition(String watchId, XContentParser parser) throws IOException { public NeverCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
return NeverCondition.parse(watchId, parser); return NeverCondition.parse(watchId, parser);
} }

View File

@ -53,9 +53,15 @@ public class ScriptCondition implements Condition {
return script.hashCode(); return script.hashCode();
} }
public static ScriptCondition parse(String watchId, XContentParser parser) throws IOException { public static ScriptCondition parse(String watchId, XContentParser parser, boolean upgradeConditionSource,
String defaultLegacyScriptLanguage) throws IOException {
try { try {
Script script = Script.parse(parser, ParseFieldMatcher.STRICT); Script script;
if (upgradeConditionSource) {
script = Script.parse(parser, ParseFieldMatcher.STRICT, defaultLegacyScriptLanguage);
} else {
script = Script.parse(parser, ParseFieldMatcher.STRICT);
}
return new ScriptCondition(script); return new ScriptCondition(script);
} catch (ElasticsearchParseException pe) { } catch (ElasticsearchParseException pe) {
throw new ElasticsearchParseException("could not parse [{}] condition for watch [{}]. failed to parse script", pe, TYPE, throw new ElasticsearchParseException("could not parse [{}] condition for watch [{}]. failed to parse script", pe, TYPE,

View File

@ -10,20 +10,20 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.xpack.watcher.condition.ConditionFactory; import org.elasticsearch.xpack.watcher.condition.ConditionFactory;
import java.io.IOException; import java.io.IOException;
/**
*
*/
public class ScriptConditionFactory extends ConditionFactory<ScriptCondition, ScriptCondition.Result, ExecutableScriptCondition> { public class ScriptConditionFactory extends ConditionFactory<ScriptCondition, ScriptCondition.Result, ExecutableScriptCondition> {
private final Settings settings;
private final ScriptService scriptService; private final ScriptService scriptService;
@Inject @Inject
public ScriptConditionFactory(Settings settings, ScriptService service) { public ScriptConditionFactory(Settings settings, ScriptService service) {
super(Loggers.getLogger(ExecutableScriptCondition.class, settings)); super(Loggers.getLogger(ExecutableScriptCondition.class, settings));
this.settings = settings;
scriptService = service; scriptService = service;
} }
@ -33,8 +33,9 @@ public class ScriptConditionFactory extends ConditionFactory<ScriptCondition, Sc
} }
@Override @Override
public ScriptCondition parseCondition(String watchId, XContentParser parser) throws IOException { public ScriptCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
return ScriptCondition.parse(watchId, parser); String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return ScriptCondition.parse(watchId, parser, upgradeConditionSource, defaultLegacyScriptLanguage);
} }
@Override @Override

View File

@ -28,16 +28,22 @@ public abstract class InputFactory<I extends Input, R extends Input.Result, E ex
/** /**
* Parses the given xcontent and creates a concrete input * Parses the given xcontent and creates a concrete input
*
* @param watchId The id of the watch
* @param parser The parser containing the input content of the watch
* @param upgradeInputSource Whether to upgrade the source related to the inpit if that source is in legacy format
* Note: depending on the version, only input implementations that have a known legacy
* format will support this option, otherwise this is a noop.
*/ */
public abstract I parseInput(String watchId, XContentParser parser) throws IOException; public abstract I parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException;
/** /**
* Creates an executable input out of the given input. * Creates an executable input out of the given input.
*/ */
public abstract E createExecutable(I input); public abstract E createExecutable(I input);
public E parseExecutable(String watchId, XContentParser parser) throws IOException { public E parseExecutable(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
I input = parseInput(watchId, parser); I input = parseInput(watchId, parser, upgradeInputSource);
return createExecutable(input); return createExecutable(input);
} }
} }

View File

@ -35,6 +35,17 @@ public class InputRegistry {
* @return A new input instance from the parser * @return A new input instance from the parser
*/ */
public ExecutableInput parse(String watchId, XContentParser parser) throws IOException { public ExecutableInput parse(String watchId, XContentParser parser) throws IOException {
return parse(watchId, parser, false);
}
/**
* Reads the contents of parser to create the correct Input
*
* @param parser The parser containing the input definition
* @param upgradeInputSource Whether to upgrade the source related to input if in legacy format.
* @return A new input instance from the parser
*/
public ExecutableInput parse(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
String type = null; String type = null;
if (parser.currentToken() != XContentParser.Token.START_OBJECT) { if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
@ -55,7 +66,7 @@ public class InputRegistry {
if (factory == null) { if (factory == null) {
throw new ElasticsearchParseException("could not parse input for watch [{}]. unknown input type [{}]", watchId, type); throw new ElasticsearchParseException("could not parse input for watch [{}]. unknown input type [{}]", watchId, type);
} }
input = factory.parseExecutable(watchId, parser); input = factory.parseExecutable(watchId, parser, upgradeInputSource);
} else { } else {
throw new ElasticsearchParseException("could not parse input for watch [{}]. expected an object representing input [{}], " + throw new ElasticsearchParseException("could not parse input for watch [{}]. expected an object representing input [{}], " +
"but found [{}] instead", watchId, type, token); "but found [{}] instead", watchId, type, token);

View File

@ -7,7 +7,6 @@ package org.elasticsearch.xpack.watcher.input.chain;
import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -36,7 +35,7 @@ public class ChainInputFactory extends InputFactory<ChainInput, ChainInput.Resul
} }
@Override @Override
public ChainInput parseInput(String watchId, XContentParser parser) throws IOException { public ChainInput parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
return ChainInput.parse(watchId, parser, inputRegistry); return ChainInput.parse(watchId, parser, inputRegistry);
} }

View File

@ -40,7 +40,7 @@ public final class HttpInputFactory extends InputFactory<HttpInput, HttpInput.Re
} }
@Override @Override
public HttpInput parseInput(String watchId, XContentParser parser) throws IOException { public HttpInput parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
return HttpInput.parse(watchId, parser, requestTemplateParser); return HttpInput.parse(watchId, parser, requestTemplateParser);
} }

View File

@ -29,7 +29,7 @@ public class NoneInputFactory extends InputFactory<NoneInput, NoneInput.Result,
} }
@Override @Override
public NoneInput parseInput(String watchId, XContentParser parser) throws IOException { public NoneInput parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
return NoneInput.parse(watchId, parser); return NoneInput.parse(watchId, parser);
} }

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.xpack.watcher.input.search; package org.elasticsearch.xpack.watcher.input.search;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
@ -12,9 +13,7 @@ import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.xpack.watcher.input.Input; import org.elasticsearch.xpack.watcher.input.Input;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils; import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
@ -109,9 +108,11 @@ public class SearchInput implements Input {
return builder; return builder;
} }
public static SearchInput parse(String watchId, XContentParser parser, QueryParseContext context, public static SearchInput parse(Logger inputLogger, String watchId, XContentParser parser,
AggregatorParsers aggParsers, Suggesters suggesters) boolean upgradeInputSource,
throws IOException { String defaultLegacyScriptLanguage,
ParseFieldMatcher parseFieldMatcher,
SearchRequestParsers searchRequestParsers) throws IOException {
WatcherSearchTemplateRequest request = null; WatcherSearchTemplateRequest request = null;
Set<String> extract = null; Set<String> extract = null;
TimeValue timeout = null; TimeValue timeout = null;
@ -124,7 +125,8 @@ public class SearchInput implements Input {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
try { 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) { } catch (ElasticsearchParseException srpe) {
throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE, throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE,
watchId, currentFieldName); watchId, currentFieldName);

View File

@ -11,12 +11,9 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser; 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.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.SearchRequestParsers; 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.security.InternalClient;
import org.elasticsearch.xpack.watcher.input.InputFactory; import org.elasticsearch.xpack.watcher.input.InputFactory;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
@ -25,11 +22,9 @@ import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateServi
import java.io.IOException; import java.io.IOException;
/**
*
*/
public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Result, ExecutableSearchInput> { public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Result, ExecutableSearchInput> {
private final Settings settings;
private final WatcherClientProxy client; private final WatcherClientProxy client;
private final TimeValue defaultTimeout; private final TimeValue defaultTimeout;
private final SearchRequestParsers searchRequestParsers; private final SearchRequestParsers searchRequestParsers;
@ -45,6 +40,7 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
public SearchInputFactory(Settings settings, WatcherClientProxy client, public SearchInputFactory(Settings settings, WatcherClientProxy client,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) { SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableSimpleInput.class, settings)); super(Loggers.getLogger(ExecutableSimpleInput.class, settings));
this.settings = settings;
this.parseFieldMatcher = new ParseFieldMatcher(settings); this.parseFieldMatcher = new ParseFieldMatcher(settings);
this.client = client; this.client = client;
this.searchRequestParsers = searchRequestParsers; this.searchRequestParsers = searchRequestParsers;
@ -58,9 +54,10 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
} }
@Override @Override
public SearchInput parseInput(String watchId, XContentParser parser) throws IOException { public SearchInput parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
QueryParseContext context = new QueryParseContext(searchRequestParsers.queryParsers, parser, parseFieldMatcher); String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return SearchInput.parse(watchId, parser, context, searchRequestParsers.aggParsers, searchRequestParsers.suggesters); return SearchInput.parse(inputLogger, watchId, parser, upgradeInputSource, defaultLegacyScriptLanguage,
parseFieldMatcher, searchRequestParsers);
} }
@Override @Override

View File

@ -29,7 +29,7 @@ public class SimpleInputFactory extends InputFactory<SimpleInput, SimpleInput.Re
} }
@Override @Override
public SimpleInput parseInput(String watchId, XContentParser parser) throws IOException { public SimpleInput parseInput(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
return SimpleInput.parse(watchId, parser); return SimpleInput.parse(watchId, parser);
} }

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.xpack.watcher.support.search; package org.elasticsearch.xpack.watcher.support.search;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
@ -15,9 +16,14 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xpack.common.text.TextTemplate;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@ -32,8 +38,6 @@ import java.util.Objects;
*/ */
public class WatcherSearchTemplateRequest implements ToXContent { public class WatcherSearchTemplateRequest implements ToXContent {
private static final String DEFAULT_LANG = "mustache";
private final String[] indices; private final String[] indices;
private final String[] types; private final String[] types;
private final SearchType searchType; private final SearchType searchType;
@ -50,12 +54,13 @@ public class WatcherSearchTemplateRequest implements ToXContent {
this.indicesOptions = indicesOptions; this.indicesOptions = indicesOptions;
// Here we convert a watch search request body into an inline search template, // Here we convert a watch search request body into an inline search template,
// this way if any Watcher related context variables are used, they will get resolved. // this way if any Watcher related context variables are used, they will get resolved.
this.template = new Script(searchSource.utf8ToString(), ScriptService.ScriptType.INLINE, DEFAULT_LANG, null); this.template = new Script(searchSource.utf8ToString(), ScriptService.ScriptType.INLINE, TextTemplate.DEFAULT_TEMPLATE_LANG, null);
this.searchSource = null; this.searchSource = null;
} }
public WatcherSearchTemplateRequest(String[] indices, String[] types, SearchType searchType, IndicesOptions indicesOptions, public WatcherSearchTemplateRequest(String[] indices, String[] types, SearchType searchType, IndicesOptions indicesOptions,
Script template) { Script template) {
assert template == null || TextTemplate.DEFAULT_TEMPLATE_LANG.equals(template.getLang());
this.indices = indices; this.indices = indices;
this.types = types; this.types = types;
this.searchType = searchType; this.searchType = searchType;
@ -113,7 +118,7 @@ public class WatcherSearchTemplateRequest implements ToXContent {
if (template != null) { if (template != null) {
return template; return template;
} else { } else {
return new Script(searchSource.utf8ToString(), ScriptService.ScriptType.INLINE, DEFAULT_LANG, null); return new Script(searchSource.utf8ToString(), ScriptService.ScriptType.INLINE, TextTemplate.DEFAULT_TEMPLATE_LANG, null);
} }
} }
@ -159,8 +164,12 @@ public class WatcherSearchTemplateRequest implements ToXContent {
/** /**
* Reads a new watcher search request instance for the specified parser. * Reads a new watcher search request instance for the specified parser.
*/ */
public static WatcherSearchTemplateRequest fromXContent(XContentParser parser, SearchType searchType) public static WatcherSearchTemplateRequest fromXContent(Logger logger, XContentParser parser,
throws IOException { SearchType searchType,
boolean upgradeSearchSource,
String defaultLegacyScriptLanguage,
ParseFieldMatcher parseFieldMatcher,
SearchRequestParsers searchRequestParsers) throws IOException {
List<String> indices = new ArrayList<>(); List<String> indices = new ArrayList<>();
List<String> types = new ArrayList<>(); List<String> types = new ArrayList<>();
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS; IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
@ -200,6 +209,19 @@ public class WatcherSearchTemplateRequest implements ToXContent {
try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) { try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) {
builder.copyCurrentStructure(parser); builder.copyCurrentStructure(parser);
searchSource = builder.bytes(); 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)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_OPTIONS_FIELD)) {
boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen(); boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen();
@ -248,7 +270,7 @@ public class WatcherSearchTemplateRequest implements ToXContent {
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed, indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed,
DEFAULT_INDICES_OPTIONS); DEFAULT_INDICES_OPTIONS);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TEMPLATE_FIELD)) { } 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 { } else {
throw new ElasticsearchParseException("could not read search request. unexpected object field [" + throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
currentFieldName + "]"); currentFieldName + "]");

View File

@ -56,7 +56,8 @@ public class WatcherSearchTemplateService extends AbstractComponent {
if (source.getParams() != null) { if (source.getParams() != null) {
watcherContextParams.putAll(source.getParams()); 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()); source.getContentType());
CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT, Collections.emptyMap()); CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
return (BytesReference) scriptService.executable(compiledScript, template.getParams()).run(); return (BytesReference) scriptService.executable(compiledScript, template.getParams()).run();

View File

@ -28,16 +28,22 @@ public abstract class TransformFactory<T extends Transform, R extends Transform.
/** /**
* Parses the given xcontent and creates a concrete transform * Parses the given xcontent and creates a concrete transform
*
* @param watchId The id of the watch
* @param parser The parsing that contains the condition content
* @param upgradeTransformSource Whether to upgrade the source related to transform if in legacy format
* Note: depending on the version, only transform implementations that have a
* known legacy format will support this option, otherwise this is a noop.
*/ */
public abstract T parseTransform(String watchId, XContentParser parser) throws IOException; public abstract T parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException;
/** /**
* Creates an executable transform out of the given transform. * Creates an executable transform out of the given transform.
*/ */
public abstract E createExecutable(T transform); public abstract E createExecutable(T transform);
public E parseExecutable(String watchId, XContentParser parser) throws IOException { public E parseExecutable(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
T transform = parseTransform(watchId, parser); T transform = parseTransform(watchId, parser, upgradeTransformSource);
return createExecutable(transform); return createExecutable(transform);
} }
} }

View File

@ -35,7 +35,7 @@ public class TransformRegistry {
return factories.get(type); return factories.get(type);
} }
public ExecutableTransform parse(String watchId, XContentParser parser) throws IOException { public ExecutableTransform parse(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
String type = null; String type = null;
XContentParser.Token token; XContentParser.Token token;
ExecutableTransform transform = null; ExecutableTransform transform = null;
@ -43,25 +43,26 @@ public class TransformRegistry {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
type = parser.currentName(); type = parser.currentName();
} else if (type != null) { } else if (type != null) {
transform = parse(watchId, type, parser); transform = parse(watchId, type, parser, upgradeTransformSource);
} }
} }
return transform; return transform;
} }
public ExecutableTransform parse(String watchId, String type, XContentParser parser) throws IOException { public ExecutableTransform parse(String watchId, String type, XContentParser parser,
boolean upgradeTransformSource) throws IOException {
TransformFactory factory = factories.get(type); TransformFactory factory = factories.get(type);
if (factory == null) { if (factory == null) {
throw new ElasticsearchParseException("could not parse transform for watch [{}], unknown transform type [{}]", watchId, type); throw new ElasticsearchParseException("could not parse transform for watch [{}], unknown transform type [{}]", watchId, type);
} }
return factory.parseExecutable(watchId, parser); return factory.parseExecutable(watchId, parser, upgradeTransformSource);
} }
public Transform parseTransform(String watchId, String type, XContentParser parser) throws IOException { public Transform parseTransform(String watchId, String type, XContentParser parser, boolean upgradeSource) throws IOException {
TransformFactory factory = factories.get(type); TransformFactory factory = factories.get(type);
if (factory == null) { if (factory == null) {
throw new ElasticsearchParseException("could not parse transform for watch [{}], unknown transform type [{}]", watchId, type); throw new ElasticsearchParseException("could not parse transform for watch [{}], unknown transform type [{}]", watchId, type);
} }
return factory.parseTransform(watchId, parser); return factory.parseTransform(watchId, parser, upgradeSource);
} }
} }

View File

@ -71,7 +71,8 @@ public class ChainTransform implements Transform {
return builder.endArray(); return builder.endArray();
} }
public static ChainTransform parse(String watchId, XContentParser parser, TransformRegistry transformRegistry) throws IOException { public static ChainTransform parse(String watchId, XContentParser parser, TransformRegistry transformRegistry,
boolean upgradeSource) throws IOException {
XContentParser.Token token = parser.currentToken(); XContentParser.Token token = parser.currentToken();
if (token != XContentParser.Token.START_ARRAY) { if (token != XContentParser.Token.START_ARRAY) {
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. expected an array of transform objects," + throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. expected an array of transform objects," +
@ -90,7 +91,7 @@ public class ChainTransform implements Transform {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else { } else {
transforms.add(transformRegistry.parseTransform(watchId, currentFieldName, parser)); transforms.add(transformRegistry.parseTransform(watchId, currentFieldName, parser, upgradeSource));
} }
} }
} }

View File

@ -31,8 +31,8 @@ public final class ChainTransformFactory extends TransformFactory<ChainTransform
} }
@Override @Override
public ChainTransform parseTransform(String watchId, XContentParser parser) throws IOException { public ChainTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
return ChainTransform.parse(watchId, parser, registry); return ChainTransform.parse(watchId, parser, registry, upgradeTransformSource);
} }
@Override @Override

View File

@ -54,9 +54,15 @@ public class ScriptTransform implements Transform {
return script.toXContent(builder, params); return script.toXContent(builder, params);
} }
public static ScriptTransform parse(String watchId, XContentParser parser) throws IOException { public static ScriptTransform parse(String watchId, XContentParser parser, boolean upgradeSource,
String defaultLegacyScriptLanguage) throws IOException {
try { try {
Script script = Script.parse(parser, ParseFieldMatcher.STRICT); Script script;
if (upgradeSource) {
script = Script.parse(parser, ParseFieldMatcher.STRICT, defaultLegacyScriptLanguage);
} else {
script = Script.parse(parser, ParseFieldMatcher.STRICT);
}
return new ScriptTransform(script); return new ScriptTransform(script);
} catch (ElasticsearchParseException pe) { } catch (ElasticsearchParseException pe) {
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse script", pe, TYPE, throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse script", pe, TYPE,

View File

@ -10,20 +10,20 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.xpack.watcher.transform.TransformFactory; import org.elasticsearch.xpack.watcher.transform.TransformFactory;
import java.io.IOException; import java.io.IOException;
/**
*
*/
public class ScriptTransformFactory extends TransformFactory<ScriptTransform, ScriptTransform.Result, ExecutableScriptTransform> { public class ScriptTransformFactory extends TransformFactory<ScriptTransform, ScriptTransform.Result, ExecutableScriptTransform> {
private final Settings settings;
private final ScriptService scriptService; private final ScriptService scriptService;
@Inject @Inject
public ScriptTransformFactory(Settings settings, ScriptService scriptService) { public ScriptTransformFactory(Settings settings, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableScriptTransform.class, settings)); super(Loggers.getLogger(ExecutableScriptTransform.class, settings));
this.settings = settings;
this.scriptService = scriptService; this.scriptService = scriptService;
} }
@ -33,8 +33,9 @@ public class ScriptTransformFactory extends TransformFactory<ScriptTransform, Sc
} }
@Override @Override
public ScriptTransform parseTransform(String watchId, XContentParser parser) throws IOException { public ScriptTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
return ScriptTransform.parse(watchId, parser); String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return ScriptTransform.parse(watchId, parser, upgradeTransformSource, defaultLegacyScriptLanguage);
} }
@Override @Override

View File

@ -5,6 +5,7 @@
*/ */
package org.elasticsearch.xpack.watcher.transform.search; package org.elasticsearch.xpack.watcher.transform.search;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
@ -12,9 +13,7 @@ import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils; import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.transform.Transform; import org.elasticsearch.xpack.watcher.transform.Transform;
@ -92,9 +91,12 @@ public class SearchTransform implements Transform {
return builder; return builder;
} }
public static SearchTransform parse(String watchId, XContentParser parser, QueryParseContext context, public static SearchTransform parse(Logger transformLogger, String watchId,
AggregatorParsers aggParsers, Suggesters suggesters) XContentParser parser,
throws IOException { boolean upgradeTransformSource,
String defaultLegacyScriptLanguage,
ParseFieldMatcher parseFieldMatcher,
SearchRequestParsers searchRequestParsers) throws IOException {
WatcherSearchTemplateRequest request = null; WatcherSearchTemplateRequest request = null;
TimeValue timeout = null; TimeValue timeout = null;
DateTimeZone dynamicNameTimeZone = null; DateTimeZone dynamicNameTimeZone = null;
@ -106,7 +108,10 @@ public class SearchTransform implements Transform {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
try { try {
request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE); request = WatcherSearchTemplateRequest.fromXContent(
transformLogger, parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE, upgradeTransformSource,
defaultLegacyScriptLanguage, parseFieldMatcher, searchRequestParsers
);
} catch (ElasticsearchParseException srpe) { } catch (ElasticsearchParseException srpe) {
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe, throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe,
TYPE, watchId, currentFieldName); TYPE, watchId, currentFieldName);

View File

@ -13,19 +13,17 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.SearchRequestParsers; import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.transform.TransformFactory; import org.elasticsearch.xpack.watcher.transform.TransformFactory;
/**
*
*/
public class SearchTransformFactory extends TransformFactory<SearchTransform, SearchTransform.Result, ExecutableSearchTransform> { public class SearchTransformFactory extends TransformFactory<SearchTransform, SearchTransform.Result, ExecutableSearchTransform> {
private final Settings settings;
protected final WatcherClientProxy client; protected final WatcherClientProxy client;
private final TimeValue defaultTimeout; private final TimeValue defaultTimeout;
private final SearchRequestParsers searchRequestParsers; private final SearchRequestParsers searchRequestParsers;
@ -40,6 +38,7 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
public SearchTransformFactory(Settings settings, WatcherClientProxy client, public SearchTransformFactory(Settings settings, WatcherClientProxy client,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) { SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableSearchTransform.class, settings)); super(Loggers.getLogger(ExecutableSearchTransform.class, settings));
this.settings = settings;
this.client = client; this.client = client;
this.parseFieldMatcher = new ParseFieldMatcher(settings); this.parseFieldMatcher = new ParseFieldMatcher(settings);
this.searchRequestParsers = searchRequestParsers; this.searchRequestParsers = searchRequestParsers;
@ -53,9 +52,10 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
} }
@Override @Override
public SearchTransform parseTransform(String watchId, XContentParser parser) throws IOException { public SearchTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
QueryParseContext context = new QueryParseContext(searchRequestParsers.queryParsers, parser, parseFieldMatcher); String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return SearchTransform.parse(watchId, parser, context, searchRequestParsers.aggParsers, searchRequestParsers.suggesters); return SearchTransform.parse(transformLogger, watchId, parser, upgradeTransformSource, defaultLegacyScriptLanguage,
parseFieldMatcher, searchRequestParsers);
} }
@Override @Override

View File

@ -236,11 +236,15 @@ public class Watch implements TriggerEngine.Job, ToXContent {
} }
public Watch parse(String name, boolean includeStatus, BytesReference source) throws IOException { public Watch parse(String name, boolean includeStatus, BytesReference source) throws IOException {
return parse(name, includeStatus, false, source, clock.nowUTC()); return parse(name, includeStatus, false, source, clock.nowUTC(), false);
}
public Watch parse(String name, boolean includeStatus, BytesReference source, boolean upgradeSource) throws IOException {
return parse(name, includeStatus, false, source, clock.nowUTC(), upgradeSource);
} }
public Watch parse(String name, boolean includeStatus, BytesReference source, DateTime now) throws IOException { public Watch parse(String name, boolean includeStatus, BytesReference source, DateTime now) throws IOException {
return parse(name, includeStatus, false, source, now); return parse(name, includeStatus, false, source, now, false);
} }
/** /**
@ -256,10 +260,11 @@ public class Watch implements TriggerEngine.Job, ToXContent {
* @see org.elasticsearch.xpack.watcher.WatcherService#putWatch(String, BytesReference, TimeValue, boolean) * @see org.elasticsearch.xpack.watcher.WatcherService#putWatch(String, BytesReference, TimeValue, boolean)
*/ */
public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now) throws IOException { public Watch parseWithSecrets(String id, boolean includeStatus, BytesReference source, DateTime now) throws IOException {
return parse(id, includeStatus, true, source, now); return parse(id, includeStatus, true, source, now, false);
} }
private Watch parse(String id, boolean includeStatus, boolean withSecrets, BytesReference source, DateTime now) throws IOException { private Watch parse(String id, boolean includeStatus, boolean withSecrets, BytesReference source, DateTime now,
boolean upgradeSource) throws IOException {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("parsing watch [{}] ", source.utf8ToString()); logger.trace("parsing watch [{}] ", source.utf8ToString());
} }
@ -267,7 +272,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
try { try {
parser = new WatcherXContentParser(createParser(source), new HaltedClock(now), withSecrets ? cryptoService : null); parser = new WatcherXContentParser(createParser(source), new HaltedClock(now), withSecrets ? cryptoService : null);
parser.nextToken(); parser.nextToken();
return parse(id, includeStatus, parser); return parse(id, includeStatus, parser, upgradeSource);
} catch (IOException ioe) { } catch (IOException ioe) {
throw ioException("could not parse watch [{}]", ioe, id); throw ioException("could not parse watch [{}]", ioe, id);
} finally { } finally {
@ -277,7 +282,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
} }
} }
public Watch parse(String id, boolean includeStatus, XContentParser parser) throws IOException { public Watch parse(String id, boolean includeStatus, XContentParser parser, boolean upgradeWatchSource) throws IOException {
Trigger trigger = null; Trigger trigger = null;
ExecutableInput input = defaultInput; ExecutableInput input = defaultInput;
ExecutableCondition condition = defaultCondition; ExecutableCondition condition = defaultCondition;
@ -299,11 +304,11 @@ public class Watch implements TriggerEngine.Job, ToXContent {
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRIGGER)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRIGGER)) {
trigger = triggerService.parseTrigger(id, parser); trigger = triggerService.parseTrigger(id, parser);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.INPUT)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.INPUT)) {
input = inputRegistry.parse(id, parser); input = inputRegistry.parse(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.CONDITION)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.CONDITION)) {
condition = conditionRegistry.parseExecutable(id, parser); condition = conditionRegistry.parseExecutable(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRANSFORM)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRANSFORM)) {
transform = transformRegistry.parse(id, parser); transform = transformRegistry.parse(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD)) {
throttlePeriod = timeValueMillis(parser.longValue()); throttlePeriod = timeValueMillis(parser.longValue());
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD_HUMAN)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD_HUMAN)) {
@ -315,7 +320,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
pe, id, currentFieldName); pe, id, currentFieldName);
} }
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.ACTIONS)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.ACTIONS)) {
actions = actionRegistry.parseActions(id, parser); actions = actionRegistry.parseActions(id, parser, upgradeWatchSource);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.METADATA)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.METADATA)) {
metatdata = parser.map(); metatdata = parser.map();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.STATUS)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.STATUS)) {

View File

@ -50,8 +50,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static org.elasticsearch.xpack.watcher.support.Exceptions.illegalState; import static org.elasticsearch.xpack.watcher.support.Exceptions.illegalState;
/**
*/
public class WatchStore extends AbstractComponent { public class WatchStore extends AbstractComponent {
public static final String INDEX = ".watches"; public static final String INDEX = ".watches";
@ -310,7 +308,7 @@ public class WatchStore extends AbstractComponent {
for (SearchHit hit : response.getHits()) { for (SearchHit hit : response.getHits()) {
String id = hit.getId(); String id = hit.getId();
try { try {
Watch watch = watchParser.parse(id, true, hit.getSourceRef()); Watch watch = watchParser.parse(id, true, hit.getSourceRef(), true);
watch.status().version(hit.version()); watch.status().version(hit.version());
watch.version(hit.version()); watch.version(hit.version());
watches.put(id, watch); watches.put(id, watch);

View File

@ -32,7 +32,7 @@ public class AlwaysConditionTests extends ESTestCase {
builder.endObject(); builder.endObject();
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
AlwaysCondition condition = factory.parseCondition("_id", parser); AlwaysCondition condition = factory.parseCondition("_id", parser, false);
ExecutableAlwaysCondition executable = factory.createExecutable(condition); ExecutableAlwaysCondition executable = factory.createExecutable(condition);
assertTrue(executable.execute(null).met()); assertTrue(executable.execute(null).met());
} }
@ -46,7 +46,7 @@ public class AlwaysConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
factor.parseCondition("_id", parser); factor.parseCondition("_id", parser, false);
fail("expected a condition exception trying to parse an invalid condition XContent, [" fail("expected a condition exception trying to parse an invalid condition XContent, ["
+ AlwaysCondition.TYPE + "] condition should not parse with a body"); + AlwaysCondition.TYPE + "] condition should not parse with a body");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {

View File

@ -177,7 +177,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
CompareCondition condition = factory.parseCondition("_id", parser); CompareCondition condition = factory.parseCondition("_id", parser, false);
assertThat(condition, notNullValue()); assertThat(condition, notNullValue());
assertThat(condition.getPath(), is("key1.key2")); assertThat(condition.getPath(), is("key1.key2"));
@ -195,7 +195,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
try { try {
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException"); fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("expected an object but found [null] instead")); assertThat(e.getMessage(), containsString("expected an object but found [null] instead"));
@ -215,7 +215,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException"); fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("unknown comparison operator [foobar]")); assertThat(e.getMessage(), containsString("unknown comparison operator [foobar]"));
@ -236,7 +236,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException"); fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("must either be a numeric, string, boolean or null value, but found [")); assertThat(e.getMessage(), containsString("must either be a numeric, string, boolean or null value, but found ["));

View File

@ -185,7 +185,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ArrayCompareCondition condition = factory.parseCondition("_id", parser); ArrayCompareCondition condition = factory.parseCondition("_id", parser, false);
assertThat(condition, notNullValue()); assertThat(condition, notNullValue());
assertThat(condition.getArrayPath(), is("key1.key2")); assertThat(condition.getArrayPath(), is("key1.key2"));
@ -221,7 +221,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate comparison operator"); expectedException.expectMessage("duplicate comparison operator");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
public void testParseContainsUnknownOperator() throws IOException { public void testParseContainsUnknownOperator() throws IOException {
@ -245,7 +245,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("unknown comparison operator"); expectedException.expectMessage("unknown comparison operator");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
public void testParseContainsDuplicateValue() throws IOException { public void testParseContainsDuplicateValue() throws IOException {
@ -271,7 +271,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate field \"value\""); expectedException.expectMessage("duplicate field \"value\"");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
public void testParseContainsDuplicateQuantifier() throws IOException { public void testParseContainsDuplicateQuantifier() throws IOException {
@ -297,7 +297,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate field \"quantifier\""); expectedException.expectMessage("duplicate field \"quantifier\"");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
public void testParseContainsUnknownQuantifier() throws IOException { public void testParseContainsUnknownQuantifier() throws IOException {
@ -321,7 +321,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("unknown comparison quantifier"); expectedException.expectMessage("unknown comparison quantifier");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
public void testParseContainsUnexpectedFieldInComparisonOperator() throws IOException { public void testParseContainsUnexpectedFieldInComparisonOperator() throws IOException {
@ -347,6 +347,6 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class); expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("expected a field indicating the comparison value or comparison quantifier"); expectedException.expectMessage("expected a field indicating the comparison value or comparison quantifier");
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
} }
} }

View File

@ -34,7 +34,7 @@ public class NeverConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
NeverCondition condition = factory.parseCondition("_id", parser); NeverCondition condition = factory.parseCondition("_id", parser, false);
ExecutableNeverCondition executable = factory.createExecutable(condition); ExecutableNeverCondition executable = factory.createExecutable(condition);
assertFalse(executable.execute(null).met()); assertFalse(executable.execute(null).met());
} }
@ -48,7 +48,7 @@ public class NeverConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
fail("expected a condition exception trying to parse an invalid condition XContent, [" fail("expected a condition exception trying to parse an invalid condition XContent, ["
+ AlwaysCondition.TYPE + "] condition should not parse with a body"); + AlwaysCondition.TYPE + "] condition should not parse with a body");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {

View File

@ -28,7 +28,6 @@ import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptSettings; import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.internal.InternalSearchResponse; import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
@ -120,7 +119,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ScriptCondition condition = factory.parseCondition("_watch", parser); ScriptCondition condition = factory.parseCondition("_watch", parser, false);
ExecutableScriptCondition executable = factory.createExecutable(condition); ExecutableScriptCondition executable = factory.createExecutable(condition);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]); SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500L, new ShardSearchFailure[0]);
@ -132,7 +131,7 @@ public class ScriptConditionTests extends ESTestCase {
builder = createConditionContent("return true", null, ScriptType.INLINE); builder = createConditionContent("return true", null, ScriptType.INLINE);
parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
condition = factory.parseCondition("_watch", parser); condition = factory.parseCondition("_watch", parser, false);
executable = factory.createExecutable(condition); executable = factory.createExecutable(condition);
ctx = mockExecutionContext("_name", new Payload.XContent(response)); ctx = mockExecutionContext("_name", new Payload.XContent(response));
@ -147,7 +146,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
factory.parseCondition("_id", parser); factory.parseCondition("_id", parser, false);
fail("expected a condition exception trying to parse an invalid condition XContent"); fail("expected a condition exception trying to parse an invalid condition XContent");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
// TODO add these when the test if fixed // TODO add these when the test if fixed
@ -171,7 +170,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentBuilder builder = createConditionContent(script, "groovy", scriptType); XContentBuilder builder = createConditionContent(script, "groovy", scriptType);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser); ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser, false);
expectThrows(GeneralScriptException.class, expectThrows(GeneralScriptException.class,
() -> conditionParser.createExecutable(scriptCondition)); () -> conditionParser.createExecutable(scriptCondition));
} }
@ -182,7 +181,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", ScriptType.INLINE); XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", ScriptType.INLINE);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser); ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser, false);
GeneralScriptException exception = expectThrows(GeneralScriptException.class, GeneralScriptException exception = expectThrows(GeneralScriptException.class,
() -> conditionParser.createExecutable(scriptCondition)); () -> conditionParser.createExecutable(scriptCondition));
assertThat(exception.getMessage(), containsString("script_lang not supported [not_a_valid_lang]]")); assertThat(exception.getMessage(), containsString("script_lang not supported [not_a_valid_lang]]"));

View File

@ -83,7 +83,7 @@ public class ChainInputTests extends ESTestCase {
// first pass JSON and check for correct inputs // first pass JSON and check for correct inputs
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ChainInput chainInput = chainInputFactory.parseInput("test", parser); ChainInput chainInput = chainInputFactory.parseInput("test", parser, false);
assertThat(chainInput.getInputs(), hasSize(2)); assertThat(chainInput.getInputs(), hasSize(2));
assertThat(chainInput.getInputs().get(0).v1(), is("first")); assertThat(chainInput.getInputs().get(0).v1(), is("first"));

View File

@ -188,7 +188,7 @@ public class HttpInputTests extends ESTestCase {
BytesReference source = jsonBuilder().value(inputBuilder.build()).bytes(); BytesReference source = jsonBuilder().value(inputBuilder.build()).bytes();
XContentParser parser = XContentHelper.createParser(source); XContentParser parser = XContentHelper.createParser(source);
parser.nextToken(); parser.nextToken();
HttpInput result = httpParser.parseInput("_id", parser); HttpInput result = httpParser.parseInput("_id", parser, false);
assertThat(result.type(), equalTo(HttpInput.TYPE)); assertThat(result.type(), equalTo(HttpInput.TYPE));
assertThat(result.getRequest().scheme(), equalTo(scheme != null ? scheme : Scheme.HTTP)); // http is the default 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()); XContentParser parser = XContentHelper.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
httpParser.parseInput("_id", parser); httpParser.parseInput("_id", parser, false);
fail("Expected IllegalArgumentException"); fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
assertThat(e.getMessage(), is("unsupported http method [_METHOD]")); assertThat(e.getMessage(), is("unsupported http method [_METHOD]"));

View File

@ -48,7 +48,7 @@ public class SimpleInputTests extends ESTestCase {
InputFactory parser = new SimpleInputFactory(Settings.builder().build()); InputFactory parser = new SimpleInputFactory(Settings.builder().build());
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
xContentParser.nextToken(); xContentParser.nextToken();
ExecutableInput input = parser.parseExecutable("_id", xContentParser); ExecutableInput input = parser.parseExecutable("_id", xContentParser, false);
assertEquals(input.type(), SimpleInput.TYPE); assertEquals(input.type(), SimpleInput.TYPE);
@ -65,7 +65,7 @@ public class SimpleInputTests extends ESTestCase {
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes()); XContentParser xContentParser = JsonXContent.jsonXContent.createParser(jsonBuilder.bytes());
xContentParser.nextToken(); xContentParser.nextToken();
try { try {
parser.parseInput("_id", xContentParser); parser.parseInput("_id", xContentParser, false);
fail("[simple] input parse should fail with an InputException for an empty json object"); fail("[simple] input parse should fail with an InputException for an empty json object");
} catch (ElasticsearchParseException e) { } catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("expected an object but found [VALUE_STRING] instead")); assertThat(e.getMessage(), containsString("expected an object but found [VALUE_STRING] instead"));

View File

@ -124,7 +124,8 @@ public class WatcherUtilsTests extends ESTestCase {
request.toXContent(builder, ToXContent.EMPTY_PARAMS); request.toXContent(builder, ToXContent.EMPTY_PARAMS);
XContentParser parser = XContentHelper.createParser(builder.bytes()); XContentParser parser = XContentHelper.createParser(builder.bytes());
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); 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.getIndices(), arrayContainingInAnyOrder(expectedIndices != null ? expectedIndices : new String[0]));
assertThat(result.getTypes(), arrayContainingInAnyOrder(expectedTypes != null ? expectedTypes : 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()); XContentParser parser = XContentHelper.createParser(builder.bytes());
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); 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.getIndices(), arrayContainingInAnyOrder(indices));
assertThat(result.getTypes(), arrayContainingInAnyOrder(types)); assertThat(result.getTypes(), arrayContainingInAnyOrder(types));

View File

@ -6,15 +6,23 @@
package org.elasticsearch.xpack.watcher.support.search; package org.elasticsearch.xpack.watcher.support.search;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.bytes.BytesArray; 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.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser; 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 org.elasticsearch.test.ESTestCase;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class WatcherSearchTemplateRequestTests extends ESTestCase { public class WatcherSearchTemplateRequestTests extends ESTestCase {
@ -33,7 +41,8 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase {
try (XContentParser parser = XContentHelper.createParser(new BytesArray(source))) { try (XContentParser parser = XContentHelper.createParser(new BytesArray(source))) {
parser.nextToken(); 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()); assertNotNull(result.getTemplate());
assertThat(result.getTemplate().getScript(), equalTo(expectedScript)); assertThat(result.getTemplate().getScript(), equalTo(expectedScript));
assertThat(result.getTemplate().getLang(), equalTo(expectedLang)); assertThat(result.getTemplate().getLang(), equalTo(expectedLang));
@ -42,4 +51,53 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase {
fail("Failed to parse watch search request: " + e.getMessage()); 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<String, Object> 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"));
}
} }

View File

@ -22,7 +22,6 @@ import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition; import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext; 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()), SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()),
searchParsers, scriptService()); searchParsers, scriptService());
SearchInput searchInput = factory.parseInput("_id", parser); SearchInput searchInput = factory.parseInput("_id", parser, false);
assertEquals(SearchInput.TYPE, searchInput.type()); assertEquals(SearchInput.TYPE, searchInput.type());
assertThat(searchInput.getTimeout(), equalTo(timeout)); assertThat(searchInput.getTimeout(), equalTo(timeout));
} }

View File

@ -217,7 +217,7 @@ public class SearchTransformTests extends ESIntegTestCase {
SearchRequestParsers searchRequestParsers = internalCluster().getInstance(SearchRequestParsers.class); SearchRequestParsers searchRequestParsers = internalCluster().getInstance(SearchRequestParsers.class);
SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()), SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()),
searchRequestParsers, scriptService()); searchRequestParsers, scriptService());
ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser); ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser, false);
assertThat(executable, notNullValue()); assertThat(executable, notNullValue());
assertThat(executable.type(), is(SearchTransform.TYPE)); assertThat(executable.type(), is(SearchTransform.TYPE));

View File

@ -12,6 +12,8 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath; import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
@ -21,7 +23,10 @@ import org.elasticsearch.xpack.watcher.watch.WatchStore;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -44,6 +49,13 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati
return false; return false;
} }
@Override
protected List<Class<? extends Plugin>> pluginTypes() {
List<Class<? extends Plugin>> plugins = super.pluginTypes();
plugins.add(FoolMeScriptLang.class);
return plugins;
}
public void testWatchLoadedSuccessfullyAfterUpgrade() throws Exception { public void testWatchLoadedSuccessfullyAfterUpgrade() throws Exception {
// setup node // setup node
Path dataDir = createTempDir(); Path dataDir = createTempDir();
@ -86,10 +98,32 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati
assertThat(getWatchResponse.isFound(), is(true)); assertThat(getWatchResponse.isFound(), is(true));
Map<String, Object> watchSourceAsMap = getWatchResponse.getSource().getAsMap(); Map<String, Object> watchSourceAsMap = getWatchResponse.getSource().getAsMap();
assertThat(ObjectPath.eval("trigger.schedule.interval", watchSourceAsMap), equalTo("99w")); 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}}")); equalTo("{{ctx.trigger.scheduled_time}}"));
assertThat(ObjectPath.eval("actions.log_error.logging.text", watchSourceAsMap), assertThat(ObjectPath.eval("actions.log_error.logging.text", watchSourceAsMap),
equalTo("Found {{ctx.payload.hits.total}} errors in the logs")); 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<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap("ctx.payload.hits.total > 0", (vars) -> true);
}
@Override
public String pluginScriptLang() {
return "groovy";
}
} }
} }

View File

@ -126,7 +126,7 @@ public class ChainTransformTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser); ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser, false);
assertThat(executable, notNullValue()); assertThat(executable, notNullValue());
assertThat(executable.transform().getTransforms(), notNullValue()); assertThat(executable.transform().getTransforms(), notNullValue());
assertThat(executable.transform().getTransforms(), hasSize(4)); assertThat(executable.transform().getTransforms(), hasSize(4));
@ -204,7 +204,7 @@ public class ChainTransformTests extends ESTestCase {
} }
@Override @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) { if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
return new Transform(parser.text()); return new Transform(parser.text());
} }
@ -273,7 +273,7 @@ public class ChainTransformTests extends ESTestCase {
} }
@Override @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; assert parser.currentToken() == XContentParser.Token.START_OBJECT;
XContentParser.Token token = parser.nextToken(); XContentParser.Token token = parser.nextToken();
assert token == XContentParser.Token.END_OBJECT; assert token == XContentParser.Token.END_OBJECT;

View File

@ -152,7 +152,7 @@ public class ScriptTransformTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); 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")); Script script = new Script("_script", type, "_lang", singletonMap("key", "value"));
assertThat(transform.transform().getScript(), equalTo(script)); assertThat(transform.transform().getScript(), equalTo(script));
} }
@ -163,7 +163,7 @@ public class ScriptTransformTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); 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"))); 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()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ScriptTransform scriptTransform = transformFactory.parseTransform("_watch", parser); ScriptTransform scriptTransform = transformFactory.parseTransform("_watch", parser, false);
try { try {
transformFactory.createExecutable(scriptTransform); transformFactory.createExecutable(scriptTransform);
fail("expected a transform validation exception trying to create an executable with a bad or missing script"); 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()); XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
ScriptTransform scriptCondition = transformFactory.parseTransform("_watch", parser); ScriptTransform scriptCondition = transformFactory.parseTransform("_watch", parser, false);
try { try {
transformFactory.createExecutable(scriptCondition); transformFactory.createExecutable(scriptCondition);
fail("expected a transform validation exception trying to create an executable with an invalid language"); fail("expected a transform validation exception trying to create an executable with an invalid language");

View File

@ -67,8 +67,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
/**
*/
public class WatchStoreTests extends ESTestCase { public class WatchStoreTests extends ESTestCase {
private WatchStore watchStore; private WatchStore watchStore;
private WatcherClientProxy clientProxy; private WatcherClientProxy clientProxy;
@ -221,10 +219,10 @@ public class WatchStoreTests extends ESTestCase {
when(watch3.status()).thenReturn(status); when(watch3.status()).thenReturn(status);
Watch watch4 = mock(Watch.class); Watch watch4 = mock(Watch.class);
when(watch4.status()).thenReturn(status); when(watch4.status()).thenReturn(status);
when(parser.parse("_id1", true, source)).thenReturn(watch1); when(parser.parse("_id1", true, source, true)).thenReturn(watch1);
when(parser.parse("_id2", true, source)).thenReturn(watch2); when(parser.parse("_id2", true, source, true)).thenReturn(watch2);
when(parser.parse("_id3", true, source)).thenReturn(watch3); when(parser.parse("_id3", true, source, true)).thenReturn(watch3);
when(parser.parse("_id4", true, source)).thenReturn(watch4); when(parser.parse("_id4", true, source, true)).thenReturn(watch4);
when(clientProxy.clearScroll(anyString())).thenReturn(new ClearScrollResponse(true, 0)); 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(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[] {})); SearchResponse searchResponse = mockSearchResponse(1, 1, hitCount, hits.toArray(new InternalSearchHit[] {}));
@ -365,7 +363,7 @@ public class WatchStoreTests extends ESTestCase {
Watch watch = mock(Watch.class); Watch watch = mock(Watch.class);
WatchStatus status = mock(WatchStatus.class); WatchStatus status = mock(WatchStatus.class);
when(watch.status()).thenReturn(status); 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)); when(clientProxy.clearScroll(anyString())).thenReturn(new ClearScrollResponse(true, 0));

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.watcher.watch;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings; 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.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryParser; import org.elasticsearch.index.query.QueryParser;
import org.elasticsearch.index.query.ScriptQueryBuilder;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.script.Script; import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.SearchRequestParsers; import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.common.http.HttpClient; 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.SimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInputFactory; import org.elasticsearch.xpack.watcher.input.simple.SimpleInputFactory;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; 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.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
@ -181,7 +185,7 @@ public class WatchTests extends ESTestCase {
TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine));
ExecutableInput input = randomInput(); ExecutableInput input = randomInput();
InputRegistry inputRegistry = registry(input); InputRegistry inputRegistry = registry(input.type());
ExecutableCondition condition = randomCondition(); ExecutableCondition condition = randomCondition();
ConditionRegistry conditionRegistry = conditionRegistry(); ConditionRegistry conditionRegistry = conditionRegistry();
@ -230,7 +234,7 @@ public class WatchTests extends ESTestCase {
TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine));
ConditionRegistry conditionRegistry = conditionRegistry(); ConditionRegistry conditionRegistry = conditionRegistry();
ExecutableInput input = randomInput(); ExecutableInput input = randomInput();
InputRegistry inputRegistry = registry(input); InputRegistry inputRegistry = registry(input.type());
TransformRegistry transformRegistry = transformRegistry(); TransformRegistry transformRegistry = transformRegistry();
@ -259,7 +263,7 @@ public class WatchTests extends ESTestCase {
TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine)); TriggerService triggerService = new TriggerService(Settings.EMPTY, singleton(triggerEngine));
ConditionRegistry conditionRegistry = conditionRegistry(); ConditionRegistry conditionRegistry = conditionRegistry();
InputRegistry inputRegistry = registry(new ExecutableNoneInput(logger)); InputRegistry inputRegistry = registry(new ExecutableNoneInput(logger).type());
TransformRegistry transformRegistry = transformRegistry(); TransformRegistry transformRegistry = transformRegistry();
ExecutableActions actions = new ExecutableActions(Collections.emptyList()); ExecutableActions actions = new ExecutableActions(Collections.emptyList());
ActionRegistry actionRegistry = registry(actions, conditionRegistry, transformRegistry); ActionRegistry actionRegistry = registry(actions, conditionRegistry, transformRegistry);
@ -282,6 +286,84 @@ public class WatchTests extends ESTestCase {
assertThat(watch.actions().count(), is(0)); 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<MatchAllQueryBuilder> queryParser1 = MatchAllQueryBuilder::fromXContent;
queryRegistry.register(queryParser1, MatchAllQueryBuilder.NAME);
QueryParser<ScriptQueryBuilder> 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() { private static Schedule randomSchedule() {
String type = randomFrom(CronSchedule.TYPE, HourlySchedule.TYPE, DailySchedule.TYPE, WeeklySchedule.TYPE, MonthlySchedule.TYPE, String type = randomFrom(CronSchedule.TYPE, HourlySchedule.TYPE, DailySchedule.TYPE, WeeklySchedule.TYPE, MonthlySchedule.TYPE,
YearlySchedule.TYPE, IntervalSchedule.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<String, InputFactory> parsers = new HashMap<>(); Map<String, InputFactory> parsers = new HashMap<>();
switch (input.type()) { switch (inputType) {
case SearchInput.TYPE: case SearchInput.TYPE:
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent; QueryParser<MatchAllQueryBuilder> queryParser1 = MatchAllQueryBuilder::fromXContent;
queryRegistry.register(queryParser, MatchAllQueryBuilder.NAME); queryRegistry.register(queryParser1, MatchAllQueryBuilder.NAME);
QueryParser<ScriptQueryBuilder> queryParser2 = ScriptQueryBuilder::fromXContent;
queryRegistry.register(queryParser2, ScriptQueryBuilder.NAME);
SearchRequestParsers searchParsers = new SearchRequestParsers(queryRegistry, null, null); SearchRequestParsers searchParsers = new SearchRequestParsers(queryRegistry, null, null);
parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, searchParsers, scriptService)); parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, searchParsers, scriptService));
return new InputRegistry(Settings.EMPTY, parsers); return new InputRegistry(Settings.EMPTY, parsers);