Merge branch 'master' into reporting-controls

Original commit: elastic/x-pack-elasticsearch@4f0e7501ce
This commit is contained in:
Joe Fleming 2016-06-27 16:39:10 -07:00
commit a66c0cf463
86 changed files with 1680 additions and 1681 deletions

View File

@ -6,9 +6,11 @@
package org.elasticsearch.xpack.security.audit; package org.elasticsearch.xpack.security.audit;
import com.carrotsearch.hppc.cursors.ObjectCursor; import com.carrotsearch.hppc.cursors.ObjectCursor;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateResponse;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexTemplateMetaData; import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -19,7 +21,6 @@ import org.elasticsearch.xpack.security.audit.index.IndexAuditTrail;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collection; import java.util.Collection;
@ -35,12 +36,12 @@ public class IndexAuditIT extends ESIntegTestCase {
private static final String USER = "test_user"; private static final String USER = "test_user";
private static final String PASS = "changeme"; private static final String PASS = "changeme";
public void testIndexAuditTrailWorking() throws Exception { public void testShieldIndexAuditTrailWorking() throws Exception {
HttpResponse response = httpClient().path("/") try (Response response = getRestClient().performRequest("GET", "/", Collections.emptyMap(), null,
.addHeader("Authorization", UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))) new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.execute(); UsernamePasswordToken.basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()))))) {
assertThat(response.getStatusCode(), is(200)); assertThat(response.getStatusLine().getStatusCode(), is(200));
}
final AtomicReference<ClusterState> lastClusterState = new AtomicReference<>(); final AtomicReference<ClusterState> lastClusterState = new AtomicReference<>();
final AtomicBoolean indexExists = new AtomicBoolean(false); final AtomicBoolean indexExists = new AtomicBoolean(false);
boolean found = awaitBusy(() -> { boolean found = awaitBusy(() -> {

View File

@ -66,13 +66,10 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
} }
public void testGroovyClosureWithAggregations() throws Exception { public void testGroovyClosureWithAggregations() throws Exception {
client().admin().indices().prepareCreate(".monitoring")
.addMapping("cluster_stats", "_timestamp", "enabled=true")
.get();
for (int seconds = 0; seconds < 60; seconds += 5) { for (int seconds = 0; seconds < 60; seconds += 5) {
client().prepareIndex(".monitoring", "cluster_stats").setTimestamp("2005-01-01T00:00:" + String timestamp = "2005-01-01T00:00:" + String.format(Locale.ROOT, "%02d", seconds);
String.format(Locale.ROOT, "%02d", seconds)).setSource("status", randomFrom("green", "yellow")).get(); client().prepareIndex(".monitoring", "cluster_stats")
.setSource("status", randomFrom("green", "yellow"), "@timestamp", timestamp).get();
} }
refresh(); refresh();
@ -80,7 +77,7 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
SearchRequestBuilder builder = client().prepareSearch(".monitoring") SearchRequestBuilder builder = client().prepareSearch(".monitoring")
.addAggregation( .addAggregation(
AggregationBuilders AggregationBuilders
.dateHistogram("minutes").field("_timestamp").interval(TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS)) .dateHistogram("minutes").field("@timestamp").interval(TimeUnit.MILLISECONDS.convert(5, TimeUnit.SECONDS))
.order(Histogram.Order.COUNT_DESC) .order(Histogram.Order.COUNT_DESC)
.subAggregation(AggregationBuilders.terms("status").field("status.keyword").size(3))); .subAggregation(AggregationBuilders.terms("status").field("status.keyword").size(3)));
SearchResponse unmetResponse = builder.get(); SearchResponse unmetResponse = builder.get();
@ -101,8 +98,8 @@ public class GroovyScriptConditionIT extends AbstractWatcherIntegrationTestCase
assertFalse(condition.execute(unmetContext).met()); assertFalse(condition.execute(unmetContext).met());
for (int seconds = 0; seconds < 60; seconds += 5) { for (int seconds = 0; seconds < 60; seconds += 5) {
client().prepareIndex(".monitoring", "cluster_stats").setTimestamp("2005-01-01T00:01:" + String timestamp = "2005-01-01T00:01:" + String.format(Locale.ROOT, "%02d", seconds);
String.format(Locale.ROOT, "%02d", seconds)).setSource("status", randomFrom("red")).get(); client().prepareIndex(".monitoring", "cluster_stats").setSource("status", randomFrom("red"), "@timestamp", timestamp).get();
} }
refresh(); refresh();

View File

@ -20,11 +20,11 @@ import org.elasticsearch.search.internal.InternalSearchHits;
import org.elasticsearch.search.internal.InternalSearchResponse; import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.condition.script.ExecutableScriptCondition; import org.elasticsearch.xpack.watcher.condition.script.ExecutableScriptCondition;
import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition; import org.elasticsearch.xpack.watcher.condition.script.ScriptCondition;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Script; import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.After; import org.junit.After;
@ -61,18 +61,14 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
} }
public void testExecuteWithAggs() throws Exception { public void testExecuteWithAggs() throws Exception {
client().admin().indices().prepareCreate("my-index") client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:00").get();
.addMapping("my-type", "_timestamp", "enabled=true") client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:10").get();
.get(); client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:20").get();
client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:30").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:00").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:10").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:20").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:30").setSource("{}").get();
refresh(); refresh();
SearchResponse response = client().prepareSearch("my-index") SearchResponse response = client().prepareSearch("my-index")
.addAggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp") .addAggregation(AggregationBuilders.dateHistogram("rate").field("@timestamp")
.dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC)) .dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get(); .get();
@ -83,10 +79,10 @@ public class ScriptConditionSearchIT extends AbstractWatcherIntegrationTestCase
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response)); WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met()); assertFalse(condition.execute(ctx).met());
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:40").setSource("{}").get(); client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:40").get();
refresh(); refresh();
response = client().prepareSearch("my-index").addAggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp") response = client().prepareSearch("my-index").addAggregation(AggregationBuilders.dateHistogram("rate").field("@timestamp")
.dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC)) .dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get(); .get();

View File

@ -12,31 +12,40 @@ import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService.ScriptType; import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.Template; import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.mustache.MustachePlugin; import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition; import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext; import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; 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.ExecutableSearchInput;
import org.elasticsearch.xpack.watcher.input.search.SearchInput; import org.elasticsearch.xpack.watcher.input.search.SearchInput;
import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory; import org.elasticsearch.xpack.watcher.input.search.SearchInputFactory;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule; import org.elasticsearch.xpack.watcher.trigger.schedule.IntervalSchedule;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger; import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTrigger;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent; 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.elasticsearch.xpack.watcher.test.WatcherTestUtils.getRandomSupportedSearchType;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.joda.time.DateTimeZone.UTC; import static org.joda.time.DateTimeZone.UTC;
/** /**
@ -81,10 +89,11 @@ public class SearchInputIT extends ESIntegTestCase {
Collection<Class<? extends Plugin>> types = new ArrayList<>(); Collection<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.nodePlugins()); types.addAll(super.nodePlugins());
types.add(MustachePlugin.class); types.add(MustachePlugin.class);
types.add(CustomScriptContextPlugin.class);
return types; 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\":" + "\"type\":\"boolean\"}}},\"filter\":{\"range\":{\"_timestamp\":" +
"{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," + "{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
"\"include_lower\":true,\"include_upper\":true}}}}}}"; "\"include_lower\":true,\"include_upper\":true}}}}}}";
@ -100,7 +109,6 @@ public class SearchInputIT extends ESIntegTestCase {
throw new RuntimeException("failed to create config dir"); 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" + try (InputStream stream = SearchInputIT.class.getResourceAsStream("/org/elasticsearch/xpack/watcher/input/search/config/scripts" +
"/test_disk_template.mustache"); "/test_disk_template.mustache");
OutputStream out = Files.newOutputStream(scriptPath.resolve("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( SearchSourceBuilder searchSourceBuilder = searchSource().query(
boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp") boolQuery().must(matchQuery("event_type", "a")).must(rangeQuery("_timestamp")
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))); .from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")));
SearchRequest request = client() SearchRequest searchRequest = client()
.prepareSearch() .prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE) .setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.request() .request()
.source(searchSourceBuilder); .source(searchSourceBuilder);
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger, ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
WatcherClientProxy.of(client()), null); WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
WatchExecutionContext ctx = new TriggeredExecutionContext( WatchExecutionContext ctx = new TriggeredExecutionContext(
new Watch("test-watch", new Watch("test-watch",
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))), new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
@ -149,21 +158,21 @@ public class SearchInputIT extends ESIntegTestCase {
timeValueSeconds(5)); timeValueSeconds(5));
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple()); 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()); assertNotNull(result.executedRequest());
assertEquals(result.executedRequest().searchType(), request.searchType()); assertThat(result.status(), is(Input.Result.Status.SUCCESS));
assertArrayEquals(result.executedRequest().indices(), request.indices()); assertEquals(result.executedRequest().searchType(), request.getRequest().searchType());
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions()); 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 { public void testSearchInlineTemplate() throws Exception {
WatchExecutionContext ctx = createContext(); 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>(); 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("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())); triggerParams.put("scheduled_time", new DateTime(1970, 01, 01, 00, 01, 00, 000, ISOChronology.getInstanceUTC()));
@ -178,17 +187,28 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> expectedParams = new HashMap<String, Object>(); Map<String, Object> expectedParams = new HashMap<String, Object>();
expectedParams.put("seconds_param", "30s"); expectedParams.put("seconds_param", "30s");
expectedParams.put("ctx", ctxParams); expectedParams.put("ctx", ctxParams);
Template expectedTemplate = new Template(expectedTemplateString, ScriptType.INLINE, null, XContentType.JSON, expectedParams);
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) SearchRequest request = client().prepareSearch()
.setIndices("test-search-index").setTemplate(template).request(); .setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index").request();
SearchInput.Result executedResult = executeSearchInput(request, ctx); SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
assertThat(executedResult.executedRequest().template(), equalTo(expectedTemplate));
assertNotNull(executedResult.executedRequest());
assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
if (getNumShards("test-search-index").numPrimaries > 1) {
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 { public void testSearchIndexedTemplate() throws Exception {
@ -204,17 +224,26 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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(); jsonBuilder().value(TextTemplate.indexed("test-template").params(params).build()).bytes();
SearchRequest request = client().prepareSearch().setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE) 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));
if (getNumShards("test-search-index").numPrimaries > 1) {
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 { public void testSearchOnDiskTemplate() throws Exception {
@ -223,15 +252,16 @@ public class SearchInputIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) 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); SearchInput.Result executedResult = executeSearchInput(request, template, ctx);
Template resultTemplate = executedResult.executedRequest().template();
assertThat(resultTemplate, notNullValue()); assertNotNull(executedResult.executedRequest());
assertThat(resultTemplate.getScript(), equalTo("test_disk_template")); assertThat(executedResult.status(), is(Input.Result.Status.SUCCESS));
assertThat(resultTemplate.getType(), equalTo(ScriptType.FILE)); assertArrayEquals(executedResult.executedRequest().indices(), request.indices());
assertEquals(executedResult.executedRequest().indicesOptions(), request.indicesOptions());
} }
public void testDifferentSearchType() throws Exception { public void testDifferentSearchType() throws Exception {
@ -241,14 +271,16 @@ public class SearchInputIT extends ESIntegTestCase {
); );
SearchType searchType = getRandomSupportedSearchType(); SearchType searchType = getRandomSupportedSearchType();
SearchRequest request = client() SearchRequest searchRequest = client()
.prepareSearch() .prepareSearch()
.setSearchType(searchType) .setSearchType(searchType)
.request() .request()
.source(searchSourceBuilder); .source(searchSourceBuilder);
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(searchRequest);
ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger, ExecutableSearchInput searchInput = new ExecutableSearchInput(new SearchInput(request, null, null, null), logger,
WatcherClientProxy.of(client()), null); WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
WatchExecutionContext ctx = new TriggeredExecutionContext( WatchExecutionContext ctx = new TriggeredExecutionContext(
new Watch("test-watch", new Watch("test-watch",
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))), new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
@ -264,15 +296,20 @@ public class SearchInputIT extends ESIntegTestCase {
timeValueSeconds(5)); timeValueSeconds(5));
SearchInput.Result result = searchInput.execute(ctx, new Payload.Simple()); 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()); assertNotNull(result.executedRequest());
assertThat(result.status(), is(Input.Result.Status.SUCCESS));
assertEquals(result.executedRequest().searchType(), searchType); assertEquals(result.executedRequest().searchType(), searchType);
assertArrayEquals(result.executedRequest().indices(), request.indices()); assertArrayEquals(result.executedRequest().indices(), searchRequest.indices());
assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions()); 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 { public void testParserValid() throws Exception {
SearchRequest request = client().prepareSearch() SearchRequest searchRequest = client().prepareSearch()
.setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE) .setSearchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE)
.request() .request()
.source(searchSource() .source(searchSource()
@ -280,13 +317,14 @@ public class SearchInputIT extends ESIntegTestCase {
.from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}")))); .from("{{ctx.trigger.scheduled_time}}||-30s").to("{{ctx.trigger.triggered_time}}"))));
TimeValue timeout = randomBoolean() ? TimeValue.timeValueSeconds(randomInt(10)) : null; 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()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class); IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry, SearchInputFactory factory = new SearchInputFactory(Settings.EMPTY, WatcherClientProxy.of(client()), indicesQueryRegistry,
null, null); null, null, scriptService());
SearchInput searchInput = factory.parseInput("_id", parser); SearchInput searchInput = factory.parseInput("_id", parser);
assertEquals(SearchInput.TYPE, searchInput.type()); assertEquals(SearchInput.TYPE, searchInput.type());
@ -309,15 +347,47 @@ public class SearchInputIT extends ESIntegTestCase {
timeValueSeconds(5)); 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"); createIndex("test-search-index");
ensureGreen("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(); 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()); 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;
}
}
} }

View File

@ -11,25 +11,28 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Requests; import org.elasticsearch.client.Requests;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService.ScriptType; import org.elasticsearch.plugins.ScriptPlugin;
import org.elasticsearch.script.Template; import org.elasticsearch.script.ScriptContext;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.mustache.MustachePlugin; import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; import org.elasticsearch.xpack.watcher.actions.ExecutableActions;
import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition; import org.elasticsearch.xpack.watcher.condition.always.ExecutableAlwaysCondition;
@ -37,7 +40,11 @@ import org.elasticsearch.xpack.watcher.execution.TriggeredExecutionContext;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.transform.Transform; import org.elasticsearch.xpack.watcher.transform.Transform;
import org.elasticsearch.xpack.watcher.transform.TransformBuilders; import org.elasticsearch.xpack.watcher.transform.TransformBuilders;
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform; import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
@ -100,6 +107,7 @@ public class SearchTransformIT extends ESIntegTestCase {
Collection<Class<? extends Plugin>> types = new ArrayList<>(); Collection<Class<? extends Plugin>> types = new ArrayList<>();
types.addAll(super.nodePlugins()); types.addAll(super.nodePlugins());
types.add(MustachePlugin.class); types.add(MustachePlugin.class);
types.add(CustomScriptContextPlugin.class);
return types; return types;
} }
@ -154,7 +162,8 @@ public class SearchTransformIT extends ESIntegTestCase {
SearchRequest request = Requests.searchRequest("idx").source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery())); SearchRequest request = Requests.searchRequest("idx").source(new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()));
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build(); 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); WatchExecutionContext ctx = mockExecutionContext("_name", EMPTY_PAYLOAD);
@ -188,7 +197,8 @@ public class SearchTransformIT extends ESIntegTestCase {
new SearchSourceBuilder().query(QueryBuilders.wrapperQuery(jsonBuilder().startObject() new SearchSourceBuilder().query(QueryBuilders.wrapperQuery(jsonBuilder().startObject()
.startObject("_unknown_query_").endObject().endObject().bytes()))); .startObject("_unknown_query_").endObject().endObject().bytes())));
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build(); 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); 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_]")); assertThat(result.reason(), containsString("no [query] registered for [_unknown_query_]"));
// extract the base64 encoded query from the template script, path is: query -> wrapper -> query // extract the base64 encoded query from the template script, path is: query -> wrapper -> query
String jsonQuery = result.executedRequest().template().getScript(); try (XContentBuilder builder = jsonBuilder()) {
Map<String, Object> map = XContentFactory.xContent(jsonQuery).createParser(jsonQuery).map(); result.executedRequest().source().toXContent(builder, ToXContent.EMPTY_PARAMS);
assertThat(map, hasKey("query")); String jsonQuery = builder.string();
assertThat(map.get("query"), instanceOf(Map.class)); Map<String, Object> map = XContentFactory.xContent(jsonQuery).createParser(jsonQuery).map();
map = (Map<String, Object>) map.get("query"); assertThat(map, hasKey("query"));
assertThat(map, hasKey("wrapper")); assertThat(map.get("query"), instanceOf(Map.class));
assertThat(map.get("wrapper"), instanceOf(Map.class));
map = (Map<String, Object>) map.get("wrapper"); map = (Map<String, Object>) map.get("query");
assertThat(map, hasKey("query")); assertThat(map, hasKey("wrapper"));
assertThat(map.get("query"), instanceOf(String.class)); assertThat(map.get("wrapper"), instanceOf(Map.class));
String queryAsBase64 = (String) map.get("query"); map = (Map<String, Object>) map.get("wrapper");
String decodedQuery = new String(Base64.getDecoder().decode(queryAsBase64), StandardCharsets.UTF_8); assertThat(map, hasKey("query"));
assertThat(decodedQuery, containsString("_unknown_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 { public void testExecuteMustacheTemplate() throws Exception {
@ -252,7 +266,8 @@ public class SearchTransformIT extends ESIntegTestCase {
.must(termQuery("value", "{{ctx.payload.value}}")))); .must(termQuery("value", "{{ctx.payload.value}}"))));
SearchTransform searchTransform = TransformBuilders.searchTransform(request).build(); 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), ScheduleTriggerEvent event = new ScheduleTriggerEvent("_name", parseDate("2015-01-04T00:00:00", UTC),
parseDate("2015-01-01T00: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); IndicesQueriesRegistry indicesQueryRegistry = internalCluster().getInstance(IndicesQueriesRegistry.class);
SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()), SearchTransformFactory transformFactory = new SearchTransformFactory(Settings.EMPTY, WatcherClientProxy.of(client()),
indicesQueryRegistry, null, null); indicesQueryRegistry, null, null, scriptService());
ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser); ExecutableSearchTransform executable = transformFactory.parseExecutable("_id", parser);
assertThat(executable, notNullValue()); assertThat(executable, notNullValue());
assertThat(executable.type(), is(SearchTransform.TYPE)); assertThat(executable.type(), is(SearchTransform.TYPE));
assertThat(executable.transform().getRequest(), notNullValue()); assertThat(executable.transform().getRequest(), notNullValue());
if (indices != null) { if (indices != null) {
assertThat(executable.transform().getRequest().indices(), arrayContainingInAnyOrder(indices)); assertThat(executable.transform().getRequest().getRequest().indices(), arrayContainingInAnyOrder(indices));
} }
if (searchType != null) { if (searchType != null) {
assertThat(executable.transform().getRequest().searchType(), is(searchType)); assertThat(executable.transform().getRequest().getRequest().searchType(), is(searchType));
} }
if (templateName != null) { if (templateName != null) {
assertThat(executable.transform().getRequest().template(), assertThat(executable.transform().getRequest().getTemplate(),
equalTo(new Template("template1", ScriptType.FILE, null, null, null))); equalTo(Script.file("template1").build()));
} }
SearchSourceBuilder source = new SearchSourceBuilder().query(QueryBuilders.matchAllQuery()); 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)); 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}}\"," + "{\"from\":\"{{ctx.trigger.scheduled_time}}||-{{seconds_param}}\",\"to\":\"{{ctx.trigger.scheduled_time}}\"," +
"\"include_lower\":true,\"include_upper\":true}}}]}}}"; "\"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>(); 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("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())); 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>(); Map<String, Object> expectedParams = new HashMap<String, Object>();
expectedParams.put("seconds_param", "30s"); expectedParams.put("seconds_param", "30s");
expectedParams.put("ctx", ctxParams); expectedParams.put("ctx", ctxParams);
Template expectedTemplate = new Template(expectedTemplateString, ScriptType.INLINE, null, XContentType.JSON, expectedParams);
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) 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 { public void testSearchIndexedTemplate() throws Exception {
@ -399,24 +415,24 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); params.put("seconds_param", "30s");
BytesReference templateSource = jsonBuilder() Script template = Script.indexed("test-script").lang("mustache").params(params).build();
.value(TextTemplate.indexed("test-script").params(params).build())
.bytes();
Template template = new Template("test-script", ScriptType.STORED, null, null, null);
SearchRequest request = client() SearchRequest request = client()
.prepareSearch() .prepareSearch()
.setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE) .setSearchType(ExecutableSearchTransform.DEFAULT_SEARCH_TYPE)
.setIndices("test-search-index") .setIndices("test-search-index")
.setTemplate(template)
.request(); .request();
SearchTransform.Result result = executeSearchTransform(request, ctx); SearchTransform.Result result = executeSearchTransform(request, template, ctx);
assertNotNull(result.executedRequest()); assertNotNull(result.executedRequest());
Template resultTemplate = result.executedRequest().template(); assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
assertThat(resultTemplate, notNullValue()); assertArrayEquals(result.executedRequest().indices(), request.indices());
assertThat(resultTemplate.getScript(), equalTo("test-script")); assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
assertThat(resultTemplate.getType(), equalTo(ScriptType.STORED));
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 { public void testSearchOnDiskTemplate() throws Exception {
@ -425,16 +441,20 @@ public class SearchTransformIT extends ESIntegTestCase {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("seconds_param", "30s"); 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) 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()); assertNotNull(result.executedRequest());
Template resultTemplate = result.executedRequest().template(); assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
assertThat(resultTemplate, notNullValue()); assertArrayEquals(result.executedRequest().indices(), request.indices());
assertThat(resultTemplate.getScript(), equalTo("test_disk_template")); assertEquals(result.executedRequest().indicesOptions(), request.indicesOptions());
assertThat(resultTemplate.getType(), equalTo(ScriptType.FILE));
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 { public void testDifferentSearchType() throws Exception {
@ -453,13 +473,18 @@ public class SearchTransformIT extends ESIntegTestCase {
.request() .request()
.source(searchSourceBuilder); .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.executedRequest(), notNullValue());
assertThat(result.status(), is(Transform.Result.Status.SUCCESS));
assertThat(result.executedRequest().searchType(), is(searchType)); assertThat(result.executedRequest().searchType(), is(searchType));
assertThat(result.executedRequest().indices(), arrayContainingInAnyOrder(request.indices())); assertThat(result.executedRequest().indices(), arrayContainingInAnyOrder(request.indices()));
assertThat(result.executedRequest().indicesOptions(), equalTo(request.indicesOptions())); 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() { private WatchExecutionContext createContext() {
@ -479,17 +504,31 @@ public class SearchTransformIT extends ESIntegTestCase {
timeValueSeconds(5)); 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"); createIndex("test-search-index");
ensureGreen("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, ExecutableSearchTransform executableSearchTransform = new ExecutableSearchTransform(searchTransform, logger,
WatcherClientProxy.of(client()), null); WatcherClientProxy.of(client()), watcherSearchTemplateService(), null);
return executableSearchTransform.execute(ctx, Payload.Simple.EMPTY); 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) { private static Map<String, Object> doc(String date, String value) {
Map<String, Object> doc = new HashMap<>(); Map<String, Object> doc = new HashMap<>();
@ -498,4 +537,21 @@ public class SearchTransformIT extends ESIntegTestCase {
return doc; 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;
}
}
} }

View File

@ -5,27 +5,27 @@
*/ */
package org.elasticsearch.messy.tests; package org.elasticsearch.messy.tests;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.indices.TermsLookup; import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.Template; import org.elasticsearch.script.Template;
import org.elasticsearch.script.mustache.MustachePlugin; import org.elasticsearch.script.mustache.MustachePlugin;
import org.elasticsearch.script.mustache.MustacheScriptEngineService; import org.elasticsearch.script.mustache.MustacheScriptEngineService;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; 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.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -72,18 +72,6 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
public void loadData() { public void loadData() {
index("data", "a", "1", "{ \"name\": \"John\", \"token\": \"token1\" }"); index("data", "a", "1", "{ \"name\": \"John\", \"token\": \"token1\" }");
index("tokens", "tokens", "1", "{ \"group\": \"1\", \"tokens\": [\"token1\", \"token2\"] }"); 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(); refresh();
} }
@ -96,38 +84,44 @@ public class SecurityCachePermissionIT extends SecurityIntegTestCase {
// Repeat with unauthorized user!!!! // Repeat with unauthorized user!!!!
try { 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())))) new SecuredString("changeme".toCharArray()))))
.prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery( .prepareSearch("data").setTypes("a").setQuery(QueryBuilders.constantScoreQuery(
QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens")))) QueryBuilders.termsLookupQuery("token", new TermsLookup("tokens", "tokens", "1", "tokens"))))
.execute().actionGet(); .execute().actionGet();
fail("search phase exception should have been thrown! response was:\n" + response.toString()); 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("ElasticsearchSecurityException[action"));
assertThat(e.toString(), containsString("unauthorized")); assertThat(e.toString(), containsString("unauthorized"));
} }
} }
public void testThatScriptServiceDoesntLeakData() { 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") SearchResponse response = client().prepareSearch("data").setTypes("a")
.setTemplate(new Template("testTemplate", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null, .setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
Collections.<String, Object>singletonMap("name", "token")))
.execute().actionGet(); .execute().actionGet();
assertThat(response.isTimedOut(), is(false)); assertThat(response.isTimedOut(), is(false));
assertThat(response.getHits().hits().length, is(1)); assertThat(response.getHits().hits().length, is(1));
// Repeat with unauthorized user!!!! // Repeat with unauthorized user!!!!
try { ElasticsearchSecurityException e = expectThrows(ElasticsearchSecurityException.class, () -> client()
response = client().filterWithHeader(Collections.singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER, .filterWithHeader(singletonMap("Authorization", basicAuthHeaderValue(READ_ONE_IDX_USER,
new SecuredString("changeme".toCharArray())))) new SecuredString("changeme".toCharArray()))))
.prepareSearch("data").setTypes("a") .prepareSearch("data").setTypes("a")
.setTemplate(new Template("testTemplate", ScriptService.ScriptType.STORED, MustacheScriptEngineService.NAME, null, .setQuery(QueryBuilders.templateQuery(source, singletonMap("name", "token")))
Collections.<String, Object>singletonMap("name", "token"))) .execute().actionGet());
.execute().actionGet(); assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
fail("search phase exception should have been thrown! response was:\n" + response.toString()); assertThat(e.toString(), containsString("unauthorized"));
} catch (SearchPhaseExecutionException e) {
assertThat(e.toString(), containsString("ElasticsearchSecurityException[action"));
assertThat(e.toString(), containsString("unauthorized"));
}
} }
} }

