mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-07 05:28:34 +00:00
Added http input.
The http input allows to let any http interface be the input for a watch. The http input can be configured with the following options: * `method` - Optional http method. (default to GET) * `host` - The host of the http service. * `port` - The port of the http service. * `path` - The url path. * `params` - Optional url query string options. * `header` - Optional http header. * `auth` - Optional authentication http heads. * `body` - Optional body The response of the http request is expected to be valid json. Closes elastic/elasticsearch#157 Original commit: elastic/x-pack-elasticsearch@0b1f122615
This commit is contained in:
parent
a632d57803
commit
e00bb69982
7
pom.xml
7
pom.xml
@ -104,6 +104,13 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp</groupId>
|
||||||
|
<artifactId>mockwebserver</artifactId>
|
||||||
|
<version>2.3.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Regular dependencies -->
|
<!-- Regular dependencies -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -20,6 +20,7 @@ import org.elasticsearch.watcher.rest.WatcherRestModule;
|
|||||||
import org.elasticsearch.watcher.shield.WatcherShieldModule;
|
import org.elasticsearch.watcher.shield.WatcherShieldModule;
|
||||||
import org.elasticsearch.watcher.support.TemplateUtils;
|
import org.elasticsearch.watcher.support.TemplateUtils;
|
||||||
import org.elasticsearch.watcher.support.clock.ClockModule;
|
import org.elasticsearch.watcher.support.clock.ClockModule;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClientModule;
|
||||||
import org.elasticsearch.watcher.support.init.InitializingModule;
|
import org.elasticsearch.watcher.support.init.InitializingModule;
|
||||||
import org.elasticsearch.watcher.support.template.TemplateModule;
|
import org.elasticsearch.watcher.support.template.TemplateModule;
|
||||||
import org.elasticsearch.watcher.transform.TransformModule;
|
import org.elasticsearch.watcher.transform.TransformModule;
|
||||||
@ -42,6 +43,7 @@ public class WatcherModule extends AbstractModule implements SpawnModules {
|
|||||||
new InitializingModule(),
|
new InitializingModule(),
|
||||||
new WatchModule(),
|
new WatchModule(),
|
||||||
new TemplateModule(),
|
new TemplateModule(),
|
||||||
|
new HttpClientModule(),
|
||||||
new ClockModule(),
|
new ClockModule(),
|
||||||
new WatcherClientModule(),
|
new WatcherClientModule(),
|
||||||
new TransformModule(),
|
new TransformModule(),
|
||||||
|
@ -5,14 +5,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.watcher.actions;
|
package org.elasticsearch.watcher.actions;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.AbstractModule;
|
||||||
|
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
||||||
import org.elasticsearch.watcher.actions.email.EmailAction;
|
import org.elasticsearch.watcher.actions.email.EmailAction;
|
||||||
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
import org.elasticsearch.watcher.actions.email.service.InternalEmailService;
|
||||||
import org.elasticsearch.watcher.actions.index.IndexAction;
|
import org.elasticsearch.watcher.actions.index.IndexAction;
|
||||||
import org.elasticsearch.watcher.actions.webhook.HttpClient;
|
|
||||||
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
|
||||||
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -46,7 +45,6 @@ public class ActionModule extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bind(ActionRegistry.class).asEagerSingleton();
|
bind(ActionRegistry.class).asEagerSingleton();
|
||||||
bind(HttpClient.class).asEagerSingleton();
|
|
||||||
bind(EmailService.class).to(InternalEmailService.class).asEagerSingleton();
|
bind(EmailService.class).to(InternalEmailService.class).asEagerSingleton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,43 +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.watcher.actions.webhook;
|
|
||||||
|
|
||||||
import org.elasticsearch.common.base.Charsets;
|
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client class to wrap http connections
|
|
||||||
*/
|
|
||||||
public class HttpClient extends AbstractComponent {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public HttpClient(Settings settings) {
|
|
||||||
super(settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int execute(HttpMethod method, String url, String body) throws IOException {
|
|
||||||
logger.debug("making [{}] request to [{}]", method.getName(), url);
|
|
||||||
if (logger.isTraceEnabled()) {
|
|
||||||
logger.trace("sending [{}] as body of request", body);
|
|
||||||
}
|
|
||||||
URL encodedUrl = new URL(URLEncoder.encode(url, Charsets.UTF_8.name()));
|
|
||||||
HttpURLConnection httpConnection = (HttpURLConnection) encodedUrl.openConnection();
|
|
||||||
httpConnection.setRequestMethod(method.getName());
|
|
||||||
httpConnection.setRequestProperty("Accept-Charset", Charsets.UTF_8.name());
|
|
||||||
httpConnection.setDoOutput(true);
|
|
||||||
httpConnection.setRequestProperty("Content-Length", Integer.toString(body.length()));
|
|
||||||
httpConnection.getOutputStream().write(body.getBytes(Charsets.UTF_8.name()));
|
|
||||||
return httpConnection.getResponseCode();
|
|
||||||
}
|
|
||||||
}
|
|
@ -5,27 +5,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.watcher.actions.webhook;
|
package org.elasticsearch.watcher.actions.webhook;
|
||||||
|
|
||||||
import org.elasticsearch.watcher.WatcherSettingsException;
|
|
||||||
import org.elasticsearch.watcher.watch.WatchExecutionContext;
|
|
||||||
import org.elasticsearch.watcher.watch.Payload;
|
|
||||||
import org.elasticsearch.watcher.actions.Action;
|
|
||||||
import org.elasticsearch.watcher.actions.ActionException;
|
|
||||||
import org.elasticsearch.watcher.actions.ActionSettingsException;
|
|
||||||
import org.elasticsearch.watcher.support.Script;
|
|
||||||
import org.elasticsearch.watcher.support.Variables;
|
|
||||||
import org.elasticsearch.watcher.support.template.Template;
|
|
||||||
import org.elasticsearch.watcher.support.template.XContentTemplate;
|
|
||||||
import org.elasticsearch.watcher.transform.Transform;
|
|
||||||
import org.elasticsearch.watcher.transform.TransformRegistry;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
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.watcher.WatcherSettingsException;
|
||||||
|
import org.elasticsearch.watcher.actions.Action;
|
||||||
|
import org.elasticsearch.watcher.actions.ActionException;
|
||||||
|
import org.elasticsearch.watcher.actions.ActionSettingsException;
|
||||||
|
import org.elasticsearch.watcher.support.Script;
|
||||||
|
import org.elasticsearch.watcher.support.Variables;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpMethod;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpResponse;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.support.template.XContentTemplate;
|
||||||
|
import org.elasticsearch.watcher.transform.Transform;
|
||||||
|
import org.elasticsearch.watcher.transform.TransformRegistry;
|
||||||
|
import org.elasticsearch.watcher.watch.Payload;
|
||||||
|
import org.elasticsearch.watcher.watch.WatchExecutionContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
@ -62,17 +64,17 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||||||
String urlText = url.render(model);
|
String urlText = url.render(model);
|
||||||
String bodyText = body != null ? body.render(model) : XContentTemplate.YAML.render(model);
|
String bodyText = body != null ? body.render(model) : XContentTemplate.YAML.render(model);
|
||||||
try {
|
try {
|
||||||
|
try (HttpResponse response = httpClient.execute(method, urlText, bodyText)) {
|
||||||
int status = httpClient.execute(method, urlText, bodyText);
|
int status = response.status();
|
||||||
if (status >= 400) {
|
if (status >= 400) {
|
||||||
logger.warn("got status [" + status + "] when connecting to [" + urlText + "]");
|
logger.warn("got status [" + status + "] when connecting to [" + urlText + "]");
|
||||||
} else {
|
} else {
|
||||||
if (status >= 300) {
|
if (status >= 300) {
|
||||||
logger.warn("a 200 range return code was expected, but got [" + status + "]");
|
logger.warn("a 200 range return code was expected, but got [" + status + "]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return new Result.Executed(status, urlText, bodyText);
|
||||||
}
|
}
|
||||||
return new Result.Executed(status, urlText, bodyText);
|
|
||||||
|
|
||||||
} catch (IOException ioe) {
|
} catch (IOException ioe) {
|
||||||
logger.error("failed to connect to [{}] for watch [{}]", ioe, urlText, ctx.watch().name());
|
logger.error("failed to connect to [{}] for watch [{}]", ioe, urlText, ctx.watch().name());
|
||||||
return new Result.Failure("failed to send http request. " + ioe.getMessage());
|
return new Result.Failure("failed to send http request. " + ioe.getMessage());
|
||||||
@ -87,7 +89,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||||||
.field(transform.type(), transform)
|
.field(transform.type(), transform)
|
||||||
.endObject();
|
.endObject();
|
||||||
}
|
}
|
||||||
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.getName().toLowerCase(Locale.ROOT));
|
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.method());
|
||||||
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
@ -222,7 +224,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||||||
if (METHOD_FIELD.match(currentFieldName)) {
|
if (METHOD_FIELD.match(currentFieldName)) {
|
||||||
method = HttpMethod.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
method = HttpMethod.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
||||||
if (method != HttpMethod.POST && method != HttpMethod.GET && method != HttpMethod.PUT) {
|
if (method != HttpMethod.POST && method != HttpMethod.GET && method != HttpMethod.PUT) {
|
||||||
throw new ActionSettingsException("could not parse webhook action. unsupported http method [" + method.getName() + "]");
|
throw new ActionSettingsException("could not parse webhook action. unsupported http method [" + method.method() + "]");
|
||||||
}
|
}
|
||||||
} else if (URL_FIELD.match(currentFieldName)) {
|
} else if (URL_FIELD.match(currentFieldName)) {
|
||||||
try {
|
try {
|
||||||
@ -339,7 +341,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||||||
builder.startObject();
|
builder.startObject();
|
||||||
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.getName().toLowerCase(Locale.ROOT));
|
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.method());
|
||||||
}
|
}
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
|
@ -7,6 +7,7 @@ package org.elasticsearch.watcher.input;
|
|||||||
|
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
import org.elasticsearch.action.search.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||||
|
import org.elasticsearch.watcher.input.http.HttpInput;
|
||||||
import org.elasticsearch.watcher.input.search.SearchInput;
|
import org.elasticsearch.watcher.input.search.SearchInput;
|
||||||
import org.elasticsearch.watcher.input.simple.SimpleInput;
|
import org.elasticsearch.watcher.input.simple.SimpleInput;
|
||||||
|
|
||||||
@ -36,4 +37,8 @@ public final class InputBuilders {
|
|||||||
public static SimpleInput.SourceBuilder simpleInput(Map<String, Object> data) {
|
public static SimpleInput.SourceBuilder simpleInput(Map<String, Object> data) {
|
||||||
return new SimpleInput.SourceBuilder(data);
|
return new SimpleInput.SourceBuilder(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static HttpInput.SourceBuilder httpInput() {
|
||||||
|
return new HttpInput.SourceBuilder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,11 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.watcher.input;
|
package org.elasticsearch.watcher.input;
|
||||||
|
|
||||||
import org.elasticsearch.watcher.input.search.SearchInput;
|
|
||||||
import org.elasticsearch.watcher.input.simple.SimpleInput;
|
|
||||||
import org.elasticsearch.common.inject.AbstractModule;
|
import org.elasticsearch.common.inject.AbstractModule;
|
||||||
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
||||||
|
import org.elasticsearch.watcher.input.http.HttpInput;
|
||||||
|
import org.elasticsearch.watcher.input.search.SearchInput;
|
||||||
|
import org.elasticsearch.watcher.input.simple.SimpleInput;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -26,12 +27,13 @@ public class InputModule extends AbstractModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
|
||||||
MapBinder<String, Input.Parser> parsersBinder = MapBinder.newMapBinder(binder(), String.class, Input.Parser.class);
|
MapBinder<String, Input.Parser> parsersBinder = MapBinder.newMapBinder(binder(), String.class, Input.Parser.class);
|
||||||
bind(SearchInput.Parser.class).asEagerSingleton();
|
bind(SearchInput.Parser.class).asEagerSingleton();
|
||||||
parsersBinder.addBinding(SearchInput.TYPE).to(SearchInput.Parser.class);
|
parsersBinder.addBinding(SearchInput.TYPE).to(SearchInput.Parser.class);
|
||||||
bind(SimpleInput.Parser.class).asEagerSingleton();
|
bind(SimpleInput.Parser.class).asEagerSingleton();
|
||||||
parsersBinder.addBinding(SimpleInput.TYPE).to(SimpleInput.Parser.class);
|
parsersBinder.addBinding(SimpleInput.TYPE).to(SimpleInput.Parser.class);
|
||||||
|
bind(HttpInput.Parser.class).asEagerSingleton();
|
||||||
|
parsersBinder.addBinding(HttpInput.TYPE).to(HttpInput.Parser.class);
|
||||||
|
|
||||||
for (Map.Entry<String, Class<? extends Input.Parser>> entry : parsers.entrySet()) {
|
for (Map.Entry<String, Class<? extends Input.Parser>> entry : parsers.entrySet()) {
|
||||||
bind(entry.getValue()).asEagerSingleton();
|
bind(entry.getValue()).asEagerSingleton();
|
||||||
|
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.input.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.watcher.input.Input;
|
||||||
|
import org.elasticsearch.watcher.support.Variables;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpRequest;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpResponse;
|
||||||
|
import org.elasticsearch.watcher.support.http.TemplatedHttpRequest;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuth;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.watch.Payload;
|
||||||
|
import org.elasticsearch.watcher.watch.WatchExecutionContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpInput extends Input<HttpInput.Result> {
|
||||||
|
|
||||||
|
public static final String TYPE = "http";
|
||||||
|
|
||||||
|
private final HttpClient client;
|
||||||
|
private final TemplatedHttpRequest request;
|
||||||
|
|
||||||
|
public HttpInput(ESLogger logger, HttpClient client, TemplatedHttpRequest request) {
|
||||||
|
super(logger);
|
||||||
|
this.request = request;
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result execute(WatchExecutionContext ctx) throws IOException {
|
||||||
|
Map<String, Object> model = Variables.createCtxModel(ctx, null);
|
||||||
|
HttpRequest httpRequest = request.render(model);
|
||||||
|
try (HttpResponse response = client.execute(httpRequest)) {
|
||||||
|
Tuple<XContentType, Map<String, Object>> result = XContentHelper.convertToMap(response.body(), true);
|
||||||
|
return new Result(TYPE, new Payload.Simple(result.v2()), httpRequest, response.status());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return request.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
HttpInput httpInput = (HttpInput) o;
|
||||||
|
|
||||||
|
if (!request.equals(httpInput.request)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return request.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplatedHttpRequest getRequest() {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class Result extends Input.Result {
|
||||||
|
|
||||||
|
private final HttpRequest request;
|
||||||
|
private final int statusCode;
|
||||||
|
|
||||||
|
public Result(String type, Payload payload, HttpRequest request, int statusCode) {
|
||||||
|
super(type, payload);
|
||||||
|
this.request = request;
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field(Parser.HTTP_STATUS_FIELD.getPreferredName(), statusCode);
|
||||||
|
builder.field(Parser.REQUEST_FIELD.getPreferredName(), request);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequest request() {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
int statusCode() {
|
||||||
|
return statusCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class Parser extends AbstractComponent implements Input.Parser<Result, HttpInput> {
|
||||||
|
|
||||||
|
public static final ParseField REQUEST_FIELD = new ParseField("request");
|
||||||
|
public static final ParseField HTTP_STATUS_FIELD = new ParseField("http_status");
|
||||||
|
|
||||||
|
private final HttpClient client;
|
||||||
|
private final HttpRequest.Parser requestParser;
|
||||||
|
private final TemplatedHttpRequest.Parser templatedRequestParser;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Parser(Settings settings, HttpClient client, HttpRequest.Parser requestParser, TemplatedHttpRequest.Parser templatedRequestParser) {
|
||||||
|
super(settings);
|
||||||
|
this.client = client;
|
||||||
|
this.requestParser = requestParser;
|
||||||
|
this.templatedRequestParser = templatedRequestParser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HttpInput parse(XContentParser parser) throws IOException {
|
||||||
|
TemplatedHttpRequest request = templatedRequestParser.parse(parser);
|
||||||
|
return new HttpInput(logger, client, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result parseResult(XContentParser parser) throws IOException {
|
||||||
|
Payload payload = null;
|
||||||
|
HttpRequest request = null;
|
||||||
|
int statusCode = -1;
|
||||||
|
|
||||||
|
XContentParser.Token token;
|
||||||
|
String currentFieldName = null;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
|
if (Input.Result.PAYLOAD_FIELD.match(currentFieldName)) {
|
||||||
|
payload = new Payload.XContent(parser);
|
||||||
|
} else if (REQUEST_FIELD.match(currentFieldName)) {
|
||||||
|
request = requestParser.parse(parser);
|
||||||
|
}
|
||||||
|
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
|
statusCode = parser.intValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Result(TYPE, payload, request, statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static class SourceBuilder implements Input.SourceBuilder {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private String method;
|
||||||
|
private Template path;
|
||||||
|
private Map<String, Template> params;
|
||||||
|
private Map<String, Template> headers;
|
||||||
|
private HttpAuth auth;
|
||||||
|
private Template body;
|
||||||
|
|
||||||
|
public SourceBuilder setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setPort(int port) {
|
||||||
|
this.port = port;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setMethod(String method) {
|
||||||
|
this.method = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setPath(Template path) {
|
||||||
|
this.path = path;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setParams(Map<String, Template> params) {
|
||||||
|
this.params = params;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setHeaders(Map<String, Template> headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setAuth(HttpAuth auth) {
|
||||||
|
this.auth = auth;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SourceBuilder setBody(Template body) {
|
||||||
|
this.body = body;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params p) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(HttpRequest.Parser.HOST_FIELD.getPreferredName(), host);
|
||||||
|
builder.field(HttpRequest.Parser.PORT_FIELD.getPreferredName(), port);
|
||||||
|
if (method != null) {
|
||||||
|
builder.field(HttpRequest.Parser.METHOD_FIELD.getPreferredName(), method);
|
||||||
|
}
|
||||||
|
if (path != null) {
|
||||||
|
builder.field(HttpRequest.Parser.PATH_FIELD.getPreferredName(), path);
|
||||||
|
}
|
||||||
|
if (params != null) {
|
||||||
|
builder.field(HttpRequest.Parser.PARAMS_FIELD.getPreferredName(), params);
|
||||||
|
}
|
||||||
|
if (headers != null) {
|
||||||
|
builder.field(HttpRequest.Parser.HEADERS_FIELD.getPreferredName(), headers);
|
||||||
|
}
|
||||||
|
if (auth != null) {
|
||||||
|
builder.field(HttpRequest.Parser.AUTH_FIELD.getPreferredName(), auth);
|
||||||
|
}
|
||||||
|
if (body != null) {
|
||||||
|
builder.field(HttpRequest.Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.common.base.Charsets;
|
||||||
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client class to wrap http connections
|
||||||
|
*/
|
||||||
|
public class HttpClient extends AbstractComponent {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public HttpClient(Settings settings) {
|
||||||
|
super(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove this when webhook action has been refactored to use this client properly
|
||||||
|
public HttpResponse execute(HttpMethod method, String urlString, String body) throws IOException {
|
||||||
|
URL url = new URL(urlString);
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.method(method);
|
||||||
|
return doExecute(url, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpResponse execute(HttpRequest request) throws IOException {
|
||||||
|
String queryString = null;
|
||||||
|
if (request.params() != null) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (Map.Entry<String, String> entry : request.params().entrySet()) {
|
||||||
|
if (builder.length() != 0) {
|
||||||
|
builder.append('&');
|
||||||
|
}
|
||||||
|
builder.append(URLEncoder.encode(entry.getKey(), "utf-8"))
|
||||||
|
.append('=')
|
||||||
|
.append(URLEncoder.encode(entry.getValue(), "utf-8"));
|
||||||
|
}
|
||||||
|
queryString = builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
URI uri;
|
||||||
|
try {
|
||||||
|
uri = new URI("http", null, request.host(), request.port(), request.path(), queryString, null);
|
||||||
|
} catch (URISyntaxException e) {
|
||||||
|
throw ExceptionsHelper.convertToElastic(e);
|
||||||
|
}
|
||||||
|
URL url = uri.toURL();
|
||||||
|
return doExecute(url, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Embed this method in execute() when webhook action has been refactored to use this client properly
|
||||||
|
private HttpResponse doExecute(URL url, HttpRequest request) throws IOException {
|
||||||
|
logger.debug("making [{}] request to [{}]", request.method().method(), url);
|
||||||
|
logger.trace("sending [{}] as body of request", request.body());
|
||||||
|
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
|
||||||
|
urlConnection.setRequestMethod(request.method().method());
|
||||||
|
if (request.headers() != null) {
|
||||||
|
for (Map.Entry<String, String> entry : request.headers().entrySet()) {
|
||||||
|
urlConnection.setRequestProperty(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.auth() != null) {
|
||||||
|
request.auth().update(urlConnection);
|
||||||
|
}
|
||||||
|
urlConnection.setUseCaches(false);
|
||||||
|
urlConnection.setRequestProperty("Accept-Charset", Charsets.UTF_8.name());
|
||||||
|
if (request.body() != null) {
|
||||||
|
urlConnection.setDoOutput(true);
|
||||||
|
byte[] bytes = request.body().getBytes(Charsets.UTF_8.name());
|
||||||
|
urlConnection.setRequestProperty("Content-Length", String.valueOf(bytes.length));
|
||||||
|
urlConnection.getOutputStream().write(bytes);
|
||||||
|
urlConnection.getOutputStream().close();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpResponse response = new HttpResponse();
|
||||||
|
response.inputStream(urlConnection.getInputStream());
|
||||||
|
response.status(urlConnection.getResponseCode());
|
||||||
|
logger.debug("http status code: {}", response.status());
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.collect.ImmutableList;
|
||||||
|
import org.elasticsearch.common.inject.AbstractModule;
|
||||||
|
import org.elasticsearch.common.inject.Module;
|
||||||
|
import org.elasticsearch.common.inject.SpawnModules;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.AuthModule;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpClientModule extends AbstractModule implements SpawnModules {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterable<? extends Module> spawnModules() {
|
||||||
|
return ImmutableList.of(new AuthModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(TemplatedHttpRequest.Parser.class).asEagerSingleton();
|
||||||
|
bind(HttpRequest.Parser.class).asEagerSingleton();
|
||||||
|
bind(HttpClient.class).asEagerSingleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public enum HttpMethod {
|
||||||
|
|
||||||
|
HEAD("HEAD"),
|
||||||
|
GET("GET"),
|
||||||
|
POST("POST"),
|
||||||
|
PUT("PUT"),
|
||||||
|
DELETE("DELETE");
|
||||||
|
|
||||||
|
private final String method;
|
||||||
|
|
||||||
|
HttpMethod(String method) {
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String method() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HttpMethod parse(String value) {
|
||||||
|
value = value.toUpperCase(Locale.ROOT);
|
||||||
|
switch (value) {
|
||||||
|
case "HEAD":
|
||||||
|
return HEAD;
|
||||||
|
case "GET":
|
||||||
|
return GET;
|
||||||
|
case "POST":
|
||||||
|
return POST;
|
||||||
|
case "PUT":
|
||||||
|
return PUT;
|
||||||
|
case "DELETE":
|
||||||
|
return DELETE;
|
||||||
|
default:
|
||||||
|
throw new ElasticsearchIllegalArgumentException("unsupported http method [" + value + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,220 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.support.WatcherUtils;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuth;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HttpRequest implements ToXContent {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private HttpMethod method;
|
||||||
|
private String path;
|
||||||
|
private Map<String, String> params;
|
||||||
|
private Map<String, String> headers;
|
||||||
|
private HttpAuth auth;
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
public HttpRequest() {
|
||||||
|
method = HttpMethod.GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String host() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void host(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int port() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void port(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpMethod method() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void method(HttpMethod method) {
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String path() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void path(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> params() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void params(Map<String, String> params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, String> headers() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void headers(Map<String, String> headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpAuth auth() {
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void auth(HttpAuth auth) {
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String body() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void body(String body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Parser.HOST_FIELD.getPreferredName(), host);
|
||||||
|
builder.field(Parser.PORT_FIELD.getPreferredName(), port);
|
||||||
|
builder.field(Parser.METHOD_FIELD.getPreferredName(), method);
|
||||||
|
if (path != null) {
|
||||||
|
builder.field(Parser.PATH_FIELD.getPreferredName(), path);
|
||||||
|
}
|
||||||
|
if (this.params != null) {
|
||||||
|
builder.startObject(Parser.PARAMS_FIELD.getPreferredName()).value(this.params).endObject();
|
||||||
|
}
|
||||||
|
if (headers != null) {
|
||||||
|
builder.startObject(Parser.HEADERS_FIELD.getPreferredName()).value(headers).endObject();
|
||||||
|
}
|
||||||
|
if (auth != null) {
|
||||||
|
builder.field(Parser.AUTH_FIELD.getPreferredName(), auth);
|
||||||
|
}
|
||||||
|
if (body != null) {
|
||||||
|
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
HttpRequest request = (HttpRequest) o;
|
||||||
|
|
||||||
|
if (port != request.port) return false;
|
||||||
|
if (auth != null ? !auth.equals(request.auth) : request.auth != null) return false;
|
||||||
|
if (body != null ? !body.equals(request.body) : request.body != null) return false;
|
||||||
|
if (headers != null ? !headers.equals(request.headers) : request.headers != null) return false;
|
||||||
|
if (!host.equals(request.host)) return false;
|
||||||
|
if (method != request.method) return false;
|
||||||
|
if (params != null ? !params.equals(request.params) : request.params != null) return false;
|
||||||
|
if (path != null ? !path.equals(request.path) : request.path != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = host.hashCode();
|
||||||
|
result = 31 * result + port;
|
||||||
|
result = 31 * result + method.hashCode();
|
||||||
|
result = 31 * result + (path != null ? path.hashCode() : 0);
|
||||||
|
result = 31 * result + (params != null ? params.hashCode() : 0);
|
||||||
|
result = 31 * result + (headers != null ? headers.hashCode() : 0);
|
||||||
|
result = 31 * result + (auth != null ? auth.hashCode() : 0);
|
||||||
|
result = 31 * result + (body != null ? body.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Parser {
|
||||||
|
|
||||||
|
public static final ParseField HOST_FIELD = new ParseField("host");
|
||||||
|
public static final ParseField PORT_FIELD = new ParseField("port");
|
||||||
|
public static final ParseField METHOD_FIELD = new ParseField("method");
|
||||||
|
public static final ParseField PATH_FIELD = new ParseField("path");
|
||||||
|
public static final ParseField PARAMS_FIELD = new ParseField("params");
|
||||||
|
public static final ParseField HEADERS_FIELD = new ParseField("headers");
|
||||||
|
public static final ParseField AUTH_FIELD = new ParseField("auth");
|
||||||
|
public static final ParseField BODY_FIELD = new ParseField("body");
|
||||||
|
|
||||||
|
private final HttpAuthRegistry httpAuthRegistry;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Parser(HttpAuthRegistry httpAuthRegistry) {
|
||||||
|
this.httpAuthRegistry = httpAuthRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest parse(XContentParser parser) throws IOException {
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
XContentParser.Token token;
|
||||||
|
String currentFieldName = null;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
|
if (HEADERS_FIELD.match(currentFieldName)) {
|
||||||
|
request.headers((Map) WatcherUtils.flattenModel(parser.map()));
|
||||||
|
} else if (PARAMS_FIELD.match(currentFieldName)) {
|
||||||
|
request.params((Map) WatcherUtils.flattenModel(parser.map()));
|
||||||
|
} else if (AUTH_FIELD.match(currentFieldName)) {
|
||||||
|
request.auth(httpAuthRegistry.parse(parser));
|
||||||
|
} else if (BODY_FIELD.match(currentFieldName)) {
|
||||||
|
request.body(parser.text());
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
if (METHOD_FIELD.match(currentFieldName)) {
|
||||||
|
request.method(HttpMethod.parse(parser.text()));
|
||||||
|
} else if (HOST_FIELD.match(currentFieldName)) {
|
||||||
|
request.host(parser.text());
|
||||||
|
} else if (PATH_FIELD.match(currentFieldName)) {
|
||||||
|
request.path(parser.text());
|
||||||
|
} else if (BODY_FIELD.match(currentFieldName)) {
|
||||||
|
request.body(parser.text());
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
|
if (PORT_FIELD.match(currentFieldName)) {
|
||||||
|
request.port(parser.intValue());
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse http request. unexpected token [" + token + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.common.io.ByteStreams;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
public class HttpResponse implements Closeable {
|
||||||
|
|
||||||
|
private int status;
|
||||||
|
private InputStream inputStream;
|
||||||
|
private byte[] body;
|
||||||
|
|
||||||
|
public int status() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void status(int status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] body() {
|
||||||
|
if (body == null) {
|
||||||
|
try {
|
||||||
|
body = ByteStreams.toByteArray(inputStream);
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw ExceptionsHelper.convertToElastic(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputStream(InputStream inputStream) {
|
||||||
|
this.inputStream = inputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
inputStream.close();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuth;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class TemplatedHttpRequest implements ToXContent {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
private int port;
|
||||||
|
private HttpMethod method;
|
||||||
|
private Template path;
|
||||||
|
private Map<String, Template> params;
|
||||||
|
private Map<String, Template> headers;
|
||||||
|
private HttpAuth auth;
|
||||||
|
private Template body;
|
||||||
|
|
||||||
|
public TemplatedHttpRequest() {
|
||||||
|
method = HttpMethod.GET;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String host() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void host(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int port() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void port(int port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpMethod method() {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void method(HttpMethod method) {
|
||||||
|
this.method = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Template path() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void path(Template path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Template> params() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void params(Map<String, Template> params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Template> headers() {
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void headers(Map<String, Template> headers) {
|
||||||
|
this.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpAuth auth() {
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void auth(HttpAuth auth) {
|
||||||
|
this.auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Template body() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void body(Template body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpRequest render(Map<String, Object> model) {
|
||||||
|
HttpRequest copy = new HttpRequest();
|
||||||
|
copy.host(host);
|
||||||
|
copy.port(port);
|
||||||
|
copy.method(method);
|
||||||
|
if (path != null) {
|
||||||
|
copy.path(path.render(model));
|
||||||
|
}
|
||||||
|
if (params != null) {
|
||||||
|
MapBuilder<String, String> mapBuilder = MapBuilder.newMapBuilder();
|
||||||
|
for (Map.Entry<String, Template> entry : params.entrySet()) {
|
||||||
|
mapBuilder.put(entry.getKey(), entry.getValue().render(model));
|
||||||
|
}
|
||||||
|
copy.params(mapBuilder.map());
|
||||||
|
}
|
||||||
|
if (headers != null) {
|
||||||
|
MapBuilder<String, String> mapBuilder = MapBuilder.newMapBuilder();
|
||||||
|
for (Map.Entry<String, Template> entry : headers.entrySet()) {
|
||||||
|
mapBuilder.put(entry.getKey(), entry.getValue().render(model));
|
||||||
|
}
|
||||||
|
copy.headers(mapBuilder.map());
|
||||||
|
}
|
||||||
|
copy.auth(auth);
|
||||||
|
if (body != null) {
|
||||||
|
copy.body(body.render(model));
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Parser.HOST_FIELD.getPreferredName(), host);
|
||||||
|
builder.field(Parser.PORT_FIELD.getPreferredName(), port);
|
||||||
|
builder.field(Parser.METHOD_FIELD.getPreferredName(), method);
|
||||||
|
if (path != null) {
|
||||||
|
builder.field(Parser.PATH_FIELD.getPreferredName(), path);
|
||||||
|
}
|
||||||
|
if (this.params != null) {
|
||||||
|
builder.startObject(Parser.PARAMS_FIELD.getPreferredName()).value(this.params).endObject();
|
||||||
|
}
|
||||||
|
if (headers != null) {
|
||||||
|
builder.startObject(Parser.HEADERS_FIELD.getPreferredName()).value(headers).endObject();
|
||||||
|
}
|
||||||
|
if (auth != null) {
|
||||||
|
builder.field(Parser.AUTH_FIELD.getPreferredName(), auth);
|
||||||
|
}
|
||||||
|
if (body != null) {
|
||||||
|
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
|
}
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Parser {
|
||||||
|
|
||||||
|
public static final ParseField HOST_FIELD = new ParseField("host");
|
||||||
|
public static final ParseField PORT_FIELD = new ParseField("port");
|
||||||
|
public static final ParseField METHOD_FIELD = new ParseField("method");
|
||||||
|
public static final ParseField PATH_FIELD = new ParseField("path");
|
||||||
|
public static final ParseField PARAMS_FIELD = new ParseField("params");
|
||||||
|
public static final ParseField HEADERS_FIELD = new ParseField("headers");
|
||||||
|
public static final ParseField AUTH_FIELD = new ParseField("auth");
|
||||||
|
public static final ParseField BODY_FIELD = new ParseField("body");
|
||||||
|
|
||||||
|
private final Template.Parser templateParser;
|
||||||
|
private final HttpAuthRegistry httpAuthRegistry;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Parser(Template.Parser templateParser, HttpAuthRegistry httpAuthRegistry) {
|
||||||
|
this.templateParser = templateParser;
|
||||||
|
this.httpAuthRegistry = httpAuthRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplatedHttpRequest parse(XContentParser parser) throws IOException {
|
||||||
|
TemplatedHttpRequest request = new TemplatedHttpRequest();
|
||||||
|
XContentParser.Token token;
|
||||||
|
String currentFieldName = null;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||||
|
if (PATH_FIELD.match(currentFieldName)) {
|
||||||
|
request.path(templateParser.parse(parser));
|
||||||
|
} else if (HEADERS_FIELD.match(currentFieldName)) {
|
||||||
|
request.headers(parseTemplates(parser));
|
||||||
|
} else if (PARAMS_FIELD.match(currentFieldName)) {
|
||||||
|
request.params(parseTemplates(parser));
|
||||||
|
} else if (AUTH_FIELD.match(currentFieldName)) {
|
||||||
|
request.auth(httpAuthRegistry.parse(parser));
|
||||||
|
} else if (BODY_FIELD.match(currentFieldName)) {
|
||||||
|
request.body(templateParser.parse(parser));
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
if (METHOD_FIELD.match(currentFieldName)) {
|
||||||
|
request.method(HttpMethod.parse(parser.text()));
|
||||||
|
} else if (HOST_FIELD.match(currentFieldName)) {
|
||||||
|
request.host(parser.text());
|
||||||
|
} else if (PATH_FIELD.match(currentFieldName)) {
|
||||||
|
request.path(templateParser.parse(parser));
|
||||||
|
} else if (BODY_FIELD.match(currentFieldName)) {
|
||||||
|
request.body(templateParser.parse(parser));
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else if (token == XContentParser.Token.VALUE_NUMBER) {
|
||||||
|
if (PORT_FIELD.match(currentFieldName)) {
|
||||||
|
request.port(parser.intValue());
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("could not parse templated http request. unexpected token [" + token + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Template> parseTemplates(XContentParser parser) throws IOException {
|
||||||
|
Map<String, Template> templates = new HashMap<>();
|
||||||
|
String currentFieldName = null;
|
||||||
|
for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) {
|
||||||
|
switch (token) {
|
||||||
|
case FIELD_NAME:
|
||||||
|
currentFieldName = parser.currentName();
|
||||||
|
break;
|
||||||
|
case VALUE_STRING:
|
||||||
|
case START_OBJECT:
|
||||||
|
templates.put(currentFieldName, templateParser.parse(parser));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ElasticsearchParseException("could not parse templated http request. unexpected token [" + token + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http.auth;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.inject.AbstractModule;
|
||||||
|
import org.elasticsearch.common.inject.multibindings.MapBinder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class AuthModule extends AbstractModule {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
MapBinder<String, HttpAuth.Parser> parsersBinder = MapBinder.newMapBinder(binder(), String.class, HttpAuth.Parser.class);
|
||||||
|
bind(BasicAuth.Parser.class).asEagerSingleton();
|
||||||
|
parsersBinder.addBinding(BasicAuth.TYPE).to(BasicAuth.Parser.class);
|
||||||
|
bind(HttpAuthRegistry.class).asEagerSingleton();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http.auth;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.common.Base64;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class BasicAuth extends HttpAuth {
|
||||||
|
|
||||||
|
public static final String TYPE = "basic";
|
||||||
|
|
||||||
|
private final String username;
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
private final String basicAuth;
|
||||||
|
|
||||||
|
public BasicAuth(String username, String password) throws UnsupportedEncodingException {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
basicAuth = "Basic " + Base64.encodeBytes(String.format(Locale.ROOT, "%s:%s", username, password).getBytes("utf-8"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Parser.USERNAME_FIELD.getPreferredName(), username);
|
||||||
|
builder.field(Parser.PASSWORD_FIELD.getPreferredName(), password);
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(HttpURLConnection connection) {
|
||||||
|
connection.setRequestProperty("Authorization", basicAuth);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
BasicAuth basicAuth = (BasicAuth) o;
|
||||||
|
|
||||||
|
if (!password.equals(basicAuth.password)) return false;
|
||||||
|
if (!username.equals(basicAuth.username)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = username.hashCode();
|
||||||
|
result = 31 * result + password.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Parser implements HttpAuth.Parser<BasicAuth> {
|
||||||
|
|
||||||
|
static final ParseField USERNAME_FIELD = new ParseField("username");
|
||||||
|
static final ParseField PASSWORD_FIELD = new ParseField("password");
|
||||||
|
|
||||||
|
public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BasicAuth parse(XContentParser parser) throws IOException {
|
||||||
|
String username = null;
|
||||||
|
String password = null;
|
||||||
|
|
||||||
|
String fieldName = null;
|
||||||
|
XContentParser.Token token;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
fieldName = parser.currentName();
|
||||||
|
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||||
|
if (USERNAME_FIELD.getPreferredName().equals(fieldName)) {
|
||||||
|
username = parser.text();
|
||||||
|
} else if (PASSWORD_FIELD.getPreferredName().equals(fieldName)) {
|
||||||
|
password = parser.text();
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("unsupported field [" + fieldName + "]");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new ElasticsearchParseException("unsupported token [" + token + "]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (username == null) {
|
||||||
|
throw new HttpAuthException("username is a required option");
|
||||||
|
}
|
||||||
|
if (password == null) {
|
||||||
|
throw new HttpAuthException("password is a required option");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BasicAuth(username, password);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http.auth;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
|
||||||
|
public abstract class HttpAuth implements ToXContent {
|
||||||
|
|
||||||
|
public abstract String type();
|
||||||
|
|
||||||
|
public abstract void update(HttpURLConnection connection);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(type());
|
||||||
|
builder = innerToXContent(builder, params);
|
||||||
|
return builder.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException;
|
||||||
|
|
||||||
|
public static interface Parser<Auth extends HttpAuth> {
|
||||||
|
|
||||||
|
String type();
|
||||||
|
|
||||||
|
Auth parse(XContentParser parser) throws IOException;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http.auth;
|
||||||
|
|
||||||
|
import org.elasticsearch.watcher.WatcherException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpAuthException extends WatcherException {
|
||||||
|
|
||||||
|
public HttpAuthException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpAuthException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http.auth;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
|
import org.elasticsearch.common.inject.Inject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HttpAuthRegistry {
|
||||||
|
|
||||||
|
private final ImmutableMap<String, HttpAuth.Parser> parsers;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public HttpAuthRegistry(Map<String, HttpAuth.Parser> parsers) {
|
||||||
|
this.parsers = ImmutableMap.copyOf(parsers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpAuth parse(XContentParser parser) throws IOException {
|
||||||
|
String type = null;
|
||||||
|
XContentParser.Token token;
|
||||||
|
HttpAuth auth = null;
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
|
type = parser.currentName();
|
||||||
|
} else if (token == XContentParser.Token.START_OBJECT && type != null) {
|
||||||
|
HttpAuth.Parser inputParser = parsers.get(type);
|
||||||
|
if (inputParser == null) {
|
||||||
|
throw new HttpAuthException("unknown http auth type [" + type + "]");
|
||||||
|
}
|
||||||
|
auth = inputParser.parse(parser);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.input.http;
|
||||||
|
|
||||||
|
import com.carrotsearch.ant.tasks.junit4.dependencies.com.google.common.collect.ImmutableMap;
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||||
|
import org.elasticsearch.ElasticsearchIllegalArgumentException;
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.elasticsearch.common.joda.time.DateTime;
|
||||||
|
import org.elasticsearch.common.joda.time.DateTimeZone;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentHelper;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.elasticsearch.watcher.actions.Action;
|
||||||
|
import org.elasticsearch.watcher.actions.Actions;
|
||||||
|
import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
|
||||||
|
import org.elasticsearch.watcher.input.Input;
|
||||||
|
import org.elasticsearch.watcher.input.simple.SimpleInput;
|
||||||
|
import org.elasticsearch.watcher.support.clock.ClockMock;
|
||||||
|
import org.elasticsearch.watcher.support.http.*;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.BasicAuth;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuth;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
|
||||||
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
|
import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule;
|
||||||
|
import org.elasticsearch.watcher.trigger.schedule.ScheduleTrigger;
|
||||||
|
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
|
||||||
|
import org.elasticsearch.watcher.watch.Payload;
|
||||||
|
import org.elasticsearch.watcher.watch.Watch;
|
||||||
|
import org.elasticsearch.watcher.watch.WatchExecutionContext;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.mockito.Matchers.any;
|
||||||
|
import static org.mockito.Matchers.anyMap;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpInputTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
|
private HttpClient httpClient;
|
||||||
|
private HttpInput.Parser httpParser;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
httpClient = mock(HttpClient.class);
|
||||||
|
Template.Parser templateParser = new MockTemplate.Parser();
|
||||||
|
HttpAuthRegistry registry = new HttpAuthRegistry(ImmutableMap.of("basic", new BasicAuth.Parser()));
|
||||||
|
httpParser = new HttpInput.Parser(
|
||||||
|
ImmutableSettings.EMPTY, httpClient, new HttpRequest.Parser(registry), new TemplatedHttpRequest.Parser(templateParser, registry)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExecute() throws Exception {
|
||||||
|
String host = "_host";
|
||||||
|
int port = 123;
|
||||||
|
String body = "_body";
|
||||||
|
TemplatedHttpRequest request = new TemplatedHttpRequest();
|
||||||
|
request.method(HttpMethod.POST);
|
||||||
|
request.host(host);
|
||||||
|
request.port(port);
|
||||||
|
Template mockBody = mock(Template.class);
|
||||||
|
when(mockBody.render(anyMap())).thenReturn(body);
|
||||||
|
request.body(mockBody);
|
||||||
|
HttpInput input = new HttpInput(logger, httpClient, request);
|
||||||
|
|
||||||
|
HttpResponse response = new HttpResponse();
|
||||||
|
response.status(123);
|
||||||
|
response.inputStream(new ByteArrayInputStream("{\"key\" : \"value\"}".getBytes(UTF8)));
|
||||||
|
when(httpClient.execute(any(HttpRequest.class))).thenReturn(response);
|
||||||
|
|
||||||
|
Watch watch = new Watch("test-watch",
|
||||||
|
new ClockMock(),
|
||||||
|
new ScheduleTrigger(new IntervalSchedule(new IntervalSchedule.Interval(1, IntervalSchedule.Interval.Unit.MINUTES))),
|
||||||
|
new SimpleInput(logger, new Payload.Simple()),
|
||||||
|
new AlwaysTrueCondition(logger),
|
||||||
|
null,
|
||||||
|
new Actions(new ArrayList<Action>()),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
new Watch.Status());
|
||||||
|
WatchExecutionContext ctx = new WatchExecutionContext("test-watch1",
|
||||||
|
watch,
|
||||||
|
new DateTime(0, DateTimeZone.UTC),
|
||||||
|
new ScheduleTriggerEvent(new DateTime(0, DateTimeZone.UTC), new DateTime(0, DateTimeZone.UTC)));
|
||||||
|
HttpInput.Result result = input.execute(ctx);
|
||||||
|
assertThat(result.type(), equalTo(HttpInput.TYPE));
|
||||||
|
assertThat(result.payload().data(), equalTo(MapBuilder.<String, Object>newMapBuilder().put("key", "value").map()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Repeat(iterations = 12)
|
||||||
|
public void testParser() throws Exception {
|
||||||
|
final String httpMethod = randomFrom("PUT", "POST", "GET", "DELETE", "HEAD", null);
|
||||||
|
String host = randomAsciiOfLength(3);
|
||||||
|
int port = randomInt();
|
||||||
|
Template path = new MockTemplate(randomAsciiOfLength(3));
|
||||||
|
String body = randomBoolean() ? randomAsciiOfLength(3) : null;
|
||||||
|
Map<String, Template> params = randomBoolean() ? new MapBuilder<String, Template>().put("a", new MockTemplate("b")).map() : null;
|
||||||
|
Map<String, Template> headers = randomBoolean() ? new MapBuilder<String, Template>().put("c", new MockTemplate("d")).map() : null;
|
||||||
|
HttpAuth auth = randomBoolean() ? new BasicAuth("username", "password") : null;
|
||||||
|
HttpInput.SourceBuilder sourceBuilder = new HttpInput.SourceBuilder()
|
||||||
|
.setMethod(httpMethod)
|
||||||
|
.setHost(host)
|
||||||
|
.setPort(port)
|
||||||
|
.setPath(path)
|
||||||
|
.setBody(body != null ? new MockTemplate(body) : null)
|
||||||
|
.setParams(params)
|
||||||
|
.setHeaders(headers)
|
||||||
|
.setAuth(auth);
|
||||||
|
XContentParser parser = XContentHelper.createParser(jsonBuilder().value(sourceBuilder).bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
HttpInput result = httpParser.parse(parser);
|
||||||
|
|
||||||
|
assertThat(result.type(), equalTo(HttpInput.TYPE));
|
||||||
|
assertThat(result.getRequest().method().method(), equalTo(httpMethod != null ? httpMethod : "GET")); // get is the default
|
||||||
|
assertThat(result.getRequest().host(), equalTo(host));
|
||||||
|
assertThat(result.getRequest().port(), equalTo(port));
|
||||||
|
assertThat(result.getRequest().path(), equalTo(path));
|
||||||
|
assertThat(result.getRequest().params(), equalTo(params));
|
||||||
|
assertThat(result.getRequest().headers(), equalTo(headers));
|
||||||
|
assertThat(result.getRequest().auth(), equalTo(auth));
|
||||||
|
if (body != null) {
|
||||||
|
assertThat(result.getRequest().body().render(Collections.<String, Object>emptyMap()), equalTo(body));
|
||||||
|
} else {
|
||||||
|
assertThat(result.getRequest().body(), nullValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ElasticsearchIllegalArgumentException.class)
|
||||||
|
public void testParser_invalidHttpMethod() throws Exception {
|
||||||
|
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", new MockTemplate("b")).map();
|
||||||
|
HttpInput.SourceBuilder sourceBuilder = new HttpInput.SourceBuilder()
|
||||||
|
.setMethod("_method")
|
||||||
|
.setHost("_host")
|
||||||
|
.setPort(123)
|
||||||
|
.setBody(new MockTemplate("_body"))
|
||||||
|
.setHeaders(headers);
|
||||||
|
XContentParser parser = XContentHelper.createParser(jsonBuilder().value(sourceBuilder).bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
httpParser.parse(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseResult() throws Exception {
|
||||||
|
String httpMethod = "get";
|
||||||
|
String body = "_body";
|
||||||
|
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", new MockTemplate("b")).map();
|
||||||
|
HttpInput.SourceBuilder sourceBuilder = new HttpInput.SourceBuilder()
|
||||||
|
.setMethod(httpMethod)
|
||||||
|
.setHost("_host")
|
||||||
|
.setPort(123)
|
||||||
|
.setBody(new MockTemplate(body))
|
||||||
|
.setHeaders(headers);
|
||||||
|
|
||||||
|
Map<String, Object> payload = MapBuilder.<String, Object>newMapBuilder().put("x", "y").map();
|
||||||
|
|
||||||
|
XContentBuilder builder = jsonBuilder().startObject();
|
||||||
|
builder.field(HttpInput.Parser.HTTP_STATUS_FIELD.getPreferredName(), 123);
|
||||||
|
builder.field(HttpInput.Parser.REQUEST_FIELD.getPreferredName(), sourceBuilder);
|
||||||
|
builder.field(Input.Result.PAYLOAD_FIELD.getPreferredName(), payload);
|
||||||
|
builder.endObject();
|
||||||
|
|
||||||
|
XContentParser parser = XContentHelper.createParser(builder.bytes());
|
||||||
|
parser.nextToken();
|
||||||
|
HttpInput.Result result = httpParser.parseResult(parser);
|
||||||
|
assertThat(result.type(), equalTo(HttpInput.TYPE));
|
||||||
|
assertThat(result.payload().data(), equalTo(payload));
|
||||||
|
assertThat(result.statusCode(), equalTo(123));
|
||||||
|
assertThat(result.request().method().method(), equalTo("GET"));
|
||||||
|
assertThat(result.request().headers().size(), equalTo(headers.size()));
|
||||||
|
for (Map.Entry<String, Template> entry : headers.entrySet()) {
|
||||||
|
assertThat(entry.getValue().render(Collections.<String, Object>emptyMap()), equalTo(result.request().headers().get(entry.getKey())));
|
||||||
|
}
|
||||||
|
assertThat(result.request().host(), equalTo("_host"));
|
||||||
|
assertThat(result.request().port(), equalTo(123));
|
||||||
|
assertThat(result.request().body(), equalTo("_body"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MockTemplate implements Template {
|
||||||
|
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
private MockTemplate(String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String render(Map<String, Object> model) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return builder.value(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
MockTemplate that = (MockTemplate) o;
|
||||||
|
|
||||||
|
if (!value.equals(that.value)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return value.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Parser implements Template.Parser {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Template parse(XContentParser parser) throws IOException, ParseException {
|
||||||
|
String value = parser.text();
|
||||||
|
return new MockTemplate(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.support.http;
|
||||||
|
|
||||||
|
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockResponse;
|
||||||
|
import com.squareup.okhttp.mockwebserver.MockWebServer;
|
||||||
|
import com.squareup.okhttp.mockwebserver.RecordedRequest;
|
||||||
|
import org.elasticsearch.common.base.Charsets;
|
||||||
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||||
|
import org.elasticsearch.watcher.support.http.auth.BasicAuth;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpClientTest extends ElasticsearchTestCase {
|
||||||
|
|
||||||
|
private MockWebServer webServer;
|
||||||
|
private HttpClient httpClient;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() throws Exception {
|
||||||
|
webServer = new MockWebServer();
|
||||||
|
webServer.start(9200);
|
||||||
|
httpClient = new HttpClient(ImmutableSettings.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws Exception {
|
||||||
|
webServer.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Repeat(iterations = 10)
|
||||||
|
public void testBasics() throws Exception {
|
||||||
|
int responseCode = randomIntBetween(200, 203);
|
||||||
|
String body = randomAsciiOfLengthBetween(2, 8096);
|
||||||
|
webServer.enqueue(new MockResponse().setResponseCode(responseCode).setBody(body));
|
||||||
|
|
||||||
|
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.method(HttpMethod.POST);
|
||||||
|
request.host("localhost");
|
||||||
|
request.port(9200);
|
||||||
|
request.path("/" + randomAsciiOfLength(5));
|
||||||
|
String paramKey;
|
||||||
|
String paramValue;
|
||||||
|
request.params(MapBuilder.<String, String>newMapBuilder()
|
||||||
|
.put(paramKey = randomAsciiOfLength(3), paramValue = randomAsciiOfLength(3))
|
||||||
|
.map());
|
||||||
|
String headerKey;
|
||||||
|
String headerValue;
|
||||||
|
request.headers(MapBuilder.<String, String>newMapBuilder()
|
||||||
|
.put(headerKey = randomAsciiOfLength(3), headerValue = randomAsciiOfLength(3))
|
||||||
|
.map());
|
||||||
|
request.body(randomAsciiOfLength(5));
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
RecordedRequest recordedRequest = webServer.takeRequest();
|
||||||
|
|
||||||
|
assertThat(response.status(), equalTo(responseCode));
|
||||||
|
assertThat(new String(response.body(), Charsets.UTF_8), equalTo(body));
|
||||||
|
assertThat(webServer.getRequestCount(), equalTo(1));
|
||||||
|
assertThat(recordedRequest.getBody().readString(Charsets.UTF_8), equalTo(request.body()));
|
||||||
|
assertThat(recordedRequest.getPath().split("\\?")[0], equalTo(request.path()));
|
||||||
|
assertThat(recordedRequest.getPath().split("\\?")[1], equalTo(paramKey + "=" + paramValue));
|
||||||
|
assertThat(recordedRequest.getHeader(headerKey), equalTo(headerValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBasicAuth() throws Exception {
|
||||||
|
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
|
||||||
|
HttpRequest request = new HttpRequest();
|
||||||
|
request.method(HttpMethod.POST);
|
||||||
|
request.host("localhost");
|
||||||
|
request.port(9200);
|
||||||
|
request.path("/test");
|
||||||
|
request.auth(new BasicAuth("user", "pass"));
|
||||||
|
request.body("body");
|
||||||
|
HttpResponse response = httpClient.execute(request);
|
||||||
|
assertThat(response.status(), equalTo(200));
|
||||||
|
assertThat(new String(response.body(), Charsets.UTF_8), equalTo("body"));
|
||||||
|
RecordedRequest recordedRequest = webServer.takeRequest();
|
||||||
|
assertThat(recordedRequest.getHeader("Authorization"), equalTo("Basic dXNlcjpwYXNz"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -40,12 +40,12 @@ import org.elasticsearch.watcher.actions.email.service.Authentication;
|
|||||||
import org.elasticsearch.watcher.actions.email.service.Email;
|
import org.elasticsearch.watcher.actions.email.service.Email;
|
||||||
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.watcher.actions.email.service.Profile;
|
import org.elasticsearch.watcher.actions.email.service.Profile;
|
||||||
import org.elasticsearch.watcher.actions.webhook.HttpClient;
|
|
||||||
import org.elasticsearch.watcher.client.WatcherClient;
|
import org.elasticsearch.watcher.client.WatcherClient;
|
||||||
import org.elasticsearch.watcher.history.HistoryStore;
|
import org.elasticsearch.watcher.history.HistoryStore;
|
||||||
import org.elasticsearch.watcher.history.WatchRecord;
|
import org.elasticsearch.watcher.history.WatchRecord;
|
||||||
import org.elasticsearch.watcher.support.WatcherUtils;
|
import org.elasticsearch.watcher.support.WatcherUtils;
|
||||||
import org.elasticsearch.watcher.support.clock.ClockMock;
|
import org.elasticsearch.watcher.support.clock.ClockMock;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
||||||
import org.elasticsearch.watcher.support.template.Template;
|
import org.elasticsearch.watcher.support.template.Template;
|
||||||
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
|
import org.elasticsearch.watcher.transport.actions.stats.WatcherStatsResponse;
|
||||||
|
@ -10,9 +10,7 @@ import org.elasticsearch.action.support.IndicesOptions;
|
|||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
import org.elasticsearch.common.joda.time.DateTime;
|
import org.elasticsearch.common.joda.time.DateTime;
|
||||||
import org.elasticsearch.common.joda.time.DateTimeZone;
|
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
@ -24,13 +22,14 @@ import org.elasticsearch.watcher.actions.email.service.Authentication;
|
|||||||
import org.elasticsearch.watcher.actions.email.service.Email;
|
import org.elasticsearch.watcher.actions.email.service.Email;
|
||||||
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.watcher.actions.email.service.Profile;
|
import org.elasticsearch.watcher.actions.email.service.Profile;
|
||||||
import org.elasticsearch.watcher.actions.webhook.HttpClient;
|
|
||||||
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
||||||
import org.elasticsearch.watcher.condition.script.ScriptCondition;
|
import org.elasticsearch.watcher.condition.script.ScriptCondition;
|
||||||
import org.elasticsearch.watcher.input.search.SearchInput;
|
import org.elasticsearch.watcher.input.search.SearchInput;
|
||||||
import org.elasticsearch.watcher.support.Script;
|
import org.elasticsearch.watcher.support.Script;
|
||||||
import org.elasticsearch.watcher.support.WatcherUtils;
|
import org.elasticsearch.watcher.support.WatcherUtils;
|
||||||
import org.elasticsearch.watcher.support.clock.SystemClock;
|
import org.elasticsearch.watcher.support.clock.SystemClock;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpMethod;
|
||||||
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
|
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
|
||||||
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
||||||
import org.elasticsearch.watcher.support.template.ScriptTemplate;
|
import org.elasticsearch.watcher.support.template.ScriptTemplate;
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* 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.watcher.test.integration;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.node.internal.InternalNode;
|
||||||
|
import org.elasticsearch.watcher.client.WatchSourceBuilder;
|
||||||
|
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
||||||
|
import org.elasticsearch.watcher.support.template.ScriptTemplate;
|
||||||
|
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
|
||||||
|
import org.elasticsearch.watcher.trigger.TriggerBuilders;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
|
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
|
||||||
|
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder;
|
||||||
|
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
|
||||||
|
import static org.elasticsearch.watcher.input.InputBuilders.httpInput;
|
||||||
|
import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*/
|
||||||
|
public class HttpInputIntegrationTest extends AbstractWatcherIntegrationTests {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
return ImmutableSettings.builder()
|
||||||
|
.put(InternalNode.HTTP_ENABLED, true)
|
||||||
|
.put(super.nodeSettings(nodeOrdinal))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shieldEnabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHttpInput() throws Exception {
|
||||||
|
ScriptServiceProxy sc = scriptService();
|
||||||
|
client().prepareIndex("index", "type", "id").setSource("{}").setRefresh(true).get();
|
||||||
|
|
||||||
|
InetSocketAddress address = internalTestCluster().httpAddresses()[0];
|
||||||
|
String body = jsonBuilder().startObject().field("size", 1).endObject().string();
|
||||||
|
WatchSourceBuilder source = watchSourceBuilder()
|
||||||
|
.trigger(TriggerBuilders.schedule(interval("5s")))
|
||||||
|
.input(httpInput()
|
||||||
|
.setHost(address.getHostName())
|
||||||
|
.setPort(address.getPort())
|
||||||
|
.setPath(new ScriptTemplate(sc, "/index/_search"))
|
||||||
|
.setBody(new ScriptTemplate(sc, body))
|
||||||
|
)
|
||||||
|
.condition(scriptCondition("ctx.payload.hits.total == 1"))
|
||||||
|
.addAction(indexAction("idx", "action"));
|
||||||
|
watcherClient().preparePutWatch("_name")
|
||||||
|
.source(source)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
if (timeWarped()) {
|
||||||
|
timeWarp().scheduler().trigger("_name");
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
assertWatchWithMinimumPerformedActionsCount("_name", 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -12,7 +12,6 @@ import org.elasticsearch.common.collect.ImmutableList;
|
|||||||
import org.elasticsearch.common.collect.ImmutableMap;
|
import org.elasticsearch.common.collect.ImmutableMap;
|
||||||
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.netty.handler.codec.http.HttpMethod;
|
|
||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
@ -27,7 +26,6 @@ import org.elasticsearch.watcher.actions.email.service.Email;
|
|||||||
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
import org.elasticsearch.watcher.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.watcher.actions.email.service.Profile;
|
import org.elasticsearch.watcher.actions.email.service.Profile;
|
||||||
import org.elasticsearch.watcher.actions.index.IndexAction;
|
import org.elasticsearch.watcher.actions.index.IndexAction;
|
||||||
import org.elasticsearch.watcher.actions.webhook.HttpClient;
|
|
||||||
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
import org.elasticsearch.watcher.actions.webhook.WebhookAction;
|
||||||
import org.elasticsearch.watcher.condition.Condition;
|
import org.elasticsearch.watcher.condition.Condition;
|
||||||
import org.elasticsearch.watcher.condition.ConditionRegistry;
|
import org.elasticsearch.watcher.condition.ConditionRegistry;
|
||||||
@ -40,6 +38,8 @@ import org.elasticsearch.watcher.input.simple.SimpleInput;
|
|||||||
import org.elasticsearch.watcher.support.Script;
|
import org.elasticsearch.watcher.support.Script;
|
||||||
import org.elasticsearch.watcher.support.WatcherUtils;
|
import org.elasticsearch.watcher.support.WatcherUtils;
|
||||||
import org.elasticsearch.watcher.support.clock.SystemClock;
|
import org.elasticsearch.watcher.support.clock.SystemClock;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpClient;
|
||||||
|
import org.elasticsearch.watcher.support.http.HttpMethod;
|
||||||
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
|
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
|
||||||
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
|
||||||
import org.elasticsearch.watcher.support.template.ScriptTemplate;
|
import org.elasticsearch.watcher.support.template.ScriptTemplate;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user