Watcher: Fix watch history template for failed inputs (elastic/elasticsearch#2928)

If the result of a search actions fails (i.e. because the index you queried does not exist yet),
the watch record failed to store into the Watch History because of a mapping issue, as the
template path match regular expression did not match properly.

Closes elastic/elasticsearch#2913

Original commit: elastic/x-pack-elasticsearch@3c2d4b3ca9
This commit is contained in:
Alexander Reelsen 2016-07-26 16:50:36 +02:00
parent 0bb6fed89f
commit 462897e8c8
2 changed files with 108 additions and 11 deletions

View File

@ -12,7 +12,7 @@
"dynamic_templates": [ "dynamic_templates": [
{ {
"disabled_payload_fields": { "disabled_payload_fields": {
"path_match": "result\\.(input|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.payload", "path_match": "result\\.(input(\\..+)*|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.payload",
"match_pattern": "regex", "match_pattern": "regex",
"mapping": { "mapping": {
"type": "object", "type": "object",
@ -22,7 +22,7 @@
}, },
{ {
"disabled_search_request_body_fields": { "disabled_search_request_body_fields": {
"path_match": "result\\.(input(\\..+)|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.search\\.request\\.(body|template)", "path_match": "result\\.(input(\\..+)*|(transform(\\..+)*)|(actions\\.transform(\\..+)*))\\.search\\.request\\.(body|template)",
"match_pattern": "regex", "match_pattern": "regex",
"mapping": { "mapping": {
"type": "object", "type": "object",

View File

@ -5,22 +5,34 @@
*/ */
package org.elasticsearch.watcher.test.integration; package org.elasticsearch.watcher.test.integration;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.xpack.watcher.actions.ActionBuilders;
import org.elasticsearch.xpack.watcher.client.WatchSourceBuilder; import org.elasticsearch.xpack.watcher.client.WatchSourceBuilder;
import org.elasticsearch.xpack.watcher.client.WatchSourceBuilders; import org.elasticsearch.xpack.watcher.input.Input;
import org.elasticsearch.xpack.watcher.input.InputBuilders; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.put.PutWatchResponse;
import org.elasticsearch.xpack.watcher.trigger.TriggerBuilders; import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
import org.elasticsearch.xpack.watcher.trigger.schedule.Schedules;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.xpack.watcher.actions.ActionBuilders.loggingAction;
import static org.elasticsearch.xpack.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.chainInput;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.simpleInput;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.newInputSearchRequest;
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.xpack.watcher.trigger.schedule.Schedules.interval;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase { public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase {
@ -32,13 +44,13 @@ public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase
index("foo", "bar", "1", xContentBuilder); index("foo", "bar", "1", xContentBuilder);
refresh(); refresh();
WatchSourceBuilder builder = WatchSourceBuilders.watchBuilder() WatchSourceBuilder builder = watchBuilder()
.trigger(TriggerBuilders.schedule(Schedules.interval("10s"))) .trigger(schedule(interval("10s")))
.addAction("logging", ActionBuilders.loggingAction("foo")); .addAction("logging", loggingAction("foo"));
SearchRequestBuilder searchRequestBuilder = client().prepareSearch("foo").addSort(SortBuilders.fieldSort("inner.date").order SearchRequestBuilder searchRequestBuilder = client().prepareSearch("foo").addSort(SortBuilders.fieldSort("inner.date").order
(SortOrder.DESC)); (SortOrder.DESC));
builder.input(InputBuilders.chainInput().add("first", InputBuilders.searchInput(searchRequestBuilder.request()))); builder.input(chainInput().add("first", searchInput(searchRequestBuilder.request())));
PutWatchResponse response = watcherClient().preparePutWatch("test_watch").setSource(builder).get(); PutWatchResponse response = watcherClient().preparePutWatch("test_watch").setSource(builder).get();
assertThat(response.isCreated(), is(true)); assertThat(response.isCreated(), is(true));
@ -49,4 +61,89 @@ public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase
SearchResponse searchResponse = client().prepareSearch(".watcher-history-*").get(); SearchResponse searchResponse = client().prepareSearch(".watcher-history-*").get();
assertHitCount(searchResponse, 1); assertHitCount(searchResponse, 1);
} }
// See https://github.com/elastic/x-plugins/issues/2913
public void testFailedInputResultWithDotsInFieldNameGetsStored() throws Exception {
SearchRequest sortSearchRequest = newInputSearchRequest("non-existing-index")
.source(searchSource()
.query(matchAllQuery())
.sort("trigger_event.triggered_time", SortOrder.DESC)
.size(1));
// The result of the search input will be a failure, because a missing index does not exist when
// the query is executed
Input.Builder input = searchInput(sortSearchRequest);
// wrapping this randomly into a chained input to test this as well
boolean useChained = randomBoolean();
if (useChained) {
input = chainInput().add("chained", input);
}
watcherClient().preparePutWatch("test_watch")
.setSource(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.HOURS)))
.input(input)
.addAction("_logger", loggingAction("#### randomLogging")))
.get();
watcherClient().prepareExecuteWatch("test_watch").setRecordExecution(true).get();
flush(".watcher-history*");
SearchResponse searchResponse = client().prepareSearch(".watcher-history*").setSize(0).get();
assertHitCount(searchResponse, 1);
// as fields with dots are allowed in 5.0 again, the mapping must be checked in addition
GetMappingsResponse response = client().admin().indices().prepareGetMappings(".watcher-history*").addTypes("watch_record").get();
byte[] bytes = response.getMappings().values().iterator().next().value.get("watch_record").source().uncompressed();
XContentSource source = new XContentSource(new BytesArray(bytes), XContentType.JSON);
// lets make sure the body fields are disabled
if (useChained) {
String chainedPath = "watch_record.properties.result.properties.input.properties.chain.properties.chained.properties.search" +
".properties.request.properties.body.enabled";
assertThat(source.getValue(chainedPath), is(false));
} else {
String path =
"watch_record.properties.result.properties.input.properties.search.properties.request.properties.body.enabled";
assertThat(source.getValue(path), is(false));
}
}
// See https://github.com/elastic/x-plugins/issues/2913
public void testPayloadInputWithDotsInFieldNameWorks() throws Exception {
Input.Builder input = simpleInput("foo.bar", "bar");
// wrapping this randomly into a chained input to test this as well
boolean useChained = randomBoolean();
if (useChained) {
input = chainInput().add("chained", input);
}
watcherClient().preparePutWatch("test_watch")
.setSource(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.HOURS)))
.input(input)
.addAction("_logger", loggingAction("#### randomLogging")))
.get();
watcherClient().prepareExecuteWatch("test_watch").setRecordExecution(true).get();
flush(".watcher-history*");
SearchResponse searchResponse = client().prepareSearch(".watcher-history*").setSize(0).get();
assertHitCount(searchResponse, 1);
// as fields with dots are allowed in 5.0 again, the mapping must be checked in addition
GetMappingsResponse response = client().admin().indices().prepareGetMappings(".watcher-history*").addTypes("watch_record").get();
byte[] bytes = response.getMappings().values().iterator().next().value.get("watch_record").source().uncompressed();
XContentSource source = new XContentSource(new BytesArray(bytes), XContentType.JSON);
// lets make sure the body fields are disabled
if (useChained) {
String path = "watch_record.properties.result.properties.input.properties.chain.properties.chained.properties.payload.enabled";
assertThat(source.getValue(path), is(false));
} else {
String path = "watch_record.properties.result.properties.input.properties.payload.enabled";
assertThat(source.getValue(path), is(false));
}
}
} }