View File

@ -5,9 +5,12 @@
*/ */
package org.elasticsearch.example.realm; package org.elasticsearch.example.realm;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -16,7 +19,6 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collection; import java.util.Collection;
@ -29,6 +31,7 @@ import static org.hamcrest.Matchers.is;
* Integration test to test authentication with the custom realm * Integration test to test authentication with the custom realm
*/ */
public class CustomRealmIT extends ESIntegTestCase { public class CustomRealmIT extends ESIntegTestCase {
@Override @Override
protected Settings externalClusterClientSettings() { protected Settings externalClusterClientSettings() {
return Settings.builder() return Settings.builder()
@ -43,18 +46,23 @@ public class CustomRealmIT extends ESIntegTestCase {
} }
public void testHttpConnectionWithNoAuthentication() throws Exception { public void testHttpConnectionWithNoAuthentication() throws Exception {
HttpResponse response = httpClient().path("/").execute(); try {
assertThat(response.getStatusCode(), is(401)); getRestClient().performRequest("GET", "/", Collections.emptyMap(), null);
String value = response.getHeaders().get("WWW-Authenticate"); fail("request should have failed");
assertThat(value, is("custom-challenge")); } catch(ResponseException e) {
Response response = e.getResponse();
assertThat(response.getStatusLine().getStatusCode(), is(401));
String value = response.getHeader("WWW-Authenticate");
assertThat(value, is("custom-challenge"));
}
} }
public void testHttpAuthentication() throws Exception { public void testHttpAuthentication() throws Exception {
HttpResponse response = httpClient().path("/") try (Response response = getRestClient().performRequest("GET", "/", Collections.emptyMap(), null,
.addHeader(CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER) new BasicHeader(CustomRealm.USER_HEADER, CustomRealm.KNOWN_USER),
.addHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW) new BasicHeader(CustomRealm.PW_HEADER, CustomRealm.KNOWN_PW))) {
.execute(); assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getStatusCode(), is(200)); }
} }
public void testTransportClient() throws Exception { public void testTransportClient() throws Exception {

View File

@ -7,9 +7,9 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
@ -19,6 +19,7 @@ import java.io.IOException;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class GraphWithSecurityIT extends ESRestTestCase { public class GraphWithSecurityIT extends ESRestTestCase {
private final static String TEST_ADMIN_USERNAME = "test_admin"; private final static String TEST_ADMIN_USERNAME = "test_admin";

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.client.RestClient; import org.elasticsearch.test.rest.client.RestTestClient;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -65,9 +65,9 @@ public class SmokeTestPluginsSslIT extends ESRestTestCase {
String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray())); String token = basicAuthHeaderValue(USER, new SecuredString(PASS.toCharArray()));
return Settings.builder() return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", token) .put(ThreadContext.PREFIX + ".Authorization", token)
.put(RestClient.PROTOCOL, "https") .put(RestTestClient.PROTOCOL, "https")
.put(RestClient.TRUSTSTORE_PATH, keyStore) .put(RestTestClient.TRUSTSTORE_PATH, keyStore)
.put(RestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS) .put(RestTestClient.TRUSTSTORE_PASSWORD, KEYSTORE_PASS)
.build(); .build();
} }
} }

View File

@ -5,22 +5,19 @@
*/ */
package org.elasticsearch.smoketest; package org.elasticsearch.smoketest;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase { public abstract class WatcherRestTestCase extends ESRestTestCase {
public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
@ -34,19 +31,11 @@ public abstract class WatcherRestTestCase extends ESRestTestCase {
@Before @Before
public void startWatcher() throws Exception { public void startWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.start", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_start", null, null));
client.execute(request);
}
} }
@After @After
public void stopWatcher() throws Exception { public void stopWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.stop", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_stop", null, null));
client.execute(request);
}
} }
} }

View File

@ -7,10 +7,6 @@ package org.elasticsearch.smoketest;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
@ -18,8 +14,9 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import java.net.URI;
import java.net.URL; import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase { public abstract class WatcherRestTestCase extends ESRestTestCase {
@ -34,19 +31,11 @@ public abstract class WatcherRestTestCase extends ESRestTestCase {
@Before @Before
public void startWatcher() throws Exception { public void startWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.start", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_start", null, null));
client.execute(request);
}
} }
@After @After
public void stopWatcher() throws Exception { public void stopWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.stop", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_stop", null, null));
client.execute(request);
}
} }
} }

View File

@ -55,7 +55,7 @@
catch: request_timeout catch: request_timeout
cluster.health: cluster.health:
wait_for_nodes: 99 wait_for_nodes: 99
timeout: 10s timeout: 5s
- match: { "timed_out": true } - match: { "timed_out": true }
- do: - do:

View File

@ -53,7 +53,7 @@
catch: request_timeout catch: request_timeout
cluster.health: cluster.health:
wait_for_nodes: 99 wait_for_nodes: 99
timeout: 10s timeout: 5s
- match: { "timed_out": true } - match: { "timed_out": true }
- do: - do:

View File

@ -5,22 +5,19 @@
*/ */
package org.elasticsearch.smoketest; package org.elasticsearch.smoketest;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
public abstract class WatcherRestTestCase extends ESRestTestCase { public abstract class WatcherRestTestCase extends ESRestTestCase {
public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) { public WatcherRestTestCase(@Name("yaml") RestTestCandidate testCandidate) {
@ -34,19 +31,11 @@ public abstract class WatcherRestTestCase extends ESRestTestCase {
@Before @Before
public void startWatcher() throws Exception { public void startWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.start", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_start", null, null));
client.execute(request);
}
} }
@After @After
public void stopWatcher() throws Exception { public void stopWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.stop", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_stop", null, null));
client.execute(request);
}
} }
} }

View File

@ -5,28 +5,26 @@
*/ */
package org.elasticsearch.smoketest; package org.elasticsearch.smoketest;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class WatcherWithSecurityIT extends ESRestTestCase { public class WatcherWithSecurityIT extends ESRestTestCase {
private final static String TEST_ADMIN_USERNAME = "test_admin"; private final static String TEST_ADMIN_USERNAME = "test_admin";
@ -43,24 +41,12 @@ public class WatcherWithSecurityIT extends ESRestTestCase {
@Before @Before
public void startWatcher() throws Exception { public void startWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.start", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_start", null, null));
String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray()));
request.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, token);
client.execute(request);
}
} }
@After @After
public void stopWatcher() throws Exception { public void stopWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { getAdminExecutionContext().callApi("xpack.watcher.stop", emptyMap(), emptyList(), emptyMap());
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/watcher/_stop", null, null));
String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecuredString(TEST_ADMIN_PASSWORD.toCharArray()));
request.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, token);
client.execute(request);
}
} }
@Override @Override

View File

@ -29,7 +29,7 @@ dependencies {
compile 'com.unboundid:unboundid-ldapsdk:2.3.8' compile 'com.unboundid:unboundid-ldapsdk:2.3.8'
compile 'org.bouncycastle:bcprov-jdk15on:1.54' compile 'org.bouncycastle:bcprov-jdk15on:1.54'
compile 'org.bouncycastle:bcpkix-jdk15on:1.54' compile 'org.bouncycastle:bcpkix-jdk15on:1.54'
testCompile 'com.google.jimfs:jimfs:1.0' testCompile 'com.google.jimfs:jimfs:1.1'
// watcher deps // watcher deps
compile 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:r239' compile 'com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:r239'

View File

@ -23,6 +23,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.DummyTransportAddress; import org.elasticsearch.common.transport.DummyTransportAddress;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.http.HttpInfo; import org.elasticsearch.http.HttpInfo;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
@ -112,7 +113,7 @@ public class ClusterStatsResolverTests extends MonitoringIndexNameResolverTestCa
Settings.EMPTY, DummyOsInfo.INSTANCE, new ProcessInfo(randomInt(), randomBoolean()), JvmInfo.jvmInfo(), Settings.EMPTY, DummyOsInfo.INSTANCE, new ProcessInfo(randomInt(), randomBoolean()), JvmInfo.jvmInfo(),
new ThreadPoolInfo(Collections.singletonList(new ThreadPool.Info("test_threadpool", ThreadPool.ThreadPoolType.FIXED, 5))), new ThreadPoolInfo(Collections.singletonList(new ThreadPool.Info("test_threadpool", ThreadPool.ThreadPoolType.FIXED, 5))),
new TransportInfo(transportAddress, Collections.emptyMap()), new HttpInfo(transportAddress, randomLong()), new TransportInfo(transportAddress, Collections.emptyMap()), new HttpInfo(transportAddress, randomLong()),
new PluginsAndModules(), new IngestInfo(Collections.emptyList())); new PluginsAndModules(), new IngestInfo(Collections.emptyList()), new ByteSizeValue(randomIntBetween(1, 1024)));
} }

View File

@ -43,6 +43,7 @@ public class NodeStatsTests extends MarvelIntegTestCase {
wipeMarvelIndices(); wipeMarvelIndices();
} }
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/2588")
public void testNodeStats() throws Exception { public void testNodeStats() throws Exception {
logger.debug("--> creating some indices for future node stats"); logger.debug("--> creating some indices for future node stats");
final int numDocs = between(50, 150); final int numDocs = between(50, 150);

View File

@ -5,21 +5,18 @@
*/ */
package org.elasticsearch.marvel.security; package org.elasticsearch.marvel.security;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.Header;
import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.marvel.MonitoringSettings; import org.elasticsearch.marvel.MonitoringSettings;
import org.elasticsearch.marvel.test.MarvelIntegTestCase; import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.After;
import java.io.IOException; import java.util.Collections;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue;
@ -29,13 +26,6 @@ import static org.hamcrest.CoreMatchers.nullValue;
public class MarvelSettingsFilterTests extends MarvelIntegTestCase { public class MarvelSettingsFilterTests extends MarvelIntegTestCase {
private CloseableHttpClient httpClient = HttpClients.createDefault();
@After
public void cleanup() throws IOException {
httpClient.close();
}
@Override @Override
protected Settings nodeSettings(int nodeOrdinal) { protected Settings nodeSettings(int nodeOrdinal) {
return Settings.builder() return Settings.builder()
@ -53,46 +43,35 @@ public class MarvelSettingsFilterTests extends MarvelIntegTestCase {
} }
public void testGetSettingsFiltered() throws Exception { public void testGetSettingsFiltered() throws Exception {
String body = executeRequest("GET", "/_nodes/settings", null, null).getBody(); Header[] headers;
Map<String, Object> response = JsonXContent.jsonXContent.createParser(body).map(); if (securityEnabled) {
Map<String, Object> nodes = (Map<String, Object>) response.get("nodes"); headers = new Header[] {
for (Object node : nodes.values()) { new BasicHeader(BASIC_AUTH_HEADER,
Map<String, Object> settings = (Map<String, Object>) ((Map<String, Object>) node).get("settings"); basicAuthHeaderValue(SecuritySettings.TEST_USERNAME,
new SecuredString(SecuritySettings.TEST_PASSWORD.toCharArray())))};
assertThat(extractValue("xpack.monitoring.agent.exporters._http.type", settings), Matchers.<Object>equalTo("http")); } else {
assertThat(extractValue("xpack.monitoring.agent.exporters._http.enabled", settings), Matchers.<Object>equalTo("false")); headers = new Header[0];
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.auth.username"); }
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.auth.password"); try (Response response = getRestClient().performRequest("GET", "/_nodes/settings",
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.truststore.path"); Collections.emptyMap(), null, headers)) {
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.truststore.password"); Map<String, Object> responseMap = JsonXContent.jsonXContent.createParser(response.getEntity().getContent()).map();
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.hostname_verification"); @SuppressWarnings("unchecked")
Map<String, Object> nodes = (Map<String, Object>) responseMap.get("nodes");
for (Object node : nodes.values()) {
@SuppressWarnings("unchecked")
Map<String, Object> settings = (Map<String, Object>) ((Map<String, Object>) node).get("settings");
assertThat(extractValue("xpack.monitoring.agent.exporters._http.type", settings), Matchers.<Object>equalTo("http"));
assertThat(extractValue("xpack.monitoring.agent.exporters._http.enabled", settings), Matchers.<Object>equalTo("false"));
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.auth.username");
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.auth.password");
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.truststore.path");
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.truststore.password");
assertNullSetting(settings, "xpack.monitoring.agent.exporters._http.ssl.hostname_verification");
}
} }
} }
private void assertNullSetting(Map<String, Object> settings, String setting) { private void assertNullSetting(Map<String, Object> settings, String setting) {
assertThat(extractValue(setting, settings), nullValue()); assertThat(extractValue(setting, settings), nullValue());
} }
protected HttpResponse executeRequest(String method, String path, String body, Map<String, String> params) throws IOException {
HttpServerTransport httpServerTransport = internalCluster().getInstance(HttpServerTransport.class,
internalCluster().getMasterName());
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient)
.httpTransport(httpServerTransport)
.method(method)
.path(path);
if (params != null) {
for (Map.Entry<String, String> entry : params.entrySet()) {
requestBuilder.addParam(entry.getKey(), entry.getValue());
}
}
if (body != null) {
requestBuilder.body(body);
}
if (securityEnabled) {
requestBuilder.addHeader(BASIC_AUTH_HEADER,
basicAuthHeaderValue(SecuritySettings.TEST_USERNAME, new SecuredString(SecuritySettings.TEST_PASSWORD.toCharArray())));
}
return requestBuilder.execute();
}
} }

View File

@ -235,10 +235,6 @@ public class RoleDescriptor implements ToXContent {
} }
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.PRIVILEGES)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.PRIVILEGES)) {
privileges = readStringArray(roleName, parser, true); privileges = readStringArray(roleName, parser, true);
if (names.length == 0) {
throw new ElasticsearchParseException("failed to parse indices privileges for role [{}]. [{}] cannot be an empty " +
"array", roleName, currentFieldName);
}
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.FIELDS)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.FIELDS)) {
fields = readStringArray(roleName, parser, true); fields = readStringArray(roleName, parser, true);
} else { } else {

View File

@ -5,16 +5,18 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.HttpEntity;
import org.apache.http.impl.client.HttpClients; import org.apache.http.StatusLine;
import org.elasticsearch.http.HttpServerTransport; import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.xpack.security.authc.support.Hasher; import org.elasticsearch.xpack.security.authc.support.Hasher;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.After;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -32,19 +34,16 @@ public abstract class AbstractPrivilegeTestCase extends SecurityIntegTestCase {
protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("passwd".toCharArray()))); protected static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("passwd".toCharArray())));
private CloseableHttpClient httpClient = HttpClients.createDefault();
@After
public void cleanup() throws IOException {
httpClient.close();
}
protected void assertAccessIsAllowed(String user, String method, String uri, String body, protected void assertAccessIsAllowed(String user, String method, String uri, String body,
Map<String, String> params) throws IOException { Map<String, String> params) throws IOException {
HttpResponse response = executeRequest(user, method, uri, body, params); try (Response response = getRestClient().performRequest(method, uri, params, entityOrNull(body),
String message = String.format(Locale.ROOT, "%s %s: Expected no error got %s %s with body %s", method, uri, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
response.getStatusCode(), response.getReasonPhrase(), response.getBody()); UsernamePasswordToken.basicAuthHeaderValue(user, new SecuredString("passwd".toCharArray()))))) {
assertThat(message, response.getStatusCode(), is(not(greaterThanOrEqualTo(400)))); StatusLine statusLine = response.getStatusLine();
String message = String.format(Locale.ROOT, "%s %s: Expected no error got %s %s with body %s", method, uri,
statusLine.getStatusCode(), statusLine.getReasonPhrase(), EntityUtils.toString(response.getEntity()));
assertThat(message, statusLine.getStatusCode(), is(not(greaterThanOrEqualTo(400))));
}
} }
protected void assertAccessIsAllowed(String user, String method, String uri, String body) throws IOException { protected void assertAccessIsAllowed(String user, String method, String uri, String body) throws IOException {
@ -65,28 +64,24 @@ public abstract class AbstractPrivilegeTestCase extends SecurityIntegTestCase {
protected void assertAccessIsDenied(String user, String method, String uri, String body, protected void assertAccessIsDenied(String user, String method, String uri, String body,
Map<String, String> params) throws IOException { Map<String, String> params) throws IOException {
HttpResponse response = executeRequest(user, method, uri, body, params); try {
String message = String.format(Locale.ROOT, "%s %s body %s: Expected 403, got %s %s with body %s", method, uri, body, getRestClient().performRequest(method, uri, params, entityOrNull(body),
response.getStatusCode(), response.getReasonPhrase(), response.getBody()); new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
assertThat(message, response.getStatusCode(), is(403)); UsernamePasswordToken.basicAuthHeaderValue(user, new SecuredString("passwd".toCharArray()))));
fail("request should have failed");
} catch(ResponseException e) {
StatusLine statusLine = e.getResponse().getStatusLine();
String message = String.format(Locale.ROOT, "%s %s body %s: Expected 403, got %s %s with body %s", method, uri, body,
statusLine.getStatusCode(), statusLine.getReasonPhrase(), e.getResponseBody());
assertThat(message, statusLine.getStatusCode(), is(403));
}
} }
protected HttpResponse executeRequest(String user, String method, String uri, String body, private static HttpEntity entityOrNull(String body) {
Map<String, String> params) throws IOException { HttpEntity entity = null;
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport);
requestBuilder.path(uri);
requestBuilder.method(method);
for (Map.Entry<String, String> entry : params.entrySet()) {
requestBuilder.addParam(entry.getKey(), entry.getValue());
}
if (body != null) { if (body != null) {
requestBuilder.body(body); entity = new StringEntity(body, RestClient.JSON_CONTENT_TYPE);
} }
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(user, return entity;
new SecuredString("passwd".toCharArray())));
return requestBuilder.execute();
} }
} }

View File

@ -5,9 +5,15 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.http.Header;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
@ -15,10 +21,10 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -49,8 +55,8 @@ public class BulkUpdateTests extends SecurityIntegTestCase {
.get().isCreated(); .get().isCreated();
assertThat(created, is(false)); assertThat(created, is(false));
getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1").setFields("test", "not test").get(); getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1").setFields("test", "not test").get();
assertThat((String) getResponse.getField("test").getValue(), equalTo("test")); assertThat(getResponse.getField("test").getValue(), equalTo("test"));
assertThat((String) getResponse.getField("not test").getValue(), equalTo("not test")); assertThat(getResponse.getField("not test").getValue(), equalTo("not test"));
// this part is important. Without this, the document may be read from the translog which would bypass the bug where // this part is important. Without this, the document may be read from the translog which would bypass the bug where
// FLS kicks in because the request can't be found and only returns meta fields // FLS kicks in because the request can't be found and only returns meta fields
@ -62,43 +68,61 @@ public class BulkUpdateTests extends SecurityIntegTestCase {
assertThat(((UpdateResponse)response.getItems()[0].getResponse()).isCreated(), is(false)); assertThat(((UpdateResponse)response.getItems()[0].getResponse()).isCreated(), is(false));
getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1"). getResponse = internalCluster().transportClient().prepareGet("index1", "type", "1").
setFields("test", "not test", "bulk updated").get(); setFields("test", "not test", "bulk updated").get();
assertThat((String) getResponse.getField("test").getValue(), equalTo("test")); assertThat(getResponse.getField("test").getValue(), equalTo("test"));
assertThat((String) getResponse.getField("not test").getValue(), equalTo("not test")); assertThat(getResponse.getField("not test").getValue(), equalTo("not test"));
assertThat((String) getResponse.getField("bulk updated").getValue(), equalTo("bulk updated")); assertThat(getResponse.getField("bulk updated").getValue(), equalTo("bulk updated"));
} }
public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException { public void testThatBulkUpdateDoesNotLoseFieldsHttp() throws IOException {
final String path = "/index1/type/1"; final String path = "/index1/type/1";
final String basicAuthHeader = UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, final Header basicAuthHeader = new BasicHeader("Authorization",
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())); UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
httpClient().path(path).addHeader("Authorization", basicAuthHeader).method("PUT").body("{\"test\":\"test\"}").execute(); StringEntity body = new StringEntity("{\"test\":\"test\"}", RestClient.JSON_CONTENT_TYPE);
HttpResponse response = httpClient().path(path).addHeader("Authorization", basicAuthHeader).method("GET").execute(); try (Response response = getRestClient().performRequest("PUT", path, Collections.emptyMap(), body, basicAuthHeader)) {
assertThat(response.getBody(), containsString("\"test\":\"test\"")); assertThat(response.getStatusLine().getStatusCode(), equalTo(201));
}
try (Response response = getRestClient().performRequest("GET", path, Collections.emptyMap(), null, basicAuthHeader)) {
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
assertThat(EntityUtils.toString(response.getEntity()), containsString("\"test\":\"test\""));
}
if (randomBoolean()) { if (randomBoolean()) {
flushAndRefresh(); flushAndRefresh();
} }
//update with new field //update with new field
httpClient().path(path + "/_update").addHeader("Authorization", basicAuthHeader).method("POST"). body = new StringEntity("{\"doc\": {\"not test\": \"not test\"}}", RestClient.JSON_CONTENT_TYPE);
body("{\"doc\": {\"not test\": \"not test\"}}").execute(); try (Response response = getRestClient().performRequest("POST", path + "/_update",
response = httpClient().path(path).addHeader("Authorization", basicAuthHeader).method("GET").execute(); Collections.emptyMap(), body, basicAuthHeader)) {
assertThat(response.getBody(), containsString("\"test\":\"test\"")); assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
assertThat(response.getBody(), containsString("\"not test\":\"not test\"")); }
try (Response response = getRestClient().performRequest("GET", path, Collections.emptyMap(), null, basicAuthHeader)) {
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
String responseBody = EntityUtils.toString(response.getEntity());
assertThat(responseBody, containsString("\"test\":\"test\""));
assertThat(responseBody, containsString("\"not test\":\"not test\""));
}
// this part is important. Without this, the document may be read from the translog which would bypass the bug where // this part is important. Without this, the document may be read from the translog which would bypass the bug where
// FLS kicks in because the request can't be found and only returns meta fields // FLS kicks in because the request can't be found and only returns meta fields
flushAndRefresh(); flushAndRefresh();
// update with bulk body = new StringEntity("{\"update\": {\"_index\": \"index1\", \"_type\": \"type\", \"_id\": \"1\"}}\n" +
httpClient().path("/_bulk").addHeader("Authorization", basicAuthHeader).method("POST") "{\"doc\": {\"bulk updated\":\"bulk updated\"}}\n", RestClient.JSON_CONTENT_TYPE);
.body("{\"update\": {\"_index\": \"index1\", \"_type\": \"type\", \"_id\": \"1\"}}\n{\"doc\": {\"bulk updated\":\"bulk " + try (Response response = getRestClient().performRequest("POST", "/_bulk",
"updated\"}}\n") Collections.emptyMap(), body, basicAuthHeader)) {
.execute(); assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
response = httpClient().path(path).addHeader("Authorization", basicAuthHeader).method("GET").execute(); }
assertThat(response.getBody(), containsString("\"test\":\"test\""));
assertThat(response.getBody(), containsString("\"not test\":\"not test\"")); try (Response response = getRestClient().performRequest("GET", path, Collections.emptyMap(), null, basicAuthHeader)) {
assertThat(response.getBody(), containsString("\"bulk updated\":\"bulk updated\"")); String responseBody = EntityUtils.toString(response.getEntity());
assertThat(responseBody, containsString("\"test\":\"test\""));
assertThat(responseBody, containsString("\"not test\":\"not test\""));
assertThat(responseBody, containsString("\"bulk updated\":\"bulk updated\""));
}
} }
} }

