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 static final String DEFAULT_TEMPLATE_LANG = "mustache";
private final Script script;
private final String inlineTemplate;
@ -37,7 +39,7 @@ public class TextTemplate implements ToXContent {
public TextTemplate(String template, @Nullable XContentType contentType, ScriptType type,
@Nullable Map<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;
}
@ -95,7 +97,7 @@ public class TextTemplate implements ToXContent {
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
return new TextTemplate(parser.text());
} else {
return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, "mustache"));
return new TextTemplate(Script.parse(parser, ParseFieldMatcher.STRICT, DEFAULT_TEMPLATE_LANG));
}
}
}

View File

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

View File

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

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
*
* @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.

View File

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

View File

@ -32,7 +32,7 @@ public class AlwaysConditionFactory extends ConditionFactory<AlwaysCondition, Al
}
@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);
}

View File

@ -33,7 +33,7 @@ public class CompareConditionFactory extends ConditionFactory<CompareCondition,
}
@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);
}

View File

@ -31,7 +31,7 @@ public class ArrayCompareConditionFactory extends ConditionFactory<ArrayCompareC
}
@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);
}

View File

@ -32,7 +32,7 @@ public class NeverConditionFactory extends ConditionFactory<NeverCondition, Neve
}
@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);
}

View File

@ -53,9 +53,15 @@ public class ScriptCondition implements Condition {
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 {
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);
} catch (ElasticsearchParseException pe) {
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.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.xpack.watcher.condition.ConditionFactory;
import java.io.IOException;
/**
*
*/
public class ScriptConditionFactory extends ConditionFactory<ScriptCondition, ScriptCondition.Result, ExecutableScriptCondition> {
private final Settings settings;
private final ScriptService scriptService;
@Inject
public ScriptConditionFactory(Settings settings, ScriptService service) {
super(Loggers.getLogger(ExecutableScriptCondition.class, settings));
this.settings = settings;
scriptService = service;
}
@ -33,8 +33,9 @@ public class ScriptConditionFactory extends ConditionFactory<ScriptCondition, Sc
}
@Override
public ScriptCondition parseCondition(String watchId, XContentParser parser) throws IOException {
return ScriptCondition.parse(watchId, parser);
public ScriptCondition parseCondition(String watchId, XContentParser parser, boolean upgradeConditionSource) throws IOException {
String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return ScriptCondition.parse(watchId, parser, upgradeConditionSource, defaultLegacyScriptLanguage);
}
@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
*
* @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.
*/
public abstract E createExecutable(I input);
public E parseExecutable(String watchId, XContentParser parser) throws IOException {
I input = parseInput(watchId, parser);
public E parseExecutable(String watchId, XContentParser parser, boolean upgradeInputSource) throws IOException {
I input = parseInput(watchId, parser, upgradeInputSource);
return createExecutable(input);
}
}

View File

@ -35,6 +35,17 @@ public class InputRegistry {
* @return A new input instance from the parser
*/
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;
if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
@ -55,7 +66,7 @@ public class InputRegistry {
if (factory == null) {
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 {
throw new ElasticsearchParseException("could not parse input for watch [{}]. expected an object representing input [{}], " +
"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.inject.Inject;
import org.elasticsearch.common.inject.Injector;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentParser;
@ -36,7 +35,7 @@ public class ChainInputFactory extends InputFactory<ChainInput, ChainInput.Resul
}
@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);
}

View File

@ -40,7 +40,7 @@ public final class HttpInputFactory extends InputFactory<HttpInput, HttpInput.Re
}
@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);
}

View File

@ -29,7 +29,7 @@ public class NoneInputFactory extends InputFactory<NoneInput, NoneInput.Result,
}
@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);
}

View File

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

View File

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

View File

