mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-17 10:25:15 +00:00
Watcher: Remove usage of SearchRequest's template support
Template support is going to be removed from the Search API to its own Search Template API in the lang-mustache module (see elastic/elasticsearch#17906, elastic/elasticsearch#18765). This commit changes Watcher's SearchInput and SearchTransform classes so that it now uses a WatcherSearchTemplateRequest that contains both the search request and the template. Search request and template are rendered using WatcherSearchTemplateRequestService before being executed. Original commit: elastic/x-pack-elasticsearch@bfa16ab80f
This commit is contained in:
parent
f6abf979ce
commit
99ade96091
@ -12,31 +12,40 @@ import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.plugins.ScriptPlugin;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
|
||||
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
|
||||
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
|
||||
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.input.Input;
|
||||
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
|
||||
import org.elasticsearch.xpack.watcher.input.search.SearchInput;
|
||||
import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
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.xcontent.XContentSource;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
||||
@ -67,7 +76,6 @@ import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
|
||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
/**
|
||||
@ -81,10 +89,11 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
||||
types.addAll(super.nodePlugins());
|
||||
types.add(MustachePlugin.class);
|
||||
types.add(CustomScriptContextPlugin.class);
|
||||
return types;
|
||||
}
|
||||
|
||||
private final static String TEMPLATE_QUERY = "{\"query\":{\"filtered\":{\"query\":{\"match\":{\"event_type\":{\"query\":\"a\"," +
|
||||
private final static String TEMPLATE_QUERY = "{\"query\":{\"bool\":{\"must\":{\"match\":{\"event_type\":{\"query\":\"a\"," +
|
||||
"\"type\":\"boolean\"}}},\"filter\":{\"range\":{\"_timestamp\":" +
|
||||
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
|
||||
"\"include_lower\":true,\"include_upper\":true}}}}}}";
|
||||
@ -100,7 +109,6 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
throw new RuntimeException("failed to create config dir");
|
||||
|
||||
}
|
||||
String path = "/org/elasticsearch/xpack/watcher/input/search/config/scripts/test_disk_template.mustache";
|
||||
try (InputStream stream = SearchInputIT.class.getResourceAsStream("/org/elasticsearch/xpack/watcher/input/search/config/scripts" +
|
||||
"/test_disk_template.mustache");
|
||||
OutputStream out = Files.newOutputStream(scriptPath.resolve("test_disk_template.mustache"))) {
|
||||
@ -126,14 +134,15 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
||||
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
|
||||
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")));
|
||||
SearchRequest request = client()
|
||||
SearchRequest searchRequest = client()
|
||||
.prepareSearch()
|
||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.request()
|
||||
.source(searchSourceBuilder);
|
||||
|
||||
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
||||
WatcherClientProxy.of(client()), null);
|
||||
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
||||
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
||||
new Watch("test-watch",
|
||||
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
||||
@ -149,21 +158,21 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
timeValueSeconds(5));
|
||||
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
||||
|
||||
assertThat((Integer) XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertNotNull(result.executedRequest());
|
||||
assertEquals(result.executedRequest().searchType(), request.searchType());
|
||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
||||
assertEquals(result.executedRequest().searchType(), request.getRequest().searchType());
|
||||
assertArrayEquals(result.executedRequest().indices(), request.getRequest().indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), request.getRequest().indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(result);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
|
||||
}
|
||||
|
||||
public void testSearchInlineTemplate() throws Exception {
|
||||
WatchExecutionContext ctx = createContext();
|
||||
|
||||
final String expectedTemplateString = "{\"query\":{\"filtered\":{\"query\":{\"match\":{\"event_type\":{\"query\":\"a\","
|
||||
+ "\"type\":\"boolean\"}}},\"filter\":{\"range\":{\"_timestamp\":"
|
||||
+ "{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\","
|
||||
+ "\"include_lower\":true,\"include_upper\":true}}}}}}";
|
||||
|
||||
Map<String, Object> triggerParams = new HashMap<String, Object>();
|
||||
triggerParams.put("triggered_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
||||
triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
||||
@ -178,17 +187,26 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
Map<String, Object> expectedParams = new HashMap<String, Object>();
|
||||
expectedParams.put("seconds_param", "30s");
|
||||
expectedParams.put("ctx", ctxParams);
|
||||
Template expectedTemplate = new Template(expectedTemplateString, ScriptType.INLINE, null, XContentType.JSON, expectedParams);
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
Template template = new Template(TEMPLATE_QUERY, ScriptType.INLINE, null, XContentType.JSON, params);
|
||||
Script template = Script.inline(TEMPLATE_QUERY).lang("mustache").params(params).build();
|
||||
|
||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").setTemplate(template).request();
|
||||
SearchRequest request = client().prepareSearch()
|
||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").request();
|
||||
|
||||
SearchInput.Result executedResult = executeSearchInput(request, ctx);
|
||||
assertThat(executedResult.executedRequest().template(), equalTo(expectedTemplate));
|
||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
||||
|
||||
assertNotNull(executedResult.executedRequest());
|
||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(executedResult);
|
||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
}
|
||||
|
||||
public void testSearchIndexedTemplate() throws Exception {
|
||||
@ -204,17 +222,24 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
Template template = new Template("test-template", ScriptType.STORED, null, null, params);
|
||||
Script template = Script.indexed("test-template").lang("mustache").params(params).build();
|
||||
|
||||
jsonBuilder().value(TextTemplate.indexed("test-template").params(params).build()).bytes();
|
||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").setTemplate(template).request();
|
||||
.setIndices("test-search-index").request();
|
||||
|
||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
||||
|
||||
assertNotNull(executedResult.executedRequest());
|
||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(executedResult);
|
||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.filter.0.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
|
||||
SearchInput.Result executedResult = executeSearchInput(request, ctx);
|
||||
Template resultTemplate = executedResult.executedRequest().template();
|
||||
assertThat(resultTemplate, notNullValue());
|
||||
assertThat(resultTemplate.getScript(), equalTo("test-template"));
|
||||
assertThat(resultTemplate.getType(), equalTo(ScriptType.STORED));
|
||||
}
|
||||
|
||||
public void testSearchOnDiskTemplate() throws Exception {
|
||||
@ -223,15 +248,16 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
Template template = new Template("test_disk_template", ScriptType.FILE, null, null, params);
|
||||
Script template = Script.file("test_disk_template").lang("mustache").params(params).build();
|
||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").setTemplate(template).request();
|
||||
.setIndices("test-search-index").request();
|
||||
|
||||
SearchInput.Result executedResult = executeSearchInput(request, ctx);
|
||||
Template resultTemplate = executedResult.executedRequest().template();
|
||||
assertThat(resultTemplate, notNullValue());
|
||||
assertThat(resultTemplate.getScript(), equalTo("test_disk_template"));
|
||||
assertThat(resultTemplate.getType(), equalTo(ScriptType.FILE));
|
||||
SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
|
||||
|
||||
assertNotNull(executedResult.executedRequest());
|
||||
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
|
||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
}
|
||||
|
||||
public void testDifferentSearchType() throws Exception {
|
||||
@ -241,14 +267,16 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
);
|
||||
SearchType searchType = getRandomSupportedSearchType();
|
||||
|
||||
SearchRequest request = client()
|
||||
SearchRequest searchRequest = client()
|
||||
.prepareSearch()
|
||||
.setSearchType(searchType)
|
||||
.request()
|
||||
.source(searchSourceBuilder);
|
||||
|
||||
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
|
||||
|
||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
|
||||
WatcherClientProxy.of(client()), null);
|
||||
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
||||
WatchExecutionContext ctx = new TriggeredExecutionContext(
|
||||
new Watch("test-watch",
|
||||
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
||||
@ -264,15 +292,20 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
timeValueSeconds(5));
|
||||
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple());
|
||||
|
||||
assertThat((Integer) XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertNotNull(result.executedRequest());
|
||||
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
|
||||
assertEquals(result.executedRequest().searchType(), searchType);
|
||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
assertArrayEquals(result.executedRequest().indices(), searchRequest.indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), searchRequest.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(result);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:00:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:00:00.000Z"));
|
||||
}
|
||||
|
||||
public void testParserValid() throws Exception {
|
||||
SearchRequest request = client().prepareSearch()
|
||||
SearchRequest searchRequest = client().prepareSearch()
|
||||
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.request()
|
||||
.source(searchSource()
|
||||
@ -280,13 +313,13 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))));
|
||||
|
||||
TimeValue timeout = randomBoolean() ? TimeValue.timeValueSeconds(randomInt(10)) : null;
|
||||
XContentBuilder builder = jsonBuilder().value(new SearchInput(request, null, timeout, null));
|
||||
XContentBuilder builder = jsonBuilder().value(new SearchInput(new WatcherSearchTemplateRequest(searchRequest), null, timeout, null));
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
||||
parser.nextToken();
|
||||
|
||||
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
|
||||
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry,
|
||||
null, null);
|
||||
null, null, scriptService());
|
||||
|
||||
SearchInput searchInput = factory.parseInput("_id", parser);
|
||||
assertEquals(SearchInput.TYPE, searchInput.type());
|
||||
@ -309,15 +342,47 @@ public class SearchInputIT extends ESIntegTestCase {
|
||||
timeValueSeconds(5));
|
||||
}
|
||||
|
||||
private SearchInput.Result executeSearchInput(SearchRequest request, WatchExecutionContext ctx) throws IOException {
|
||||
private SearchInput.Result executeSearchInput(SearchRequest request, Script template, WatchExecutionContext ctx) throws IOException {
|
||||
createIndex("test-search-index");
|
||||
ensureGreen("test-search-index");
|
||||
SearchInput.Builder siBuilder = SearchInput.builder(request);
|
||||
SearchInput.Builder siBuilder = SearchInput.builder(new WatcherSearchTemplateRequest(request, template));
|
||||
|
||||
SearchInput si = siBuilder.build();
|
||||
|
||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(si, logger, WatcherClientProxy.of(client()), null);
|
||||
ExecutableSearchInput searchInput = new ExecutableSearchInput(si, logger, WatcherClientProxy.of(client()),
|
||||
watcherSearchTemplateService(), null);
|
||||
return searchInput.execute(ctx, new Payload.Simple());
|
||||
}
|
||||
|
||||
protected WatcherSearchTemplateService watcherSearchTemplateService() {
|
||||
String master = internalCluster().getMasterName();
|
||||
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
||||
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class, master), internalCluster().clusterService(master)),
|
||||
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
|
||||
internalCluster().getInstance(AggregatorParsers.class, master),
|
||||
internalCluster().getInstance(Suggesters.class, master)
|
||||
);
|
||||
}
|
||||
|
||||
protected ScriptServiceProxy scriptService() {
|
||||
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class), internalCluster().clusterService());
|
||||
}
|
||||
|
||||
private XContentSource toXContentSource(SearchInput.Result result) throws IOException {
|
||||
try (XContentBuilder builder = jsonBuilder()) {
|
||||
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
return new XContentSource(builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom plugin that registers XPack script context.
|
||||
*/
|
||||
public static class CustomScriptContextPlugin extends Plugin implements ScriptPlugin {
|
||||
|
||||
@Override
|
||||
public ScriptContext.Plugin getCustomScriptContexts() {
|
||||
return ScriptServiceProxy.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,25 +11,28 @@ import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.Streams;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.plugins.ScriptPlugin;
|
||||
import org.elasticsearch.script.ScriptContext;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
|
||||
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
|
||||
@ -37,7 +40,11 @@ import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
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.xcontent.XContentSource;
|
||||
import org.elasticsearch.xpack.watcher.transform.Transform;
|
||||
import org.elasticsearch.xpack.watcher.transform.TransformBuilders;
|
||||
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
|
||||
@ -100,6 +107,7 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
Collection<Class<? extends Plugin>> types = new ArrayList<>();
|
||||
types.addAll(super.nodePlugins());
|
||||
types.add(MustachePlugin.class);
|
||||
types.add(CustomScriptContextPlugin.class);
|
||||
return types;
|
||||
}
|
||||
|
||||
@ -154,7 +162,8 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
|
||||
SearchRequest request = Requests.searchRequest("idx").source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
|
||||
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()), null);
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()),
|
||||
watcherSearchTemplateService(), null);
|
||||
|
||||
WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
|
||||
|
||||
@ -188,7 +197,8 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
new SearchSourceBuilder().query(QueryBuilders.wrapperQuery(jsonBuilder().startObject()
|
||||
.startObject("_unknown_query_").endObject().endObject().bytes())));
|
||||
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()), null);
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()),
|
||||
watcherSearchTemplateService(), null);
|
||||
|
||||
WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
|
||||
|
||||
@ -200,23 +210,27 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
assertThat(result.reason(), containsString("no [query] registered for [_unknown_query_]"));
|
||||
|
||||
// extract the base64 encoded query from the template script, path is: query -> wrapper -> query
|
||||
String jsonQuery = result.executedRequest().template().getScript();
|
||||
Map<String, Object> map = XContentFactory.xContent(jsonQuery).createParser(jsonQuery).map();
|
||||
try (XContentBuilder builder = jsonBuilder()) {
|
||||
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
assertThat(map, hasKey("query"));
|
||||
assertThat(map.get("query"), instanceOf(Map.class));
|
||||
String jsonQuery = builder.string();
|
||||
Map<String, Object> map = XContentFactory.xContent(jsonQuery).createParser(jsonQuery).map();
|
||||
|
||||
map = (Map<String, Object>) map.get("query");
|
||||
assertThat(map, hasKey("wrapper"));
|
||||
assertThat(map.get("wrapper"), instanceOf(Map.class));
|
||||
assertThat(map, hasKey("query"));
|
||||
assertThat(map.get("query"), instanceOf(Map.class));
|
||||
|
||||
map = (Map<String, Object>) map.get("wrapper");
|
||||
assertThat(map, hasKey("query"));
|
||||
assertThat(map.get("query"), instanceOf(String.class));
|
||||
map = (Map<String, Object>) map.get("query");
|
||||
assertThat(map, hasKey("wrapper"));
|
||||
assertThat(map.get("wrapper"), instanceOf(Map.class));
|
||||
|
||||
String queryAsBase64 = (String) map.get("query");
|
||||
String decodedQuery = new String(Base64.getDecoder().decode(queryAsBase64), StandardCharsets.UTF_8);
|
||||
assertThat(decodedQuery, containsString("_unknown_query_"));
|
||||
map = (Map<String, Object>) map.get("wrapper");
|
||||
assertThat(map, hasKey("query"));
|
||||
assertThat(map.get("query"), instanceOf(String.class));
|
||||
|
||||
String queryAsBase64 = (String) map.get("query");
|
||||
String decodedQuery = new String(Base64.getDecoder().decode(queryAsBase64), StandardCharsets.UTF_8);
|
||||
assertThat(decodedQuery, containsString("_unknown_query_"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testExecuteMustacheTemplate() throws Exception {
|
||||
@ -252,7 +266,8 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
.must(termQuery("value", "{{ctx.payload.value}}"))));
|
||||
|
||||
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()), null);
|
||||
ExecutableSearchTransform transform = new ExecutableSearchTransform(searchTransform, logger, WatcherClientProxy.of(client()),
|
||||
watcherSearchTemplateService(), null);
|
||||
|
||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent("_name", parseDate("2015-01-04T00:00:00", UTC),
|
||||
parseDate("2015-01-01T00:00:00", UTC));
|
||||
@ -319,24 +334,24 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
|
||||
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
|
||||
SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()),
|
||||
indicesQueryRegistry, null, null);
|
||||
indicesQueryRegistry, null, null, scriptService());
|
||||
ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser);
|
||||
|
||||
assertThat(executable, notNullValue());
|
||||
assertThat(executable.type(), is(SearchTransform.TYPE));
|
||||
assertThat(executable.transform().getRequest(), notNullValue());
|
||||
if (indices != null) {
|
||||
assertThat(executable.transform().getRequest().indices(), arrayContainingInAnyOrder(indices));
|
||||
assertThat(executable.transform().getRequest().getRequest().indices(), arrayContainingInAnyOrder(indices));
|
||||
}
|
||||
if (searchType != null) {
|
||||
assertThat(executable.transform().getRequest().searchType(), is(searchType));
|
||||
assertThat(executable.transform().getRequest().getRequest().searchType(), is(searchType));
|
||||
}
|
||||
if (templateName != null) {
|
||||
assertThat(executable.transform().getRequest().template(),
|
||||
equalTo(new Template("template1", ScriptType.FILE, null, null, null)));
|
||||
assertThat(executable.transform().getRequest().getTemplate(),
|
||||
equalTo(Script.file("template1").build()));
|
||||
}
|
||||
SearchSourceBuilder source = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery());
|
||||
assertThat(executable.transform().getRequest().source(), equalTo(source));
|
||||
assertThat(executable.transform().getRequest().getRequest().source(), equalTo(source));
|
||||
assertThat(executable.transform().getTimeout(), equalTo(readTimeout));
|
||||
}
|
||||
|
||||
@ -348,11 +363,6 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
|
||||
"\"include_lower\":true,\"include_upper\":true}}}]}}}";
|
||||
|
||||
final String expectedTemplateString = "{\"query\":{\"bool\":{\"must\":[{\"match\":{\"event_type\":{\"query\":\"a\","
|
||||
+ "\"type\":\"boolean\"}}},{\"range\":{\"_timestamp\":"
|
||||
+ "{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\","
|
||||
+ "\"include_lower\":true,\"include_upper\":true}}}]}}}";
|
||||
|
||||
Map<String, Object> triggerParams = new HashMap<String, Object>();
|
||||
triggerParams.put("triggered_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
||||
triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
|
||||
@ -367,18 +377,24 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
Map<String, Object> expectedParams = new HashMap<String, Object>();
|
||||
expectedParams.put("seconds_param", "30s");
|
||||
expectedParams.put("ctx", ctxParams);
|
||||
Template expectedTemplate = new Template(expectedTemplateString, ScriptType.INLINE, null, XContentType.JSON, expectedParams);
|
||||
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
Template template = new Template(templateQuery, ScriptType.INLINE, null, XContentType.JSON, params);
|
||||
Script template = Script.inline(templateQuery).lang("mustache").params(params).build();
|
||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").setTemplate(template).request();
|
||||
.setIndices("test-search-index").request();
|
||||
|
||||
SearchTransform.Result executedResult = executeSearchTransform(request, ctx);
|
||||
SearchTransform.Result executedResult = executeSearchTransform(request, template, ctx);
|
||||
|
||||
assertThat(executedResult.executedRequest().template(), equalTo(expectedTemplate));
|
||||
assertThat(executedResult.status(), is(Transform.Result.Status.SUCCESS));
|
||||
assertEquals(executedResult.executedRequest().searchType(), request.searchType());
|
||||
assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
|
||||
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(executedResult);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
}
|
||||
|
||||
public void testSearchIndexedTemplate() throws Exception {
|
||||
@ -399,24 +415,24 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
BytesReference templateSource = jsonBuilder()
|
||||
.value(TextTemplate.indexed("test-script").params(params).build())
|
||||
.bytes();
|
||||
Template template = new Template("test-script", ScriptType.STORED, null, null, null);
|
||||
Script template = Script.indexed("test-script").lang("mustache").params(params).build();
|
||||
|
||||
SearchRequest request = client()
|
||||
.prepareSearch()
|
||||
.setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index")
|
||||
.setTemplate(template)
|
||||
.request();
|
||||
|
||||
SearchTransform.Result result = executeSearchTransform(request, ctx);
|
||||
SearchTransform.Result result = executeSearchTransform(request, template, ctx);
|
||||
|
||||
assertNotNull(result.executedRequest());
|
||||
Template resultTemplate = result.executedRequest().template();
|
||||
assertThat(resultTemplate, notNullValue());
|
||||
assertThat(resultTemplate.getScript(), equalTo("test-script"));
|
||||
assertThat(resultTemplate.getType(), equalTo(ScriptType.STORED));
|
||||
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
|
||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(result);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
}
|
||||
|
||||
public void testSearchOnDiskTemplate() throws Exception {
|
||||
@ -425,16 +441,20 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("seconds_param", "30s");
|
||||
|
||||
Template template = new Template("test_disk_template", ScriptType.FILE, null, null, null);
|
||||
Script template = Script.file("test_disk_template").lang("mustache").params(params).build();
|
||||
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
|
||||
.setIndices("test-search-index").setTemplate(template).request();
|
||||
.setIndices("test-search-index").request();
|
||||
|
||||
SearchTransform.Result result = executeSearchTransform(request, template, ctx);
|
||||
|
||||
SearchTransform.Result result = executeSearchTransform(request, ctx);
|
||||
assertNotNull(result.executedRequest());
|
||||
Template resultTemplate = result.executedRequest().template();
|
||||
assertThat(resultTemplate, notNullValue());
|
||||
assertThat(resultTemplate.getScript(), equalTo("test_disk_template"));
|
||||
assertThat(resultTemplate.getType(), equalTo(ScriptType.FILE));
|
||||
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
|
||||
assertArrayEquals(result.executedRequest().indices(), request.indices());
|
||||
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
|
||||
|
||||
XContentSource source = toXContentSource(result);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
}
|
||||
|
||||
public void testDifferentSearchType() throws Exception {
|
||||
@ -453,13 +473,18 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
.request()
|
||||
.source(searchSourceBuilder);
|
||||
|
||||
SearchTransform.Result result = executeSearchTransform(request, ctx);
|
||||
SearchTransform.Result result = executeSearchTransform(request, null, ctx);
|
||||
|
||||
assertThat((Integer) XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertThat(XContentMapValues.extractValue("hits.total", result.payload().data()), equalTo(0));
|
||||
assertThat(result.executedRequest(), notNullValue());
|
||||
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
|
||||
assertThat(result.executedRequest().searchType(), is(searchType));
|
||||
assertThat(result.executedRequest().indices(), arrayContainingInAnyOrder(request.indices()));
|
||||
assertThat(result.executedRequest().indicesOptions(), equalTo(request.indicesOptions()));
|
||||
|
||||
XContentSource source = toXContentSource(result);
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.from"), equalTo("1970-01-01T00:01:00.000Z||-30s"));
|
||||
assertThat(source.getValue("query.bool.must.1.range._timestamp.to"), equalTo("1970-01-01T00:01:00.000Z"));
|
||||
}
|
||||
|
||||
private WatchExecutionContext createContext() {
|
||||
@ -479,17 +504,31 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
timeValueSeconds(5));
|
||||
}
|
||||
|
||||
private SearchTransform.Result executeSearchTransform(SearchRequest request, WatchExecutionContext ctx) throws IOException {
|
||||
private SearchTransform.Result executeSearchTransform(SearchRequest request, Script template, WatchExecutionContext ctx)
|
||||
throws IOException {
|
||||
createIndex("test-search-index");
|
||||
ensureGreen("test-search-index");
|
||||
|
||||
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build();
|
||||
SearchTransform searchTransform = TransformBuilders.searchTransform(new WatcherSearchTemplateRequest(request, template)).build();
|
||||
ExecutableSearchTransform executableSearchTransform = new ExecutableSearchTransform(searchTransform, logger,
|
||||
WatcherClientProxy.of(client()), null);
|
||||
WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
|
||||
|
||||
return executableSearchTransform.execute(ctx, Payload.Simple.EMPTY);
|
||||
}
|
||||
|
||||
protected WatcherSearchTemplateService watcherSearchTemplateService() {
|
||||
String master = internalCluster().getMasterName();
|
||||
return new WatcherSearchTemplateService(internalCluster().clusterService(master).getSettings(),
|
||||
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class, master), internalCluster().clusterService(master)),
|
||||
internalCluster().getInstance(IndicesQueriesRegistry.class, master),
|
||||
internalCluster().getInstance(AggregatorParsers.class, master),
|
||||
internalCluster().getInstance(Suggesters.class, master)
|
||||
);
|
||||
}
|
||||
|
||||
protected ScriptServiceProxy scriptService() {
|
||||
return ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class), internalCluster().clusterService());
|
||||
}
|
||||
|
||||
private static Map<String, Object> doc(String date, String value) {
|
||||
Map<String, Object> doc = new HashMap<>();
|
||||
@ -498,4 +537,21 @@ public class SearchTransformIT extends ESIntegTestCase {
|
||||
return doc;
|
||||
}
|
||||
|
||||
private XContentSource toXContentSource(SearchTransform.Result result) throws IOException {
|
||||
try (XContentBuilder builder = jsonBuilder()) {
|
||||
result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
return new XContentSource(builder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom plugin that registers XPack script context.
|
||||
*/
|
||||
public static class CustomScriptContextPlugin extends Plugin implements ScriptPlugin {
|
||||
|
||||
@Override
|
||||
public ScriptContext.Plugin getCustomScriptContexts() {
|
||||
return ScriptServiceProxy.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,32 +5,32 @@
|
||||
*/
|
||||
package org.elasticsearch.messy.tests;
|
||||
|
||||
import org.elasticsearch.ElasticsearchSecurityException;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.action.search.SearchPhaseExecutionException;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.bytes.BytesArray;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.indices.TermsLookup;
|
||||
import org.elasticsearch.plugins.Plugin;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.script.mustache.MustachePlugin;
|
||||
import org.elasticsearch.script.mustache.MustacheScriptEngineService;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.elasticsearch.test.SecurityIntegTestCase;
|
||||
import org.elasticsearch.test.SecuritySettingsSource;
|
||||
import org.elasticsearch.xpack.security.authc.support.SecuredString;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.elasticsearch.script.ScriptService.ScriptType.INLINE;
|
||||
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@SecurityIntegTestCase.AwaitsFix(bugUrl = "clean up test to not use mustache templates, otherwise needs many resources here")
|
||||
//@SecurityIntegTestCase.AwaitsFix(bugUrl = "clean up test to not use mustache templates, otherwise needs many resources here")
|
||||
public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
||||
static final String READ_ONE_IDX_USER = "read_user";
|
||||
|
||||
@ -72,18 +72,6 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
||||
public void loadData() {
|
||||
index("data", "a", "1", "{ \"name\": \"John\", \"token\": \"token1\" }");
|
||||
index("tokens", "tokens", "1", "{ \"group\": \"1\", \"tokens\": [\"token1\", \"token2\"] }");
|
||||
client().admin().cluster().preparePutStoredScript().setSource(new BytesArray("{\n" +
|
||||
"\"template\": {\n" +
|
||||
" \"query\": {\n" +
|
||||
" \"exists\": {\n" +
|
||||
" \"field\": \"{{name}}\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}"))
|
||||
.setScriptLang("mustache")
|
||||
.setId("testTemplate")
|
||||
.execute().actionGet();
|
||||
refresh();
|
||||
}
|
||||
|
||||
@ -96,38 +84,44 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
|
||||
|
||||
// Repeat with unauthorized user!!!!
|
||||
try {
|
||||
response = client().filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
||||
response = client().filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
||||
new SecuredString("changeme".toCharArray()))))
|
||||
.prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery(
|
||||
QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
|
||||
.execute().actionGet();
|
||||
fail("search phase exception should have been thrown! response was:\n" + response.toString());
|
||||
} catch (SearchPhaseExecutionException e) {
|
||||
} catch (ElasticsearchSecurityException e) {
|
||||
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
|
||||
assertThat(e.toString(), containsString("unauthorized"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThatScriptServiceDoesntLeakData() {
|
||||
String source = "{\n" +
|
||||
"\"template\": {\n" +
|
||||
" \"query\": {\n" +
|
||||
" \"exists\": {\n" +
|
||||
" \"field\": \"{{name}}\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
|
||||
//Template template = new Template(source, INLINE, MustacheScriptEngineService.NAME, null, singletonMap("name", "token"));
|
||||
SearchResponse response = client().prepareSearch("data").setTypes("a")
|
||||
.setTemplate(new Template("testTemplate", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
Collections.<String, Object>singletonMap("name", "token")))
|
||||
.setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
|
||||
.execute().actionGet();
|
||||
assertThat(response.isTimedOut(), is(false));
|
||||
assertThat(response.getHits().hits().length, is(1));
|
||||
|
||||
// Repeat with unauthorized user!!!!
|
||||
try {
|
||||
response = client().filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
||||
new SecuredString("changeme".toCharArray()))))
|
||||
ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> client()
|
||||
.filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
|
||||
new SecuredString("changeme".toCharArray()))))
|
||||
.prepareSearch("data").setTypes("a")
|
||||
.setTemplate(new Template("testTemplate", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null,
|
||||
Collections.<String, Object>singletonMap("name", "token")))
|
||||
.execute().actionGet();
|
||||
fail("search phase exception should have been thrown! response was:\n" + response.toString());
|
||||
} catch (SearchPhaseExecutionException e) {
|
||||
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
|
||||
assertThat(e.toString(), containsString("unauthorized"));
|
||||
}
|
||||
.setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
|
||||
.execute().actionGet());
|
||||
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
|
||||
assertThat(e.toString(), containsString("unauthorized"));
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
cluster:admin/render/template/search
|
||||
cluster:admin/repository/delete
|
||||
cluster:admin/repository/get
|
||||
cluster:admin/repository/put
|
||||
|
@ -1,4 +1,3 @@
|
||||
cluster:admin/render/template/search
|
||||
cluster:admin/snapshot/status[nodes]
|
||||
cluster:admin/snapshot/status[nodes][n]
|
||||
cluster:admin/tasks/cancel[n]
|
||||
|
@ -31,7 +31,6 @@ import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
|
||||
import org.elasticsearch.xpack.watcher.history.HistoryModule;
|
||||
import org.elasticsearch.xpack.watcher.history.HistoryStore;
|
||||
import org.elasticsearch.xpack.watcher.input.InputModule;
|
||||
import org.elasticsearch.xpack.watcher.input.chain.ChainInputFactory;
|
||||
import org.elasticsearch.xpack.watcher.rest.action.RestAckWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.rest.action.RestActivateWatchAction;
|
||||
import org.elasticsearch.xpack.watcher.rest.action.RestDeleteWatchAction;
|
||||
@ -266,5 +265,5 @@ public class Watcher {
|
||||
"[.watcher-history-YYYY.MM.dd] are allowed to be created", value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,14 +6,14 @@
|
||||
package org.elasticsearch.xpack.watcher.input;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.watcher.input.chain.ChainInput;
|
||||
import org.elasticsearch.xpack.watcher.input.http.HttpInput;
|
||||
import org.elasticsearch.xpack.watcher.input.none.NoneInput;
|
||||
import org.elasticsearch.xpack.watcher.input.search.SearchInput;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -31,12 +31,12 @@ public final class InputBuilders {
|
||||
return NoneInput.builder();
|
||||
}
|
||||
|
||||
public static SearchInput.Builder searchInput(SearchRequest request) {
|
||||
public static SearchInput.Builder searchInput(WatcherSearchTemplateRequest request) {
|
||||
return SearchInput.builder(request);
|
||||
}
|
||||
|
||||
public static SearchInput.Builder searchInput(SearchRequestBuilder builder) {
|
||||
return searchInput(builder.request());
|
||||
public static SearchInput.Builder searchInput(SearchRequest request) {
|
||||
return searchInput(new WatcherSearchTemplateRequest(request));
|
||||
}
|
||||
|
||||
public static SimpleInput.Builder simpleInput() {
|
||||
|
@ -11,16 +11,15 @@ import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
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.search.SearchHit;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.input.ExecutableInput;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.XContentFilterKeysUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
|
||||
import java.util.Map;
|
||||
@ -35,11 +34,14 @@ public class ExecutableSearchInput extends ExecutableInput<SearchInput, SearchIn
|
||||
public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.QUERY_THEN_FETCH;
|
||||
|
||||
private final WatcherClientProxy client;
|
||||
private final WatcherSearchTemplateService searchTemplateService;
|
||||
private final @Nullable TimeValue timeout;
|
||||
|
||||
public ExecutableSearchInput(SearchInput input, ESLogger logger, WatcherClientProxy client, @Nullable TimeValue defaultTimeout) {
|
||||
public ExecutableSearchInput(SearchInput input, ESLogger logger, WatcherClientProxy client,
|
||||
WatcherSearchTemplateService searchTemplateService, @Nullable TimeValue defaultTimeout) {
|
||||
super(input, logger);
|
||||
this.client = client;
|
||||
this.searchTemplateService = searchTemplateService;
|
||||
this.timeout = input.getTimeout() != null ? input.getTimeout() : defaultTimeout;
|
||||
}
|
||||
|
||||
@ -47,7 +49,7 @@ public class ExecutableSearchInput extends ExecutableInput<SearchInput, SearchIn
|
||||
public SearchInput.Result execute(WatchExecutionContext ctx, Payload payload) {
|
||||
SearchRequest request = null;
|
||||
try {
|
||||
request = WatcherUtils.createSearchRequestFromPrototype(input.getSearchRequest(), ctx, payload);
|
||||
request = searchTemplateService.createSearchRequestFromPrototype(input.getRequest(), ctx, payload);
|
||||
return doExecute(ctx, request);
|
||||
} catch (Exception e) {
|
||||
logger.error("failed to execute [{}] input for [{}]", e, SearchInput.TYPE, ctx.watch());
|
||||
@ -57,8 +59,7 @@ public class ExecutableSearchInput extends ExecutableInput<SearchInput, SearchIn
|
||||
|
||||
SearchInput.Result doExecute(WatchExecutionContext ctx, SearchRequest request) throws Exception {
|
||||
if (logger.isTraceEnabled()) {
|
||||
ToXContent source = request.source() != null ? request.source() : request.template();
|
||||
logger.trace("[{}] running query for [{}] [{}]", ctx.id(), ctx.watch().id(), XContentHelper.toString(source));
|
||||
logger.trace("[{}] running query for [{}] [{}]", ctx.id(), ctx.watch().id(), XContentHelper.toString(request.source()));
|
||||
}
|
||||
|
||||
SearchResponse response = client.search(request, timeout);
|
||||
|
@ -17,9 +17,8 @@ import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.watcher.input.Input;
|
||||
import org.elasticsearch.xpack.watcher.support.SearchRequestEquivalence;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
import org.joda.time.DateTimeZone;
|
||||
|
||||
@ -38,14 +37,14 @@ public class SearchInput implements Input {
|
||||
|
||||
public static final String TYPE = "search";
|
||||
|
||||
private final SearchRequest searchRequest;
|
||||
private final WatcherSearchTemplateRequest request;
|
||||
private final @Nullable Set<String> extractKeys;
|
||||
private final @Nullable TimeValue timeout;
|
||||
private final @Nullable DateTimeZone dynamicNameTimeZone;
|
||||
|
||||
public SearchInput(SearchRequest searchRequest, @Nullable Set<String> extractKeys,
|
||||
public SearchInput(WatcherSearchTemplateRequest request, @Nullable Set<String> extractKeys,
|
||||
@Nullable TimeValue timeout, @Nullable DateTimeZone dynamicNameTimeZone) {
|
||||
this.searchRequest = searchRequest;
|
||||
this.request = request;
|
||||
this.extractKeys = extractKeys;
|
||||
this.timeout = timeout;
|
||||
this.dynamicNameTimeZone = dynamicNameTimeZone;
|
||||
@ -63,7 +62,7 @@ public class SearchInput implements Input {
|
||||
|
||||
SearchInput that = (SearchInput) o;
|
||||
|
||||
if (!SearchRequestEquivalence.INSTANCE.equivalent(searchRequest, this.searchRequest)) return false;
|
||||
if (request != null ? !request.equals(that.request) : that.request != null) return false;
|
||||
if (extractKeys != null ? !extractKeys.equals(that.extractKeys) : that.extractKeys != null) return false;
|
||||
if (timeout != null ? !timeout.equals(that.timeout) : that.timeout != null) return false;
|
||||
return !(dynamicNameTimeZone != null ? !dynamicNameTimeZone.equals(that.dynamicNameTimeZone) : that.dynamicNameTimeZone != null);
|
||||
@ -71,15 +70,15 @@ public class SearchInput implements Input {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = searchRequest.hashCode();
|
||||
int result = request != null ? request.hashCode() : 0;
|
||||
result = 31 * result + (extractKeys != null ? extractKeys.hashCode() : 0);
|
||||
result = 31 * result + (timeout != null ? timeout.hashCode() : 0);
|
||||
result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
public SearchRequest getSearchRequest() {
|
||||
return searchRequest;
|
||||
public WatcherSearchTemplateRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public Set<String> getExtractKeys() {
|
||||
@ -97,8 +96,9 @@ public class SearchInput implements Input {
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Field.REQUEST.getPreferredName());
|
||||
builder = WatcherUtils.writeSearchRequest(searchRequest, builder, params);
|
||||
if (request != null) {
|
||||
builder.field(Field.REQUEST.getPreferredName(), request);
|
||||
}
|
||||
if (extractKeys != null) {
|
||||
builder.field(Field.EXTRACT.getPreferredName(), extractKeys);
|
||||
}
|
||||
@ -115,7 +115,7 @@ public class SearchInput implements Input {
|
||||
public static SearchInput parse(String watchId, XContentParser parser, QueryParseContext context,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters)
|
||||
throws IOException {
|
||||
SearchRequest request = null;
|
||||
WatcherSearchTemplateRequest request = null;
|
||||
Set<String> extract = null;
|
||||
TimeValue timeout = null;
|
||||
DateTimeZone dynamicNameTimeZone = null;
|
||||
@ -127,7 +127,7 @@ public class SearchInput implements Input {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
|
||||
try {
|
||||
request = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context,
|
||||
request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context,
|
||||
aggParsers, suggesters);
|
||||
} catch (ElasticsearchParseException srpe) {
|
||||
throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE,
|
||||
@ -170,7 +170,7 @@ public class SearchInput implements Input {
|
||||
return new SearchInput(request, extract, timeout, dynamicNameTimeZone);
|
||||
}
|
||||
|
||||
public static Builder builder(SearchRequest request) {
|
||||
public static Builder builder(WatcherSearchTemplateRequest request) {
|
||||
return new Builder(request);
|
||||
}
|
||||
|
||||
@ -198,20 +198,19 @@ public class SearchInput implements Input {
|
||||
return builder;
|
||||
}
|
||||
builder.startObject(type);
|
||||
builder.field(Field.REQUEST.getPreferredName());
|
||||
WatcherUtils.writeSearchRequest(request, builder, params);
|
||||
builder.field(Field.REQUEST.getPreferredName(), new WatcherSearchTemplateRequest(request));
|
||||
return builder.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder implements Input.Builder<SearchInput> {
|
||||
|
||||
private final SearchRequest request;
|
||||
private final WatcherSearchTemplateRequest request;
|
||||
private final Set<String> extractKeys = new HashSet<>();
|
||||
private TimeValue timeout;
|
||||
private DateTimeZone dynamicNameTimeZone;
|
||||
|
||||
private Builder(SearchRequest request) {
|
||||
private Builder(WatcherSearchTemplateRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,6 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.watcher.input.search;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
@ -17,10 +15,14 @@ import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.security.InternalClient;
|
||||
import org.elasticsearch.xpack.watcher.input.InputFactory;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -33,15 +35,16 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
|
||||
private final AggregatorParsers aggParsers;
|
||||
private final Suggesters suggesters;
|
||||
private final ParseFieldMatcher parseFieldMatcher;
|
||||
private final WatcherSearchTemplateService searchTemplateService;
|
||||
|
||||
@Inject
|
||||
public SearchInputFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters);
|
||||
AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
|
||||
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters, scriptService);
|
||||
}
|
||||
|
||||
public SearchInputFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
|
||||
super(Loggers.getLogger(ExecutableSimpleInput.class, settings));
|
||||
this.parseFieldMatcher = new ParseFieldMatcher(settings);
|
||||
this.client = client;
|
||||
@ -49,6 +52,7 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
|
||||
this.aggParsers = aggParsers;
|
||||
this.suggesters = suggesters;
|
||||
this.defaultTimeout = settings.getAsTime("xpack.watcher.input.search.default_timeout", null);
|
||||
this.searchTemplateService = new WatcherSearchTemplateService(settings, scriptService, queryRegistry, aggParsers, suggesters);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -64,6 +68,6 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
|
||||
|
||||
@Override
|
||||
public ExecutableSearchInput createExecutable(SearchInput input) {
|
||||
return new ExecutableSearchInput(input, inputLogger, client, defaultTimeout);
|
||||
return new ExecutableSearchInput(input, inputLogger, client, searchTemplateService, defaultTimeout);
|
||||
}
|
||||
}
|
||||
|
@ -5,54 +5,22 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.watcher.support;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils.formatDate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
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.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
*/
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils.formatDate;
|
||||
|
||||
public final class WatcherUtils {
|
||||
|
||||
static final ParseField INDICES_FIELD = new ParseField("indices");
|
||||
static final ParseField TYPES_FIELD = new ParseField("types");
|
||||
static final ParseField BODY_FIELD = new ParseField("body");
|
||||
static final ParseField SEARCH_TYPE_FIELD = new ParseField("search_type");
|
||||
static final ParseField INDICES_OPTIONS_FIELD = new ParseField("indices_options");
|
||||
static final ParseField EXPAND_WILDCARDS_FIELD = new ParseField("expand_wildcards");
|
||||
static final ParseField IGNORE_UNAVAILABLE_FIELD = new ParseField("ignore_unavailable");
|
||||
static final ParseField ALLOW_NO_INDICES_FIELD = new ParseField("allow_no_indices");
|
||||
static final ParseField TEMPLATE_FIELD = new ParseField("template");
|
||||
|
||||
public final static IndicesOptions DEFAULT_INDICES_OPTIONS = IndicesOptions.lenientExpandOpen();
|
||||
|
||||
private WatcherUtils() {
|
||||
}
|
||||
@ -62,214 +30,6 @@ public final class WatcherUtils {
|
||||
return XContentHelper.convertToMap(builder.bytes(), false).v2();
|
||||
}
|
||||
|
||||
public static SearchRequest createSearchRequestFromPrototype(SearchRequest requestPrototype, WatchExecutionContext ctx,
|
||||
Payload payload) throws IOException {
|
||||
SearchRequest request = new SearchRequest()
|
||||
.indicesOptions(requestPrototype.indicesOptions())
|
||||
.searchType(requestPrototype.searchType())
|
||||
.indices(requestPrototype.indices())
|
||||
.types(requestPrototype.types());
|
||||
|
||||
// Due the inconsistency with templates in ES 1.x, we maintain our own template format.
|
||||
// This template format we use now, will become the template structure in ES 2.0
|
||||
Map<String, Object> watcherContextParams = Variables.createCtxModel(ctx, payload);
|
||||
if (requestPrototype.source() != null) {
|
||||
// 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,
|
||||
// by ES search template support
|
||||
XContentBuilder builder = jsonBuilder();
|
||||
requestPrototype.source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
Template template = new Template(builder.string(), ScriptType.INLINE, null, builder.contentType(), watcherContextParams);
|
||||
request.template(template);
|
||||
} else if (requestPrototype.template() != null) {
|
||||
// Here we convert watcher template into a ES core templates. Due to the different format we use, we
|
||||
// convert to the template format used in ES core
|
||||
Template template = requestPrototype.template();
|
||||
if (template.getParams() != null) {
|
||||
watcherContextParams.putAll(template.getParams());
|
||||
}
|
||||
template = new Template(template.getScript(), template.getType(), template.getLang(), template.getContentType(),
|
||||
watcherContextParams);
|
||||
request.template(template);
|
||||
// }
|
||||
}
|
||||
// falling back to an empty body
|
||||
return request;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a new search request instance for the specified parser.
|
||||
*/
|
||||
public static SearchRequest readSearchRequest(XContentParser parser, SearchType searchType, QueryParseContext context,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters)
|
||||
throws IOException {
|
||||
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
|
||||
XContentParser.Token token;
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, BODY_FIELD)) {
|
||||
searchRequest.source(SearchSourceBuilder.fromXContent(context, aggParsers, suggesters));
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_FIELD)) {
|
||||
List<String> indices = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
indices.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. expected string values in [" +
|
||||
currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.indices(indices.toArray(new String[indices.size()]));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TYPES_FIELD)) {
|
||||
List<String> types = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
types.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. expected string values in [" +
|
||||
currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.types(types.toArray(new String[types.size()]));
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected array field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_OPTIONS_FIELD)) {
|
||||
boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen();
|
||||
boolean expandClosed = DEFAULT_INDICES_OPTIONS.expandWildcardsClosed();
|
||||
boolean allowNoIndices = DEFAULT_INDICES_OPTIONS.allowNoIndices();
|
||||
boolean ignoreUnavailable = DEFAULT_INDICES_OPTIONS.ignoreUnavailable();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, EXPAND_WILDCARDS_FIELD)) {
|
||||
switch (parser.text()) {
|
||||
case "all":
|
||||
expandOpen = true;
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "open":
|
||||
expandOpen = true;
|
||||
expandClosed = false;
|
||||
break;
|
||||
case "closed":
|
||||
expandOpen = false;
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "none":
|
||||
expandOpen = false;
|
||||
expandClosed = false;
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchParseException("could not read search request. unknown value [" +
|
||||
parser.text() + "] for [" + currentFieldName + "] field ");
|
||||
}
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, IGNORE_UNAVAILABLE_FIELD)) {
|
||||
ignoreUnavailable = parser.booleanValue();
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, ALLOW_NO_INDICES_FIELD)) {
|
||||
allowNoIndices = parser.booleanValue();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected index option [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
}
|
||||
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed,
|
||||
DEFAULT_INDICES_OPTIONS);
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TEMPLATE_FIELD)) {
|
||||
Template template = Template.parse(parser, ParseFieldMatcher.STRICT);
|
||||
searchRequest.template(template);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_FIELD)) {
|
||||
String indicesStr = parser.text();
|
||||
searchRequest.indices(Strings.delimitedListToStringArray(indicesStr, ",", " \t"));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TYPES_FIELD)) {
|
||||
String typesStr = parser.text();
|
||||
searchRequest.types(Strings.delimitedListToStringArray(typesStr, ",", " \t"));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, SEARCH_TYPE_FIELD)) {
|
||||
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT), ParseFieldMatcher.EMPTY);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected string field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected token [" + token + "]");
|
||||
}
|
||||
}
|
||||
|
||||
if (searchRequest.indices() == null) {
|
||||
searchRequest.indices(Strings.EMPTY_ARRAY);
|
||||
}
|
||||
searchRequest.searchType(searchType);
|
||||
searchRequest.indicesOptions(indicesOptions);
|
||||
return searchRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the searchRequest to the specified builder.
|
||||
*/
|
||||
public static XContentBuilder writeSearchRequest(SearchRequest searchRequest, XContentBuilder builder,
|
||||
ToXContent.Params params) throws IOException {
|
||||
if (searchRequest == null) {
|
||||
builder.nullValue();
|
||||
return builder;
|
||||
}
|
||||
|
||||
builder.startObject();
|
||||
if (searchRequest.searchType() != null) {
|
||||
builder.field(SEARCH_TYPE_FIELD.getPreferredName(), searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (searchRequest.indices() != null) {
|
||||
builder.array(INDICES_FIELD.getPreferredName(), searchRequest.indices());
|
||||
}
|
||||
if (searchRequest.types() != null) {
|
||||
builder.array(TYPES_FIELD.getPreferredName(), searchRequest.types());
|
||||
}
|
||||
if (searchRequest.source() != null) {
|
||||
builder.field(BODY_FIELD.getPreferredName(), searchRequest.source());
|
||||
}
|
||||
if (searchRequest.template() != null) {
|
||||
builder.field(TEMPLATE_FIELD.getPreferredName(), searchRequest.template());
|
||||
}
|
||||
|
||||
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||
IndicesOptions options = searchRequest.indicesOptions();
|
||||
builder.startObject(INDICES_OPTIONS_FIELD.getPreferredName());
|
||||
String value;
|
||||
if (options.expandWildcardsClosed() && options.expandWildcardsOpen()) {
|
||||
value = "all";
|
||||
} else if (options.expandWildcardsOpen()) {
|
||||
value = "open";
|
||||
} else if (options.expandWildcardsClosed()) {
|
||||
value = "closed";
|
||||
} else {
|
||||
value = "none";
|
||||
}
|
||||
builder.field(EXPAND_WILDCARDS_FIELD.getPreferredName(), value);
|
||||
builder.field(IGNORE_UNAVAILABLE_FIELD.getPreferredName(), options.ignoreUnavailable());
|
||||
builder.field(ALLOW_NO_INDICES_FIELD.getPreferredName(), options.allowNoIndices());
|
||||
builder.endObject();
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public static Map<String, Object> flattenModel(Map<String, Object> map) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
flattenModel("", map, result);
|
||||
|
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.watcher.support.search;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
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.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
import org.elasticsearch.xpack.watcher.support.SearchRequestEquivalence;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A {@link WatcherSearchTemplateRequest} contains the search request and the eventual template that will
|
||||
* be rendered as a script by {@link WatcherSearchTemplateService} before being executed.
|
||||
*/
|
||||
public class WatcherSearchTemplateRequest implements ToXContent {
|
||||
|
||||
private final SearchRequest request;
|
||||
private final @Nullable Script template;
|
||||
|
||||
public WatcherSearchTemplateRequest(SearchRequest searchRequest, @Nullable Script template) {
|
||||
this.request = Objects.requireNonNull(searchRequest);
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
public WatcherSearchTemplateRequest(SearchRequest request) {
|
||||
this(request, null);
|
||||
}
|
||||
|
||||
public SearchRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
public Script getTemplate() {
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (request != null) {
|
||||
if (request.searchType() != null) {
|
||||
builder.field(SEARCH_TYPE_FIELD.getPreferredName(), request.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (request.indices() != null) {
|
||||
builder.array(INDICES_FIELD.getPreferredName(), request.indices());
|
||||
}
|
||||
if (request.types() != null) {
|
||||
builder.array(TYPES_FIELD.getPreferredName(), request.types());
|
||||
}
|
||||
if (request.source() != null) {
|
||||
builder.field(BODY_FIELD.getPreferredName(), request.source());
|
||||
}
|
||||
if (request.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||
IndicesOptions options = request.indicesOptions();
|
||||
builder.startObject(INDICES_OPTIONS_FIELD.getPreferredName());
|
||||
String value;
|
||||
if (options.expandWildcardsClosed() && options.expandWildcardsOpen()) {
|
||||
value = "all";
|
||||
} else if (options.expandWildcardsOpen()) {
|
||||
value = "open";
|
||||
} else if (options.expandWildcardsClosed()) {
|
||||
value = "closed";
|
||||
} else {
|
||||
value = "none";
|
||||
}
|
||||
builder.field(EXPAND_WILDCARDS_FIELD.getPreferredName(), value);
|
||||
builder.field(IGNORE_UNAVAILABLE_FIELD.getPreferredName(), options.ignoreUnavailable());
|
||||
builder.field(ALLOW_NO_INDICES_FIELD.getPreferredName(), options.allowNoIndices());
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
||||
if (template != null) {
|
||||
builder.field(TEMPLATE_FIELD.getPreferredName(), template);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads a new watcher search request instance for the specified parser.
|
||||
*/
|
||||
public static WatcherSearchTemplateRequest fromXContent(XContentParser parser, SearchType searchType, QueryParseContext context,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters)
|
||||
throws IOException {
|
||||
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
SearchRequest searchRequest = new SearchRequest();
|
||||
Script template = null;
|
||||
|
||||
XContentParser.Token token;
|
||||
String currentFieldName = null;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, BODY_FIELD)) {
|
||||
searchRequest.source(SearchSourceBuilder.fromXContent(context, aggParsers, suggesters));
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_FIELD)) {
|
||||
List<String> indices = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
indices.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. expected string values in [" +
|
||||
currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.indices(indices.toArray(new String[indices.size()]));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TYPES_FIELD)) {
|
||||
List<String> types = new ArrayList<>();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
types.add(parser.textOrNull());
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. expected string values in [" +
|
||||
currentFieldName + "] field, but instead found [" + token + "]");
|
||||
}
|
||||
}
|
||||
searchRequest.types(types.toArray(new String[types.size()]));
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected array field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_OPTIONS_FIELD)) {
|
||||
boolean expandOpen = DEFAULT_INDICES_OPTIONS.expandWildcardsOpen();
|
||||
boolean expandClosed = DEFAULT_INDICES_OPTIONS.expandWildcardsClosed();
|
||||
boolean allowNoIndices = DEFAULT_INDICES_OPTIONS.allowNoIndices();
|
||||
boolean ignoreUnavailable = DEFAULT_INDICES_OPTIONS.ignoreUnavailable();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, EXPAND_WILDCARDS_FIELD)) {
|
||||
switch (parser.text()) {
|
||||
case "all":
|
||||
expandOpen = true;
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "open":
|
||||
expandOpen = true;
|
||||
expandClosed = false;
|
||||
break;
|
||||
case "closed":
|
||||
expandOpen = false;
|
||||
expandClosed = true;
|
||||
break;
|
||||
case "none":
|
||||
expandOpen = false;
|
||||
expandClosed = false;
|
||||
break;
|
||||
default:
|
||||
throw new ElasticsearchParseException("could not read search request. unknown value [" +
|
||||
parser.text() + "] for [" + currentFieldName + "] field ");
|
||||
}
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, IGNORE_UNAVAILABLE_FIELD)) {
|
||||
ignoreUnavailable = parser.booleanValue();
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, ALLOW_NO_INDICES_FIELD)) {
|
||||
allowNoIndices = parser.booleanValue();
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected index option [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
}
|
||||
indicesOptions = IndicesOptions.fromOptions(ignoreUnavailable, allowNoIndices, expandOpen, expandClosed,
|
||||
DEFAULT_INDICES_OPTIONS);
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TEMPLATE_FIELD)) {
|
||||
template = Script.parse(parser);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected object field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
if (ParseFieldMatcher.STRICT.match(currentFieldName, INDICES_FIELD)) {
|
||||
String indicesStr = parser.text();
|
||||
searchRequest.indices(Strings.delimitedListToStringArray(indicesStr, ",", " \t"));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, TYPES_FIELD)) {
|
||||
String typesStr = parser.text();
|
||||
searchRequest.types(Strings.delimitedListToStringArray(typesStr, ",", " \t"));
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, SEARCH_TYPE_FIELD)) {
|
||||
searchType = SearchType.fromString(parser.text().toLowerCase(Locale.ROOT), ParseFieldMatcher.EMPTY);
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected string field [" +
|
||||
currentFieldName + "]");
|
||||
}
|
||||
} else {
|
||||
throw new ElasticsearchParseException("could not read search request. unexpected token [" + token + "]");
|
||||
}
|
||||
}
|
||||
|
||||
if (searchRequest.indices() == null) {
|
||||
searchRequest.indices(Strings.EMPTY_ARRAY);
|
||||
}
|
||||
searchRequest.searchType(searchType);
|
||||
searchRequest.indicesOptions(indicesOptions);
|
||||
return new WatcherSearchTemplateRequest(searchRequest, template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
WatcherSearchTemplateRequest that = (WatcherSearchTemplateRequest) o;
|
||||
|
||||
if (!SearchRequestEquivalence.INSTANCE.equivalent(request, that.request)) return false;
|
||||
return template != null ? template.equals(that.template) : that.template == null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = request != null ? request.hashCode() : 0;
|
||||
result = 31 * result + (template != null ? template.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
static final ParseField INDICES_FIELD = new ParseField("indices");
|
||||
static final ParseField TYPES_FIELD = new ParseField("types");
|
||||
static final ParseField BODY_FIELD = new ParseField("body");
|
||||
static final ParseField SEARCH_TYPE_FIELD = new ParseField("search_type");
|
||||
static final ParseField INDICES_OPTIONS_FIELD = new ParseField("indices_options");
|
||||
static final ParseField EXPAND_WILDCARDS_FIELD = new ParseField("expand_wildcards");
|
||||
static final ParseField IGNORE_UNAVAILABLE_FIELD = new ParseField("ignore_unavailable");
|
||||
static final ParseField ALLOW_NO_INDICES_FIELD = new ParseField("allow_no_indices");
|
||||
static final ParseField TEMPLATE_FIELD = new ParseField("template");
|
||||
|
||||
public final static IndicesOptions DEFAULT_INDICES_OPTIONS = IndicesOptions.lenientExpandOpen();
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.xpack.watcher.support.search;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.common.ParseFieldMatcher;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
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.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
import org.elasticsearch.xpack.watcher.support.Variables;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
|
||||
/**
|
||||
* {@link WatcherSearchTemplateService} renders {@link WatcherSearchTemplateRequest} before their execution.
|
||||
*/
|
||||
public class WatcherSearchTemplateService extends AbstractComponent {
|
||||
|
||||
private static final String DEFAULT_LANG = "mustache";
|
||||
|
||||
private final ScriptServiceProxy scriptService;
|
||||
private final ParseFieldMatcher parseFieldMatcher;
|
||||
private final IndicesQueriesRegistry queryRegistry;
|
||||
private final AggregatorParsers aggsParsers;
|
||||
private final Suggesters suggesters;
|
||||
|
||||
@Inject
|
||||
public WatcherSearchTemplateService(Settings settings, ScriptServiceProxy scriptServiceProxy,
|
||||
IndicesQueriesRegistry queryRegistry, AggregatorParsers aggregatorParsers, Suggesters suggesters) {
|
||||
super(settings);
|
||||
this.scriptService = scriptServiceProxy;
|
||||
this.queryRegistry = queryRegistry;
|
||||
this.aggsParsers = aggregatorParsers;
|
||||
this.suggesters = suggesters;
|
||||
this.parseFieldMatcher = new ParseFieldMatcher(settings);
|
||||
}
|
||||
|
||||
public SearchRequest createSearchRequestFromPrototype(WatcherSearchTemplateRequest prototype, WatchExecutionContext ctx,
|
||||
Payload payload) throws IOException {
|
||||
|
||||
SearchRequest request = new SearchRequest()
|
||||
.indicesOptions(prototype.getRequest().indicesOptions())
|
||||
.searchType(prototype.getRequest().searchType())
|
||||
.indices(prototype.getRequest().indices())
|
||||
.types(prototype.getRequest().types());
|
||||
|
||||
Script template = null;
|
||||
|
||||
// Due the inconsistency with templates in ES 1.x, we maintain our own template format.
|
||||
// This template format we use now, will become the template structure in ES 2.0
|
||||
Map<String, Object> watcherContextParams = Variables.createCtxModel(ctx, payload);
|
||||
|
||||
// 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.
|
||||
if (prototype.getRequest().source() != null) {
|
||||
try (XContentBuilder builder = jsonBuilder()) {
|
||||
prototype.getRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
template = Script.inline(builder.string()).lang(DEFAULT_LANG).params(watcherContextParams).build();
|
||||
}
|
||||
|
||||
} else if (prototype.getTemplate() != null) {
|
||||
// Here we convert watcher template into a ES core templates. Due to the different format we use, we
|
||||
// convert to the template format used in ES core
|
||||
Script templatePrototype = prototype.getTemplate();
|
||||
if (templatePrototype.params() != null) {
|
||||
watcherContextParams.putAll(templatePrototype.params());
|
||||
}
|
||||
|
||||
Script.Builder builder;
|
||||
if (templatePrototype.type() == ScriptService.ScriptType.INLINE) {
|
||||
builder = Script.inline(templatePrototype.script());
|
||||
} else if (templatePrototype.type() == ScriptService.ScriptType.FILE) {
|
||||
builder = Script.file(templatePrototype.script());
|
||||
} else if (templatePrototype.type() == ScriptService.ScriptType.STORED) {
|
||||
builder = Script.indexed(templatePrototype.script());
|
||||
} else {
|
||||
builder = Script.defaultType(templatePrototype.script());
|
||||
}
|
||||
template = builder.lang(templatePrototype.lang()).params(watcherContextParams).build();
|
||||
}
|
||||
|
||||
request.source(convert(template));
|
||||
return request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link Script} to a {@link org.elasticsearch.search.builder.SearchSourceBuilder}
|
||||
*/
|
||||
private SearchSourceBuilder convert(Script template) throws IOException {
|
||||
SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
|
||||
if (template == null) {
|
||||
// falling back to an empty body
|
||||
return sourceBuilder;
|
||||
}
|
||||
|
||||
BytesReference source = (BytesReference) scriptService.executable(scriptService.compile(template), template.params()).run();
|
||||
if (source != null && source.length() > 0) {
|
||||
try (XContentParser parser = XContentFactory.xContent(source).createParser(source)) {
|
||||
sourceBuilder.parseXContent(new QueryParseContext(queryRegistry, parser, parseFieldMatcher), aggsParsers, suggesters);
|
||||
}
|
||||
}
|
||||
return sourceBuilder;
|
||||
}
|
||||
}
|
@ -6,8 +6,8 @@
|
||||
package org.elasticsearch.xpack.watcher.transform;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform;
|
||||
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform;
|
||||
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
|
||||
@ -20,12 +20,12 @@ public final class TransformBuilders {
|
||||
private TransformBuilders() {
|
||||
}
|
||||
|
||||
public static SearchTransform.Builder searchTransform(SearchRequest request) {
|
||||
public static SearchTransform.Builder searchTransform(WatcherSearchTemplateRequest request) {
|
||||
return SearchTransform.builder(request);
|
||||
}
|
||||
|
||||
public static SearchTransform.Builder searchTransform(SearchRequestBuilder request) {
|
||||
return searchTransform(request.request());
|
||||
public static SearchTransform.Builder searchTransform(SearchRequest request) {
|
||||
return searchTransform(new WatcherSearchTemplateRequest(request));
|
||||
}
|
||||
|
||||
public static ScriptTransform.Builder scriptTransform(String script) {
|
||||
|
@ -12,8 +12,8 @@ import org.elasticsearch.common.Nullable;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
|
||||
@ -25,12 +25,14 @@ public class ExecutableSearchTransform extends ExecutableTransform<SearchTransfo
|
||||
public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.QUERY_THEN_FETCH;
|
||||
|
||||
protected final WatcherClientProxy client;
|
||||
private final WatcherSearchTemplateService searchTemplateService;
|
||||
protected final @Nullable TimeValue timeout;
|
||||
|
||||
public ExecutableSearchTransform(SearchTransform transform, ESLogger logger, WatcherClientProxy client,
|
||||
@Nullable TimeValue defaultTimeout) {
|
||||
WatcherSearchTemplateService searchTemplateService, @Nullable TimeValue defaultTimeout) {
|
||||
super(transform, logger);
|
||||
this.client = client;
|
||||
this.searchTemplateService = searchTemplateService;
|
||||
this.timeout = transform.getTimeout() != null ? transform.getTimeout() : defaultTimeout;
|
||||
}
|
||||
|
||||
@ -38,7 +40,7 @@ public class ExecutableSearchTransform extends ExecutableTransform<SearchTransfo
|
||||
public SearchTransform.Result execute(WatchExecutionContext ctx, Payload payload) {
|
||||
SearchRequest request = null;
|
||||
try {
|
||||
request = WatcherUtils.createSearchRequestFromPrototype(transform.getRequest(), ctx, payload);
|
||||
request = searchTemplateService.createSearchRequestFromPrototype(transform.getRequest(), ctx, payload);
|
||||
SearchResponse resp = client.search(request, timeout);
|
||||
return new SearchTransform.Result(request, new Payload.XContent(resp));
|
||||
} catch (Exception e) {
|
||||
|
@ -16,9 +16,8 @@ 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.xpack.watcher.support.SearchRequestEquivalence;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.transform.Transform;
|
||||
import org.elasticsearch.xpack.watcher.watch.Payload;
|
||||
import org.joda.time.DateTimeZone;
|
||||
@ -32,11 +31,11 @@ public class SearchTransform implements Transform {
|
||||
|
||||
public static final String TYPE = "search";
|
||||
|
||||
private final SearchRequest request;
|
||||
private final WatcherSearchTemplateRequest request;
|
||||
private final @Nullable TimeValue timeout;
|
||||
private final @Nullable DateTimeZone dynamicNameTimeZone;
|
||||
|
||||
public SearchTransform(SearchRequest request, @Nullable TimeValue timeout, @Nullable DateTimeZone dynamicNameTimeZone) {
|
||||
public SearchTransform(WatcherSearchTemplateRequest request, @Nullable TimeValue timeout, @Nullable DateTimeZone dynamicNameTimeZone) {
|
||||
this.request = request;
|
||||
this.timeout = timeout;
|
||||
this.dynamicNameTimeZone = dynamicNameTimeZone;
|
||||
@ -47,7 +46,7 @@ public class SearchTransform implements Transform {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public SearchRequest getRequest() {
|
||||
public WatcherSearchTemplateRequest getRequest() {
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -66,14 +65,14 @@ public class SearchTransform implements Transform {
|
||||
|
||||
SearchTransform that = (SearchTransform) o;
|
||||
|
||||
if (!SearchRequestEquivalence.INSTANCE.equivalent(request, this.request)) return false;
|
||||
if (request != null ? !request.equals(that.request) : that.request != null) return false;
|
||||
if (timeout != null ? !timeout.equals(that.timeout) : that.timeout != null) return false;
|
||||
return !(dynamicNameTimeZone != null ? !dynamicNameTimeZone.equals(that.dynamicNameTimeZone) : that.dynamicNameTimeZone != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = request.hashCode();
|
||||
int result = request != null ? request.hashCode() : 0;
|
||||
result = 31 * result + (timeout != null ? timeout.hashCode() : 0);
|
||||
result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0);
|
||||
return result;
|
||||
@ -82,8 +81,9 @@ public class SearchTransform implements Transform {
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Field.REQUEST.getPreferredName());
|
||||
builder = WatcherUtils.writeSearchRequest(request, builder, params);
|
||||
if (request != null) {
|
||||
builder.field(Field.REQUEST.getPreferredName(), request);
|
||||
}
|
||||
if (timeout != null) {
|
||||
builder.field(Field.TIMEOUT.getPreferredName(), timeout);
|
||||
}
|
||||
@ -97,7 +97,7 @@ public class SearchTransform implements Transform {
|
||||
public static SearchTransform parse(String watchId, XContentParser parser, QueryParseContext context,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters)
|
||||
throws IOException {
|
||||
SearchRequest request = null;
|
||||
WatcherSearchTemplateRequest request = null;
|
||||
TimeValue timeout = null;
|
||||
DateTimeZone dynamicNameTimeZone = null;
|
||||
|
||||
@ -108,7 +108,7 @@ public class SearchTransform implements Transform {
|
||||
currentFieldName = parser.currentName();
|
||||
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
|
||||
try {
|
||||
request = WatcherUtils.readSearchRequest(parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE, context,
|
||||
request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE, context,
|
||||
aggParsers, suggesters);
|
||||
} catch (ElasticsearchParseException srpe) {
|
||||
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe,
|
||||
@ -136,7 +136,7 @@ public class SearchTransform implements Transform {
|
||||
return new SearchTransform(request, timeout, dynamicNameTimeZone);
|
||||
}
|
||||
|
||||
public static Builder builder(SearchRequest request) {
|
||||
public static Builder builder(WatcherSearchTemplateRequest request) {
|
||||
return new Builder(request);
|
||||
}
|
||||
|
||||
@ -162,8 +162,7 @@ public class SearchTransform implements Transform {
|
||||
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (request != null) {
|
||||
builder.startObject(type);
|
||||
builder.field(Field.REQUEST.getPreferredName());
|
||||
WatcherUtils.writeSearchRequest(request, builder, params);
|
||||
builder.field(Field.REQUEST.getPreferredName(), new WatcherSearchTemplateRequest(request));
|
||||
builder.endObject();
|
||||
}
|
||||
return builder;
|
||||
@ -172,11 +171,11 @@ public class SearchTransform implements Transform {
|
||||
|
||||
public static class Builder implements Transform.Builder<SearchTransform> {
|
||||
|
||||
private final SearchRequest request;
|
||||
private final WatcherSearchTemplateRequest request;
|
||||
private TimeValue timeout;
|
||||
private DateTimeZone dynamicNameTimeZone;
|
||||
|
||||
public Builder(SearchRequest request) {
|
||||
public Builder(WatcherSearchTemplateRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,9 @@ import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.search.aggregations.AggregatorParsers;
|
||||
import org.elasticsearch.search.suggest.Suggesters;
|
||||
import org.elasticsearch.xpack.security.InternalClient;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.transform.TransformFactory;
|
||||
|
||||
/**
|
||||
@ -32,14 +34,15 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
|
||||
private final AggregatorParsers aggParsers;
|
||||
private final Suggesters suggesters;
|
||||
private final ParseFieldMatcher parseFieldMatcher;
|
||||
private final WatcherSearchTemplateService searchTemplateService;
|
||||
|
||||
@Inject
|
||||
public SearchTransformFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters);
|
||||
AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
|
||||
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters, scriptService);
|
||||
}
|
||||
public SearchTransformFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry,
|
||||
AggregatorParsers aggParsers, Suggesters suggesters) {
|
||||
AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
|
||||
super(Loggers.getLogger(ExecutableSearchTransform.class, settings));
|
||||
this.client = client;
|
||||
this.parseFieldMatcher = new ParseFieldMatcher(settings);
|
||||
@ -47,6 +50,7 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
|
||||
this.aggParsers = aggParsers;
|
||||
this.suggesters = suggesters;
|
||||
this.defaultTimeout = settings.getAsTime("xpack.watcher.transform.search.default_timeout", null);
|
||||
this.searchTemplateService = new WatcherSearchTemplateService(settings, scriptService, queryRegistry, aggParsers, suggesters);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -62,6 +66,6 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
|
||||
|
||||
@Override
|
||||
public ExecutableSearchTransform createExecutable(SearchTransform transform) {
|
||||
return new ExecutableSearchTransform(transform, transformLogger, client, defaultTimeout);
|
||||
return new ExecutableSearchTransform(transform, transformLogger, client, searchTemplateService, defaultTimeout);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase
|
||||
|
||||
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("foo").addSort(SortBuilders.fieldSort("inner.date").order
|
||||
(SortOrder.DESC));
|
||||
builder.input(InputBuilders.chainInput().add("first", InputBuilders.searchInput(searchRequestBuilder)));
|
||||
builder.input(InputBuilders.chainInput().add("first", InputBuilders.searchInput(searchRequestBuilder.request())));
|
||||
|
||||
PutWatchResponse response = watcherClient().preparePutWatch("test_watch").setSource(builder).get();
|
||||
assertThat(response.isCreated(), is(true));
|
||||
|
@ -31,6 +31,7 @@ import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.common.secret.SecretService;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
|
||||
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
|
||||
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
|
||||
@ -238,7 +239,7 @@ public class WebhookActionTests extends ESTestCase {
|
||||
|
||||
ExecutableWebhookAction executable = new ExecutableWebhookAction(action, logger, httpClient, templateEngine);
|
||||
String watchId = "test_url_encode" + randomAsciiOfLength(10);
|
||||
Watch watch = createWatch(watchId, mock(WatcherClientProxy.class), "account1");
|
||||
Watch watch = createWatch(watchId, "account1");
|
||||
WatchExecutionContext ctx = new TriggeredExecutionContext(watch, new DateTime(UTC),
|
||||
new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5));
|
||||
executable.execute("_id", ctx, new Payload.Simple());
|
||||
@ -264,16 +265,16 @@ public class WebhookActionTests extends ESTestCase {
|
||||
|
||||
ExecutableWebhookAction executable = new ExecutableWebhookAction(action, logger, client, templateEngine);
|
||||
|
||||
Watch watch = createWatch(watchId, mock(WatcherClientProxy.class), "account1");
|
||||
Watch watch = createWatch(watchId, "account1");
|
||||
WatchExecutionContext ctx = new TriggeredExecutionContext(watch, new DateTime(UTC),
|
||||
new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5));
|
||||
Action.Result result = executable.execute("_id", ctx, new Payload.Simple());
|
||||
assertThat(result, Matchers.instanceOf(WebhookAction.Result.Success.class));
|
||||
}
|
||||
|
||||
private Watch createWatch(String watchId, WatcherClientProxy client, final String account) throws AddressException, IOException {
|
||||
private Watch createWatch(String watchId, final String account) throws AddressException, IOException {
|
||||
return WatcherTestUtils.createTestWatch(watchId,
|
||||
client,
|
||||
mock(WatcherClientProxy.class),
|
||||
ExecuteScenario.Success.client(),
|
||||
new AbstractWatcherIntegrationTestCase.NoopEmailService() {
|
||||
@Override
|
||||
@ -286,6 +287,7 @@ public class WebhookActionTests extends ESTestCase {
|
||||
return new EmailSent(account, email);
|
||||
}
|
||||
},
|
||||
mock(WatcherSearchTemplateService.class),
|
||||
logger);
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher.execution;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
|
||||
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
|
||||
@ -21,7 +22,8 @@ import static org.hamcrest.Matchers.equalTo;
|
||||
*/
|
||||
public class TriggeredWatchTests extends AbstractWatcherIntegrationTestCase {
|
||||
public void testParser() throws Exception {
|
||||
Watch watch = WatcherTestUtils.createTestWatch("fired_test", watcherHttpClient(), noopEmailService(), logger);
|
||||
Watch watch = WatcherTestUtils.createTestWatch("fired_test", watcherHttpClient(), noopEmailService(),
|
||||
watcherSearchTemplateService(), logger);
|
||||
ScheduleTriggerEvent event = new ScheduleTriggerEvent(watch.id(), DateTime.now(DateTimeZone.UTC), DateTime.now(DateTimeZone.UTC));
|
||||
Wid wid = new Wid("_record", randomLong(), DateTime.now(DateTimeZone.UTC));
|
||||
TriggeredWatch triggeredWatch = new TriggeredWatch(wid, event);
|
||||
@ -38,4 +40,8 @@ public class TriggeredWatchTests extends AbstractWatcherIntegrationTestCase {
|
||||
private TriggeredWatch.Parser triggeredWatchParser() {
|
||||
return internalCluster().getInstance(TriggeredWatch.Parser.class);
|
||||
}
|
||||
|
||||
protected WatcherSearchTemplateService watcherSearchTemplateService() {
|
||||
return internalCluster().getInstance(WatcherSearchTemplateService.class);
|
||||
}
|
||||
}
|
||||
|
@ -6,23 +6,6 @@
|
||||
package org.elasticsearch.xpack.watcher.support;
|
||||
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils.formatDate;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherUtils.DEFAULT_INDICES_OPTIONS;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherUtils.flattenModel;
|
||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
@ -40,15 +23,30 @@ import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.query.QueryParseContext;
|
||||
import org.elasticsearch.index.query.QueryParser;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput.DEFAULT_SEARCH_TYPE;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils.formatDate;
|
||||
import static org.elasticsearch.xpack.watcher.support.WatcherUtils.flattenModel;
|
||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
|
||||
import static org.hamcrest.Matchers.arrayContainingInAnyOrder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasEntry;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -100,6 +98,7 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
public void testSerializeSearchRequest() throws Exception {
|
||||
String[] randomIndices = generateRandomStringArray(5, 5, false);
|
||||
SearchRequest expectedRequest = new SearchRequest(randomIndices);
|
||||
Script expectedTemplate = null;
|
||||
|
||||
if (randomBoolean()) {
|
||||
String[] randomTypes = generateRandomStringArray(2, 5, false);
|
||||
@ -107,7 +106,7 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
}
|
||||
|
||||
expectedRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(),
|
||||
randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS));
|
||||
randomBoolean(), WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS));
|
||||
expectedRequest.searchType(getRandomSupportedSearchType());
|
||||
|
||||
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource().query(QueryBuilders.matchAllQuery()).size(11);
|
||||
@ -122,30 +121,29 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
}
|
||||
}
|
||||
String text = randomAsciiOfLengthBetween(1, 5);
|
||||
Template template = randomFrom(
|
||||
new Template(text, ScriptType.INLINE, null, null, params),
|
||||
new Template(text, ScriptType.FILE, null, null, params),
|
||||
new Template(text, ScriptType.STORED, null, null, params)
|
||||
);
|
||||
expectedRequest.template(template);
|
||||
expectedTemplate = randomFrom(Script.inline(text), Script.file(text), Script.indexed(text)).params(params).build();
|
||||
}
|
||||
|
||||
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(expectedRequest, expectedTemplate);
|
||||
|
||||
XContentBuilder builder = jsonBuilder();
|
||||
builder = WatcherUtils.writeSearchRequest(expectedRequest, builder, ToXContent.EMPTY_PARAMS);
|
||||
request.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
XContentParser parser = XContentHelper.createParser(builder.bytes());
|
||||
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
|
||||
IndicesQueriesRegistry registry = new IndicesQueriesRegistry();
|
||||
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
|
||||
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
|
||||
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT);
|
||||
SearchRequest result = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context, null, null);
|
||||
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE, context, null, null);
|
||||
|
||||
assertThat(result.indices(), arrayContainingInAnyOrder(expectedRequest.indices()));
|
||||
assertThat(result.types(), arrayContainingInAnyOrder(expectedRequest.types()));
|
||||
assertThat(result.indicesOptions(), equalTo(expectedRequest.indicesOptions()));
|
||||
assertThat(result.searchType(), equalTo(expectedRequest.searchType()));
|
||||
assertThat(result.source(), equalTo(searchSourceBuilder));
|
||||
assertThat(result.template(), equalTo(expectedRequest.template()));
|
||||
assertThat(result.getRequest(), is(notNullValue()));
|
||||
assertThat(result.getRequest().indices(), arrayContainingInAnyOrder(expectedRequest.indices()));
|
||||
assertThat(result.getRequest().types(), arrayContainingInAnyOrder(expectedRequest.types()));
|
||||
assertThat(result.getRequest().indicesOptions(), equalTo(expectedRequest.indicesOptions()));
|
||||
assertThat(result.getRequest().searchType(), equalTo(expectedRequest.searchType()));
|
||||
assertThat(result.getRequest().source(), equalTo(searchSourceBuilder));
|
||||
|
||||
assertThat(result.getTemplate(), equalTo(expectedTemplate));
|
||||
}
|
||||
|
||||
public void testDeserializeSearchRequest() throws Exception {
|
||||
@ -172,10 +170,10 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
IndicesOptions indicesOptions = DEFAULT_INDICES_OPTIONS;
|
||||
IndicesOptions indicesOptions = WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS;
|
||||
if (randomBoolean()) {
|
||||
indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(),
|
||||
randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS);
|
||||
randomBoolean(), WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS);
|
||||
builder.startObject("indices_options")
|
||||
.field("allow_no_indices", indicesOptions.allowNoIndices())
|
||||
.field("expand_wildcards", indicesOptions.expandWildcardsClosed() && indicesOptions.expandWildcardsOpen() ? "all" :
|
||||
@ -201,7 +199,7 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
source = searchSourceBuilder.buildAsBytes(XContentType.JSON);
|
||||
builder.rawField("body", source);
|
||||
}
|
||||
Template templateSource = null;
|
||||
Script template = null;
|
||||
if (randomBoolean()) {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
if (randomBoolean()) {
|
||||
@ -211,14 +209,8 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
}
|
||||
}
|
||||
String text = randomAsciiOfLengthBetween(1, 5);
|
||||
TextTemplate template = randomFrom(
|
||||
TextTemplate.inline(text).params(params).build(),
|
||||
TextTemplate.file(text).params(params).build(),
|
||||
TextTemplate.indexed(text).params(params).build()
|
||||
);
|
||||
template = randomFrom(Script.inline(text), Script.file(text), Script.indexed(text)) .params(params).build();
|
||||
builder.field("template", template);
|
||||
templateSource = new Template(template.getTemplate(), template.getType(), null, template.getContentType(),
|
||||
template.getParams());
|
||||
}
|
||||
builder.endObject();
|
||||
|
||||
@ -228,14 +220,15 @@ public class WatcherUtilsTests extends ESTestCase {
|
||||
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
|
||||
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
|
||||
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT);
|
||||
SearchRequest result = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context, null, null);
|
||||
WatcherSearchTemplateRequest result = WatcherSearchTemplateRequest.fromXContent(parser, DEFAULT_SEARCH_TYPE, context, null, null);
|
||||
|
||||
assertThat(result.indices(), arrayContainingInAnyOrder(indices));
|
||||
assertThat(result.types(), arrayContainingInAnyOrder(types));
|
||||
assertThat(result.indicesOptions(), equalTo(indicesOptions));
|
||||
assertThat(result.searchType(), equalTo(searchType));
|
||||
assertThat(result.source(), equalTo(searchSourceBuilder));
|
||||
assertThat(result.template(), equalTo(templateSource));
|
||||
assertThat(result.getRequest(), is(notNullValue()));
|
||||
assertThat(result.getRequest().indices(), arrayContainingInAnyOrder(indices));
|
||||
assertThat(result.getRequest().types(), arrayContainingInAnyOrder(types));
|
||||
assertThat(result.getRequest().indicesOptions(), equalTo(indicesOptions));
|
||||
assertThat(result.getRequest().searchType(), equalTo(searchType));
|
||||
assertThat(result.getRequest().source(), equalTo(searchSourceBuilder));
|
||||
assertThat(result.getTemplate(), equalTo(template));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,13 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.test.ESIntegTestCase;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.watcher.ResourceWatcherService;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.common.secret.Secret;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.notification.email.Authentication;
|
||||
import org.elasticsearch.xpack.notification.email.EmailService;
|
||||
import org.elasticsearch.xpack.notification.email.EmailTemplate;
|
||||
@ -49,15 +56,9 @@ import org.elasticsearch.xpack.watcher.execution.Wid;
|
||||
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
|
||||
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.common.secret.Secret;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
|
||||
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
|
||||
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
|
||||
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
|
||||
@ -76,7 +77,6 @@ import javax.mail.internet.AddressException;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
@ -122,7 +122,7 @@ public final class WatcherTestUtils {
|
||||
public static SearchRequest newInputSearchRequest(String... indices) {
|
||||
SearchRequest request = new SearchRequest();
|
||||
request.indices(indices);
|
||||
request.indicesOptions(WatcherUtils.DEFAULT_INDICES_OPTIONS);
|
||||
request.indicesOptions(WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS);
|
||||
request.searchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE);
|
||||
return request;
|
||||
}
|
||||
@ -175,13 +175,14 @@ public final class WatcherTestUtils {
|
||||
|
||||
|
||||
public static Watch createTestWatch(String watchName, HttpClient httpClient, EmailService emailService,
|
||||
ESLogger logger) throws AddressException {
|
||||
return createTestWatch(watchName, WatcherClientProxy.of(ESIntegTestCase.client()), httpClient, emailService, logger);
|
||||
WatcherSearchTemplateService searchTemplateService, ESLogger logger) throws AddressException {
|
||||
WatcherClientProxy client = WatcherClientProxy.of(ESIntegTestCase.client());
|
||||
return createTestWatch(watchName, client, httpClient, emailService, searchTemplateService, logger);
|
||||
}
|
||||
|
||||
|
||||
public static Watch createTestWatch(String watchName, WatcherClientProxy client, HttpClient httpClient, EmailService emailService,
|
||||
ESLogger logger) throws AddressException {
|
||||
WatcherSearchTemplateService searchTemplateService, ESLogger logger) throws AddressException {
|
||||
|
||||
SearchRequest conditionRequest = newInputSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest transformRequest = newInputSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||
@ -229,12 +230,15 @@ public final class WatcherTestUtils {
|
||||
Map<String, ActionStatus> statuses = new HashMap<>();
|
||||
statuses.put("_webhook", new ActionStatus(now));
|
||||
statuses.put("_email", new ActionStatus(now));
|
||||
|
||||
SearchTransform searchTransform = new SearchTransform(new WatcherSearchTemplateRequest(transformRequest), null, null);
|
||||
|
||||
return new Watch(
|
||||
watchName,
|
||||
new ScheduleTrigger(new CronSchedule("0/5 * * * * ? *")),
|
||||
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple(inputData)), logger),
|
||||
new ExecutableAlwaysCondition(logger),
|
||||
new ExecutableSearchTransform(new SearchTransform(transformRequest, null, null), logger, client, null),
|
||||
new ExecutableSearchTransform(searchTransform, logger, client, searchTemplateService, null),
|
||||
new TimeValue(0),
|
||||
new ExecutableActions(actions),
|
||||
metadata,
|
||||
@ -247,7 +251,7 @@ public final class WatcherTestUtils {
|
||||
.put("script.indexed", "true")
|
||||
.put("path.home", createTempDir())
|
||||
.build();
|
||||
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Arrays.asList(ScriptServiceProxy.INSTANCE));
|
||||
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.singletonList(ScriptServiceProxy.INSTANCE));
|
||||
|
||||
ScriptEngineRegistry scriptEngineRegistry =
|
||||
new ScriptEngineRegistry(Collections.emptyList());
|
||||
|
@ -7,20 +7,16 @@ package org.elasticsearch.xpack.watcher.test.integration;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.util.Callback;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.script.ScriptService.ScriptType;
|
||||
import org.elasticsearch.script.Template;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.watcher.client.WatchSourceBuilder;
|
||||
import org.elasticsearch.xpack.watcher.client.WatcherClient;
|
||||
import org.elasticsearch.xpack.watcher.condition.compare.CompareCondition;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
|
||||
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
|
||||
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
|
||||
import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse;
|
||||
@ -151,8 +147,8 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||
watchSource.field("unknown_field", "x");
|
||||
watchSource.startObject("schedule").field("cron", "0/5 * * * * ? *").endObject();
|
||||
|
||||
watchSource.startObject("condition").startObject("script").field("script", "return true").field("request");
|
||||
WatcherUtils.writeSearchRequest(newInputSearchRequest(), watchSource, ToXContent.EMPTY_PARAMS);
|
||||
watchSource.startObject("condition").startObject("script").field("script", "return true");
|
||||
watchSource.field("request", new WatcherSearchTemplateRequest(newInputSearchRequest()));
|
||||
watchSource.endObject().endObject();
|
||||
|
||||
watchSource.endObject();
|
||||
@ -252,22 +248,20 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||
|
||||
public void testConditionSearchWithSource() throws Exception {
|
||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
|
||||
testConditionSearch(newInputSearchRequest("events").source(searchSourceBuilder));
|
||||
testConditionSearch(newInputSearchRequest("events").source(searchSourceBuilder), null);
|
||||
}
|
||||
|
||||
public void testConditionSearchWithIndexedTemplate() throws Exception {
|
||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
|
||||
client().admin().cluster().preparePutStoredScript()
|
||||
assertAcked(client().admin().cluster().preparePutStoredScript()
|
||||
.setScriptLang("mustache")
|
||||
.setId("my-template")
|
||||
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject().bytes())
|
||||
.get();
|
||||
.get());
|
||||
|
||||
Template template = new Template("my-template", ScriptType.STORED, null, null, null);
|
||||
Script template = Script.indexed("my-template").lang("mustache").build();
|
||||
SearchRequest searchRequest = newInputSearchRequest("events");
|
||||
// TODO (2.0 upgrade): move back to BytesReference instead of coverting to a string
|
||||
searchRequest.template(template);
|
||||
testConditionSearch(searchRequest);
|
||||
testConditionSearch(searchRequest, template);
|
||||
}
|
||||
|
||||
public void testInputFiltering() throws Exception {
|
||||
@ -298,12 +292,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||
|
||||
// Check that the input result payload has been filtered
|
||||
refresh();
|
||||
SearchResponse searchResponse = searchWatchRecords(new Callback<SearchRequestBuilder>() {
|
||||
@Override
|
||||
public void handle(SearchRequestBuilder builder) {
|
||||
builder.setQuery(matchQuery("watch_id", "_name1"));
|
||||
}
|
||||
});
|
||||
SearchResponse searchResponse = searchWatchRecords(builder -> builder.setQuery(matchQuery("watch_id", "_name1")));
|
||||
assertHitCount(searchResponse, 1);
|
||||
XContentSource source = xContentSource(searchResponse.getHits().getAt(0).getSourceRef());
|
||||
assertThat(source.getValue("result.input.payload.hits.total"), equalTo((Object) 1));
|
||||
@ -379,7 +368,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
private void testConditionSearch(SearchRequest request) throws Exception {
|
||||
private void testConditionSearch(SearchRequest request, Script template) throws Exception {
|
||||
// reset, so we don't miss event docs when we filter over the _timestamp field.
|
||||
timeWarp().clock().setTime(SystemClock.INSTANCE.nowUTC());
|
||||
|
||||
@ -389,7 +378,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
|
||||
watcherClient().preparePutWatch(watchName)
|
||||
.setSource(watchBuilder()
|
||||
.trigger(schedule(interval("5s")))
|
||||
.input(searchInput(request))
|
||||
.input(searchInput(new WatcherSearchTemplateRequest(request, template)))
|
||||
.condition(compareCondition("ctx.payload.hits.total", CompareCondition.Op.GTE, 3L)))
|
||||
.get();
|
||||
|
||||
|
@ -5,14 +5,6 @@
|
||||
*/
|
||||
package org.elasticsearch.xpack.watcher.watch;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.ElasticsearchParseException;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
@ -25,12 +17,31 @@ import org.elasticsearch.index.query.MatchAllQueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryParser;
|
||||
import org.elasticsearch.indices.query.IndicesQueriesRegistry;
|
||||
import org.elasticsearch.test.ESTestCase;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory;
|
||||
import org.elasticsearch.xpack.common.secret.SecretService;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
import org.elasticsearch.xpack.notification.email.DataAttachment;
|
||||
import org.elasticsearch.xpack.notification.email.EmailService;
|
||||
import org.elasticsearch.xpack.notification.email.EmailTemplate;
|
||||
import org.elasticsearch.xpack.notification.email.HtmlSanitizer;
|
||||
import org.elasticsearch.xpack.notification.email.Profile;
|
||||
import org.elasticsearch.xpack.notification.email.attachment.EmailAttachments;
|
||||
import org.elasticsearch.xpack.notification.email.attachment.EmailAttachmentsParser;
|
||||
import org.elasticsearch.xpack.support.clock.Clock;
|
||||
import org.elasticsearch.xpack.support.clock.ClockMock;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.watcher.WatcherLicensee;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionFactory;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionStatus;
|
||||
import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
|
||||
import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
|
||||
import org.elasticsearch.xpack.notification.email.DataAttachment;
|
||||
import org.elasticsearch.xpack.watcher.actions.email.EmailAction;
|
||||
import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory;
|
||||
import org.elasticsearch.xpack.watcher.actions.email.ExecutableEmailAction;
|
||||
@ -68,28 +79,15 @@ import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
|
||||
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.WatcherLicensee;
|
||||
import org.elasticsearch.xpack.watcher.support.Script;
|
||||
import org.elasticsearch.xpack.watcher.support.WatcherUtils;
|
||||
import org.elasticsearch.xpack.support.clock.Clock;
|
||||
import org.elasticsearch.xpack.support.clock.ClockMock;
|
||||
import org.elasticsearch.xpack.support.clock.SystemClock;
|
||||
import org.elasticsearch.xpack.common.http.HttpClient;
|
||||
import org.elasticsearch.xpack.common.http.HttpMethod;
|
||||
import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
|
||||
import org.elasticsearch.xpack.common.http.auth.HttpAuthRegistry;
|
||||
import org.elasticsearch.xpack.common.http.auth.basic.BasicAuthFactory;
|
||||
import org.elasticsearch.xpack.common.ScriptServiceProxy;
|
||||
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
|
||||
import org.elasticsearch.xpack.common.secret.SecretService;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplate;
|
||||
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
|
||||
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;
|
||||
import org.elasticsearch.xpack.watcher.transform.TransformFactory;
|
||||
import org.elasticsearch.xpack.watcher.transform.TransformRegistry;
|
||||
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform;
|
||||
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransformFactory;
|
||||
import org.elasticsearch.xpack.watcher.transform.chain.ExecutableChainTransform;
|
||||
import org.elasticsearch.xpack.watcher.transform.script.ExecutableScriptTransform;
|
||||
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform;
|
||||
@ -116,21 +114,23 @@ import org.elasticsearch.xpack.watcher.trigger.schedule.support.Month;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.support.MonthTimes;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.support.WeekTimes;
|
||||
import org.elasticsearch.xpack.watcher.trigger.schedule.support.YearTimes;
|
||||
import org.elasticsearch.xpack.notification.email.EmailService;
|
||||
import org.elasticsearch.xpack.notification.email.EmailTemplate;
|
||||
import org.elasticsearch.xpack.notification.email.HtmlSanitizer;
|
||||
import org.elasticsearch.xpack.notification.email.Profile;
|
||||
import org.elasticsearch.xpack.notification.email.attachment.EmailAttachments;
|
||||
import org.elasticsearch.xpack.notification.email.attachment.EmailAttachmentsParser;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Collections.singleton;
|
||||
import static java.util.Collections.singletonMap;
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
|
||||
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput;
|
||||
import static org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS;
|
||||
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.matchAllRequest;
|
||||
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
@ -153,6 +153,7 @@ public class WatchTests extends ESTestCase {
|
||||
private WatcherLicensee watcherLicensee;
|
||||
private ESLogger logger;
|
||||
private Settings settings = Settings.EMPTY;
|
||||
private WatcherSearchTemplateService searchTemplateService;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
@ -166,6 +167,7 @@ public class WatchTests extends ESTestCase {
|
||||
watcherLicensee = mock(WatcherLicensee.class);
|
||||
authRegistry = new HttpAuthRegistry(singletonMap("basic", new BasicAuthFactory(secretService)));
|
||||
logger = Loggers.getLogger(WatchTests.class);
|
||||
searchTemplateService = mock(WatcherSearchTemplateService.class);
|
||||
}
|
||||
|
||||
public void testParserSelfGenerated() throws Exception {
|
||||
@ -341,7 +343,7 @@ public class WatchTests extends ESTestCase {
|
||||
switch (type) {
|
||||
case SearchInput.TYPE:
|
||||
SearchInput searchInput = searchInput(WatcherTestUtils.newInputSearchRequest("idx")).build();
|
||||
return new ExecutableSearchInput(searchInput, logger, client, null);
|
||||
return new ExecutableSearchInput(searchInput, logger, client, searchTemplateService, null);
|
||||
default:
|
||||
SimpleInput simpleInput = InputBuilders.simpleInput(singletonMap("_key", "_val")).build();
|
||||
return new ExecutableSimpleInput(simpleInput, logger);
|
||||
@ -355,7 +357,7 @@ public class WatchTests extends ESTestCase {
|
||||
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
|
||||
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
|
||||
queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
|
||||
parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, queryRegistry, null, null));
|
||||
parsers.put(SearchInput.TYPE, new SearchInputFactory(settings, client, queryRegistry, null, null, scriptService));
|
||||
return new InputRegistry(Settings.EMPTY, parsers);
|
||||
default:
|
||||
parsers.put(SimpleInput.TYPE, new SimpleInputFactory(settings));
|
||||
@ -406,15 +408,19 @@ public class WatchTests extends ESTestCase {
|
||||
case ScriptTransform.TYPE:
|
||||
return new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService);
|
||||
case SearchTransform.TYPE:
|
||||
return new ExecutableSearchTransform(new SearchTransform(
|
||||
matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS), timeout, timeZone), logger, client, null);
|
||||
SearchTransform transform = new SearchTransform(
|
||||
new WatcherSearchTemplateRequest(matchAllRequest(DEFAULT_INDICES_OPTIONS), null), timeout, timeZone);
|
||||
return new ExecutableSearchTransform(transform, logger, client, searchTemplateService, null);
|
||||
default: // chain
|
||||
ChainTransform chainTransform = new ChainTransform(Arrays.asList(
|
||||
new SearchTransform(matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS), timeout, timeZone),
|
||||
new ScriptTransform(Script.inline("_script").build())));
|
||||
SearchTransform searchTransform = new SearchTransform(
|
||||
new WatcherSearchTemplateRequest(matchAllRequest(DEFAULT_INDICES_OPTIONS), null), timeout, timeZone);
|
||||
ScriptTransform scriptTransform = new ScriptTransform(Script.inline("_script").build());
|
||||
|
||||
ChainTransform chainTransform = new ChainTransform(Arrays.asList(searchTransform, scriptTransform));
|
||||
return new ExecutableChainTransform(chainTransform, logger, Arrays.<ExecutableTransform>asList(
|
||||
new ExecutableSearchTransform(new SearchTransform(
|
||||
matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS), timeout, timeZone), logger, client, null),
|
||||
new WatcherSearchTemplateRequest(matchAllRequest(DEFAULT_INDICES_OPTIONS), null), timeout, timeZone),
|
||||
logger, client, searchTemplateService, null),
|
||||
new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService)));
|
||||
}
|
||||
}
|
||||
@ -425,7 +431,7 @@ public class WatchTests extends ESTestCase {
|
||||
queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
|
||||
Map<String, TransformFactory> factories = new HashMap<>();
|
||||
factories.put(ScriptTransform.TYPE, new ScriptTransformFactory(settings, scriptService));
|
||||
factories.put(SearchTransform.TYPE, new SearchTransformFactory(settings, client, queryRegistry, null, null));
|
||||
factories.put(SearchTransform.TYPE, new SearchTransformFactory(settings, client, queryRegistry, null, null, scriptService));
|
||||
TransformRegistry registry = new TransformRegistry(Settings.EMPTY, unmodifiableMap(factories));
|
||||
return registry;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user