View File

@ -5,14 +5,15 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.message.BasicHeader;
import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionListener;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.xpack.security.user.User; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheRequest;
import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse; import org.elasticsearch.xpack.security.action.realm.ClearRealmCacheResponse;
import org.elasticsearch.xpack.security.authc.Realm; import org.elasticsearch.xpack.security.authc.Realm;
@ -22,10 +23,7 @@ import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.SecuredStringTests; import org.elasticsearch.xpack.security.authc.support.SecuredStringTests;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.xpack.security.user.User;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.util.ArrayList; import java.util.ArrayList;
@ -39,14 +37,10 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.Matchers.sameInstance;
/**
*
*/
public class ClearRealmsCacheTests extends SecurityIntegTestCase { public class ClearRealmsCacheTests extends SecurityIntegTestCase {
private static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("passwd".toCharArray()))); private static final String USERS_PASSWD_HASHED = new String(Hasher.BCRYPT.hash(new SecuredString("passwd".toCharArray())));
@ -168,21 +162,12 @@ public class ClearRealmsCacheTests extends SecurityIntegTestCase {
} }
static void executeHttpRequest(String path, Map<String, String> params) throws Exception { static void executeHttpRequest(String path, Map<String, String> params) throws Exception {
try (CloseableHttpClient client = HttpClients.createDefault()) { try (Response response = getRestClient().performRequest("POST", path, params, null,
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(client) new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.httpTransport(internalCluster().getDataNodeInstance(HttpServerTransport.class)) UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
.method("POST") new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.path(path); assertNotNull(response.getEntity());
for (Map.Entry<String, String> entry : params.entrySet()) { assertTrue(EntityUtils.toString(response.getEntity()).contains("cluster_name"));
requestBuilder.addParam(entry.getKey(), entry.getValue());
}
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
HttpResponse response = requestBuilder.execute();
assertThat(response.hasBody(), is(true));
String body = response.getBody();
assertThat(body.contains("cluster_name"), is(true));
} }
} }
} }

View File

@ -5,9 +5,11 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -23,11 +25,11 @@ import org.elasticsearch.xpack.security.authz.store.NativeRolesStore;
import org.elasticsearch.xpack.security.client.SecurityClient; import org.elasticsearch.xpack.security.client.SecurityClient;
import org.elasticsearch.test.NativeRealmIntegTestCase; import org.elasticsearch.test.NativeRealmIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.junit.Before; import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
@ -81,7 +83,7 @@ public class ClearRolesCacheTests extends NativeRealmIntegTestCase {
logger.debug("using poller interval [{}]", pollerInterval); logger.debug("using poller interval [{}]", pollerInterval);
return Settings.builder() return Settings.builder()
.put(super.nodeSettings(nodeOrdinal)) .put(super.nodeSettings(nodeOrdinal))
.put(NativeRolesStore.POLL_INTERVAL_SETTING.getKey(), pollerInterval) .put(NativeRolesStore.POLL_INTERVAL_SETTING.getKey(), pollerInterval.getStringRep())
.put(NetworkModule.HTTP_ENABLED.getKey(), true) .put(NetworkModule.HTTP_ENABLED.getKey(), true)
.build(); .build();
} }
@ -128,7 +130,7 @@ public class ClearRolesCacheTests extends NativeRealmIntegTestCase {
final boolean useHttp = randomBoolean(); final boolean useHttp = randomBoolean();
final boolean clearAll = randomBoolean(); final boolean clearAll = randomBoolean();
logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll); logger.debug("--> starting to clear roles. using http [{}] clearing all [{}]", useHttp, clearAll);
String[] rolesToClear = clearAll ? (randomBoolean() ? roles : null) : toModify.toArray(Strings.EMPTY_ARRAY); String[] rolesToClear = clearAll ? (randomBoolean() ? roles : null) : toModify.toArray(new String[toModify.size()]);
if (useHttp) { if (useHttp) {
String path; String path;
if (rolesToClear == null) { if (rolesToClear == null) {
@ -136,12 +138,12 @@ public class ClearRolesCacheTests extends NativeRealmIntegTestCase {
} else { } else {
path = "/_xpack/security/role/" + Strings.arrayToCommaDelimitedString(rolesToClear) + "/_clear_cache"; path = "/_xpack/security/role/" + Strings.arrayToCommaDelimitedString(rolesToClear) + "/_clear_cache";
} }
HttpResponse response = httpClient().path(path).method("POST") try (Response response = getRestClient().performRequest("POST", path, Collections.emptyMap(), null,
.addHeader("Authorization", new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))) new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.execute(); assertThat(response.getStatusLine().getStatusCode(), is(RestStatus.OK.getStatus()));
assertThat(response.getStatusCode(), is(RestStatus.OK.getStatus())); }
} else { } else {
securityClient.prepareClearRolesCache().names(rolesToClear).get(); securityClient.prepareClearRolesCache().names(rolesToClear).get();
} }

View File

@ -5,20 +5,21 @@
*/ */
package org.elasticsearch.integration; package org.elasticsearch.integration;
import org.apache.lucene.util.LuceneTestCase.BadApple; import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.junit.Before; import org.junit.Before;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static org.hamcrest.Matchers.containsString; import static org.apache.lucene.util.LuceneTestCase.BadApple;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
//test is just too slow, please fix it to not be sleep-based //test is just too slow, please fix it to not be sleep-based
@ -303,8 +304,14 @@ public class IndexPrivilegeTests extends AbstractPrivilegeTestCase {
} }
public void testThatUnknownUserIsRejectedProperly() throws Exception { public void testThatUnknownUserIsRejectedProperly() throws Exception {
HttpResponse response = executeRequest("idonotexist", "GET", "/", null, new HashMap<>()); try {
assertThat(response.getStatusCode(), is(401)); getRestClient().performRequest("GET", "/", Collections.emptyMap(), null,
new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue("idonotexist", new SecuredString("passwd".toCharArray()))));
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
} }
private void assertUserExecutes(String user, String action, String index, boolean userIsAllowed) throws Exception { private void assertUserExecutes(String user, String action, String index, boolean userIsAllowed) throws Exception {

View File

@ -14,6 +14,8 @@ import org.elasticsearch.action.admin.cluster.stats.ClusterStatsResponse;
import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
@ -194,13 +196,20 @@ public class LicensingTests extends SecurityIntegTestCase {
} }
public void testRestAuthenticationByLicenseType() throws Exception { public void testRestAuthenticationByLicenseType() throws Exception {
// the default of the licensing tests is basic try (Response response = getRestClient().performRequest("GET", "/", Collections.emptyMap(), null)) {
assertThat(httpClient().path("/").execute().getStatusCode(), is(200)); // the default of the licensing tests is basic
assertThat(response.getStatusLine().getStatusCode(), is(200));
}
// generate a new license with a mode that enables auth // generate a new license with a mode that enables auth
OperationMode mode = randomFrom(OperationMode.GOLD, OperationMode.TRIAL, OperationMode.PLATINUM, OperationMode.STANDARD); OperationMode mode = randomFrom(OperationMode.GOLD, OperationMode.TRIAL, OperationMode.PLATINUM, OperationMode.STANDARD);
enableLicensing(mode); enableLicensing(mode);
assertThat(httpClient().path("/").execute().getStatusCode(), is(401)); try {
getRestClient().performRequest("GET", "/", Collections.emptyMap(), null);
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
} }
public void testTransportClientAuthenticationByLicenseType() throws Exception { public void testTransportClientAuthenticationByLicenseType() throws Exception {

View File

@ -19,7 +19,6 @@ import org.junit.After;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
/** /**

View File

@ -5,23 +5,21 @@
*/ */
package org.elasticsearch.xpack.security; package org.elasticsearch.xpack.security;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.message.BasicHeader;
import org.apache.http.impl.client.HttpClients; import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.elasticsearch.rest.RestStatus.OK; import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.RestStatus.UNAUTHORIZED; import static org.elasticsearch.rest.RestStatus.UNAUTHORIZED;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
public class SecurityPluginTests extends SecurityIntegTestCase { public class SecurityPluginTests extends SecurityIntegTestCase {
@ -35,24 +33,20 @@ public class SecurityPluginTests extends SecurityIntegTestCase {
} }
public void testThatPluginIsLoaded() throws IOException { public void testThatPluginIsLoaded() throws IOException {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class); try {
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
logger.info("executing unauthorized request to /_xpack info"); logger.info("executing unauthorized request to /_xpack info");
HttpResponse response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport) getRestClient().performRequest("GET", "/_xpack", Collections.emptyMap(), null);
.method("GET") fail("request should have failed");
.path("/_xpack") } catch(ResponseException e) {
.execute(); assertThat(e.getResponse().getStatusLine().getStatusCode(), is(UNAUTHORIZED.getStatus()));
assertThat(response.getStatusCode(), is(UNAUTHORIZED.getStatus())); }
logger.info("executing authorized request to /_xpack infos"); logger.info("executing authorized request to /_xpack infos");
response = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport) try (Response response = getRestClient().performRequest("GET", "/_xpack", Collections.emptyMap(), null,
.method("GET") new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.path("/_xpack")
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))) new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.execute(); assertThat(response.getStatusLine().getStatusCode(), is(OK.getStatus()));
assertThat(response.getStatusCode(), is(OK.getStatus()));
} }
} }
} }

View File

@ -5,10 +5,13 @@
*/ */
package org.elasticsearch.xpack.security.authc; package org.elasticsearch.xpack.security.authc;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.ElasticsearchSecurityException; import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
@ -20,7 +23,6 @@ import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import java.util.Collections; import java.util.Collections;
@ -115,30 +117,36 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
public void testUserImpersonationUsingHttp() throws Exception { public void testUserImpersonationUsingHttp() throws Exception {
// use the transport client user and try to run as // use the transport client user and try to run as
HttpResponse response = httpClient().method("GET") try {
.path("/_nodes") getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))) UsernamePasswordToken.basicAuthHeaderValue(TRANSPORT_CLIENT_USER,
.addHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME) SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
.execute(); new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME));
assertThat(response.getStatusCode(), is(403)); fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
//the run as user shouldn't have access to the nodes api try {
response = httpClient().method("GET") //the run as user shouldn't have access to the nodes api
.path("/_nodes") getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))) UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
.execute(); SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))));
assertThat(response.getStatusCode(), is(403)); fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
// but when running as a different user it should work // but when running as a different user it should work
response = httpClient().method("GET") try (Response response = getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.path("/_nodes") new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))) SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
.addHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME) new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, SecuritySettingsSource.DEFAULT_USER_NAME))) {
.execute(); assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getStatusCode(), is(200)); }
} }
public void testEmptyUserImpersonationHeader() throws Exception { public void testEmptyUserImpersonationHeader() throws Exception {
@ -164,13 +172,16 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
} }
public void testEmptyHeaderUsingHttp() throws Exception { public void testEmptyHeaderUsingHttp() throws Exception {
HttpResponse response = httpClient().method("GET") try {
.path("/_nodes") getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))) UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
.addHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "") SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
.execute(); new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, ""));
assertThat(response.getStatusCode(), is(401)); fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
} }
public void testNonExistentRunAsUser() throws Exception { public void testNonExistentRunAsUser() throws Exception {
@ -196,13 +207,16 @@ public class RunAsIntegTests extends SecurityIntegTestCase {
} }
public void testNonExistentRunAsUserUsingHttp() throws Exception { public void testNonExistentRunAsUserUsingHttp() throws Exception {
HttpResponse response = httpClient().method("GET") try {
.path("/_nodes") getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER, new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))) UsernamePasswordToken.basicAuthHeaderValue(RUN_AS_USER,
.addHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist") SecuredStringTests.build(SecuritySettingsSource.DEFAULT_PASSWORD))),
.execute(); new BasicHeader(InternalAuthenticationService.RUN_AS_USER_HEADER, "idontexist"));
assertThat(response.getStatusCode(), is(403)); fail("request should have failed");
} catch (ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(403));
}
} }
// build our own here to better mimic an actual client... // build our own here to better mimic an actual client...

View File

@ -7,11 +7,14 @@ package org.elasticsearch.xpack.security.authc.pki;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
@ -20,8 +23,6 @@ import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerT
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.junit.BeforeClass; import org.junit.BeforeClass;
@ -34,6 +35,7 @@ import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Collections;
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD; import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_PASSWORD;
import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_USER_NAME; import static org.elasticsearch.test.SecuritySettingsSource.DEFAULT_USER_NAME;
@ -78,23 +80,21 @@ public class PkiOptionalClientAuthTests extends SecurityIntegTestCase {
} }
public void testRestClientWithoutClientCertificate() throws Exception { public void testRestClientWithoutClientCertificate() throws Exception {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class); CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(getSSLContext()).build();
try (RestClient restClient = createRestClient(httpClient, "https")) {
try {
restClient.performRequest("GET", "_nodes", Collections.emptyMap(), null);
fail("request should have failed");
} catch(ResponseException e) {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
try (CloseableHttpClient httpClient = HttpClients.custom().setSslcontext(getSSLContext()).build()) { try (Response response = restClient.performRequest("GET", "_nodes", Collections.emptyMap(), null,
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient) new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.host("localhost") UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
.port(((InetSocketTransportAddress)httpServerTransport.boundAddress().publishAddress()).address().getPort()) new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.protocol("https") assertThat(response.getStatusLine().getStatusCode(), is(200));
.method("GET") }
.path("/_nodes");
HttpResponse response = requestBuilder.execute();
assertThat(response.getStatusCode(), is(401));
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
response = requestBuilder.execute();
assertThat(response.getStatusCode(), is(200));
} }
} }

View File

@ -8,27 +8,27 @@ package org.elasticsearch.xpack.security.authc.pki;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.xpack.security.transport.SSLClientAuth; import org.elasticsearch.xpack.security.transport.SSLClientAuth;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Locale; import java.util.Locale;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -77,21 +77,16 @@ public class PkiWithoutClientAuthenticationTests extends SecurityIntegTestCase {
} }
public void testThatHttpWorks() throws Exception { public void testThatHttpWorks() throws Exception {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
SSLContext sc = SSLContext.getInstance("SSL"); SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom()); sc.init(null, trustAllCerts, new SecureRandom());
try (CloseableHttpClient httpClient = HttpClients.custom().setSslcontext(sc).build()) { CloseableHttpClient httpClient = HttpClients.custom().setSSLContext(sc).build();
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient) try (RestClient restClient = createRestClient(httpClient, "https")) {
.host("localhost") try (Response response = restClient.performRequest("GET", "/_nodes", Collections.emptyMap(), null,
.port(((InetSocketTransportAddress)httpServerTransport.boundAddress().publishAddress()).address().getPort()) new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
.protocol("https") UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
.method("GET") new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.path("/_nodes"); assertThat(response.getStatusLine().getStatusCode(), is(200));
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER, }
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
HttpResponse response = requestBuilder.execute();
assertThat(response.getStatusCode(), is(200));
} }
} }
} }

View File

@ -5,19 +5,18 @@
*/ */
package org.elasticsearch.xpack.security.authc.pki; package org.elasticsearch.xpack.security.authc.pki;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.message.BasicHeader;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.client.http.HttpResponse; import org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken;
import java.util.Collections;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -44,17 +43,11 @@ public class PkiWithoutSSLTests extends SecurityIntegTestCase {
} }
public void testThatHttpWorks() throws Exception { public void testThatHttpWorks() throws Exception {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class); try (Response response = getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null,
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { new BasicHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient) UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
.httpTransport(httpServerTransport) new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
.method("GET") assertThat(response.getStatusLine().getStatusCode(), is(200));
.path("/_nodes");
requestBuilder.addHeader(UsernamePasswordToken.BASIC_AUTH_HEADER,
UsernamePasswordToken.basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray())));
HttpResponse response = requestBuilder.execute();
assertThat(response.getStatusCode(), is(200));
} }
} }
} }

View File

@ -64,6 +64,7 @@ import java.util.Collections;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Set; import java.util.Set;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptySet; import static java.util.Collections.emptySet;
import static java.util.Collections.singleton; import static java.util.Collections.singleton;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
@ -94,7 +95,7 @@ public class SecurityIndexSearcherWrapperUnitTests extends ESTestCase {
Collections.emptyMap(), Collections.emptyMap()); Collections.emptyMap(), Collections.emptyMap());
SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap()); SimilarityService similarityService = new SimilarityService(indexSettings, Collections.emptyMap());
mapperService = new MapperService(indexSettings, analysisService, similarityService, mapperService = new MapperService(indexSettings, analysisService, similarityService,
new IndicesModule(new NamedWriteableRegistry()).getMapperRegistry(), () -> null); new IndicesModule(new NamedWriteableRegistry(), emptyList()).getMapperRegistry(), () -> null);
ShardId shardId = new ShardId(index, 0); ShardId shardId = new ShardId(index, 0);
licenseState = mock(SecurityLicenseState.class); licenseState = mock(SecurityLicenseState.class);

View File

@ -5,6 +5,10 @@
*/ */
package org.elasticsearch.xpack.security.rest.action; package org.elasticsearch.xpack.security.rest.action;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
@ -12,10 +16,10 @@ import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.xpack.security.user.AnonymousUser; import org.elasticsearch.xpack.security.user.AnonymousUser;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.SecuritySettingsSource; import org.elasticsearch.test.SecuritySettingsSource;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.test.rest.json.JsonPath; import org.elasticsearch.test.rest.json.JsonPath;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import java.util.Collections;
import java.util.List; import java.util.List;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
@ -47,32 +51,40 @@ public class RestAuthenticateActionTests extends SecurityIntegTestCase {
} }
public void testAuthenticateApi() throws Exception { public void testAuthenticateApi() throws Exception {
HttpResponse response = httpClient().method("GET").path("/_xpack/security/_authenticate") try (Response response = getRestClient().performRequest(
.addHeader("Authorization", basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME, "GET", "/_xpack/security/_authenticate", Collections.emptyMap(), null,
new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))) new BasicHeader("Authorization", basicAuthHeaderValue(SecuritySettingsSource.DEFAULT_USER_NAME,
.execute(); new SecuredString(SecuritySettingsSource.DEFAULT_PASSWORD.toCharArray()))))) {
assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getStatusCode(), is(200)); JsonPath jsonPath = new JsonPath(EntityUtils.toString(response.getEntity()));
JsonPath jsonPath = new JsonPath(response.getBody()); assertThat(jsonPath.evaluate("username").toString(), equalTo(SecuritySettingsSource.DEFAULT_USER_NAME));
assertThat(jsonPath.evaluate("username").toString(), equalTo(SecuritySettingsSource.DEFAULT_USER_NAME)); @SuppressWarnings("unchecked")
List<String> roles = (List<String>) jsonPath.evaluate("roles"); List<String> roles = (List<String>) jsonPath.evaluate("roles");
assertThat(roles.size(), is(1)); assertThat(roles.size(), is(1));
assertThat(roles, contains(SecuritySettingsSource.DEFAULT_ROLE)); assertThat(roles, contains(SecuritySettingsSource.DEFAULT_ROLE));
}
} }
public void testAuthenticateApiWithoutAuthentication() throws Exception { public void testAuthenticateApiWithoutAuthentication() throws Exception {
HttpResponse response = httpClient().method("GET").path("/_xpack/security/_authenticate") try (Response response = getRestClient().performRequest("GET", "/_xpack/security/_authenticate",
.execute(); Collections.emptyMap(), null)) {
if (anonymousEnabled) {
if (anonymousEnabled) { assertThat(response.getStatusLine().getStatusCode(), is(200));
assertThat(response.getStatusCode(), is(200)); JsonPath jsonPath = new JsonPath(EntityUtils.toString(response.getEntity()));
JsonPath jsonPath = new JsonPath(response.getBody()); assertThat(jsonPath.evaluate("username").toString(), equalTo("anon"));
assertThat(jsonPath.evaluate("username").toString(), equalTo("anon")); @SuppressWarnings("unchecked")
List<String> roles = (List<String>) jsonPath.evaluate("roles"); List<String> roles = (List<String>) jsonPath.evaluate("roles");
assertThat(roles.size(), is(2)); assertThat(roles.size(), is(2));
assertThat(roles, contains(SecuritySettingsSource.DEFAULT_ROLE, "foo")); assertThat(roles, contains(SecuritySettingsSource.DEFAULT_ROLE, "foo"));
} else { } else {
assertThat(response.getStatusCode(), is(401)); fail("request should have failed");
}
} catch(ResponseException e) {
if (anonymousEnabled) {
fail("request should have succeeded");
} else {
assertThat(e.getResponse().getStatusLine().getStatusCode(), is(401));
}
} }
} }
} }

View File