@ -29,7 +29,7 @@ public class SimpleInputFactory extends InputFactory<SimpleInput, SimpleInput.Re
}
@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);
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.watcher.support.search;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.search.SearchType;
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.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.Script;
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.util.ArrayList;
@ -32,8 +38,6 @@ import java.util.Objects;
*/
public class WatcherSearchTemplateRequest implements ToXContent {
private static final String DEFAULT_LANG = "mustache";
private final String[] indices;
private final String[] types;
private final SearchType searchType;
@ -50,12 +54,13 @@ public class WatcherSearchTemplateRequest implements ToXContent {
this.indicesOptions = indicesOptions;
// 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.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;
}
public WatcherSearchTemplateRequest(String[] indices, String[] types, SearchType searchType, IndicesOptions indicesOptions,
Script template) {
assert template == null || TextTemplate.DEFAULT_TEMPLATE_LANG.equals(template.getLang());
this.indices = indices;
this.types = types;
this.searchType = searchType;
@ -113,7 +118,7 @@ public class WatcherSearchTemplateRequest implements ToXContent {
if (template != null) {
return template;
} 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.
*/
public static WatcherSearchTemplateRequest fromXContent(XContentParser parser, SearchType searchType)
throws IOException {
public static WatcherSearchTemplateRequest fromXContent(Logger logger, XContentParser parser,
SearchType searchType,
boolean upgradeSearchSource,
String defaultLegacyScriptLanguage,
ParseFieldMatcher parseFieldMatcher,
SearchRequestParsers searchRequestParsers) throws IOException {
List<String> indices = new ArrayList<>();
List<String> types = new ArrayList<>();
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
@ -200,6 +209,19 @@ public class WatcherSearchTemplateRequest implements ToXContent {
try (XContentBuilder builder = XContentBuilder.builder(parser.contentType().xContent())) {
builder.copyCurrentStructure(parser);
searchSource = builder.bytes();
if (upgradeSearchSource) {
XContentParser searchSourceParser = XContentHelper.createParser(searchSource);
QueryParseContext context = new QueryParseContext(defaultLegacyScriptLanguage,
searchRequestParsers.queryParsers, searchSourceParser, parseFieldMatcher);
try (XContentBuilder upgradeBuilder = XContentBuilder.builder(parser.contentType().xContent())) {
SearchSourceBuilder sourceBuilder = SearchSourceBuilder.fromXContent(context,
searchRequestParsers.aggParsers, searchRequestParsers.suggesters);
upgradeBuilder.value(sourceBuilder);
searchSource = upgradeBuilder.bytes();
} catch (Exception e) {
logger.warn("Unable to upgrade search source: [" + searchSource.utf8ToString() + "]", e);
}
}
}
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_OPTIONS_FIELD)) {
boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen();
@ -248,7 +270,7 @@ public class WatcherSearchTemplateRequest implements ToXContent {
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed,
DEFAULT_INDICES_OPTIONS);
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TEMPLATE_FIELD)) {
template = Script.parse(parser, ParseFieldMatcher.STRICT, DEFAULT_LANG);
template = Script.parse(parser, ParseFieldMatcher.STRICT, TextTemplate.DEFAULT_TEMPLATE_LANG);
} else {
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
currentFieldName + "]");

View File

@ -56,7 +56,8 @@ public class WatcherSearchTemplateService extends AbstractComponent {
if (source.getParams() != null) {
watcherContextParams.putAll(source.getParams());
}
Script template = new Script(source.getScript(), source.getType(), source.getLang(), watcherContextParams,
// Templates are always of lang mustache:
Script template = new Script(source.getScript(), source.getType(), "mustache", watcherContextParams,
source.getContentType());
CompiledScript compiledScript = scriptService.compile(template, Watcher.SCRIPT_CONTEXT, Collections.emptyMap());
return (BytesReference) scriptService.executable(compiledScript, template.getParams()).run();

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
*
* @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.
*/
public abstract E createExecutable(T transform);
public E parseExecutable(String watchId, XContentParser parser) throws IOException {
T transform = parseTransform(watchId, parser);
public E parseExecutable(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
T transform = parseTransform(watchId, parser, upgradeTransformSource);
return createExecutable(transform);
}
}

View File

@ -35,7 +35,7 @@ public class TransformRegistry {
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;
XContentParser.Token token;
ExecutableTransform transform = null;
@ -43,25 +43,26 @@ public class TransformRegistry {
if (token == XContentParser.Token.FIELD_NAME) {
type = parser.currentName();
} else if (type != null) {
transform = parse(watchId, type, parser);
transform = parse(watchId, type, parser, upgradeTransformSource);
}
}
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);
if (factory == null) {
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);
if (factory == null) {
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();
}
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();
if (token != XContentParser.Token.START_ARRAY) {
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) {
currentFieldName = parser.currentName();
} 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
public ChainTransform parseTransform(String watchId, XContentParser parser) throws IOException {
return ChainTransform.parse(watchId, parser, registry);
public ChainTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
return ChainTransform.parse(watchId, parser, registry, upgradeTransformSource);
}
@Override

View File

@ -54,9 +54,15 @@ public class ScriptTransform implements Transform {
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 {
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);
} catch (ElasticsearchParseException pe) {
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.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.xpack.watcher.transform.TransformFactory;
import java.io.IOException;
/**
*
*/
public class ScriptTransformFactory extends TransformFactory<ScriptTransform, ScriptTransform.Result, ExecutableScriptTransform> {
private final Settings settings;
private final ScriptService scriptService;
@Inject
public ScriptTransformFactory(Settings settings, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableScriptTransform.class, settings));
this.settings = settings;
this.scriptService = scriptService;
}
@ -33,8 +33,9 @@ public class ScriptTransformFactory extends TransformFactory<ScriptTransform, Sc
}
@Override
public ScriptTransform parseTransform(String watchId, XContentParser parser) throws IOException {
return ScriptTransform.parse(watchId, parser);
public ScriptTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return ScriptTransform.parse(watchId, parser, upgradeTransformSource, defaultLegacyScriptLanguage);
}
@Override

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.watcher.transform.search;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
@ -12,9 +13,7 @@ import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.transform.Transform;
@ -92,9 +91,12 @@ public class SearchTransform implements Transform {
return builder;
}
public static SearchTransform parse(String watchId, XContentParser parser, QueryParseContext context,
AggregatorParsers aggParsers, Suggesters suggesters)
throws IOException {
public static SearchTransform parse(Logger transformLogger, String watchId,
XContentParser parser,
boolean upgradeTransformSource,
String defaultLegacyScriptLanguage,
ParseFieldMatcher parseFieldMatcher,
SearchRequestParsers searchRequestParsers) throws IOException {
WatcherSearchTemplateRequest request = null;
TimeValue timeout = null;
DateTimeZone dynamicNameTimeZone = null;
@ -106,7 +108,10 @@ public class SearchTransform implements Transform {
currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
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) {
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe,
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.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.transform.TransformFactory;
/**
*
*/
public class SearchTransformFactory extends TransformFactory<SearchTransform, SearchTransform.Result, ExecutableSearchTransform> {
private final Settings settings;
protected final WatcherClientProxy client;
private final TimeValue defaultTimeout;
private final SearchRequestParsers searchRequestParsers;
@ -40,6 +38,7 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
public SearchTransformFactory(Settings settings, WatcherClientProxy client,
SearchRequestParsers searchRequestParsers, ScriptService scriptService) {
super(Loggers.getLogger(ExecutableSearchTransform.class, settings));
this.settings = settings;
this.client = client;
this.parseFieldMatcher = new ParseFieldMatcher(settings);
this.searchRequestParsers = searchRequestParsers;
@ -53,9 +52,10 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
}
@Override
public SearchTransform parseTransform(String watchId, XContentParser parser) throws IOException {
QueryParseContext context = new QueryParseContext(searchRequestParsers.queryParsers, parser, parseFieldMatcher);
return SearchTransform.parse(watchId, parser, context, searchRequestParsers.aggParsers, searchRequestParsers.suggesters);
public SearchTransform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
String defaultLegacyScriptLanguage = ScriptSettings.getLegacyDefaultLang(settings);
return SearchTransform.parse(transformLogger, watchId, parser, upgradeTransformSource, defaultLegacyScriptLanguage,
parseFieldMatcher, searchRequestParsers);
}
@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 {
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 {
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)
*/
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()) {
logger.trace("parsing watch [{}] ", source.utf8ToString());
}
@ -267,7 +272,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
try {
parser = new WatcherXContentParser(createParser(source), new HaltedClock(now), withSecrets ? cryptoService : null);
parser.nextToken();
return parse(id, includeStatus, parser);
return parse(id, includeStatus, parser, upgradeSource);
} catch (IOException ioe) {
throw ioException("could not parse watch [{}]", ioe, id);
} 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;
ExecutableInput input = defaultInput;
ExecutableCondition condition = defaultCondition;
@ -299,11 +304,11 @@ public class Watch implements TriggerEngine.Job, ToXContent {
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.TRIGGER)) {
trigger = triggerService.parseTrigger(id, parser);
} 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)) {
condition = conditionRegistry.parseExecutable(id, parser);
condition = conditionRegistry.parseExecutable(id, parser, upgradeWatchSource);
} 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)) {
throttlePeriod = timeValueMillis(parser.longValue());
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.THROTTLE_PERIOD_HUMAN)) {
@ -315,7 +320,7 @@ public class Watch implements TriggerEngine.Job, ToXContent {
pe, id, currentFieldName);
}
} 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)) {
metatdata = parser.map();
} 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;
/**
*/
public class WatchStore extends AbstractComponent {
public static final String INDEX = ".watches";
@ -310,7 +308,7 @@ public class WatchStore extends AbstractComponent {
for (SearchHit hit : response.getHits()) {
String id = hit.getId();
try {
Watch watch = watchParser.parse(id, true, hit.getSourceRef());
Watch watch = watchParser.parse(id, true, hit.getSourceRef(), true);
watch.status().version(hit.version());
watch.version(hit.version());
watches.put(id, watch);

View File

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

View File

@ -177,7 +177,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken();
CompareCondition condition = factory.parseCondition("_id", parser);
CompareCondition condition = factory.parseCondition("_id", parser, false);
assertThat(condition, notNullValue());
assertThat(condition.getPath(), is("key1.key2"));
@ -195,7 +195,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
try {
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
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());
parser.nextToken();
try {
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
assertThat(e.getMessage(), containsString("unknown comparison operator [foobar]"));
@ -236,7 +236,7 @@ public class CompareConditionTests extends ESTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken();
try {
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
fail("Expected ElasticsearchParseException");
} catch (ElasticsearchParseException e) {
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());
parser.nextToken();
ArrayCompareCondition condition = factory.parseCondition("_id", parser);
ArrayCompareCondition condition = factory.parseCondition("_id", parser, false);
assertThat(condition, notNullValue());
assertThat(condition.getArrayPath(), is("key1.key2"));
@ -221,7 +221,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate comparison operator");
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
}
public void testParseContainsUnknownOperator() throws IOException {
@ -245,7 +245,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("unknown comparison operator");
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
}
public void testParseContainsDuplicateValue() throws IOException {
@ -271,7 +271,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate field \"value\"");
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
}
public void testParseContainsDuplicateQuantifier() throws IOException {
@ -297,7 +297,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("duplicate field \"quantifier\"");
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
}
public void testParseContainsUnknownQuantifier() throws IOException {
@ -321,7 +321,7 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
expectedException.expectMessage("unknown comparison quantifier");
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
}
public void testParseContainsUnexpectedFieldInComparisonOperator() throws IOException {
@ -347,6 +347,6 @@ public class ArrayCompareConditionTests extends ESTestCase {
expectedException.expect(ElasticsearchParseException.class);
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());
parser.nextToken();
NeverCondition condition = factory.parseCondition("_id", parser);
NeverCondition condition = factory.parseCondition("_id", parser, false);
ExecutableNeverCondition executable = factory.createExecutable(condition);
assertFalse(executable.execute(null).met());
}
@ -48,7 +48,7 @@ public class NeverConditionTests extends ESTestCase {
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
try {
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
fail("expected a condition exception trying to parse an invalid condition XContent, ["
+ AlwaysCondition.TYPE + "] condition should not parse with a body");
} catch (ElasticsearchParseException e) {

View File

@ -28,7 +28,6 @@ import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.ScriptSettings;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
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());
parser.nextToken();
ScriptCondition condition = factory.parseCondition("_watch", parser);
ScriptCondition condition = factory.parseCondition("_watch", parser, false);
ExecutableScriptCondition executable = factory.createExecutable(condition);
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);
parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
condition = factory.parseCondition("_watch", parser);
condition = factory.parseCondition("_watch", parser, false);
executable = factory.createExecutable(condition);
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());
parser.nextToken();
try {
factory.parseCondition("_id", parser);
factory.parseCondition("_id", parser, false);
fail("expected a condition exception trying to parse an invalid condition XContent");
} catch (ElasticsearchParseException e) {
// TODO add these when the test if fixed
@ -171,7 +170,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentBuilder builder = createConditionContent(script, "groovy", scriptType);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser);
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser, false);
expectThrows(GeneralScriptException.class,
() -> conditionParser.createExecutable(scriptCondition));
}
@ -182,7 +181,7 @@ public class ScriptConditionTests extends ESTestCase {
XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", ScriptType.INLINE);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser);
ScriptCondition scriptCondition = conditionParser.parseCondition("_watch", parser, false);
GeneralScriptException exception = expectThrows(GeneralScriptException.class,
() -> conditionParser.createExecutable(scriptCondition));
assertThat(exception.getMessage(), containsString("script_lang not supported [not_a_valid_lang]]"));

View File

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

View File

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

View File

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

View File

@ -124,7 +124,8 @@ public class WatcherUtilsTests extends ESTestCase {
request.toXContent(builder, ToXContent.EMPTY_PARAMS);
XContentParser parser = XContentHelper.createParser(builder.bytes());
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE);
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(logger, parser, DEFAULT_SEARCH_TYPE,
false, null, null, null);
assertThat(result.getIndices(), arrayContainingInAnyOrder(expectedIndices != null ? expectedIndices : new String[0]));
assertThat(result.getTypes(), arrayContainingInAnyOrder(expectedTypes != null ? expectedTypes : new String[0]));
@ -213,7 +214,8 @@ public class WatcherUtilsTests extends ESTestCase {
XContentParser parser = XContentHelper.createParser(builder.bytes());
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE);
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(logger, parser, DEFAULT_SEARCH_TYPE,
false, null, null, null);
assertThat(result.getIndices(), arrayContainingInAnyOrder(indices));
assertThat(result.getTypes(), arrayContainingInAnyOrder(types));

View File

@ -6,15 +6,23 @@
package org.elasticsearch.xpack.watcher.support.search;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.SearchRequestParsers;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.equalTo;
public class WatcherSearchTemplateRequestTests extends ESTestCase {
@ -33,7 +41,8 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase {
try (XContentParser parser = XContentHelper.createParser(new BytesArray(source))) {
parser.nextToken();
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, randomFrom(SearchType.values()));
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(
logger, parser, randomFrom(SearchType.values()), false, null, null, null);
assertNotNull(result.getTemplate());
assertThat(result.getTemplate().getScript(), equalTo(expectedScript));
assertThat(result.getTemplate().getLang(), equalTo(expectedLang));
@ -42,4 +51,53 @@ public class WatcherSearchTemplateRequestTests extends ESTestCase {
fail("Failed to parse watch search request: " + e.getMessage());
}
}
public void testUpgradeSearchSource() throws IOException {
XContentBuilder contentBuilder = jsonBuilder();
contentBuilder.startObject();
contentBuilder.startObject("body");
contentBuilder.startObject("query");
contentBuilder.startObject("script");
contentBuilder.startObject("script");
contentBuilder.field("inline", "return true");
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.startObject("aggregations");
contentBuilder.startObject("avg_grade");
contentBuilder.startObject("avg");
contentBuilder.startObject("script");
contentBuilder.field("inline", "1 + 1");
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.startObject("another_avg");
contentBuilder.startObject("avg");
contentBuilder.startObject("script");
contentBuilder.field("inline", "1 + 2");
contentBuilder.field("lang", "javascript");
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
contentBuilder.endObject();
XContentParser parser = XContentHelper.createParser(contentBuilder.bytes());
parser.nextToken();
SearchRequestParsers searchRequestParsers = new SearchModule(Settings.EMPTY, false, Collections.emptyList())
.getSearchRequestParsers();
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(
logger, parser, SearchType.DEFAULT, true, "your_legacy_lang", ParseFieldMatcher.STRICT, searchRequestParsers);
Map<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.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
@ -152,7 +151,7 @@ public class SearchInputTests extends ESIntegTestCase {
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()),
searchParsers, scriptService());
SearchInput searchInput = factory.parseInput("_id", parser);
SearchInput searchInput = factory.parseInput("_id", parser, false);
assertEquals(SearchInput.TYPE, searchInput.type());
assertThat(searchInput.getTimeout(), equalTo(timeout));
}

View File

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

View File

@ -12,6 +12,8 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
@ -21,7 +23,10 @@ import org.elasticsearch.xpack.watcher.watch.WatchStore;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
@ -44,6 +49,13 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati
return false;
}
@Override
protected List<Class<? extends Plugin>> pluginTypes() {
List<Class<? extends Plugin>> plugins = super.pluginTypes();
plugins.add(FoolMeScriptLang.class);
return plugins;
}
public void testWatchLoadedSuccessfullyAfterUpgrade() throws Exception {
// setup node
Path dataDir = createTempDir();
@ -86,10 +98,32 @@ public class WatcherBackwardsCompatibilityTests extends AbstractWatcherIntegrati
assertThat(getWatchResponse.isFound(), is(true));
Map<String, Object> watchSourceAsMap = getWatchResponse.getSource().getAsMap();
assertThat(ObjectPath.eval("trigger.schedule.interval", watchSourceAsMap), equalTo("99w"));
assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.1.range.date.lte", watchSourceAsMap),
assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.1.range.date.to", watchSourceAsMap),
equalTo("{{ctx.trigger.scheduled_time}}"));
assertThat(ObjectPath.eval("actions.log_error.logging.text", watchSourceAsMap),
equalTo("Found {{ctx.payload.hits.total}} errors in the logs"));
// Check that all scripts have been upgraded, so that the language has been set to groovy (legacy language default):
assertThat(ObjectPath.eval("input.search.request.body.query.bool.filter.2.script.script.lang", watchSourceAsMap),
equalTo("groovy"));
assertThat(ObjectPath.eval("input.search.request.body.aggregations.avg_grade.avg.script.lang", watchSourceAsMap),
equalTo("groovy"));
assertThat(ObjectPath.eval("condition.script.lang", watchSourceAsMap), equalTo("groovy"));
}
// Fool the script service that this is the groovy script language, so that we can just load the watch upon startup
// and verify that the lang options on scripts have been set.
public static class FoolMeScriptLang extends MockScriptPlugin{
@Override
protected Map<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());
parser.nextToken();
ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser);
ExecutableChainTransform executable = transformParser.parseExecutable("_id", parser, false);
assertThat(executable, notNullValue());
assertThat(executable.transform().getTransforms(), notNullValue());
assertThat(executable.transform().getTransforms(), hasSize(4));
@ -204,7 +204,7 @@ public class ChainTransformTests extends ESTestCase {
}
@Override
public Transform parseTransform(String watchId, XContentParser parser) throws IOException {
public Transform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
if (parser.currentToken() == XContentParser.Token.VALUE_STRING) {
return new Transform(parser.text());
}
@ -273,7 +273,7 @@ public class ChainTransformTests extends ESTestCase {
}
@Override
public Transform parseTransform(String watchId, XContentParser parser) throws IOException {
public Transform parseTransform(String watchId, XContentParser parser, boolean upgradeTransformSource) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
XContentParser.Token token = parser.nextToken();
assert token == XContentParser.Token.END_OBJECT;

View File

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

View File

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

View File

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