@ -9,20 +9,21 @@ import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts; import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.xpack.security.ssl.ClientSSLService; import org.elasticsearch.xpack.security.ssl.ClientSSLService;
import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global; import org.elasticsearch.xpack.security.ssl.SSLConfiguration.Global;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyHttpServerTransport;
import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport; import org.elasticsearch.xpack.security.transport.netty.SecurityNettyTransport;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.transport.Transport; import org.elasticsearch.transport.Transport;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
@ -30,10 +31,12 @@ import javax.net.ssl.SSLHandshakeException;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.Collections;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore; import static org.elasticsearch.test.SecuritySettingsSource.getSSLSettingsForStore;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
public class SslClientAuthTests extends SecurityIntegTestCase { public class SslClientAuthTests extends SecurityIntegTestCase {
@Override @Override
@ -59,14 +62,8 @@ public class SslClientAuthTests extends SecurityIntegTestCase {
SSLContexts.createDefault(), SSLContexts.createDefault(),
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build(); try (RestClient restClient = createRestClient(HttpClients.custom().setSSLSocketFactory(socketFactory).build(), "https")) {
restClient.performRequest("GET", "/", Collections.emptyMap(), null);
try {
new HttpRequestBuilder(client)
.httpTransport(internalCluster().getInstance(HttpServerTransport.class))
.method("GET").path("/")
.protocol("https")
.execute();
fail("Expected SSLHandshakeException"); fail("Expected SSLHandshakeException");
} catch (SSLHandshakeException e) { } catch (SSLHandshakeException e) {
assertThat(e.getMessage(), containsString("unable to find valid certification path to requested target")); assertThat(e.getMessage(), containsString("unable to find valid certification path to requested target"));
@ -85,13 +82,13 @@ public class SslClientAuthTests extends SecurityIntegTestCase {
CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build(); CloseableHttpClient client = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
HttpResponse response = new HttpRequestBuilder(client) try (RestClient restClient = createRestClient(client, "https")) {
.httpTransport(internalCluster().getInstance(HttpServerTransport.class)) try (Response response = restClient.performRequest("GET", "/", Collections.emptyMap(), null,
.method("GET").path("/") new BasicHeader("Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword())))) {
.protocol("https") assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
.addHeader("Authorization", basicAuthHeaderValue(transportClientUsername(), transportClientPassword())) assertThat(EntityUtils.toString(response.getEntity()), containsString("You Know, for Search"));
.execute(); }
assertThat(response.getBody(), containsString("You Know, for Search")); }
} }
public void testThatTransportWorksWithoutSslClientAuth() throws Exception { public void testThatTransportWorksWithoutSslClientAuth() throws Exception {

View File

@ -5,25 +5,16 @@
*/ */
package org.elasticsearch.xpack.security.user; package org.elasticsearch.xpack.security.user;
import org.apache.http.client.methods.CloseableHttpResponse; import org.elasticsearch.client.Response;
import org.apache.http.client.methods.HttpGet; import org.elasticsearch.client.ResponseException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.xpack.security.authz.InternalAuthorizationService; import org.elasticsearch.xpack.security.authz.InternalAuthorizationService;
import org.elasticsearch.test.SecurityIntegTestCase; import org.elasticsearch.test.SecurityIntegTestCase;
import java.io.InputStreamReader; import java.util.Collections;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
@ -51,28 +42,22 @@ public class AnonymousUserIntegTests extends SecurityIntegTestCase {
} }
public void testAnonymousViaHttp() throws Exception { public void testAnonymousViaHttp() throws Exception {
try (CloseableHttpClient client = HttpClients.createDefault(); try {
CloseableHttpResponse response = client.execute(new HttpGet(getNodeUrl() + "_nodes"))) { getRestClient().performRequest("GET", "/_nodes", Collections.emptyMap(), null);
int statusCode = response.getStatusLine().getStatusCode(); fail("request should have failed");
String data = Streams.copyToString(new InputStreamReader(response.getEntity().getContent(), StandardCharsets.UTF_8)); } catch(ResponseException e) {
int statusCode = e.getResponse().getStatusLine().getStatusCode();
Response response = e.getResponse();
if (authorizationExceptionsEnabled) { if (authorizationExceptionsEnabled) {
assertThat(statusCode, is(403)); assertThat(statusCode, is(403));
assertThat(response.getFirstHeader("WWW-Authenticate"), nullValue()); assertThat(response.getHeader("WWW-Authenticate"), nullValue());
assertThat(data, containsString("security_exception")); assertThat(e.getResponseBody(), containsString("security_exception"));
} else { } else {
assertThat(statusCode, is(401)); assertThat(statusCode, is(401));
assertThat(response.getFirstHeader("WWW-Authenticate"), notNullValue()); assertThat(response.getHeader("WWW-Authenticate"), notNullValue());
assertThat(response.getFirstHeader("WWW-Authenticate").getValue(), containsString("Basic")); assertThat(response.getHeader("WWW-Authenticate"), containsString("Basic"));
assertThat(data, containsString("security_exception")); assertThat(e.getResponseBody(), containsString("security_exception"));
} }
} }
} }
private String getNodeUrl() {
TransportAddress transportAddress =
randomFrom(internalCluster().getInstance(HttpServerTransport.class).boundAddress().boundAddresses());
assertThat(transportAddress, is(instanceOf(InetSocketTransportAddress.class)));
InetSocketTransportAddress inetSocketTransportAddress = (InetSocketTransportAddress) transportAddress;
return String.format(Locale.ROOT, "http://%s:%s/", "localhost", inetSocketTransportAddress.address().getPort());
}
} }

View File

@ -1,4 +1,3 @@
cluster:admin/render/template/search
cluster:admin/repository/delete cluster:admin/repository/delete
cluster:admin/repository/get cluster:admin/repository/get
cluster:admin/repository/put cluster:admin/repository/put

View File

@ -1,4 +1,3 @@
cluster:admin/render/template/search
cluster:admin/snapshot/status[nodes] cluster:admin/snapshot/status[nodes]
cluster:admin/snapshot/status[nodes][n] cluster:admin/snapshot/status[nodes][n]
cluster:admin/tasks/cancel[n] cluster:admin/tasks/cancel[n]

View File

@ -22,6 +22,21 @@
} }
- match: { role: { created: true } } - match: { role: { created: true } }
- do:
xpack.security.put_role:
name: "backwards_role"
body: >
{
"cluster": ["all"],
"indices": [
{
"privileges": ["all"],
"names": "*"
}
]
}
- match: { role: { created: true } }
- do: - do:
xpack.security.put_user: xpack.security.put_user:
username: "joe" username: "joe"

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.common.http; package org.elasticsearch.xpack.common.http;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
@ -87,11 +86,11 @@ public class HttpResponse implements ToXContent {
* in the payload * in the payload
*/ */
public Map<String, List<String>> headers() { public Map<String, List<String>> headers() {
ImmutableMap.Builder<String, List<String>> builder = ImmutableMap.builder(); MapBuilder<String, List<String>> builder = MapBuilder.newMapBuilder();
for (Map.Entry<String, String[]> entry : headers.entrySet()) { for (Map.Entry<String, String[]> entry : headers.entrySet()) {
builder.put(entry.getKey().toLowerCase(Locale.ROOT), Arrays.asList(entry.getValue())); builder.put(entry.getKey().toLowerCase(Locale.ROOT), Arrays.asList(entry.getValue()));
} }
return builder.build(); return builder.immutableMap();
} }
public String[] header(String header) { public String[] header(String header) {

View File

@ -7,6 +7,7 @@ package org.elasticsearch.xpack.notification.email;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
@ -16,19 +17,26 @@ import javax.activation.DataHandler;
import javax.activation.DataSource; import javax.activation.DataSource;
import javax.activation.FileDataSource; import javax.activation.FileDataSource;
import javax.mail.MessagingException; import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeBodyPart;
import javax.mail.util.ByteArrayDataSource; import javax.mail.util.ByteArrayDataSource;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path; import java.nio.file.Path;
import static javax.mail.Part.ATTACHMENT;
import static javax.mail.Part.INLINE;
/** /**
* *
*/ */
public abstract class Attachment extends BodyPartSource { public abstract class Attachment extends BodyPartSource {
protected Attachment(String id, String name, String contentType) { private final boolean inline;
protected Attachment(String id, String name, String contentType, boolean inline) {
super(id, name, contentType); super(id, name, contentType);
this.inline = inline;
} }
@Override @Override
@ -36,13 +44,17 @@ public abstract class Attachment extends BodyPartSource {
MimeBodyPart part = new MimeBodyPart(); MimeBodyPart part = new MimeBodyPart();
part.setContentID(id); part.setContentID(id);
part.setFileName(name); part.setFileName(name);
part.setDisposition(Part.ATTACHMENT); part.setDisposition(inline ? INLINE : ATTACHMENT);
writeTo(part); writeTo(part);
return part; return part;
} }
public abstract String type(); public abstract String type();
public boolean isInline() {
return inline;
}
/** /**
* intentionally not emitting path as it may come as an information leak * intentionally not emitting path as it may come as an information leak
*/ */
@ -65,22 +77,22 @@ public abstract class Attachment extends BodyPartSource {
private final Path path; private final Path path;
private final DataSource dataSource; private final DataSource dataSource;
public File(String id, Path path) { public File(String id, Path path, boolean inline) {
this(id, path.getFileName().toString(), path); this(id, path.getFileName().toString(), path, inline);
} }
public File(String id, Path path, String contentType) { public File(String id, Path path, String contentType, boolean inline) {
this(id, path.getFileName().toString(), path, contentType); this(id, path.getFileName().toString(), path, contentType, inline);
} }
@SuppressForbidden(reason = "uses toFile") @SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path) { public File(String id, String name, Path path, boolean inline) {
this(id, name, path, fileTypeMap.getContentType(path.toFile())); this(id, name, path, fileTypeMap.getContentType(path.toFile()), inline);
} }
@SuppressForbidden(reason = "uses toFile") @SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path, String contentType) { public File(String id, String name, Path path, String contentType, boolean inline) {
super(id, name, contentType); super(id, name, contentType, inline);
this.path = path; this.path = path;
this.dataSource = new FileDataSource(path.toFile()); this.dataSource = new FileDataSource(path.toFile());
} }
@ -105,16 +117,16 @@ public abstract class Attachment extends BodyPartSource {
private final byte[] bytes; private final byte[] bytes;
public Bytes(String id, byte[] bytes, String contentType) { public Bytes(String id, byte[] bytes, String contentType, boolean inline) {
this(id, id, bytes, contentType); this(id, id, bytes, contentType, inline);
} }
public Bytes(String id, String name, byte[] bytes) { public Bytes(String id, String name, byte[] bytes, boolean inline) {
this(id, name, bytes, fileTypeMap.getContentType(name)); this(id, name, bytes, fileTypeMap.getContentType(name), inline);
} }
public Bytes(String id, String name, byte[] bytes, String contentType) { public Bytes(String id, String name, byte[] bytes, String contentType, boolean inline) {
super(id, name, contentType); super(id, name, contentType, inline);
this.bytes = bytes; this.bytes = bytes;
} }
@ -134,6 +146,68 @@ public abstract class Attachment extends BodyPartSource {
} }
} }
public static class Stream extends Attachment {
static final String TYPE = "stream";
private final Provider<InputStream> source;
public Stream(String id, String name, boolean inline, Provider<InputStream> source) {
this(id, name, fileTypeMap.getContentType(name), inline, source);
}
public Stream(String id, String name, String contentType, boolean inline, Provider<InputStream> source) {
super(id, name, contentType, inline);
this.source = source;
}
@Override
public String type() {
return TYPE;
}
@Override
protected void writeTo(MimeBodyPart part) throws MessagingException {
DataSource ds = new StreamDataSource(name, contentType, source);
DataHandler dh = new DataHandler(ds);
part.setDataHandler(dh);
}
static class StreamDataSource implements DataSource {
private final String name;
private final String contentType;
private final Provider<InputStream> source;
public StreamDataSource(String name, String contentType, Provider<InputStream> source) {
this.name = name;
this.contentType = contentType;
this.source = source;
}
@Override
public InputStream getInputStream() throws IOException {
return source.get();
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return name;
}
}
}
public static class XContent extends Bytes { public static class XContent extends Bytes {
protected XContent(String id, ToXContent content, XContentType type) { protected XContent(String id, ToXContent content, XContentType type) {
@ -141,7 +215,7 @@ public abstract class Attachment extends BodyPartSource {
} }
protected XContent(String id, String name, ToXContent content, XContentType type) { protected XContent(String id, String name, ToXContent content, XContentType type) {
super(id, name, bytes(name, content, type), mimeType(type)); super(id, name, bytes(name, content, type), mimeType(type), false);
} }
static String mimeType(XContentType type) { static String mimeType(XContentType type) {

View File

@ -49,11 +49,10 @@ public class Email implements ToXContent {
final String textBody; final String textBody;
final String htmlBody; final String htmlBody;
final Map<String, Attachment> attachments; final Map<String, Attachment> attachments;
final Map<String, Inline> inlines;
public Email(String id, Address from, AddressList replyTo, Priority priority, DateTime sentDate, public Email(String id, Address from, AddressList replyTo, Priority priority, DateTime sentDate,
AddressList to, AddressList cc, AddressList bcc, String subject, String textBody, String htmlBody, AddressList to, AddressList cc, AddressList bcc, String subject, String textBody, String htmlBody,
Map<String, Attachment> attachments, Map<String, Inline> inlines) { Map<String, Attachment> attachments) {
this.id = id; this.id = id;
this.from = from; this.from = from;
@ -67,7 +66,6 @@ public class Email implements ToXContent {
this.textBody = textBody; this.textBody = textBody;
this.htmlBody = htmlBody; this.htmlBody = htmlBody;
this.attachments = attachments; this.attachments = attachments;
this.inlines = inlines;
} }
public String id() { public String id() {
@ -118,10 +116,6 @@ public class Email implements ToXContent {
return attachments; return attachments;
} }
public Map<String, Inline> inlines() {
return inlines;
}
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
@ -249,7 +243,6 @@ public class Email implements ToXContent {
private String textBody; private String textBody;
private String htmlBody; private String htmlBody;
private Map<String, Attachment> attachments = new HashMap<>(); private Map<String, Attachment> attachments = new HashMap<>();
private Map<String, Inline> inlines = new HashMap<>();
private Builder() { private Builder() {
} }
@ -267,7 +260,6 @@ public class Email implements ToXContent {
textBody = email.textBody; textBody = email.textBody;
htmlBody = email.htmlBody; htmlBody = email.htmlBody;
attachments.putAll(email.attachments); attachments.putAll(email.attachments);
inlines.putAll(email.inlines);
return this; return this;
} }
@ -358,14 +350,6 @@ public class Email implements ToXContent {
return this; return this;
} }
public Builder inline(Inline inline) {
if (inlines == null) {
throw new IllegalStateException("Email has already been built!");
}
inlines.put(inline.id(), inline);
return this;
}
/** /**
* Build the email. Note that adding items to attachments or inlines * Build the email. Note that adding items to attachments or inlines
* after this is called is incorrect. * after this is called is incorrect.
@ -373,9 +357,8 @@ public class Email implements ToXContent {
public Email build() { public Email build() {
assert id != null : "email id should not be null (should be set to the watch id"; assert id != null : "email id should not be null (should be set to the watch id";
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody, Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody,
unmodifiableMap(attachments), unmodifiableMap(inlines)); unmodifiableMap(attachments));
attachments = null; attachments = null;
inlines = null;
return email; return email;
} }

View File

@ -1,189 +0,0 @@
/*
* 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.notification.email;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.inject.Provider;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.xpack.notification.email.support.BodyPartSource;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.mail.MessagingException;
import javax.mail.Part;
import javax.mail.internet.MimeBodyPart;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Path;
/**
*
*/
public abstract class Inline extends BodyPartSource {
protected Inline(String id, String name, String contentType) {
super(id, name, contentType);
}
public abstract String type();
@Override
public final MimeBodyPart bodyPart() throws MessagingException {
MimeBodyPart part = new MimeBodyPart();
part.setDisposition(Part.INLINE);
part.setContentID(id);
part.setFileName(name);
writeTo(part);
return part;
}
/**
* intentionally not emitting path as it may come as an information leak
*/
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field("type", type())
.field("id", id)
.field("name", name)
.field("content_type", contentType)
.endObject();
}
protected abstract void writeTo(MimeBodyPart part) throws MessagingException;
public static class File extends Inline {
static final String TYPE = "file";
private final Path path;
private DataSource dataSource;
public File(String id, Path path) {
this(id, path.getFileName().toString(), path);
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path) {
this(id, name, path, fileTypeMap.getContentType(path.toFile()));
}
@SuppressForbidden(reason = "uses toFile")
public File(String id, String name, Path path, String contentType) {
super(id, name, contentType);
this.path = path;
this.dataSource = new FileDataSource(path.toFile());
}
public Path path() {
return path;
}
public String type() {
return TYPE;
}
@Override
public void writeTo(MimeBodyPart part) throws MessagingException {
part.setDataHandler(new DataHandler(dataSource, contentType));
}
}
public static class Stream extends Inline {
static final String TYPE = "stream";
private final Provider<InputStream> source;
public Stream(String id, String name, Provider<InputStream> source) {
this(id, name, fileTypeMap.getContentType(name), source);
}
public Stream(String id, String name, String contentType, Provider<InputStream> source) {
super(id, name, contentType);
this.source = source;
}
@Override
public String type() {
return TYPE;
}
@Override
protected void writeTo(MimeBodyPart part) throws MessagingException {
DataSource ds = new StreamDataSource(name, contentType, source);
DataHandler dh = new DataHandler(ds);
part.setDataHandler(dh);
}
static class StreamDataSource implements DataSource {
private final String name;
private final String contentType;
private final Provider<InputStream> source;
public StreamDataSource(String name, String contentType, Provider<InputStream> source) {
this.name = name;
this.contentType = contentType;
this.source = source;
}
@Override
public InputStream getInputStream() throws IOException {
return source.get();
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getContentType() {
return contentType;
}
@Override
public String getName() {
return name;
}
}
}
public static class Bytes extends Stream {
public Bytes(String id, String name, String contentType, byte[] bytes) {
super(id, name, contentType, new BytesStreamProvider(bytes));
}
public Bytes(String id, String name, String contentType, BytesReference bytes) {
super(id, name, contentType, new BytesStreamProvider(bytes));
}
static class BytesStreamProvider implements Provider<InputStream> {
private final BytesReference bytes;
public BytesStreamProvider(byte[] bytes) {
this(new BytesArray(bytes));
}
public BytesStreamProvider(BytesReference bytes) {
this.bytes = bytes;
}
@Override
public InputStream get() {
return new ByteArrayInputStream(bytes.array(), bytes.arrayOffset(), bytes.length());
}
}
}
}

View File

@ -92,15 +92,13 @@ public enum Profile implements ToXContent {
alternative.addBodyPart(html); alternative.addBodyPart(html);
} }
if (!email.inlines.isEmpty()) {
for (Inline inline : email.inlines.values()) {
related.addBodyPart(inline.bodyPart());
}
}
if (!email.attachments.isEmpty()) { if (!email.attachments.isEmpty()) {
for (Attachment attachment : email.attachments.values()) { for (Attachment attachment : email.attachments.values()) {
mixed.addBodyPart(attachment.bodyPart()); if (attachment.isInline()) {
related.addBodyPart(attachment.bodyPart());
} else {
mixed.addBodyPart(attachment.bodyPart());
}
} }
} }

View File

@ -54,10 +54,16 @@ public class DataAttachment implements EmailAttachmentParser.EmailAttachment {
return Objects.hash(id, dataAttachment); return Objects.hash(id, dataAttachment);
} }
@Override
public String id() { public String id() {
return id; return id;
} }
@Override
public boolean inline() {
return false;
}
public static Builder builder(String id) { public static Builder builder(String id) {
return new Builder(id); return new Builder(id);
} }

View File

@ -30,6 +30,14 @@ public interface EmailAttachmentParser<T extends EmailAttachmentParser.EmailAtta
* @return The id of this attachment * @return The id of this attachment
*/ */
String id(); String id();
/**
* Allows the attachment to decide of it should be of disposition type attachment or inline, which is important
* for being able to display inside of desktop email clients
*
* @return a boolean flagging this attachment as being inline
*/
boolean inline();
} }
/** /**

View File

@ -14,15 +14,15 @@ import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Variables;
import org.elasticsearch.xpack.common.http.HttpClient; import org.elasticsearch.xpack.common.http.HttpClient;
import org.elasticsearch.xpack.common.http.HttpRequest; import org.elasticsearch.xpack.common.http.HttpRequest;
import org.elasticsearch.xpack.common.http.HttpRequestTemplate; import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.common.http.HttpResponse; import org.elasticsearch.xpack.common.http.HttpResponse;
import org.elasticsearch.xpack.common.text.TextTemplateEngine; import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.notification.email.Attachment; import org.elasticsearch.xpack.notification.email.Attachment;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Variables;
import org.elasticsearch.xpack.watcher.watch.Payload;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -30,6 +30,7 @@ import java.util.Map;
public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpRequestAttachment> { public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpRequestAttachment> {
public interface Fields { public interface Fields {
ParseField INLINE = new ParseField("inline");
ParseField REQUEST = new ParseField("request"); ParseField REQUEST = new ParseField("request");
ParseField CONTENT_TYPE = new ParseField("content_type"); ParseField CONTENT_TYPE = new ParseField("content_type");
} }
@ -56,6 +57,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
@Override @Override
public HttpRequestAttachment parse(String id, XContentParser parser) throws IOException { public HttpRequestAttachment parse(String id, XContentParser parser) throws IOException {
boolean inline = false;
String contentType = null; String contentType = null;
HttpRequestTemplate requestTemplate = null; HttpRequestTemplate requestTemplate = null;
@ -66,6 +68,8 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.CONTENT_TYPE)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.CONTENT_TYPE)) {
contentType = parser.text(); contentType = parser.text();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.INLINE)) {
inline = parser.booleanValue();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.REQUEST)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Fields.REQUEST)) {
requestTemplate = requestTemplateParser.parse(parser); requestTemplate = requestTemplateParser.parse(parser);
} else { } else {
@ -75,7 +79,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
} }
if (requestTemplate != null) { if (requestTemplate != null) {
return new HttpRequestAttachment(id, requestTemplate, contentType); return new HttpRequestAttachment(id, requestTemplate, inline, contentType);
} }
throw new ElasticsearchParseException("Could not parse http request attachment"); throw new ElasticsearchParseException("Could not parse http request attachment");
@ -94,7 +98,7 @@ public class HttpEmailAttachementParser implements EmailAttachmentParser<HttpReq
if (response.hasContent()) { if (response.hasContent()) {
String contentType = attachment.getContentType(); String contentType = attachment.getContentType();
String attachmentContentType = Strings.hasLength(contentType) ? contentType : response.contentType(); String attachmentContentType = Strings.hasLength(contentType) ? contentType : response.contentType();
return new Attachment.Bytes(attachment.id(), response.body().toBytes(), attachmentContentType); return new Attachment.Bytes(attachment.id(), response.body().toBytes(), attachmentContentType, attachment.inline());
} else { } else {
logger.error("Empty response body: [host[{}], port[{}], method[{}], path[{}]: response status [{}]", httpRequest.host(), logger.error("Empty response body: [host[{}], port[{}], method[{}], path[{}]: response status [{}]", httpRequest.host(),
httpRequest.port(), httpRequest.method(), httpRequest.path(), response.status()); httpRequest.port(), httpRequest.method(), httpRequest.path(), response.status());

View File

@ -16,12 +16,14 @@ import java.util.Objects;
public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachment { public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachment {
private final HttpRequestTemplate requestTemplate; private final HttpRequestTemplate requestTemplate;
private boolean inline;
private final String contentType; private final String contentType;
private final String id; private final String id;
public HttpRequestAttachment(String id, HttpRequestTemplate requestTemplate, @Nullable String contentType) { public HttpRequestAttachment(String id, HttpRequestTemplate requestTemplate, boolean inline, @Nullable String contentType) {
this.id = id; this.id = id;
this.requestTemplate = requestTemplate; this.requestTemplate = requestTemplate;
this.inline = inline;
this.contentType = contentType; this.contentType = contentType;
} }
@ -38,6 +40,11 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
return id; return id;
} }
@Override
public boolean inline() {
return inline;
}
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(id) builder.startObject(id)
@ -46,6 +53,9 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
if (Strings.hasLength(contentType)) { if (Strings.hasLength(contentType)) {
builder.field(HttpEmailAttachementParser.Fields.CONTENT_TYPE.getPreferredName(), contentType); builder.field(HttpEmailAttachementParser.Fields.CONTENT_TYPE.getPreferredName(), contentType);
} }
if (inline) {
builder.field(HttpEmailAttachementParser.Fields.INLINE.getPreferredName(), inline);
}
return builder.endObject().endObject(); return builder.endObject().endObject();
} }
@ -65,12 +75,12 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
HttpRequestAttachment otherDataAttachment = (HttpRequestAttachment) o; HttpRequestAttachment otherDataAttachment = (HttpRequestAttachment) o;
return Objects.equals(id, otherDataAttachment.id) && Objects.equals(requestTemplate, otherDataAttachment.requestTemplate) return Objects.equals(id, otherDataAttachment.id) && Objects.equals(requestTemplate, otherDataAttachment.requestTemplate)
&& Objects.equals(contentType, otherDataAttachment.contentType); && Objects.equals(contentType, otherDataAttachment.contentType) && Objects.equals(inline, otherDataAttachment.inline);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(id, requestTemplate, contentType); return Objects.hash(id, requestTemplate, contentType, inline);
} }
public static class Builder { public static class Builder {
@ -78,6 +88,7 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
private String id; private String id;
private HttpRequestTemplate httpRequestTemplate; private HttpRequestTemplate httpRequestTemplate;
private String contentType; private String contentType;
private boolean inline = false;
private Builder(String id) { private Builder(String id) {
this.id = id; this.id = id;
@ -93,8 +104,13 @@ public class HttpRequestAttachment implements EmailAttachmentParser.EmailAttachm
return this; return this;
} }
public Builder inline(boolean inline) {
this.inline = inline;
return this;
}
public HttpRequestAttachment build() { public HttpRequestAttachment build() {
return new HttpRequestAttachment(id, httpRequestTemplate, contentType); return new HttpRequestAttachment(id, httpRequestTemplate, inline, contentType);
} }
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.common.http; package org.elasticsearch.xpack.common.http;
import com.google.common.collect.Lists;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
@ -13,9 +12,9 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.common.http.HttpResponse;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -29,8 +28,8 @@ import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
/** /**
* *
@ -122,9 +121,9 @@ public class HttpResponseTests extends ESTestCase {
Map<String, Object> responseHeaders = (Map<String, Object>) responseMap.get("headers"); Map<String, Object> responseHeaders = (Map<String, Object>) responseMap.get("headers");
assertThat(responseHeaders, not(hasKey("es.index"))); assertThat(responseHeaders, not(hasKey("es.index")));
assertThat(responseHeaders, hasEntry("es_index", Lists.newArrayList("value"))); assertThat(responseHeaders, hasEntry("es_index", Collections.singletonList("value")));
assertThat(responseHeaders, not(hasKey("es.index.2"))); assertThat(responseHeaders, not(hasKey("es.index.2")));
assertThat(responseHeaders, hasEntry("es_index_2", Lists.newArrayList("value"))); assertThat(responseHeaders, hasEntry("es_index_2", Collections.singletonList("value")));
} }
} }

View File

@ -41,9 +41,8 @@ public class EmailTests extends ESTestCase {
String textBody = randomFrom("Random Body", "", null); String textBody = randomFrom("Random Body", "", null);
String htmlBody = randomFrom("<hr /><b>BODY</b><hr />", "", null); String htmlBody = randomFrom("<hr /><b>BODY</b><hr />", "", null);
Map<String, Attachment> attachments = null; Map<String, Attachment> attachments = null;
Map<String, Inline> inlines = null;
Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody, attachments, inlines); Email email = new Email(id, from, replyTo, priority, sentDate, to, cc, bcc, subject, textBody, htmlBody, attachments);
XContentBuilder builder = XContentFactory.jsonBuilder(); XContentBuilder builder = XContentFactory.jsonBuilder();
email.toXContent(builder, ToXContent.EMPTY_PARAMS); email.toXContent(builder, ToXContent.EMPTY_PARAMS);

View File

@ -6,14 +6,13 @@
package org.elasticsearch.xpack.notification.email; package org.elasticsearch.xpack.notification.email;
import org.apache.lucene.util.LuceneTestCase.AwaitsFix; import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.cli.Terminal; import org.elasticsearch.cli.Terminal;
import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.ClusterSettings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.xpack.common.secret.SecretService; import org.elasticsearch.xpack.common.secret.SecretService;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.Locale; import java.util.Locale;
@ -26,13 +25,13 @@ public class ManualPublicSmtpServersTester {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
test(Profile.GMAIL, Settings.builder() test(Profile.GMAIL, Settings.builder()
.put("xpack.notification.email.service.account.gmail.smtp.auth", true) .put("xpack.notification.email.account.gmail.smtp.auth", true)
.put("xpack.notification.email.service.account.gmail.smtp.starttls.enable", true) .put("xpack.notification.email.account.gmail.smtp.starttls.enable", true)
.put("xpack.notification.email.service.account.gmail.smtp.host", "smtp.gmail.com") .put("xpack.notification.email.account.gmail.smtp.host", "smtp.gmail.com")
.put("xpack.notification.email.service.account.gmail.smtp.port", 587) .put("xpack.notification.email.account.gmail.smtp.port", 587)
.put("xpack.notification.email.service.account.gmail.smtp.user", terminal.readText("username: ")) .put("xpack.notification.email.account.gmail.smtp.user", terminal.readText("username: "))
.put("xpack.notification.email.service.account.gmail.smtp.password", new String(terminal.readSecret("password: "))) .put("xpack.notification.email.account.gmail.smtp.password", new String(terminal.readSecret("password: ")))
.put("xpack.notification.email.service.account.gmail.email_defaults.to", terminal.readText("to: ")) .put("xpack.notification.email.account.gmail.email_defaults.to", terminal.readText("to: "))
); );
} }
} }
@ -41,13 +40,13 @@ public class ManualPublicSmtpServersTester {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
test(Profile.STANDARD, Settings.builder() test(Profile.STANDARD, Settings.builder()
.put("xpack.notification.email.service.account.outlook.smtp.auth", true) .put("xpack.notification.email.account.outlook.smtp.auth", true)
.put("xpack.notification.email.service.account.outlook.smtp.starttls.enable", true) .put("xpack.notification.email.account.outlook.smtp.starttls.enable", true)
.put("xpack.notification.email.service.account.outlook.smtp.host", "smtp-mail.outlook.com") .put("xpack.notification.email.account.outlook.smtp.host", "smtp-mail.outlook.com")
.put("xpack.notification.email.service.account.outlook.smtp.port", 587) .put("xpack.notification.email.account.outlook.smtp.port", 587)
.put("xpack.notification.email.service.account.outlook.smtp.user", "elastic.user@outlook.com") .put("xpack.notification.email.account.outlook.smtp.user", "elastic.user@outlook.com")
.put("xpack.notification.email.service.account.outlook.smtp.password", "fantastic42") .put("xpack.notification.email.account.outlook.smtp.password", "fantastic42")
.put("xpack.notification.email.service.account.outlook.email_defaults.to", "elastic.user@outlook.com") .put("xpack.notification.email.account.outlook.email_defaults.to", "elastic.user@outlook.com")
.put() .put()
); );
} }
@ -57,15 +56,15 @@ public class ManualPublicSmtpServersTester {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
test(Profile.STANDARD, Settings.builder() test(Profile.STANDARD, Settings.builder()
.put("xpack.notification.email.service.account.yahoo.smtp.starttls.enable", true) .put("xpack.notification.email.account.yahoo.smtp.starttls.enable", true)
.put("xpack.notification.email.service.account.yahoo.smtp.auth", true) .put("xpack.notification.email.account.yahoo.smtp.auth", true)
.put("xpack.notification.email.service.account.yahoo.smtp.host", "smtp.mail.yahoo.com") .put("xpack.notification.email.account.yahoo.smtp.host", "smtp.mail.yahoo.com")
.put("xpack.notification.email.service.account.yahoo.smtp.port", 587) .put("xpack.notification.email.account.yahoo.smtp.port", 587)
.put("xpack.notification.email.service.account.yahoo.smtp.user", "elastic.user@yahoo.com") .put("xpack.notification.email.account.yahoo.smtp.user", "elastic.user@yahoo.com")
.put("xpack.notification.email.service.account.yahoo.smtp.password", "fantastic42") .put("xpack.notification.email.account.yahoo.smtp.password", "fantastic42")
// note: from must be set to the same authenticated user account // note: from must be set to the same authenticated user account
.put("xpack.notification.email.service.account.yahoo.email_defaults.from", "elastic.user@yahoo.com") .put("xpack.notification.email.account.yahoo.email_defaults.from", "elastic.user@yahoo.com")
.put("xpack.notification.email.service.account.yahoo.email_defaults.to", "elastic.user@yahoo.com") .put("xpack.notification.email.account.yahoo.email_defaults.to", "elastic.user@yahoo.com")
); );
} }
} }
@ -75,42 +74,43 @@ public class ManualPublicSmtpServersTester {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
test(Profile.STANDARD, Settings.builder() test(Profile.STANDARD, Settings.builder()
.put("xpack.notification.email.service.account.ses.smtp.auth", true) .put("xpack.notification.email.account.ses.smtp.auth", true)
.put("xpack.notification.email.service.account.ses.smtp.starttls.enable", true) .put("xpack.notification.email.account.ses.smtp.starttls.enable", true)
.put("xpack.notification.email.service.account.ses.smtp.starttls.required", true) .put("xpack.notification.email.account.ses.smtp.starttls.required", true)
.put("xpack.notification.email.service.account.ses.smtp.host", "email-smtp.us-east-1.amazonaws.com") .put("xpack.notification.email.account.ses.smtp.host", "email-smtp.us-east-1.amazonaws.com")
.put("xpack.notification.email.service.account.ses.smtp.port", 587) .put("xpack.notification.email.account.ses.smtp.port", 587)
.put("xpack.notification.email.service.account.ses.smtp.user", terminal.readText("user: ")) .put("xpack.notification.email.account.ses.smtp.user", terminal.readText("user: "))
.put("xpack.notification.email.service.account.ses.email_defaults.from", "dummy.user@elasticsearch.com") .put("xpack.notification.email.account.ses.email_defaults.from", "dummy.user@elasticsearch.com")
.put("xpack.notification.email.service.account.ses.email_defaults.to", terminal.readText("to: ")) .put("xpack.notification.email.account.ses.email_defaults.to", terminal.readText("to: "))
.put("xpack.notification.email.service.account.ses.smtp.password", .put("xpack.notification.email.account.ses.smtp.password",
new String(terminal.readSecret("password: "))) new String(terminal.readSecret("password: ")))
); );
} }
} }
static void test(Profile profile, Settings.Builder builder) throws Exception { static void test(Profile profile, Settings.Builder settingsBuilder) throws Exception {
InternalEmailService service = startEmailService(builder); String path = "/org/elasticsearch/xpack/watcher/actions/email/service/logo.png";
if (InternalEmailServiceTests.class.getResourceAsStream(path) == null) {
throw new ElasticsearchException("Could not find logo at path {}", path);
}
InternalEmailService service = startEmailService(settingsBuilder);
try { try {
ToXContent content = new ToXContent() { ToXContent content = (xContentBuilder, params) -> xContentBuilder.startObject()
@Override .field("key1", "value1")
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { .field("key2", "value2")
return builder.startObject() .field("key3", "value3")
.field("key1", "value1") .endObject();
.field("key2", "value2")
.field("key3", "value3")
.endObject();
}
};
Email email = Email.builder() Email email = Email.builder()
.id("_id") .id("_id")
.subject("_subject") .subject("_subject")
.textBody("_text_body") .textBody("_text_body")
.htmlBody("<b>html body</b><p/><p/><img src=\"cid:logo\"/>") .htmlBody("<b>html body</b><p/><p/><img src=\"cid:logo.png\"/>")
.attach(new Attachment.XContent.Yaml("test.yml", content)) .attach(new Attachment.XContent.Yaml("test.yml", content))
.inline(new Inline.Stream("logo", "logo.jpg", () -> InternalEmailServiceTests.class.getResourceAsStream("logo.png"))) .attach(new Attachment.Stream("logo.png", "logo.png", true,
() -> InternalEmailServiceTests.class.getResourceAsStream(path)))
.build(); .build();
EmailService.EmailSent sent = service.send(email, null, profile); EmailService.EmailSent sent = service.send(email, null, profile);

View File

@ -0,0 +1,62 @@
/*
* 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.notification.email;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.common.secret.SecretService;
import javax.mail.BodyPart;
import javax.mail.Part;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class ProfileTests extends ESTestCase {
public void testThatInlineAttachmentsAreCreated() throws Exception {
String path = "/org/elasticsearch/xpack/watcher/actions/email/service/logo.png";
Attachment attachment = new Attachment.Stream("inline.png", "inline.png", true,
() -> InternalEmailServiceTests.class.getResourceAsStream(path));
Email email = Email.builder()
.id("foo")
.from("foo@example.org")
.to("bar@example.org")
.subject(randomAsciiOfLength(10))
.attach(attachment)
.build();
Settings settings = Settings.builder()
.put("default_account", "foo")
.put("account.foo.smtp.host", "_host")
.build();
Accounts accounts = new Accounts(settings, SecretService.Insecure.INSTANCE, logger);
Session session = accounts.account("foo").getConfig().createSession();
MimeMessage mimeMessage = Profile.STANDARD.toMimeMessage(email, session);
Object content = ((MimeMultipart) mimeMessage.getContent()).getBodyPart(0).getContent();
assertThat(content, instanceOf(MimeMultipart.class));
MimeMultipart multipart = (MimeMultipart) content;
assertThat(multipart.getCount(), is(2));
boolean foundInlineAttachment = false;
BodyPart bodyPart = null;
for (int i = 0; i < multipart.getCount(); i++) {
bodyPart = multipart.getBodyPart(i);
if (Part.INLINE.equalsIgnoreCase(bodyPart.getDisposition())) {
foundInlineAttachment = true;
break;
}
}
assertThat("Expected to find an inline attachment in mime message, but didnt", foundInlineAttachment, is(true));
}
}

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.notification.email.attachment; package org.elasticsearch.xpack.notification.email.attachment;
import com.google.common.base.Charsets;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
@ -13,13 +12,14 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.common.http.HttpRequestTemplate; import org.elasticsearch.xpack.common.http.HttpRequestTemplate;
import org.elasticsearch.xpack.common.http.Scheme; import org.elasticsearch.xpack.common.http.Scheme;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.elasticsearch.xpack.notification.email.Attachment; import org.elasticsearch.xpack.notification.email.Attachment;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.watch.Payload;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -93,7 +93,8 @@ public class EmailAttachmentParsersTests extends ESTestCase {
attachments.add(new DataAttachment("my-name.json", org.elasticsearch.xpack.notification.email.DataAttachment.JSON)); attachments.add(new DataAttachment("my-name.json", org.elasticsearch.xpack.notification.email.DataAttachment.JSON));
HttpRequestTemplate requestTemplate = HttpRequestTemplate.builder("localhost", 80).scheme(Scheme.HTTP).path("/").build(); HttpRequestTemplate requestTemplate = HttpRequestTemplate.builder("localhost", 80).scheme(Scheme.HTTP).path("/").build();
HttpRequestAttachment httpRequestAttachment = new HttpRequestAttachment("other-id", requestTemplate, null); boolean inline = randomBoolean();
HttpRequestAttachment httpRequestAttachment = new HttpRequestAttachment("other-id", requestTemplate, inline, null);
attachments.add(httpRequestAttachment); attachments.add(httpRequestAttachment);
EmailAttachments emailAttachments = new EmailAttachments(attachments); EmailAttachments emailAttachments = new EmailAttachments(attachments);
@ -105,6 +106,9 @@ public class EmailAttachmentParsersTests extends ESTestCase {
assertThat(builder.string(), containsString("other-id")); assertThat(builder.string(), containsString("other-id"));
assertThat(builder.string(), containsString("localhost")); assertThat(builder.string(), containsString("localhost"));
assertThat(builder.string(), containsString("/")); assertThat(builder.string(), containsString("/"));
if (inline) {
assertThat(builder.string(), containsString("inline"));
}
} }
public void testThatTwoAttachmentsWithTheSameIdThrowError() throws Exception { public void testThatTwoAttachmentsWithTheSameIdThrowError() throws Exception {
@ -161,7 +165,8 @@ public class EmailAttachmentParsersTests extends ESTestCase {
@Override @Override
public Attachment toAttachment(WatchExecutionContext ctx, Payload payload, TestEmailAttachment attachment) { public Attachment toAttachment(WatchExecutionContext ctx, Payload payload, TestEmailAttachment attachment) {
return new Attachment.Bytes(attachment.id(), attachment.getValue().getBytes(Charsets.UTF_8), "personalContentType"); return new Attachment.Bytes(attachment.id(), attachment.getValue().getBytes(StandardCharsets.UTF_8),
"personalContentType", false);
} }
} }
@ -193,6 +198,11 @@ public class EmailAttachmentParsersTests extends ESTestCase {
return id; return id;
} }
@Override
public boolean inline() {
return false;
}
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject(id) return builder.startObject(id)

View File

@ -37,15 +37,13 @@ import static org.mockito.Mockito.when;
public class HttpEmailAttachementParserTests extends ESTestCase { public class HttpEmailAttachementParserTests extends ESTestCase {
private SecretService.Insecure secretService;
private HttpAuthRegistry authRegistry;
private HttpRequestTemplate.Parser httpRequestTemplateParser; private HttpRequestTemplate.Parser httpRequestTemplateParser;
private HttpClient httpClient; private HttpClient httpClient;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
secretService = SecretService.Insecure.INSTANCE; SecretService.Insecure secretService = SecretService.Insecure.INSTANCE;
authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(secretService))); HttpAuthRegistry authRegistry = new HttpAuthRegistry(singletonMap(BasicAuth.TYPE, new BasicAuthFactory(secretService)));
httpRequestTemplateParser = new HttpRequestTemplate.Parser(authRegistry); httpRequestTemplateParser = new HttpRequestTemplate.Parser(authRegistry);
httpClient = mock(HttpClient.class); httpClient = mock(HttpClient.class);
@ -77,9 +75,12 @@ public class HttpEmailAttachementParserTests extends ESTestCase {
if (configureContentType) { if (configureContentType) {
builder.field("content_type", "application/foo"); builder.field("content_type", "application/foo");
} }
boolean isInline = randomBoolean();
if (isInline) {
builder.field("inline", true);
}
builder.endObject().endObject().endObject(); builder.endObject().endObject().endObject();
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
logger.info("JSON: {}", builder.string());
EmailAttachments emailAttachments = emailAttachmentsParser.parse(parser); EmailAttachments emailAttachments = emailAttachmentsParser.parse(parser);
assertThat(emailAttachments.getAttachments(), hasSize(1)); assertThat(emailAttachments.getAttachments(), hasSize(1));
@ -89,6 +90,7 @@ public class HttpEmailAttachementParserTests extends ESTestCase {
attachments.get(0).toXContent(toXcontentBuilder, ToXContent.EMPTY_PARAMS); attachments.get(0).toXContent(toXcontentBuilder, ToXContent.EMPTY_PARAMS);
toXcontentBuilder.endObject(); toXcontentBuilder.endObject();
assertThat(toXcontentBuilder.string(), is(builder.string())); assertThat(toXcontentBuilder.string(), is(builder.string()));
}
assertThat(attachments.get(0).inline(), is(isInline));
}
} }

View File

@ -5,26 +5,10 @@
*/ */
package org.elasticsearch.xpack.test.rest; package org.elasticsearch.xpack.test.rest;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.carrotsearch.randomizedtesting.annotations.Name; import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.util.concurrent.ThreadContext;
@ -33,15 +17,25 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.license.plugin.TestUtils; import org.elasticsearch.license.plugin.TestUtils;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ESRestTestCase;
import org.elasticsearch.test.rest.RestTestCandidate; import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.test.rest.client.RestTestResponse;
import org.elasticsearch.test.rest.parser.RestTestParseException; import org.elasticsearch.test.rest.parser.RestTestParseException;
import org.elasticsearch.xpack.security.authc.esnative.ReservedRealm;
import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.xpack.security.authz.store.ReservedRolesStore;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.hamcrest.Matchers.is;
public abstract class XPackRestTestCase extends ESRestTestCase { public abstract class XPackRestTestCase extends ESRestTestCase {
@ -56,46 +50,16 @@ public abstract class XPackRestTestCase extends ESRestTestCase {
return ESRestTestCase.createParameters(0, 1); return ESRestTestCase.createParameters(0, 1);
} }
@Before
public void startWatcher() throws Exception {
try (CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) {
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http",
null,
url.getHost(),
url.getPort(),
"/_xpack/watcher/_start", null, null));
request.addHeader("Authorization", BASIC_AUTH_VALUE);
try (CloseableHttpResponse response = client.execute(request)) {
}
}
}
@After
public void stopWatcher() throws Exception {
try(CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) {
URL url = getClusterUrls()[0];
HttpPut request = new HttpPut(new URI("http",
null,
url.getHost(),
url.getPort(),
"/_xpack/watcher/_stop", null, null));
request.addHeader("Authorization", BASIC_AUTH_VALUE);
try (CloseableHttpResponse response = client.execute(request)) {
}
}
}
@Before @Before
public void installLicense() throws Exception { public void installLicense() throws Exception {
final XContentBuilder builder = XContentFactory.jsonBuilder(); final XContentBuilder builder = XContentFactory.jsonBuilder();
TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)).toXContent(builder, ToXContent.EMPTY_PARAMS); TestUtils.generateSignedLicense("trial", TimeValue.timeValueHours(2)).toXContent(builder, ToXContent.EMPTY_PARAMS);
final BytesReference bytes = builder.bytes(); final BytesReference bytes = builder.bytes();
try (XContentParser parser = XContentFactory.xContent(bytes).createParser(bytes)) { try (XContentParser parser = XContentFactory.xContent(bytes).createParser(bytes)) {
final List<Map<String, Object>> bodies = Collections.singletonList(Collections.singletonMap("license", final List<Map<String, Object>> bodies = singletonList(singletonMap("license",
parser.map())); parser.map()));
getAdminExecutionContext().callApi("license.post", Collections.singletonMap("acknowledge", "true"), getAdminExecutionContext().callApi("license.post", singletonMap("acknowledge", "true"),
bodies, Collections.singletonMap("Authorization", BASIC_AUTH_VALUE)); bodies, singletonMap("Authorization", BASIC_AUTH_VALUE));
} }
} }
@ -103,43 +67,21 @@ public abstract class XPackRestTestCase extends ESRestTestCase {
public void clearUsersAndRoles() throws Exception { public void clearUsersAndRoles() throws Exception {
// we cannot delete the .security index from a rest test since we aren't the internal user, lets wipe the data // we cannot delete the .security index from a rest test since we aren't the internal user, lets wipe the data
// TODO remove this once the built-in SUPERUSER role is added that can delete the index and we use the built in admin user here // TODO remove this once the built-in SUPERUSER role is added that can delete the index and we use the built in admin user here
try (CloseableHttpClient client = HttpClients.createMinimal(new BasicHttpClientConnectionManager())) { RestTestResponse response = getAdminExecutionContext().callApi("xpack.security.get_user", emptyMap(), emptyList(), emptyMap());
final URL url = getClusterUrls()[0]; @SuppressWarnings("unchecked")
HttpGet getUsersRequest = new HttpGet(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/security/user", null, null)); Map<String, Object> users = (Map<String, Object>) response.getBody();
getUsersRequest.addHeader("Authorization", BASIC_AUTH_VALUE); for (String user: users.keySet()) {
try (CloseableHttpResponse closeableHttpResponse = client.execute(getUsersRequest)) { if (ReservedRealm.isReserved(user) == false) {
assertThat(closeableHttpResponse.getStatusLine().getStatusCode(), is(200)); getAdminExecutionContext().callApi("xpack.security.delete_user", singletonMap("username", user), emptyList(), emptyMap());
String response = Streams.copyToString(
new InputStreamReader(closeableHttpResponse.getEntity().getContent(), StandardCharsets.UTF_8));
Map<String, Object> responseMap = XContentFactory.xContent(response).createParser(response).map();
// in the structure of this API, the users are the keyset
for (String user : responseMap.keySet()) {
HttpDelete delete = new HttpDelete(new URI("http", null, url.getHost(), url.getPort(),
"/_xpack/security/user/" + user, null, null));
delete.addHeader("Authorization", BASIC_AUTH_VALUE);
try (CloseableHttpResponse deleteResponse = client.execute(delete)) {
}
}
} }
}
HttpGet getRolesRequest = new HttpGet(new URI("http", null, url.getHost(), url.getPort(), "/_xpack/security/role", response = getAdminExecutionContext().callApi("xpack.security.get_role", emptyMap(), emptyList(), emptyMap());
null, null)); @SuppressWarnings("unchecked")
getRolesRequest.addHeader("Authorization", BASIC_AUTH_VALUE); Map<String, Object> roles = (Map<String, Object>) response.getBody();
try (CloseableHttpResponse closeableHttpResponse = client.execute(getRolesRequest)) { for (String role: roles.keySet()) {
assertThat(closeableHttpResponse.getStatusLine().getStatusCode(), is(200)); if (ReservedRolesStore.isReserved(role) == false) {
String response = Streams.copyToString( getAdminExecutionContext().callApi("xpack.security.delete_role", singletonMap("name", role), emptyList(), emptyMap());
new InputStreamReader(closeableHttpResponse.getEntity().getContent(), StandardCharsets.UTF_8));
Map<String, Object> responseMap = XContentFactory.xContent(response).createParser(response).map();
// in the structure of this API, the users are the keyset
for (String role : responseMap.keySet()) {
HttpDelete delete = new HttpDelete(new URI("http", null, url.getHost(), url.getPort(),
"/_xpack/security/role/" + role, null, null));
delete.addHeader("Authorization", BASIC_AUTH_VALUE);
try (CloseableHttpResponse deleteResponse = client.execute(delete)) {
}
}
} }
} }
} }

View File

@ -31,7 +31,6 @@ import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
import org.elasticsearch.xpack.watcher.history.HistoryModule; import org.elasticsearch.xpack.watcher.history.HistoryModule;
import org.elasticsearch.xpack.watcher.history.HistoryStore; import org.elasticsearch.xpack.watcher.history.HistoryStore;
import org.elasticsearch.xpack.watcher.input.InputModule; 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.RestAckWatchAction;
import org.elasticsearch.xpack.watcher.rest.action.RestActivateWatchAction; import org.elasticsearch.xpack.watcher.rest.action.RestActivateWatchAction;
import org.elasticsearch.xpack.watcher.rest.action.RestDeleteWatchAction; 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); "[.watcher-history-YYYY.MM.dd] are allowed to be created", value);
} }
} }

View File

@ -15,7 +15,6 @@ import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.internal.TimestampFieldMapper;
import org.elasticsearch.xpack.watcher.actions.Action; import org.elasticsearch.xpack.watcher.actions.Action;
import org.elasticsearch.xpack.watcher.actions.ExecutableAction; import org.elasticsearch.xpack.watcher.actions.ExecutableAction;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
@ -24,6 +23,7 @@ import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.joda.time.DateTime;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -63,19 +63,9 @@ public class ExecutableIndexAction extends ExecutableAction<IndexAction> {
} }
IndexRequest indexRequest = new IndexRequest(); IndexRequest indexRequest = new IndexRequest();
indexRequest.index(action.index); indexRequest.index(action.index);
indexRequest.type(action.docType); indexRequest.type(action.docType);
data = addTimestampToDocument(data, ctx.executionTime());
if (action.executionTimeField != null && !TimestampFieldMapper.NAME.equals(action.executionTimeField)) {
if (!(data instanceof HashMap)) {
data = new HashMap<>(data); // ensuring mutability
}
data.put(action.executionTimeField, WatcherDateTimeUtils.formatDate(ctx.executionTime()));
} else {
indexRequest.timestamp(WatcherDateTimeUtils.formatDate(ctx.executionTime()));
}
indexRequest.source(jsonBuilder().prettyPrint().map(data)); indexRequest.source(jsonBuilder().prettyPrint().map(data));
if (ctx.simulateAction(actionId)) { if (ctx.simulateAction(actionId)) {
@ -100,14 +90,7 @@ public class ExecutableIndexAction extends ExecutableAction<IndexAction> {
IndexRequest indexRequest = new IndexRequest(); IndexRequest indexRequest = new IndexRequest();
indexRequest.index(action.index); indexRequest.index(action.index);
indexRequest.type(action.docType); indexRequest.type(action.docType);
if (action.executionTimeField != null && !TimestampFieldMapper.NAME.equals(action.executionTimeField)) { doc = addTimestampToDocument(doc, ctx.executionTime());
if (!(doc instanceof HashMap)) {
doc = new HashMap<>(doc); // ensuring mutability
}
doc.put(action.executionTimeField, WatcherDateTimeUtils.formatDate(ctx.executionTime()));
} else {
indexRequest.timestamp(WatcherDateTimeUtils.formatDate(ctx.executionTime()));
}
indexRequest.source(jsonBuilder().prettyPrint().map(doc)); indexRequest.source(jsonBuilder().prettyPrint().map(doc));
bulkRequest.add(indexRequest); bulkRequest.add(indexRequest);
} }
@ -121,6 +104,16 @@ public class ExecutableIndexAction extends ExecutableAction<IndexAction> {
return new IndexAction.Result.Success(new XContentSource(jsonBuilder.bytes(), XContentType.JSON)); return new IndexAction.Result.Success(new XContentSource(jsonBuilder.bytes(), XContentType.JSON));
} }
private Map<String, Object> addTimestampToDocument(Map<String, Object> data, DateTime executionTime) {
if (action.executionTimeField != null) {
if (!(data instanceof HashMap)) {
data = new HashMap<>(data); // ensuring mutability
}
data.put(action.executionTimeField, WatcherDateTimeUtils.formatDate(executionTime));
}
return data;
}
static void indexResponseToXContent(XContentBuilder builder, IndexResponse response) throws IOException { static void indexResponseToXContent(XContentBuilder builder, IndexResponse response) throws IOException {
builder.startObject() builder.startObject()
.field("created", response.isCreated()) .field("created", response.isCreated())

View File

@ -6,14 +6,14 @@
package org.elasticsearch.xpack.watcher.input; package org.elasticsearch.xpack.watcher.input;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.common.collect.MapBuilder; 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.chain.ChainInput;
import org.elasticsearch.xpack.watcher.input.http.HttpInput; import org.elasticsearch.xpack.watcher.input.http.HttpInput;
import org.elasticsearch.xpack.watcher.input.none.NoneInput; import org.elasticsearch.xpack.watcher.input.none.NoneInput;
import org.elasticsearch.xpack.watcher.input.search.SearchInput; import org.elasticsearch.xpack.watcher.input.search.SearchInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; 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 org.elasticsearch.xpack.watcher.watch.Payload;
import java.util.HashMap; import java.util.HashMap;
@ -31,12 +31,12 @@ public final class InputBuilders {
return NoneInput.builder(); return NoneInput.builder();
} }
public static SearchInput.Builder searchInput(SearchRequest request) { public static SearchInput.Builder searchInput(WatcherSearchTemplateRequest request) {
return SearchInput.builder(request); return SearchInput.builder(request);
} }
public static SearchInput.Builder searchInput(SearchRequestBuilder builder) { public static SearchInput.Builder searchInput(SearchRequest request) {
return searchInput(builder.request()); return searchInput(new WatcherSearchTemplateRequest(request));
} }
public static SimpleInput.Builder simpleInput() { public static SimpleInput.Builder simpleInput() {

View File

@ -11,16 +11,15 @@ import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHit;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.input.ExecutableInput; 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.XContentFilterKeysUtils;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import java.util.Map; 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; public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.QUERY_THEN_FETCH;
private final WatcherClientProxy client; private final WatcherClientProxy client;
private final WatcherSearchTemplateService searchTemplateService;
private final @Nullable TimeValue timeout; 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); super(input, logger);
this.client = client; this.client = client;
this.searchTemplateService = searchTemplateService;
this.timeout = input.getTimeout() != null ? input.getTimeout() : defaultTimeout; 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) { public SearchInput.Result execute(WatchExecutionContext ctx, Payload payload) {
SearchRequest request = null; SearchRequest request = null;
try { try {
request = WatcherUtils.createSearchRequestFromPrototype(input.getSearchRequest(), ctx, payload); request = searchTemplateService.createSearchRequestFromPrototype(input.getRequest(), ctx, payload);
return doExecute(ctx, request); return doExecute(ctx, request);
} catch (Exception e) { } catch (Exception e) {
logger.error("failed to execute [{}] input for [{}]", e, SearchInput.TYPE, ctx.watch()); 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 { SearchInput.Result doExecute(WatchExecutionContext ctx, SearchRequest request) throws Exception {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
ToXContent source = request.source() != null ? request.source() : request.template(); logger.trace("[{}] running query for [{}] [{}]", ctx.id(), ctx.watch().id(), XContentHelper.toString(request.source()));
logger.trace("[{}] running query for [{}] [{}]", ctx.id(), ctx.watch().id(), XContentHelper.toString(source));
} }
SearchResponse response = client.search(request, timeout); SearchResponse response = client.search(request, timeout);

View File

@ -17,9 +17,8 @@ import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.xpack.watcher.input.Input; import org.elasticsearch.xpack.watcher.input.Input;
import org.elasticsearch.xpack.watcher.support.SearchRequestEquivalence;
import org.elasticsearch.xpack.watcher.support.WatcherDateTimeUtils; 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.elasticsearch.xpack.watcher.watch.Payload;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
@ -38,14 +37,14 @@ public class SearchInput implements Input {
public static final String TYPE = "search"; public static final String TYPE = "search";
private final SearchRequest searchRequest; private final WatcherSearchTemplateRequest request;
private final @Nullable Set<String> extractKeys; private final @Nullable Set<String> extractKeys;
private final @Nullable TimeValue timeout; private final @Nullable TimeValue timeout;
private final @Nullable DateTimeZone dynamicNameTimeZone; 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) { @Nullable TimeValue timeout, @Nullable DateTimeZone dynamicNameTimeZone) {
this.searchRequest = searchRequest; this.request = request;
this.extractKeys = extractKeys; this.extractKeys = extractKeys;
this.timeout = timeout; this.timeout = timeout;
this.dynamicNameTimeZone = dynamicNameTimeZone; this.dynamicNameTimeZone = dynamicNameTimeZone;
@ -63,7 +62,7 @@ public class SearchInput implements Input {
SearchInput that = (SearchInput) o; 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 (extractKeys != null ? !extractKeys.equals(that.extractKeys) : that.extractKeys != null) return false;
if (timeout != null ? !timeout.equals(that.timeout) : that.timeout != 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); return !(dynamicNameTimeZone != null ? !dynamicNameTimeZone.equals(that.dynamicNameTimeZone) : that.dynamicNameTimeZone != null);
@ -71,15 +70,15 @@ public class SearchInput implements Input {
@Override @Override
public int hashCode() { 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 + (extractKeys != null ? extractKeys.hashCode() : 0);
result = 31 * result + (timeout != null ? timeout.hashCode() : 0); result = 31 * result + (timeout != null ? timeout.hashCode() : 0);
result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0); result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0);
return result; return result;
} }
public SearchRequest getSearchRequest() { public WatcherSearchTemplateRequest getRequest() {
return searchRequest; return request;
} }
public Set<String> getExtractKeys() { public Set<String> getExtractKeys() {
@ -97,8 +96,9 @@ public class SearchInput implements Input {
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(Field.REQUEST.getPreferredName()); if (request != null) {
builder = WatcherUtils.writeSearchRequest(searchRequest, builder, params); builder.field(Field.REQUEST.getPreferredName(), request);
}
if (extractKeys != null) { if (extractKeys != null) {
builder.field(Field.EXTRACT.getPreferredName(), extractKeys); 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, public static SearchInput parse(String watchId, XContentParser parser, QueryParseContext context,
AggregatorParsers aggParsers, Suggesters suggesters) AggregatorParsers aggParsers, Suggesters suggesters)
throws IOException { throws IOException {
SearchRequest request = null; WatcherSearchTemplateRequest request = null;
Set<String> extract = null; Set<String> extract = null;
TimeValue timeout = null; TimeValue timeout = null;
DateTimeZone dynamicNameTimeZone = null; DateTimeZone dynamicNameTimeZone = null;
@ -127,7 +127,7 @@ public class SearchInput implements Input {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
try { try {
request = WatcherUtils.readSearchRequest(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context, request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchInput.DEFAULT_SEARCH_TYPE, context,
aggParsers, suggesters); aggParsers, suggesters);
} catch (ElasticsearchParseException srpe) { } catch (ElasticsearchParseException srpe) {
throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE, throw new ElasticsearchParseException("could not parse [{}] input for watch [{}]. failed to parse [{}]", srpe, TYPE,
@ -170,7 +170,7 @@ public class SearchInput implements Input {
return new SearchInput(request, extract, timeout, dynamicNameTimeZone); return new SearchInput(request, extract, timeout, dynamicNameTimeZone);
} }
public static Builder builder(SearchRequest request) { public static Builder builder(WatcherSearchTemplateRequest request) {
return new Builder(request); return new Builder(request);
} }
@ -198,20 +198,19 @@ public class SearchInput implements Input {
return builder; return builder;
} }
builder.startObject(type); builder.startObject(type);
builder.field(Field.REQUEST.getPreferredName()); builder.field(Field.REQUEST.getPreferredName(), new WatcherSearchTemplateRequest(request));
WatcherUtils.writeSearchRequest(request, builder, params);
return builder.endObject(); return builder.endObject();
} }
} }
public static class Builder implements Input.Builder<SearchInput> { public static class Builder implements Input.Builder<SearchInput> {
private final SearchRequest request; private final WatcherSearchTemplateRequest request;
private final Set<String> extractKeys = new HashSet<>(); private final Set<String> extractKeys = new HashSet<>();
private TimeValue timeout; private TimeValue timeout;
private DateTimeZone dynamicNameTimeZone; private DateTimeZone dynamicNameTimeZone;
private Builder(SearchRequest request) { private Builder(WatcherSearchTemplateRequest request) {
this.request = request; this.request = request;
} }

View File

@ -5,8 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.input.search; package org.elasticsearch.xpack.watcher.input.search;
import java.io.IOException;
import org.elasticsearch.common.ParseFieldMatcher; import org.elasticsearch.common.ParseFieldMatcher;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.logging.Loggers; 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.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.watcher.input.InputFactory; import org.elasticsearch.xpack.watcher.input.InputFactory;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy; import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import java.io.IOException;
/** /**
* *
@ -33,15 +35,16 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
private final AggregatorParsers aggParsers; private final AggregatorParsers aggParsers;
private final Suggesters suggesters; private final Suggesters suggesters;
private final ParseFieldMatcher parseFieldMatcher; private final ParseFieldMatcher parseFieldMatcher;
private final WatcherSearchTemplateService searchTemplateService;
@Inject @Inject
public SearchInputFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry, public SearchInputFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry,
AggregatorParsers aggParsers, Suggesters suggesters) { AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters); this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters, scriptService);
} }
public SearchInputFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry, public SearchInputFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry,
AggregatorParsers aggParsers, Suggesters suggesters) { AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
super(Loggers.getLogger(ExecutableSimpleInput.class, settings)); super(Loggers.getLogger(ExecutableSimpleInput.class, settings));
this.parseFieldMatcher = new ParseFieldMatcher(settings); this.parseFieldMatcher = new ParseFieldMatcher(settings);
this.client = client; this.client = client;
@ -49,6 +52,7 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
this.aggParsers = aggParsers; this.aggParsers = aggParsers;
this.suggesters = suggesters; this.suggesters = suggesters;
this.defaultTimeout = settings.getAsTime("xpack.watcher.input.search.default_timeout", null); this.defaultTimeout = settings.getAsTime("xpack.watcher.input.search.default_timeout", null);
this.searchTemplateService = new WatcherSearchTemplateService(settings, scriptService, queryRegistry, aggParsers, suggesters);
} }
@Override @Override
@ -64,6 +68,6 @@ public class SearchInputFactory extends InputFactory<SearchInput, SearchInput.Re
@Override @Override
public ExecutableSearchInput createExecutable(SearchInput input) { public ExecutableSearchInput createExecutable(SearchInput input) {
return new ExecutableSearchInput(input, inputLogger, client, defaultTimeout); return new ExecutableSearchInput(input, inputLogger, client, searchTemplateService, defaultTimeout);
} }
} }

View File

@ -33,6 +33,9 @@ public class RestAckWatchAction extends WatcherRestHandler {
super(settings, client); super(settings, client);
controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_ack", this); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_ack", this);
controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_ack", this); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_ack", this);
controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/_ack/{actions}", this);
controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/_ack/{actions}", this);
// these are going to be removed in 6.0
controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/{actions}/_ack", this); controller.registerHandler(RestRequest.Method.PUT, URI_BASE + "/watch/{id}/{actions}/_ack", this);
controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/{actions}/_ack", this); controller.registerHandler(RestRequest.Method.POST, URI_BASE + "/watch/{id}/{actions}/_ack", this);
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.support; package org.elasticsearch.xpack.watcher.support;
import com.google.common.base.Charsets;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse; import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterChangedEvent;
@ -21,9 +20,10 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.gateway.GatewayService; import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.security.InternalClient; import org.elasticsearch.xpack.security.InternalClient;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.template.TemplateUtils; import org.elasticsearch.xpack.template.TemplateUtils;
import org.elasticsearch.xpack.watcher.support.init.proxy.WatcherClientProxy;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
@ -168,7 +168,7 @@ public class WatcherIndexTemplateRegistry extends AbstractComponent implements C
} }
executor.execute(() -> { executor.execute(() -> {
final byte[] template = TemplateUtils.loadTemplate("/" + config.getFileName()+ ".json", INDEX_TEMPLATE_VERSION, final byte[] template = TemplateUtils.loadTemplate("/" + config.getFileName()+ ".json", INDEX_TEMPLATE_VERSION,
Pattern.quote("${xpack.watcher.template.version}")).getBytes(Charsets.UTF_8); Pattern.quote("${xpack.watcher.template.version}")).getBytes(StandardCharsets.UTF_8);
PutIndexTemplateRequest request = new PutIndexTemplateRequest(config.getTemplateName()).source(template); PutIndexTemplateRequest request = new PutIndexTemplateRequest(config.getTemplateName()).source(template);
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); request.masterNodeTimeout(TimeValue.timeValueMinutes(1));

View File

@ -5,54 +5,22 @@
*/ */
package org.elasticsearch.xpack.watcher.support; 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.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.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 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 { 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() { private WatcherUtils() {
} }
@ -62,214 +30,6 @@ public final class WatcherUtils {
return XContentHelper.convertToMap(builder.bytes(), false).v2(); 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) { public static Map<String, Object> flattenModel(Map<String, Object> map) {
Map<String, Object> result = new HashMap<>(); Map<String, Object> result = new HashMap<>();
flattenModel("", map, result); flattenModel("", map, result);

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -6,8 +6,8 @@
package org.elasticsearch.xpack.watcher.transform; package org.elasticsearch.xpack.watcher.transform;
import org.elasticsearch.action.search.SearchRequest; 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.Script;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform; import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform; import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform;
import org.elasticsearch.xpack.watcher.transform.search.SearchTransform; import org.elasticsearch.xpack.watcher.transform.search.SearchTransform;
@ -20,12 +20,12 @@ public final class TransformBuilders {
private TransformBuilders() { private TransformBuilders() {
} }
public static SearchTransform.Builder searchTransform(SearchRequest request) { public static SearchTransform.Builder searchTransform(WatcherSearchTemplateRequest request) {
return SearchTransform.builder(request); return SearchTransform.builder(request);
} }
public static SearchTransform.Builder searchTransform(SearchRequestBuilder request) { public static SearchTransform.Builder searchTransform(SearchRequest request) {
return searchTransform(request.request()); return searchTransform(new WatcherSearchTemplateRequest(request));
} }
public static ScriptTransform.Builder scriptTransform(String script) { public static ScriptTransform.Builder scriptTransform(String script) {

View File

@ -12,8 +12,8 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext; 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.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
import org.elasticsearch.xpack.watcher.watch.Payload; 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; public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.QUERY_THEN_FETCH;
protected final WatcherClientProxy client; protected final WatcherClientProxy client;
private final WatcherSearchTemplateService searchTemplateService;
protected final @Nullable TimeValue timeout; protected final @Nullable TimeValue timeout;
public ExecutableSearchTransform(SearchTransform transform, ESLogger logger, WatcherClientProxy client, public ExecutableSearchTransform(SearchTransform transform, ESLogger logger, WatcherClientProxy client,
@Nullable TimeValue defaultTimeout) { WatcherSearchTemplateService searchTemplateService, @Nullable TimeValue defaultTimeout) {
super(transform, logger); super(transform, logger);
this.client = client; this.client = client;
this.searchTemplateService = searchTemplateService;
this.timeout = transform.getTimeout() != null ? transform.getTimeout() : defaultTimeout; 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) { public SearchTransform.Result execute(WatchExecutionContext ctx, Payload payload) {
SearchRequest request = null; SearchRequest request = null;
try { try {
request = WatcherUtils.createSearchRequestFromPrototype(transform.getRequest(), ctx, payload); request = searchTemplateService.createSearchRequestFromPrototype(transform.getRequest(), ctx, payload);
SearchResponse resp = client.search(request, timeout); SearchResponse resp = client.search(request, timeout);
return new SearchTransform.Result(request, new Payload.XContent(resp)); return new SearchTransform.Result(request, new Payload.XContent(resp));
} catch (Exception e) { } catch (Exception e) {

View File

@ -16,9 +16,8 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters; 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.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.transform.Transform;
import org.elasticsearch.xpack.watcher.watch.Payload; import org.elasticsearch.xpack.watcher.watch.Payload;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
@ -32,11 +31,11 @@ public class SearchTransform implements Transform {
public static final String TYPE = "search"; public static final String TYPE = "search";
private final SearchRequest request; private final WatcherSearchTemplateRequest request;
private final @Nullable TimeValue timeout; private final @Nullable TimeValue timeout;
private final @Nullable DateTimeZone dynamicNameTimeZone; 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.request = request;
this.timeout = timeout; this.timeout = timeout;
this.dynamicNameTimeZone = dynamicNameTimeZone; this.dynamicNameTimeZone = dynamicNameTimeZone;
@ -47,7 +46,7 @@ public class SearchTransform implements Transform {
return TYPE; return TYPE;
} }
public SearchRequest getRequest() { public WatcherSearchTemplateRequest getRequest() {
return request; return request;
} }
@ -66,14 +65,14 @@ public class SearchTransform implements Transform {
SearchTransform that = (SearchTransform) o; 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; if (timeout != null ? !timeout.equals(that.timeout) : that.timeout != null) return false;
return !(dynamicNameTimeZone != null ? !dynamicNameTimeZone.equals(that.dynamicNameTimeZone) : that.dynamicNameTimeZone != null); return !(dynamicNameTimeZone != null ? !dynamicNameTimeZone.equals(that.dynamicNameTimeZone) : that.dynamicNameTimeZone != null);
} }
@Override @Override
public int hashCode() { 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 + (timeout != null ? timeout.hashCode() : 0);
result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0); result = 31 * result + (dynamicNameTimeZone != null ? dynamicNameTimeZone.hashCode() : 0);
return result; return result;
@ -82,8 +81,9 @@ public class SearchTransform implements Transform {
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(Field.REQUEST.getPreferredName()); if (request != null) {
builder = WatcherUtils.writeSearchRequest(request, builder, params); builder.field(Field.REQUEST.getPreferredName(), request);
}
if (timeout != null) { if (timeout != null) {
builder.field(Field.TIMEOUT.getPreferredName(), timeout); 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, public static SearchTransform parse(String watchId, XContentParser parser, QueryParseContext context,
AggregatorParsers aggParsers, Suggesters suggesters) AggregatorParsers aggParsers, Suggesters suggesters)
throws IOException { throws IOException {
SearchRequest request = null; WatcherSearchTemplateRequest request = null;
TimeValue timeout = null; TimeValue timeout = null;
DateTimeZone dynamicNameTimeZone = null; DateTimeZone dynamicNameTimeZone = null;
@ -108,7 +108,7 @@ public class SearchTransform implements Transform {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) { } else if (ParseFieldMatcher.STRICT.match(currentFieldName, Field.REQUEST)) {
try { try {
request = WatcherUtils.readSearchRequest(parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE, context, request = WatcherSearchTemplateRequest.fromXContent(parser, ExecutableSearchTransform.DEFAULT_SEARCH_TYPE, context,
aggParsers, suggesters); aggParsers, suggesters);
} catch (ElasticsearchParseException srpe) { } catch (ElasticsearchParseException srpe) {
throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe, throw new ElasticsearchParseException("could not parse [{}] transform for watch [{}]. failed to parse [{}]", srpe,
@ -136,7 +136,7 @@ public class SearchTransform implements Transform {
return new SearchTransform(request, timeout, dynamicNameTimeZone); return new SearchTransform(request, timeout, dynamicNameTimeZone);
} }
public static Builder builder(SearchRequest request) { public static Builder builder(WatcherSearchTemplateRequest request) {
return new Builder(request); return new Builder(request);
} }
@ -162,8 +162,7 @@ public class SearchTransform implements Transform {
protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException { protected XContentBuilder typeXContent(XContentBuilder builder, Params params) throws IOException {
if (request != null) { if (request != null) {
builder.startObject(type); builder.startObject(type);
builder.field(Field.REQUEST.getPreferredName()); builder.field(Field.REQUEST.getPreferredName(), new WatcherSearchTemplateRequest(request));
WatcherUtils.writeSearchRequest(request, builder, params);
builder.endObject(); builder.endObject();
} }
return builder; return builder;
@ -172,11 +171,11 @@ public class SearchTransform implements Transform {
public static class Builder implements Transform.Builder<SearchTransform> { public static class Builder implements Transform.Builder<SearchTransform> {
private final SearchRequest request; private final WatcherSearchTemplateRequest request;
private TimeValue timeout; private TimeValue timeout;
private DateTimeZone dynamicNameTimeZone; private DateTimeZone dynamicNameTimeZone;
public Builder(SearchRequest request) { public Builder(WatcherSearchTemplateRequest request) {
this.request = request; this.request = request;
} }

View File

@ -18,7 +18,9 @@ import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.search.aggregations.AggregatorParsers; import org.elasticsearch.search.aggregations.AggregatorParsers;
import org.elasticsearch.search.suggest.Suggesters; import org.elasticsearch.search.suggest.Suggesters;
import org.elasticsearch.xpack.security.InternalClient; 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.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.watcher.transform.TransformFactory; import org.elasticsearch.xpack.watcher.transform.TransformFactory;
/** /**
@ -32,14 +34,15 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
private final AggregatorParsers aggParsers; private final AggregatorParsers aggParsers;
private final Suggesters suggesters; private final Suggesters suggesters;
private final ParseFieldMatcher parseFieldMatcher; private final ParseFieldMatcher parseFieldMatcher;
private final WatcherSearchTemplateService searchTemplateService;
@Inject @Inject
public SearchTransformFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry, public SearchTransformFactory(Settings settings, InternalClient client, IndicesQueriesRegistry queryRegistry,
AggregatorParsers aggParsers, Suggesters suggesters) { AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters); this(settings, new WatcherClientProxy(settings, client), queryRegistry, aggParsers, suggesters, scriptService);
} }
public SearchTransformFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry, public SearchTransformFactory(Settings settings, WatcherClientProxy client, IndicesQueriesRegistry queryRegistry,
AggregatorParsers aggParsers, Suggesters suggesters) { AggregatorParsers aggParsers, Suggesters suggesters, ScriptServiceProxy scriptService) {
super(Loggers.getLogger(ExecutableSearchTransform.class, settings)); super(Loggers.getLogger(ExecutableSearchTransform.class, settings));
this.client = client; this.client = client;
this.parseFieldMatcher = new ParseFieldMatcher(settings); this.parseFieldMatcher = new ParseFieldMatcher(settings);
@ -47,6 +50,7 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
this.aggParsers = aggParsers; this.aggParsers = aggParsers;
this.suggesters = suggesters; this.suggesters = suggesters;
this.defaultTimeout = settings.getAsTime("xpack.watcher.transform.search.default_timeout", null); this.defaultTimeout = settings.getAsTime("xpack.watcher.transform.search.default_timeout", null);
this.searchTemplateService = new WatcherSearchTemplateService(settings, scriptService, queryRegistry, aggParsers, suggesters);
} }
@Override @Override
@ -62,6 +66,6 @@ public class SearchTransformFactory extends TransformFactory<SearchTransform, Se
@Override @Override
public ExecutableSearchTransform createExecutable(SearchTransform transform) { public ExecutableSearchTransform createExecutable(SearchTransform transform) {
return new ExecutableSearchTransform(transform, transformLogger, client, defaultTimeout); return new ExecutableSearchTransform(transform, transformLogger, client, searchTemplateService, defaultTimeout);
} }
} }

View File

@ -38,7 +38,7 @@ public class HistoryIntegrationTests extends AbstractWatcherIntegrationTestCase
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))); builder.input(InputBuilders.chainInput().add("first", InputBuilders.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));

View File

@ -6,10 +6,9 @@
package org.elasticsearch.xpack.watcher; package org.elasticsearch.xpack.watcher;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo; import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.http.HttpServerTransport;
@ -18,12 +17,10 @@ import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.xpack.security.Security; import org.elasticsearch.xpack.security.Security;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope; import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.threadpool.ThreadPoolInfo; import org.elasticsearch.threadpool.ThreadPoolInfo;
import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
import org.elasticsearch.xpack.XPackPlugin; import org.elasticsearch.xpack.XPackPlugin;
import org.elasticsearch.xpack.watcher.execution.InternalWatchExecutor;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -70,12 +67,11 @@ public class WatcherPluginDisableTests extends ESIntegTestCase {
public void testRestEndpoints() throws Exception { public void testRestEndpoints() throws Exception {
HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class); HttpServerTransport httpServerTransport = internalCluster().getDataNodeInstance(HttpServerTransport.class);
try (CloseableHttpClient httpClient = HttpClients.createDefault()) { try {
HttpRequestBuilder request = new HttpRequestBuilder(httpClient).httpTransport(httpServerTransport) getRestClient().performRequest("GET", "/_xpack/watcher", Collections.emptyMap(), null);
.method("GET") fail("request should have failed");
.path("/_xpack/watcher"); } catch(ResponseException e) {
HttpResponse response = request.execute(); assertThat(e.getResponse().getStatusLine().getStatusCode(), is(HttpStatus.SC_BAD_REQUEST));
assertThat(response.getStatusCode(), is(HttpStatus.SC_BAD_REQUEST));
} }
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.actions.email; package org.elasticsearch.xpack.watcher.actions.email;
import com.google.common.base.Charsets;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
@ -55,6 +54,7 @@ import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -478,7 +478,7 @@ public class EmailActionTests extends ESTestCase {
Attachment externalAttachment = attachments.get(attachmentId); Attachment externalAttachment = attachments.get(attachmentId);
assertThat(externalAttachment.bodyPart(), is(notNullValue())); assertThat(externalAttachment.bodyPart(), is(notNullValue()));
InputStream is = externalAttachment.bodyPart().getInputStream(); InputStream is = externalAttachment.bodyPart().getInputStream();
String data = Streams.copyToString(new InputStreamReader(is, Charsets.UTF_8)); String data = Streams.copyToString(new InputStreamReader(is, StandardCharsets.UTF_8));
assertThat(data, is(content)); assertThat(data, is(content));
} }
@ -610,7 +610,8 @@ public class EmailActionTests extends ESTestCase {
when(httpClient.execute(any(HttpRequest.class))).thenReturn(mockResponse); when(httpClient.execute(any(HttpRequest.class))).thenReturn(mockResponse);
HttpRequestTemplate template = HttpRequestTemplate.builder("localhost", 1234).build(); HttpRequestTemplate template = HttpRequestTemplate.builder("localhost", 1234).build();
attachments.add(new HttpRequestAttachment(randomAsciiOfLength(10), template, randomFrom("my/custom-type", null))); attachments.add(new HttpRequestAttachment(randomAsciiOfLength(10), template,
randomBoolean(), randomFrom("my/custom-type", null)));
} else if ("data".equals(attachmentType)) { } else if ("data".equals(attachmentType)) {
attachments.add(new org.elasticsearch.xpack.notification.email.attachment.DataAttachment(randomAsciiOfLength(10), attachments.add(new org.elasticsearch.xpack.notification.email.attachment.DataAttachment(randomAsciiOfLength(10),
randomFrom(DataAttachment.JSON, DataAttachment.YAML))); randomFrom(DataAttachment.JSON, DataAttachment.YAML)));

View File

@ -207,7 +207,4 @@ public class EmailAttachmentTests extends AbstractWatcherIntegrationTestCase {
fail("waited too long for email to be received"); fail("waited too long for email to be received");
} }
} }
} }

View File

@ -6,6 +6,7 @@
package org.elasticsearch.xpack.watcher.actions.index; package org.elasticsearch.xpack.watcher.actions.index;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
@ -64,14 +65,8 @@ public class IndexActionTests extends ESIntegTestCase {
} }
public void testIndexActionExecuteSingleDoc() throws Exception { public void testIndexActionExecuteSingleDoc() throws Exception {
String timestampField = randomFrom(null, "_timestamp", "@timestamp"); String timestampField = randomFrom(null, "@timestamp");
boolean customTimestampField = "@timestamp".equals(timestampField); boolean customTimestampField = timestampField != null;
if (timestampField == null || "_timestamp".equals(timestampField)) {
assertThat(prepareCreate("test-index")
.addMapping("test-type", "{ \"test-type\" : { \"_timestamp\" : { \"enabled\" : \"true\" }}}")
.get().isAcknowledged(), is(true));
}
IndexAction action = new IndexAction("test-index", "test-type", timestampField, null, null); IndexAction action = new IndexAction("test-index", "test-type", timestampField, null, null);
ExecutableIndexAction executable = new ExecutableIndexAction(action, logger, WatcherClientProxy.of(client()), null); ExecutableIndexAction executable = new ExecutableIndexAction(action, logger, WatcherClientProxy.of(client()), null);
@ -92,12 +87,15 @@ public class IndexActionTests extends ESIntegTestCase {
refresh(); //Manually refresh to make sure data is available refresh(); //Manually refresh to make sure data is available
SearchResponse searchResponse = client().prepareSearch("test-index") SearchRequestBuilder searchRequestbuilder = client().prepareSearch("test-index")
.setTypes("test-type") .setTypes("test-type")
.setSource(searchSource() .setSource(searchSource().query(matchAllQuery()));
.query(matchAllQuery())
.aggregation(terms("timestamps").field(customTimestampField ? timestampField : "_timestamp"))) if (customTimestampField) {
.get(); searchRequestbuilder.addAggregation(terms("timestamps").field(timestampField));
}
SearchResponse searchResponse = searchRequestbuilder.get();
assertThat(searchResponse.getHits().totalHits(), equalTo(1L)); assertThat(searchResponse.getHits().totalHits(), equalTo(1L));
SearchHit hit = searchResponse.getHits().getAt(0); SearchHit hit = searchResponse.getHits().getAt(0);
@ -106,28 +104,24 @@ public class IndexActionTests extends ESIntegTestCase {
assertThat(hit.getSource().size(), is(2)); assertThat(hit.getSource().size(), is(2));
assertThat(hit.getSource(), hasEntry("foo", (Object) "bar")); assertThat(hit.getSource(), hasEntry("foo", (Object) "bar"));
assertThat(hit.getSource(), hasEntry(timestampField, (Object) WatcherDateTimeUtils.formatDate(executionTime))); assertThat(hit.getSource(), hasEntry(timestampField, (Object) WatcherDateTimeUtils.formatDate(executionTime)));
Terms terms = searchResponse.getAggregations().get("timestamps");
assertThat(terms, notNullValue());
assertThat(terms.getBuckets(), hasSize(1));
assertThat(terms.getBuckets().get(0).getKeyAsNumber().longValue(), is(executionTime.getMillis()));
assertThat(terms.getBuckets().get(0).getDocCount(), is(1L));
} else { } else {
assertThat(hit.getSource().size(), is(1)); assertThat(hit.getSource().size(), is(1));
assertThat(hit.getSource(), hasEntry("foo", (Object) "bar")); assertThat(hit.getSource(), hasEntry("foo", (Object) "bar"));
} }
Terms terms = searchResponse.getAggregations().get("timestamps");
assertThat(terms, notNullValue());
assertThat(terms.getBuckets(), hasSize(1));
assertThat(terms.getBuckets().get(0).getKeyAsNumber().longValue(), is(executionTime.getMillis()));
assertThat(terms.getBuckets().get(0).getDocCount(), is(1L));
} }
public void testIndexActionExecuteMultiDoc() throws Exception { public void testIndexActionExecuteMultiDoc() throws Exception {
String timestampField = randomFrom(null, "_timestamp", "@timestamp"); String timestampField = randomFrom(null, "@timestamp");
boolean customTimestampField = "@timestamp".equals(timestampField); boolean customTimestampField = "@timestamp".equals(timestampField);
if (timestampField == null || "_timestamp".equals(timestampField)) { assertAcked(prepareCreate("test-index")
assertAcked(prepareCreate("test-index") .addMapping("test-type", "foo", "type=keyword"));
.addMapping("test-type", "_timestamp", "enabled=true", "foo", "type=keyword"));
} else {
assertAcked(prepareCreate("test-index")
.addMapping("test-type", "foo", "type=keyword"));
}
Object list = randomFrom( Object list = randomFrom(
new Map[] { singletonMap("foo", "bar"), singletonMap("foo", "bar1") }, new Map[] { singletonMap("foo", "bar"), singletonMap("foo", "bar1") },
@ -160,8 +154,7 @@ public class IndexActionTests extends ESIntegTestCase {
SearchResponse searchResponse = client().prepareSearch("test-index") SearchResponse searchResponse = client().prepareSearch("test-index")
.setTypes("test-type") .setTypes("test-type")
.setSource(searchSource().sort("foo", SortOrder.ASC) .setSource(searchSource().sort("foo", SortOrder.ASC)
.query(matchAllQuery()) .query(matchAllQuery()))
.aggregation(terms("timestamps").field(customTimestampField ? timestampField : "_timestamp")))
.get(); .get();
assertThat(searchResponse.getHits().totalHits(), equalTo(2L)); assertThat(searchResponse.getHits().totalHits(), equalTo(2L));

View File

@ -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.secret.SecretService;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.common.text.TextTemplate;
import org.elasticsearch.xpack.common.text.TextTemplateEngine; 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.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine; import org.elasticsearch.xpack.watcher.test.MockTextTemplateEngine;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
@ -238,7 +239,7 @@ public class WebhookActionTests extends ESTestCase {
ExecutableWebhookAction executable = new ExecutableWebhookAction(action, logger, httpClient, templateEngine); ExecutableWebhookAction executable = new ExecutableWebhookAction(action, logger, httpClient, templateEngine);
String watchId = "test_url_encode" + randomAsciiOfLength(10); 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), WatchExecutionContext ctx = new TriggeredExecutionContext(watch, new DateTime(UTC),
new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5)); new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5));
executable.execute("_id", ctx, new Payload.Simple()); executable.execute("_id", ctx, new Payload.Simple());
@ -264,16 +265,16 @@ public class WebhookActionTests extends ESTestCase {
ExecutableWebhookAction executable = new ExecutableWebhookAction(action, logger, client, templateEngine); 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), WatchExecutionContext ctx = new TriggeredExecutionContext(watch, new DateTime(UTC),
new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5)); new ScheduleTriggerEvent(watchId, new DateTime(UTC), new DateTime(UTC)), timeValueSeconds(5));
Action.Result result = executable.execute("_id", ctx, new Payload.Simple()); Action.Result result = executable.execute("_id", ctx, new Payload.Simple());
assertThat(result, Matchers.instanceOf(WebhookAction.Result.Success.class)); 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, return WatcherTestUtils.createTestWatch(watchId,
client, mock(WatcherClientProxy.class),
ExecuteScenario.Success.client(), ExecuteScenario.Success.client(),
new AbstractWatcherIntegrationTestCase.NoopEmailService() { new AbstractWatcherIntegrationTestCase.NoopEmailService() {
@Override @Override
@ -286,6 +287,7 @@ public class WebhookActionTests extends ESTestCase {
return new EmailSent(account, email); return new EmailSent(account, email);
} }
}, },
mock(WatcherSearchTemplateService.class),
logger); logger);
}; };

View File

@ -39,18 +39,14 @@ public class CompareConditionSearchTests extends AbstractWatcherIntegrationTestC
} }
public void testExecuteWithAggs() throws Exception { public void testExecuteWithAggs() throws Exception {
client().admin().indices().prepareCreate("my-index") client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:00").get();
.addMapping("my-type", "_timestamp", "enabled=true") client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:10").get();
.get(); client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:20").get();
client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:30").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:00").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:10").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:20").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:30").setSource("{}").get();
refresh(); refresh();
SearchResponse response = client().prepareSearch("my-index") SearchResponse response = client().prepareSearch("my-index")
.addAggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp") .addAggregation(AggregationBuilders.dateHistogram("rate").field("@timestamp")
.dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC)) .dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get(); .get();
@ -65,12 +61,12 @@ public class CompareConditionSearchTests extends AbstractWatcherIntegrationTestC
assertThat(resolvedValues.size(), is(1)); assertThat(resolvedValues.size(), is(1));
assertThat(resolvedValues, hasEntry("ctx.payload.aggregations.rate.buckets.0.doc_count", (Object) 4)); assertThat(resolvedValues, hasEntry("ctx.payload.aggregations.rate.buckets.0.doc_count", (Object) 4));
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:40").setSource("{}").get(); client().prepareIndex("my-index", "my-type").setSource("@timestamp", "2005-01-01T00:40").get();
refresh(); refresh();
response = client().prepareSearch("my-index") response = client().prepareSearch("my-index")
.addAggregation(AggregationBuilders.dateHistogram("rate") .addAggregation(AggregationBuilders.dateHistogram("rate")
.field("_timestamp").dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC)) .field("@timestamp").dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get(); .get();
ctx = mockExecutionContext("_name", new Payload.XContent(response)); ctx = mockExecutionContext("_name", new Payload.XContent(response));

View File

@ -1,105 +0,0 @@
/*
* 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.condition.script;
import org.apache.lucene.util.LuceneTestCase.AwaitsFix;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.Index;
import org.elasticsearch.search.SearchShardTarget;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
import org.elasticsearch.search.internal.InternalSearchHit;
import org.elasticsearch.search.internal.InternalSearchHits;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.threadpool.TestThreadPool;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xpack.watcher.execution.WatchExecutionContext;
import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.common.ScriptServiceProxy;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.watch.Payload;
import org.junit.After;
import org.junit.Before;
import static org.elasticsearch.xpack.watcher.test.WatcherTestUtils.mockExecutionContext;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
/**
*/
@AwaitsFix(bugUrl = "https://github.com/elastic/x-plugins/issues/724")
public class ScriptConditionSearchTests extends AbstractWatcherIntegrationTestCase {
private ThreadPool tp = null;
private ScriptServiceProxy scriptService;
@Before
public void init() throws Exception {
tp = new TestThreadPool(ThreadPool.Names.SAME);
scriptService = WatcherTestUtils.getScriptServiceProxy(tp);
}
@After
public void cleanup() {
tp.shutdownNow();
}
public void testExecuteWithAggs() throws Exception {
client().admin().indices().prepareCreate("my-index")
.addMapping("my-type", "_timestamp", "enabled=true")
.get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:00").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:10").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:20").setSource("{}").get();
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:30").setSource("{}").get();
refresh();
SearchResponse response = client().prepareSearch("my-index")
.addAggregation(AggregationBuilders.dateHistogram("rate")
.field("_timestamp").dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get();
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("ctx.payload.aggregations.rate.buckets[0]?.doc_count >= 5").build()),
logger, scriptService);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met());
client().prepareIndex("my-index", "my-type").setTimestamp("2005-01-01T00:40").setSource("{}").get();
refresh();
response = client().prepareSearch("my-index")
.addAggregation(AggregationBuilders.dateHistogram("rate")
.field("_timestamp").dateHistogramInterval(DateHistogramInterval.HOUR).order(Histogram.Order.COUNT_DESC))
.get();
ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertThat(condition.execute(ctx).met(), is(true));
}
public void testExecuteAccessHits() throws Exception {
ExecutableScriptCondition condition = new ExecutableScriptCondition(
new ScriptCondition(Script.inline("ctx.payload.hits?.hits[0]?._score == 1.0").build()), logger, scriptService);
InternalSearchHit hit = new InternalSearchHit(0, "1", new Text("type"), null);
hit.score(1f);
hit.shard(new SearchShardTarget("a", new Index("a", "testUUID"), 0));
InternalSearchResponse internalSearchResponse = new InternalSearchResponse(
new InternalSearchHits(new InternalSearchHit[]{hit}, 1L, 1f), null, null, null, false, false);
SearchResponse response = new SearchResponse(internalSearchResponse, "", 3, 3, 500L, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_watch_name", new Payload.XContent(response));
assertThat(condition.execute(ctx).met(), is(true));
hit.score(2f);
when(ctx.payload()).thenReturn(new Payload.XContent(response));
assertThat(condition.execute(ctx).met(), is(false));
}
}

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.watcher.execution;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; 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.AbstractWatcherIntegrationTestCase;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.xpack.watcher.trigger.schedule.ScheduleTriggerEvent;
@ -21,7 +22,8 @@ import static org.hamcrest.Matchers.equalTo;
*/ */
public class TriggeredWatchTests extends AbstractWatcherIntegrationTestCase { public class TriggeredWatchTests extends AbstractWatcherIntegrationTestCase {
public void testParser() throws Exception { 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)); ScheduleTriggerEvent event = new ScheduleTriggerEvent(watch.id(), DateTime.now(DateTimeZone.UTC), DateTime.now(DateTimeZone.UTC));
Wid wid = new Wid("_record", randomLong(), DateTime.now(DateTimeZone.UTC)); Wid wid = new Wid("_record", randomLong(), DateTime.now(DateTimeZone.UTC));
TriggeredWatch triggeredWatch = new TriggeredWatch(wid, event); TriggeredWatch triggeredWatch = new TriggeredWatch(wid, event);
@ -38,4 +40,8 @@ public class TriggeredWatchTests extends AbstractWatcherIntegrationTestCase {
private TriggeredWatch.Parser triggeredWatchParser() { private TriggeredWatch.Parser triggeredWatchParser() {
return internalCluster().getInstance(TriggeredWatch.Parser.class); return internalCluster().getInstance(TriggeredWatch.Parser.class);
} }
protected WatcherSearchTemplateService watcherSearchTemplateService() {
return internalCluster().getInstance(WatcherSearchTemplateService.class);
}
} }

View File

@ -5,7 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.rest.action; package org.elasticsearch.xpack.watcher.rest.action;
import com.google.common.collect.Lists;
import org.elasticsearch.client.Client; import org.elasticsearch.client.Client;
import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
@ -18,6 +17,8 @@ import org.elasticsearch.xpack.watcher.client.WatcherClient;
import org.elasticsearch.xpack.watcher.transport.actions.execute.ExecuteWatchRequestBuilder; import org.elasticsearch.xpack.watcher.transport.actions.execute.ExecuteWatchRequestBuilder;
import org.elasticsearch.xpack.watcher.trigger.TriggerService; import org.elasticsearch.xpack.watcher.trigger.TriggerService;
import java.util.Arrays;
import static org.hamcrest.core.Is.is; import static org.hamcrest.core.Is.is;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@ -32,9 +33,9 @@ public class RestExecuteWatchActionTests extends ESTestCase {
public void testThatFlagsCanBeSpecifiedViaParameters() throws Exception { public void testThatFlagsCanBeSpecifiedViaParameters() throws Exception {
String randomId = randomAsciiOfLength(10); String randomId = randomAsciiOfLength(10);
for (String recordExecution : Lists.newArrayList("true", "false", null)) { for (String recordExecution : Arrays.asList("true", "false", null)) {
for (String ignoreCondition : Lists.newArrayList("true", "false", null)) { for (String ignoreCondition : Arrays.asList("true", "false", null)) {
for (String debugCondition : Lists.newArrayList("true", "false", null)) { for (String debugCondition : Arrays.asList("true", "false", null)) {
ExecuteWatchRequestBuilder builder = new ExecuteWatchRequestBuilder(client); ExecuteWatchRequestBuilder builder = new ExecuteWatchRequestBuilder(client);
when(watcherClient.prepareExecuteWatch()).thenReturn(builder); when(watcherClient.prepareExecuteWatch()).thenReturn(builder);

View File

@ -6,23 +6,6 @@
package org.elasticsearch.xpack.watcher.support; 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.SearchRequest;
import org.elasticsearch.action.search.SearchType; import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.IndicesOptions; 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.QueryParseContext;
import org.elasticsearch.index.query.QueryParser; import org.elasticsearch.index.query.QueryParser;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; 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.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.watcher.input.search.ExecutableSearchInput;
import org.elasticsearch.xpack.support.clock.SystemClock; 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 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 { public void testSerializeSearchRequest() throws Exception {
String[] randomIndices = generateRandomStringArray(5, 5, false); String[] randomIndices = generateRandomStringArray(5, 5, false);
SearchRequest expectedRequest = new SearchRequest(randomIndices); SearchRequest expectedRequest = new SearchRequest(randomIndices);
Script expectedTemplate = null;
if (randomBoolean()) { if (randomBoolean()) {
String[] randomTypes = generateRandomStringArray(2, 5, false); String[] randomTypes = generateRandomStringArray(2, 5, false);
@ -107,7 +106,7 @@ public class WatcherUtilsTests extends ESTestCase {
} }
expectedRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), expectedRequest.indicesOptions(IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(),
randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS)); randomBoolean(), WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS));
expectedRequest.searchType(getRandomSupportedSearchType()); expectedRequest.searchType(getRandomSupportedSearchType());
SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource().query(QueryBuilders.matchAllQuery()).size(11); SearchSourceBuilder searchSourceBuilder = SearchSourceBuilder.searchSource().query(QueryBuilders.matchAllQuery()).size(11);
@ -122,30 +121,29 @@ public class WatcherUtilsTests extends ESTestCase {
} }
} }
String text = randomAsciiOfLengthBetween(1, 5); String text = randomAsciiOfLengthBetween(1, 5);
Template template = randomFrom( expectedTemplate = randomFrom(Script.inline(text), Script.file(text), Script.indexed(text)).params(params).build();
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);
} }
WatcherSearchTemplateRequest request = new WatcherSearchTemplateRequest(expectedRequest, expectedTemplate);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
builder = WatcherUtils.writeSearchRequest(expectedRequest, builder, ToXContent.EMPTY_PARAMS); request.toXContent(builder, ToXContent.EMPTY_PARAMS);
XContentParser parser = XContentHelper.createParser(builder.bytes()); XContentParser parser = XContentHelper.createParser(builder.bytes());
assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT)); assertThat(parser.nextToken(), equalTo(XContentParser.Token.START_OBJECT));
IndicesQueriesRegistry registry = new IndicesQueriesRegistry(); IndicesQueriesRegistry registry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent; QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT); 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.getRequest(), is(notNullValue()));
assertThat(result.types(), arrayContainingInAnyOrder(expectedRequest.types())); assertThat(result.getRequest().indices(), arrayContainingInAnyOrder(expectedRequest.indices()));
assertThat(result.indicesOptions(), equalTo(expectedRequest.indicesOptions())); assertThat(result.getRequest().types(), arrayContainingInAnyOrder(expectedRequest.types()));
assertThat(result.searchType(), equalTo(expectedRequest.searchType())); assertThat(result.getRequest().indicesOptions(), equalTo(expectedRequest.indicesOptions()));
assertThat(result.source(), equalTo(searchSourceBuilder)); assertThat(result.getRequest().searchType(), equalTo(expectedRequest.searchType()));
assertThat(result.template(), equalTo(expectedRequest.template())); assertThat(result.getRequest().source(), equalTo(searchSourceBuilder));
assertThat(result.getTemplate(), equalTo(expectedTemplate));
} }
public void testDeserializeSearchRequest() throws Exception { 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()) { if (randomBoolean()) {
indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(), indicesOptions = IndicesOptions.fromOptions(randomBoolean(), randomBoolean(), randomBoolean(),
randomBoolean(), WatcherUtils.DEFAULT_INDICES_OPTIONS); randomBoolean(), WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS);
builder.startObject("indices_options") builder.startObject("indices_options")
.field("allow_no_indices", indicesOptions.allowNoIndices()) .field("allow_no_indices", indicesOptions.allowNoIndices())
.field("expand_wildcards", indicesOptions.expandWildcardsClosed() && indicesOptions.expandWildcardsOpen() ? "all" : .field("expand_wildcards", indicesOptions.expandWildcardsClosed() && indicesOptions.expandWildcardsOpen() ? "all" :
@ -201,7 +199,7 @@ public class WatcherUtilsTests extends ESTestCase {
source = searchSourceBuilder.buildAsBytes(XContentType.JSON); source = searchSourceBuilder.buildAsBytes(XContentType.JSON);
builder.rawField("body", source); builder.rawField("body", source);
} }
Template templateSource = null; Script template = null;
if (randomBoolean()) { if (randomBoolean()) {
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
if (randomBoolean()) { if (randomBoolean()) {
@ -211,14 +209,8 @@ public class WatcherUtilsTests extends ESTestCase {
} }
} }
String text = randomAsciiOfLengthBetween(1, 5); String text = randomAsciiOfLengthBetween(1, 5);
TextTemplate template = randomFrom( template = randomFrom(Script.inline(text), Script.file(text), Script.indexed(text)) .params(params).build();
TextTemplate.inline(text).params(params).build(),
TextTemplate.file(text).params(params).build(),
TextTemplate.indexed(text).params(params).build()
);
builder.field("template", template); builder.field("template", template);
templateSource = new Template(template.getTemplate(), template.getType(), null, template.getContentType(),
template.getParams());
} }
builder.endObject(); builder.endObject();
@ -228,14 +220,15 @@ public class WatcherUtilsTests extends ESTestCase {
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent; QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); registry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
QueryParseContext context = new QueryParseContext(registry, parser, ParseFieldMatcher.STRICT); 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.getRequest(), is(notNullValue()));
assertThat(result.types(), arrayContainingInAnyOrder(types)); assertThat(result.getRequest().indices(), arrayContainingInAnyOrder(indices));
assertThat(result.indicesOptions(), equalTo(indicesOptions)); assertThat(result.getRequest().types(), arrayContainingInAnyOrder(types));
assertThat(result.searchType(), equalTo(searchType)); assertThat(result.getRequest().indicesOptions(), equalTo(indicesOptions));
assertThat(result.source(), equalTo(searchSourceBuilder)); assertThat(result.getRequest().searchType(), equalTo(searchType));
assertThat(result.template(), equalTo(templateSource)); assertThat(result.getRequest().source(), equalTo(searchSourceBuilder));
assertThat(result.getTemplate(), equalTo(template));
} }
} }

View File

@ -31,6 +31,13 @@ import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService; 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.Authentication;
import org.elasticsearch.xpack.notification.email.EmailService; import org.elasticsearch.xpack.notification.email.EmailService;
import org.elasticsearch.xpack.notification.email.EmailTemplate; 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.search.ExecutableSearchInput;
import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput; import org.elasticsearch.xpack.watcher.input.simple.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.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.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.common.secret.Secret; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath; import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource;
import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform; import org.elasticsearch.xpack.watcher.transform.search.ExecutableSearchTransform;
@ -76,7 +77,6 @@ import javax.mail.internet.AddressException;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -122,7 +122,7 @@ public final class WatcherTestUtils {
public static SearchRequest newInputSearchRequest(String... indices) { public static SearchRequest newInputSearchRequest(String... indices) {
SearchRequest request = new SearchRequest(); SearchRequest request = new SearchRequest();
request.indices(indices); request.indices(indices);
request.indicesOptions(WatcherUtils.DEFAULT_INDICES_OPTIONS); request.indicesOptions(WatcherSearchTemplateRequest.DEFAULT_INDICES_OPTIONS);
request.searchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE); request.searchType(ExecutableSearchInput.DEFAULT_SEARCH_TYPE);
return request; return request;
} }
@ -175,13 +175,14 @@ public final class WatcherTestUtils {
public static Watch createTestWatch(String watchName, HttpClient httpClient, EmailService emailService, public static Watch createTestWatch(String watchName, HttpClient httpClient, EmailService emailService,
ESLogger logger) throws AddressException { WatcherSearchTemplateService searchTemplateService, ESLogger logger) throws AddressException {
return createTestWatch(watchName, WatcherClientProxy.of(ESIntegTestCase.client()), httpClient, emailService, logger); 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, 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 conditionRequest = newInputSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
SearchRequest transformRequest = newInputSearchRequest("my-payload-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<>(); Map<String, ActionStatus> statuses = new HashMap<>();
statuses.put("_webhook", new ActionStatus(now)); statuses.put("_webhook", new ActionStatus(now));
statuses.put("_email", new ActionStatus(now)); statuses.put("_email", new ActionStatus(now));
SearchTransform searchTransform = new SearchTransform(new WatcherSearchTemplateRequest(transformRequest), null, null);
return new Watch( return new Watch(
watchName, watchName,
new ScheduleTrigger(new CronSchedule("0/5 * * * * ? *")), new ScheduleTrigger(new CronSchedule("0/5 * * * * ? *")),
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple(inputData)), logger), new ExecutableSimpleInput(new SimpleInput(new Payload.Simple(inputData)), logger),
new ExecutableAlwaysCondition(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 TimeValue(0),
new ExecutableActions(actions), new ExecutableActions(actions),
metadata, metadata,
@ -247,7 +251,7 @@ public final class WatcherTestUtils {
.put("script.indexed", "true") .put("script.indexed", "true")
.put("path.home", createTempDir()) .put("path.home", createTempDir())
.build(); .build();
ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Arrays.asList(ScriptServiceProxy.INSTANCE)); ScriptContextRegistry scriptContextRegistry = new ScriptContextRegistry(Collections.singletonList(ScriptServiceProxy.INSTANCE));
ScriptEngineRegistry scriptEngineRegistry = ScriptEngineRegistry scriptEngineRegistry =
new ScriptEngineRegistry(Collections.emptyList()); new ScriptEngineRegistry(Collections.emptyList());

View File

@ -7,20 +7,16 @@ package org.elasticsearch.xpack.watcher.test.integration;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.unit.TimeValue; 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.common.xcontent.XContentBuilder;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.script.Template;
import org.elasticsearch.search.builder.SearchSourceBuilder; 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.WatchSourceBuilder;
import org.elasticsearch.xpack.watcher.client.WatcherClient; import org.elasticsearch.xpack.watcher.client.WatcherClient;
import org.elasticsearch.xpack.watcher.condition.compare.CompareCondition; import org.elasticsearch.xpack.watcher.condition.compare.CompareCondition;
import org.elasticsearch.xpack.watcher.support.WatcherUtils; import org.elasticsearch.xpack.watcher.support.Script;
import org.elasticsearch.xpack.support.clock.SystemClock; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.watcher.support.xcontent.XContentSource; 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.delete.DeleteWatchResponse; import org.elasticsearch.xpack.watcher.transport.actions.delete.DeleteWatchResponse;
@ -151,8 +147,8 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
watchSource.field("unknown_field", "x"); watchSource.field("unknown_field", "x");
watchSource.startObject("schedule").field("cron", "0/5 * * * * ? *").endObject(); watchSource.startObject("schedule").field("cron", "0/5 * * * * ? *").endObject();
watchSource.startObject("condition").startObject("script").field("script", "return true").field("request"); watchSource.startObject("condition").startObject("script").field("script", "return true");
WatcherUtils.writeSearchRequest(newInputSearchRequest(), watchSource, ToXContent.EMPTY_PARAMS); watchSource.field("request", new WatcherSearchTemplateRequest(newInputSearchRequest()));
watchSource.endObject().endObject(); watchSource.endObject().endObject();
watchSource.endObject(); watchSource.endObject();
@ -252,22 +248,20 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
public void testConditionSearchWithSource() throws Exception { public void testConditionSearchWithSource() throws Exception {
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a")); SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
testConditionSearch(newInputSearchRequest("events").source(searchSourceBuilder)); testConditionSearch(newInputSearchRequest("events").source(searchSourceBuilder), null);
} }
public void testConditionSearchWithIndexedTemplate() throws Exception { public void testConditionSearchWithIndexedTemplate() throws Exception {
SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a")); SearchSourceBuilder searchSourceBuilder = searchSource().query(matchQuery("level", "a"));
client().admin().cluster().preparePutStoredScript() assertAcked(client().admin().cluster().preparePutStoredScript()
.setScriptLang("mustache") .setScriptLang("mustache")
.setId("my-template") .setId("my-template")
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject().bytes()) .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"); SearchRequest searchRequest = newInputSearchRequest("events");
// TODO (2.0 upgrade): move back to BytesReference instead of coverting to a string testConditionSearch(searchRequest, template);
searchRequest.template(template);
testConditionSearch(searchRequest);
} }
public void testInputFiltering() throws Exception { public void testInputFiltering() throws Exception {
@ -298,12 +292,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTestCase {
// Check that the input result payload has been filtered // Check that the input result payload has been filtered
refresh(); refresh();
SearchResponse searchResponse = searchWatchRecords(new Callback<SearchRequestBuilder>() { SearchResponse searchResponse = searchWatchRecords(builder -> builder.setQuery(matchQuery("watch_id", "_name1")));
@Override
public void handle(SearchRequestBuilder builder) {
builder.setQuery(matchQuery("watch_id", "_name1"));
}
});
assertHitCount(searchResponse, 1); assertHitCount(searchResponse, 1);
XContentSource source = xContentSource(searchResponse.getHits().getAt(0).getSourceRef()); XContentSource source = xContentSource(searchResponse.getHits().getAt(0).getSourceRef());
assertThat(source.getValue("result.input.payload.hits.total"), equalTo((Object) 1)); assertThat(source.getValue("result.input.payload.hits.total"), equalTo((Object) 1));
@ -379,17 +368,17 @@ 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. // reset, so we don't miss event docs when we filter over the _timestamp field.
timeWarp().clock().setTime(SystemClock.INSTANCE.nowUTC()); timeWarp().clock().setTime(SystemClock.INSTANCE.nowUTC());
String watchName = "_name"; String watchName = "_name";
assertAcked(prepareCreate("events").addMapping("event", "_timestamp", "enabled=true", "level", "type=text")); assertAcked(prepareCreate("events").addMapping("event", "level", "type=text"));
watcherClient().preparePutWatch(watchName) watcherClient().preparePutWatch(watchName)
.setSource(watchBuilder() .setSource(watchBuilder()
.trigger(schedule(interval("5s"))) .trigger(schedule(interval("5s")))
.input(searchInput(request)) .input(searchInput(new WatcherSearchTemplateRequest(request, template)))
.condition(compareCondition("ctx.payload.hits.total", CompareCondition.Op.GTE, 3L))) .condition(compareCondition("ctx.payload.hits.total", CompareCondition.Op.GTE, 3L)))
.get(); .get();

View File

@ -5,32 +5,29 @@
*/ */
package org.elasticsearch.xpack.watcher.test.integration; package org.elasticsearch.xpack.watcher.test.integration;
import org.apache.http.Header;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.Response;
import org.elasticsearch.common.network.NetworkModule; import org.elasticsearch.common.network.NetworkModule;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.http.HttpServerTransport; import org.elasticsearch.marvel.test.MarvelIntegTestCase;
import org.elasticsearch.xpack.security.authc.support.SecuredString; import org.elasticsearch.xpack.security.authc.support.SecuredString;
import org.elasticsearch.test.rest.client.http.HttpRequestBuilder;
import org.elasticsearch.test.rest.client.http.HttpResponse;
import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase; import org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase;
import org.junit.After; import org.junit.After;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.BASIC_AUTH_HEADER;
import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue; import static org.elasticsearch.xpack.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
import static org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase.SecuritySettings.TEST_PASSWORD;
import static org.elasticsearch.xpack.watcher.test.AbstractWatcherIntegrationTestCase.SecuritySettings.TEST_USERNAME;
import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
/**
*
*/
public class WatcherSettingsFilterTests extends AbstractWatcherIntegrationTestCase { public class WatcherSettingsFilterTests extends AbstractWatcherIntegrationTestCase {
private CloseableHttpClient httpClient = HttpClients.createDefault(); private CloseableHttpClient httpClient = HttpClients.createDefault();
@ -52,37 +49,26 @@ public class WatcherSettingsFilterTests extends AbstractWatcherIntegrationTestCa
} }
public void testGetSettingsSmtpPassword() throws Exception { public void testGetSettingsSmtpPassword() throws Exception {
String body = executeRequest("GET", "/_nodes/settings", null, null).getBody(); Header[] headers;
Map<String, Object> response = JsonXContent.jsonXContent.createParser(body).map(); if (securityEnabled()) {
Map<String, Object> nodes = (Map<String, Object>) response.get("nodes"); headers = new Header[] {
for (Object node : nodes.values()) { new BasicHeader(BASIC_AUTH_HEADER,
Map<String, Object> settings = (Map<String, Object>) ((Map<String, Object>) node).get("settings"); basicAuthHeaderValue(MarvelIntegTestCase.SecuritySettings.TEST_USERNAME,
assertThat(XContentMapValues.extractValue("xpack.notification.email.account._email.smtp.user", settings), new SecuredString(MarvelIntegTestCase.SecuritySettings.TEST_PASSWORD.toCharArray())))};
is((Object) "_user")); } else {
assertThat(XContentMapValues.extractValue("xpack.notification.email.account._email.smtp.password", settings), headers = new Header[0];
nullValue());
} }
} try (Response response = getRestClient().performRequest("GET", "/_nodes/settings",
Collections.emptyMap(), null, headers)) {
protected HttpResponse executeRequest(String method, String path, String body, Map<String, String> params) throws IOException { Map<String, Object> responseMap = JsonXContent.jsonXContent.createParser(response.getEntity().getContent()).map();
HttpServerTransport httpServerTransport = getInstanceFromMaster(HttpServerTransport.class); Map<String, Object> nodes = (Map<String, Object>) responseMap.get("nodes");
HttpRequestBuilder requestBuilder = new HttpRequestBuilder(httpClient) for (Object node : nodes.values()) {
.httpTransport(httpServerTransport) Map<String, Object> settings = (Map<String, Object>) ((Map<String, Object>) node).get("settings");
.method(method) assertThat(XContentMapValues.extractValue("xpack.notification.email.account._email.smtp.user", settings),
.path(path); is((Object) "_user"));
assertThat(XContentMapValues.extractValue("xpack.notification.email.account._email.smtp.password", settings),
if (params != null) { nullValue());
for (Map.Entry<String, String> entry : params.entrySet()) {
requestBuilder.addParam(entry.getKey(), entry.getValue());
} }
} }
if (body != null) {
requestBuilder.body(body);
}
if (securityEnabled()) {
requestBuilder.addHeader(BASIC_AUTH_HEADER,
basicAuthHeaderValue(TEST_USERNAME, new SecuredString(TEST_PASSWORD.toCharArray())));
}
return requestBuilder.execute();
} }
} }

View File

@ -5,14 +5,6 @@
*/ */
package org.elasticsearch.xpack.watcher.watch; 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.ElasticsearchParseException;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.ESLogger; 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.index.query.QueryParser;
import org.elasticsearch.indices.query.IndicesQueriesRegistry; import org.elasticsearch.indices.query.IndicesQueriesRegistry;
import org.elasticsearch.test.ESTestCase; 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.ActionFactory;
import org.elasticsearch.xpack.watcher.actions.ActionRegistry; import org.elasticsearch.xpack.watcher.actions.ActionRegistry;
import org.elasticsearch.xpack.watcher.actions.ActionStatus; import org.elasticsearch.xpack.watcher.actions.ActionStatus;
import org.elasticsearch.xpack.watcher.actions.ActionWrapper; import org.elasticsearch.xpack.watcher.actions.ActionWrapper;
import org.elasticsearch.xpack.watcher.actions.ExecutableActions; 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.EmailAction;
import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory; import org.elasticsearch.xpack.watcher.actions.email.EmailActionFactory;
import org.elasticsearch.xpack.watcher.actions.email.ExecutableEmailAction; 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.ExecutableSimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInput; import org.elasticsearch.xpack.watcher.input.simple.SimpleInput;
import org.elasticsearch.xpack.watcher.input.simple.SimpleInputFactory; import org.elasticsearch.xpack.watcher.input.simple.SimpleInputFactory;
import org.elasticsearch.xpack.watcher.WatcherLicensee;
import org.elasticsearch.xpack.watcher.support.Script; 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.watcher.support.init.proxy.WatcherClientProxy;
import org.elasticsearch.xpack.common.secret.SecretService; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateRequest;
import org.elasticsearch.xpack.common.text.TextTemplate; import org.elasticsearch.xpack.watcher.support.search.WatcherSearchTemplateService;
import org.elasticsearch.xpack.common.text.TextTemplateEngine;
import org.elasticsearch.xpack.watcher.test.WatcherTestUtils; import org.elasticsearch.xpack.watcher.test.WatcherTestUtils;
import org.elasticsearch.xpack.watcher.transform.ExecutableTransform; import org.elasticsearch.xpack.watcher.transform.ExecutableTransform;
import org.elasticsearch.xpack.watcher.transform.TransformFactory; import org.elasticsearch.xpack.watcher.transform.TransformFactory;
import org.elasticsearch.xpack.watcher.transform.TransformRegistry; import org.elasticsearch.xpack.watcher.transform.TransformRegistry;
import org.elasticsearch.xpack.watcher.transform.chain.ChainTransform; 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.chain.ExecutableChainTransform;
import org.elasticsearch.xpack.watcher.transform.script.ExecutableScriptTransform; import org.elasticsearch.xpack.watcher.transform.script.ExecutableScriptTransform;
import org.elasticsearch.xpack.watcher.transform.script.ScriptTransform; 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.MonthTimes;
import org.elasticsearch.xpack.watcher.trigger.schedule.support.WeekTimes; import org.elasticsearch.xpack.watcher.trigger.schedule.support.WeekTimes;
import org.elasticsearch.xpack.watcher.trigger.schedule.support.YearTimes; 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.DateTime;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.junit.Before; 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.singleton;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static java.util.Collections.unmodifiableMap; import static java.util.Collections.unmodifiableMap;
import static org.elasticsearch.xpack.watcher.input.InputBuilders.searchInput; 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.test.WatcherTestUtils.matchAllRequest;
import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule; import static org.elasticsearch.xpack.watcher.trigger.TriggerBuilders.schedule;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -153,6 +153,7 @@ public class WatchTests extends ESTestCase {
private WatcherLicensee watcherLicensee; private WatcherLicensee watcherLicensee;
private ESLogger logger; private ESLogger logger;
private Settings settings = Settings.EMPTY; private Settings settings = Settings.EMPTY;
private WatcherSearchTemplateService searchTemplateService;
@Before @Before
public void init() throws Exception { public void init() throws Exception {
@ -166,6 +167,7 @@ public class WatchTests extends ESTestCase {
watcherLicensee = mock(WatcherLicensee.class); watcherLicensee = mock(WatcherLicensee.class);
authRegistry = new HttpAuthRegistry(singletonMap("basic", new BasicAuthFactory(secretService))); authRegistry = new HttpAuthRegistry(singletonMap("basic", new BasicAuthFactory(secretService)));
logger = Loggers.getLogger(WatchTests.class); logger = Loggers.getLogger(WatchTests.class);
searchTemplateService = mock(WatcherSearchTemplateService.class);
} }
public void testParserSelfGenerated() throws Exception { public void testParserSelfGenerated() throws Exception {
@ -341,7 +343,7 @@ public class WatchTests extends ESTestCase {
switch (type) { switch (type) {
case SearchInput.TYPE: case SearchInput.TYPE:
SearchInput searchInput = searchInput(WatcherTestUtils.newInputSearchRequest("idx")).build(); SearchInput searchInput = searchInput(WatcherTestUtils.newInputSearchRequest("idx")).build();
return new ExecutableSearchInput(searchInput, logger, client, null); return new ExecutableSearchInput(searchInput, logger, client, searchTemplateService, null);
default: default:
SimpleInput simpleInput = InputBuilders.simpleInput(singletonMap("_key", "_val")).build(); SimpleInput simpleInput = InputBuilders.simpleInput(singletonMap("_key", "_val")).build();
return new ExecutableSimpleInput(simpleInput, logger); return new ExecutableSimpleInput(simpleInput, logger);
@ -355,7 +357,7 @@ public class WatchTests extends ESTestCase {
IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry(); IndicesQueriesRegistry queryRegistry = new IndicesQueriesRegistry();
QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent; QueryParser<MatchAllQueryBuilder> queryParser = MatchAllQueryBuilder::fromXContent;
queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD); 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); return new InputRegistry(Settings.EMPTY, parsers);
default: default:
parsers.put(SimpleInput.TYPE, new SimpleInputFactory(settings)); parsers.put(SimpleInput.TYPE, new SimpleInputFactory(settings));
@ -406,15 +408,19 @@ public class WatchTests extends ESTestCase {
case ScriptTransform.TYPE: case ScriptTransform.TYPE:
return new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService); return new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService);
case SearchTransform.TYPE: case SearchTransform.TYPE:
return new ExecutableSearchTransform(new SearchTransform( SearchTransform transform = new SearchTransform(
matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS), timeout, timeZone), logger, client, null); new WatcherSearchTemplateRequest(matchAllRequest(DEFAULT_INDICES_OPTIONS), null), timeout, timeZone);
return new ExecutableSearchTransform(transform, logger, client, searchTemplateService, null);
default: // chain default: // chain
ChainTransform chainTransform = new ChainTransform(Arrays.asList( SearchTransform searchTransform = new SearchTransform(
new SearchTransform(matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS), timeout, timeZone), new WatcherSearchTemplateRequest(matchAllRequest(DEFAULT_INDICES_OPTIONS), null), timeout, timeZone);
new ScriptTransform(Script.inline("_script").build()))); ScriptTransform scriptTransform = new ScriptTransform(Script.inline("_script").build());
ChainTransform chainTransform = new ChainTransform(Arrays.asList(searchTransform, scriptTransform));
return new ExecutableChainTransform(chainTransform, logger, Arrays.<ExecutableTransform>asList( return new ExecutableChainTransform(chainTransform, logger, Arrays.<ExecutableTransform>asList(
new ExecutableSearchTransform(new SearchTransform( 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))); 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); queryRegistry.register(queryParser, MatchAllQueryBuilder.QUERY_NAME_FIELD);
Map<String, TransformFactory> factories = new HashMap<>(); Map<String, TransformFactory> factories = new HashMap<>();
factories.put(ScriptTransform.TYPE, new ScriptTransformFactory(settings, scriptService)); 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)); TransformRegistry registry = new TransformRegistry(Settings.EMPTY, unmodifiableMap(factories));
return registry; return registry;
} }

View File

@ -4,7 +4,7 @@
"methods": [ "PUT", "POST" ], "methods": [ "PUT", "POST" ],
"url": { "url": {
"path": "/_xpack/watcher/watch/{watch_id}/_ack", "path": "/_xpack/watcher/watch/{watch_id}/_ack",
"paths": [ "/_xpack/watcher/watch/{watch_id}/_ack", "/_xpack/watcher/watch/{watch_id}/{action_id}/_ack"], "paths": [ "/_xpack/watcher/watch/{watch_id}/_ack", "/_xpack/watcher/watch/{watch_id}/_ack/{action_id}"],
"parts": { "parts": {
"watch_id": { "watch_id": {
"type" : "string", "type" : "string",