changed the actions format and added the notion of an action id

- actions are not identified by a unique id. The actions in a "watch" definition are now keyed (instead of an array)
- the `ActionWrapper` is now a construct that holds: and action, the id of the action and optionally a transform
- the `webhook` action is now structured based on the templated http request it holds (no need for extra `request` element there`
- the `webhook` reponse holds the http response (not the `status` and `body` directly)
- the action builders now accept an `id` when created
- introduced `WatchSourceBuilders` for quickly access various source builders
- introduced `Template.SourceBuilder` to help building a template
- changed templated http request builder to accept template source builders (instead of templates directly)
- changed `HttpResponse` to accept the body as a `ByteReference` in the ctor (this construct used to be in an inconsistent state holding an input stream that could have already been read)

Original commit: elastic/x-pack-elasticsearch@296350b6a8
This commit is contained in:
uboness 2015-04-06 00:35:13 +02:00
parent 46e27cf517
commit f9004eed31
39 changed files with 1105 additions and 878 deletions

View File

@ -5,14 +5,15 @@
*/ */
package org.elasticsearch.watcher.actions; package org.elasticsearch.watcher.actions;
import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.elasticsearch.common.Nullable;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.logging.ESLogger; import org.elasticsearch.common.logging.ESLogger;
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.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.WatchExecutionContext;
import java.io.IOException; import java.io.IOException;
@ -21,18 +22,9 @@ import java.io.IOException;
public abstract class Action<R extends Action.Result> implements ToXContent { public abstract class Action<R extends Action.Result> implements ToXContent {
protected final ESLogger logger; protected final ESLogger logger;
protected final Transform transform;
protected Action(ESLogger logger, Transform transform) { protected Action(ESLogger logger) {
this.logger = logger; this.logger = logger;
this.transform = transform;
}
/**
* @return the transform associated with this action (may be {@code null})
*/
public Transform transform() {
return transform;
} }
/** /**
@ -40,29 +32,12 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
*/ */
public abstract String type(); public abstract String type();
/** protected abstract R execute(String actionId, WatchExecutionContext context, Payload payload) throws IOException;
* Executes this action
*/
public R execute(WatchExecutionContext context) throws IOException {
Payload payload = context.payload();
Transform.Result transformResult = null;
if (transform != null) {
transformResult = transform.apply(context, payload);
payload = transformResult.payload();
}
R result = execute(context, payload);
if (transformResult != null) {
result.transformResult = transformResult;
}
return result;
}
protected abstract R execute(WatchExecutionContext context, Payload payload) throws IOException;
/** /**
* Parses xcontent to a concrete action of the same type. * Parses xcontent to a concrete action of the same type.
*/ */
public static interface Parser<R extends Result, T extends Action<R>> { public interface Parser<R extends Result, T extends Action<R>> {
/** /**
* @return The type of the action * @return The type of the action
@ -84,8 +59,6 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
protected final String type; protected final String type;
protected final boolean success; protected final boolean success;
protected Transform.Result transformResult;
protected Result(String type, boolean success) { protected Result(String type, boolean success) {
this.type = type; this.type = type;
this.success = success; this.success = success;
@ -99,19 +72,10 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
return success; return success;
} }
public Transform.Result transformResult() {
return transformResult;
}
@Override @Override
public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public final XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(SUCCESS_FIELD.getPreferredName(), success); builder.field(SUCCESS_FIELD.getPreferredName(), success);
if (transformResult != null) {
builder.startObject(Transform.Parser.TRANSFORM_RESULT_FIELD.getPreferredName())
.field(transformResult.type(), transformResult)
.endObject();
}
xContentBody(builder, params); xContentBody(builder, params);
return builder.endObject(); return builder.endObject();
} }
@ -120,9 +84,40 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
} }
public static interface SourceBuilder extends ToXContent { public static abstract class SourceBuilder<SB extends SourceBuilder<SB>> implements ToXContent {
String type(); protected final String id;
protected @Nullable Transform.SourceBuilder transform;
public SourceBuilder(String id) {
this.id = id;
}
public String id() {
return id;
}
public SB transform(Transform.SourceBuilder transform) {
this.transform = transform;
return (SB) this;
}
public abstract String type();
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform)
.endObject();
}
builder.field(type());
actionXContent(builder, params);
return builder.endObject();
}
protected abstract XContentBuilder actionXContent(XContentBuilder builder, Params params) throws IOException;
} }
} }

View File

@ -18,16 +18,16 @@ public final class ActionBuilders {
private ActionBuilders() { private ActionBuilders() {
} }
public static EmailAction.SourceBuilder emailAction() { public static EmailAction.SourceBuilder emailAction(String id) {
return new EmailAction.SourceBuilder(); return new EmailAction.SourceBuilder(id);
} }
public static IndexAction.SourceBuilder indexAction(String index, String type) { public static IndexAction.SourceBuilder indexAction(String id, String index, String type) {
return new IndexAction.SourceBuilder(index, type); return new IndexAction.SourceBuilder(id, index, type);
} }
public static WebhookAction.SourceBuilder webhookAction(TemplatedHttpRequest request) { public static WebhookAction.SourceBuilder webhookAction(String id, TemplatedHttpRequest.SourceBuilder httpRequest) {
return new WebhookAction.SourceBuilder(request); return new WebhookAction.SourceBuilder(id, httpRequest);
} }
} }

View File

@ -8,9 +8,11 @@ package org.elasticsearch.watcher.actions;
import org.elasticsearch.common.collect.ImmutableMap; import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.transform.TransformRegistry;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -19,68 +21,50 @@ import java.util.Map;
public class ActionRegistry { public class ActionRegistry {
private final ImmutableMap<String, Action.Parser> parsers; private final ImmutableMap<String, Action.Parser> parsers;
private final TransformRegistry transformRegistry;
@Inject @Inject
public ActionRegistry(Map<String, Action.Parser> parsers) { public ActionRegistry(Map<String, Action.Parser> parsers, TransformRegistry transformRegistry) {
this.parsers = ImmutableMap.copyOf(parsers); this.parsers = ImmutableMap.copyOf(parsers);
this.transformRegistry = transformRegistry;
} }
/** Action.Parser parser(String type) {
* Reads the contents of parser to create the correct Action return parsers.get(type);
*/ }
public Action parse(XContentParser parser) throws IOException {
String type = null; public Actions.Results parseResults(XContentParser parser) throws IOException {
Map<String, ActionWrapper.Result> results = new HashMap<>();
String id = null;
XContentParser.Token token; XContentParser.Token token;
Action action = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
type = parser.currentName(); id = parser.currentName();
} else if (token == XContentParser.Token.START_OBJECT && type != null) { } else if (token == XContentParser.Token.START_OBJECT && id != null) {
Action.Parser actionParser = parsers.get(type); ActionWrapper.Result result = ActionWrapper.Result.parse(parser, id, this, transformRegistry);
if (actionParser == null) { results.put(id, result);
throw new ActionException("unknown action type [" + type + "]");
}
action = actionParser.parse(parser);
} }
} }
return action; return new Actions.Results(results);
} }
/**
* Reads the contents of parser to create the correct Action.Result
*
* @param parser The parser containing the action definition
* @return A new Action.Result instance from the parser
* @throws IOException
*/
public Action.Result parseResult(XContentParser parser) throws IOException {
String type = null;
XContentParser.Token token;
Action.Result result = 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) {
Action.Parser actionParser = parsers.get(type);
if (actionParser == null) {
throw new ActionException("unknown action type [" + type + "]");
}
result = actionParser.parseResult(parser);
}
}
return result;
}
public Actions parseActions(XContentParser parser) throws IOException { public Actions parseActions(XContentParser parser) throws IOException {
List<Action> actions = new ArrayList<>(); List<ActionWrapper> actions = new ArrayList<>();
while (parser.nextToken() != XContentParser.Token.END_ARRAY) { String id = null;
actions.add(parse(parser)); XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
id = parser.currentName();
} else if (token == XContentParser.Token.START_OBJECT && id != null) {
ActionWrapper action = ActionWrapper.parse(parser, id, this, transformRegistry);
actions.add(action);
}
} }
return new Actions(actions); return new Actions(actions);
} }
} }

View File

@ -0,0 +1,215 @@
/*
* 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;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
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;
/**
*
*/
public class ActionWrapper implements ToXContent {
private String id;
private final @Nullable Transform transform;
private final Action action;
public ActionWrapper(String id, Action action) {
this(id, null, action);
}
public ActionWrapper(String id, @Nullable Transform transform, Action action) {
this.id = id;
this.transform = transform;
this.action = action;
}
public String id() {
return id;
}
public Transform transform() {
return transform;
}
public Action action() {
return action;
}
public ActionWrapper.Result execute(WatchExecutionContext ctx) throws IOException {
Payload payload = ctx.payload();
Transform.Result transformResult = null;
if (transform != null) {
transformResult = transform.apply(ctx, payload);
payload = transformResult.payload();
}
Action.Result actionResult = action.execute(id, ctx, payload);
return new ActionWrapper.Result(id, transformResult, actionResult);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ActionWrapper that = (ActionWrapper) o;
if (!id.equals(that.id)) return false;
if (transform != null ? !transform.equals(that.transform) : that.transform != null) return false;
return action.equals(that.action);
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + (transform != null ? transform.hashCode() : 0);
result = 31 * result + action.hashCode();
return result;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform)
.endObject();
}
builder.field(action.type(), action);
return builder.endObject();
}
static ActionWrapper parse(XContentParser parser, String id, ActionRegistry actionRegistry, TransformRegistry transformRegistry) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
Transform transform = null;
Action action = null;
String currentFieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else {
if (Transform.Parser.TRANSFORM_FIELD.match(currentFieldName)) {
transform = transformRegistry.parse(parser);
} else {
// it's the type of the action
Action.Parser actionParser = actionRegistry.parser(currentFieldName);
if (actionParser == null) {
throw new ActionException("could not parse action [" + id + "]. unknown action type [" + currentFieldName + "]");
}
action = actionParser.parse(parser);
}
}
}
if (action == null) {
throw new ActionException("could not parse watch action [" + id + "]. missing action type");
}
return new ActionWrapper(id, transform, action);
}
public static class Result implements ToXContent {
private final String id;
private final @Nullable Transform.Result transform;
private final Action.Result action;
public Result(String id, Action.Result action) {
this(id, null, action);
}
public Result(String id, @Nullable Transform.Result transform, Action.Result action) {
this.id = id;
this.transform = transform;
this.action = action;
}
public String id() {
return id;
}
public Transform.Result transform() {
return transform;
}
public Action.Result action() {
return action;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Result result = (Result) o;
if (!id.equals(result.id)) return false;
if (transform != null ? !transform.equals(result.transform) : result.transform != null) return false;
return action.equals(result.action);
}
@Override
public int hashCode() {
int result = id.hashCode();
result = 31 * result + (transform != null ? transform.hashCode() : 0);
result = 31 * result + action.hashCode();
return result;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_RESULT_FIELD.getPreferredName())
.field(transform.type(), transform)
.endObject();
}
builder.field(action.type(), action);
return builder.endObject();
}
static Result parse(XContentParser parser, String id, ActionRegistry actionRegistry, TransformRegistry transformRegistry) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
Transform.Result transformResult = null;
Action.Result actionResult = null;
String currentFieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else {
if (Transform.Parser.TRANSFORM_FIELD.match(currentFieldName)) {
transformResult = transformRegistry.parseResult(parser);
} else {
// it's the type of the action
Action.Parser actionParser = actionRegistry.parser(currentFieldName);
if (actionParser == null) {
throw new ActionException("could not parse action result [" + id + "]. unknown action type [" + currentFieldName + "]");
}
actionResult = actionParser.parseResult(parser);
}
}
}
if (actionResult == null) {
throw new ActionException("could not parse watch action result [" + id + "]. missing action result type");
}
return new Result(id, transformResult, actionResult);
}
}
}

View File

@ -11,15 +11,16 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* *
*/ */
public class Actions implements Iterable<Action>, ToXContent { public class Actions implements Iterable<ActionWrapper>, ToXContent {
private final List<Action> actions; private final List<ActionWrapper> actions;
public Actions(List<Action> actions) { public Actions(List<ActionWrapper> actions) {
this.actions = actions; this.actions = actions;
} }
@ -28,18 +29,17 @@ public class Actions implements Iterable<Action>, ToXContent {
} }
@Override @Override
public Iterator<Action> iterator() { public Iterator<ActionWrapper> iterator() {
return actions.iterator(); return actions.iterator();
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startArray(); builder.startObject();
for (Action action : actions){ for (ActionWrapper action : actions) {
builder.startObject().field(action.type(), action).endObject(); builder.field(action.id(), action);
} }
builder.endArray(); return builder.endObject();
return builder;
} }
@Override @Override
@ -58,4 +58,50 @@ public class Actions implements Iterable<Action>, ToXContent {
public int hashCode() { public int hashCode() {
return actions.hashCode(); return actions.hashCode();
} }
public static class Results implements Iterable<ActionWrapper.Result>, ToXContent {
private final Map<String, ActionWrapper.Result> results;
public Results(Map<String, ActionWrapper.Result> results) {
this.results = results;
}
public int count() {
return results.size();
}
@Override
public Iterator<ActionWrapper.Result> iterator() {
return results.values().iterator();
}
public ActionWrapper.Result get(String id) {
return results.get(id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Results results1 = (Results) o;
return results.equals(results1.results);
}
@Override
public int hashCode() {
return results.hashCode();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
for (ActionWrapper.Result result : results.values()) {
builder.field(result.id(), result);
}
return builder.endObject();
}
}
} }

View File

@ -5,15 +5,6 @@
*/ */
package org.elasticsearch.watcher.actions.email; package org.elasticsearch.watcher.actions.email;
import org.elasticsearch.watcher.watch.WatchExecutionContext;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.actions.email.service.*;
import org.elasticsearch.watcher.support.Variables;
import org.elasticsearch.watcher.support.template.Template;
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;
@ -23,6 +14,13 @@ 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.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.actions.email.service.*;
import org.elasticsearch.watcher.support.Variables;
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.io.IOException;
import java.util.Map; import java.util.Map;
@ -45,11 +43,11 @@ public class EmailAction extends Action<EmailAction.Result> {
final EmailService emailService; final EmailService emailService;
public EmailAction(ESLogger logger, @Nullable Transform transform, EmailService emailService, Email emailPrototype, public EmailAction(ESLogger logger, EmailService emailService, Email emailPrototype,
Authentication auth, Profile profile, String account, @Nullable Template subject, Authentication auth, Profile profile, String account, @Nullable Template subject,
@Nullable Template textBody, @Nullable Template htmlBody, boolean attachPayload) { @Nullable Template textBody, @Nullable Template htmlBody, boolean attachPayload) {
super(logger, transform); super(logger);
this.emailService = emailService; this.emailService = emailService;
this.emailPrototype = emailPrototype; this.emailPrototype = emailPrototype;
this.auth = auth; this.auth = auth;
@ -67,7 +65,7 @@ public class EmailAction extends Action<EmailAction.Result> {
} }
@Override @Override
protected Result execute(WatchExecutionContext ctx, Payload payload) throws IOException { protected Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws IOException {
Map<String, Object> model = Variables.createCtxModel(ctx, payload); Map<String, Object> model = Variables.createCtxModel(ctx, payload);
Email.Builder email = Email.builder() Email.Builder email = Email.builder()
@ -91,14 +89,14 @@ public class EmailAction extends Action<EmailAction.Result> {
EmailService.EmailSent sent = emailService.send(email.build(), auth, profile, account); EmailService.EmailSent sent = emailService.send(email.build(), auth, profile, account);
return new Result.Success(sent); return new Result.Success(sent);
} catch (EmailException ee) { } catch (EmailException ee) {
logger.error("could not send email for watch [{}]", ee, ctx.watch().name()); logger.error("could not send email [{}] for watch [{}]", ee, actionId, ctx.watch().name());
return new Result.Failure("could not send email for watch [" + ctx.watch().name() + "]. error: " + ee.getMessage()); return new Result.Failure("could not send email. error: " + ee.getMessage());
} }
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(emailPrototype, auth, profile, account, subject, textBody, htmlBody, attachPayload, transform); return Objects.hash(emailPrototype, auth, profile, account, subject, textBody, htmlBody, attachPayload);
} }
@Override @Override
@ -117,18 +115,12 @@ public class EmailAction extends Action<EmailAction.Result> {
&& Objects.equals(this.subject, other.subject) && Objects.equals(this.subject, other.subject)
&& Objects.equals(this.textBody, other.textBody) && Objects.equals(this.textBody, other.textBody)
&& Objects.equals(this.htmlBody, other.htmlBody) && Objects.equals(this.htmlBody, other.htmlBody)
&& Objects.equals(this.attachPayload, other.attachPayload) && Objects.equals(this.attachPayload, other.attachPayload);
&& Objects.equals(this.transform, other.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();
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform)
.endObject();
}
if (account != null) { if (account != null) {
builder.field(Parser.ACCOUNT_FIELD.getPreferredName(), account); builder.field(Parser.ACCOUNT_FIELD.getPreferredName(), account);
} }
@ -182,14 +174,12 @@ public class EmailAction extends Action<EmailAction.Result> {
private final Template.Parser templateParser; private final Template.Parser templateParser;
private final EmailService emailService; private final EmailService emailService;
private final TransformRegistry transformRegistry;
@Inject @Inject
public Parser(Settings settings, EmailService emailService, Template.Parser templateParser, TransformRegistry transformRegistry) { public Parser(Settings settings, EmailService emailService, Template.Parser templateParser) {
super(settings); super(settings);
this.emailService = emailService; this.emailService = emailService;
this.templateParser = templateParser; this.templateParser = templateParser;
this.transformRegistry = transformRegistry;
} }
@Override @Override
@ -199,7 +189,6 @@ public class EmailAction extends Action<EmailAction.Result> {
@Override @Override
public EmailAction parse(XContentParser parser) throws IOException { public EmailAction parse(XContentParser parser) throws IOException {
Transform transform = null;
String user = null; String user = null;
String password = null; String password = null;
String account = null; String account = null;
@ -264,12 +253,6 @@ public class EmailAction extends Action<EmailAction.Result> {
} else { } else {
throw new ActionSettingsException("could not parse email action. unrecognized boolean field [" + currentFieldName + "]"); throw new ActionSettingsException("could not parse email action. unrecognized boolean field [" + currentFieldName + "]");
} }
} else if (token == XContentParser.Token.START_OBJECT) {
if (Transform.Parser.TRANSFORM_FIELD.match(currentFieldName)) {
transform = transformRegistry.parse(parser);
} else {
throw new ActionSettingsException("could not parse email action. unexpected object field [" + currentFieldName + "]");
}
} else { } else {
throw new ActionSettingsException("could not parse email action. unexpected token [" + token + "]"); throw new ActionSettingsException("could not parse email action. unexpected token [" + token + "]");
} }
@ -278,12 +261,11 @@ public class EmailAction extends Action<EmailAction.Result> {
Authentication auth = user != null ? new Authentication(user, password) : null; Authentication auth = user != null ? new Authentication(user, password) : null;
return new EmailAction(logger, transform, emailService, email.build(), auth, profile, account, subject, textBody, htmlBody, attachPayload); return new EmailAction(logger, emailService, email.build(), auth, profile, account, subject, textBody, htmlBody, attachPayload);
} }
@Override @Override
public EmailAction.Result parseResult(XContentParser parser) throws IOException { public EmailAction.Result parseResult(XContentParser parser) throws IOException {
Transform.Result transformResult = null;
Boolean success = null; Boolean success = null;
Email email = null; Email email = null;
String account = null; String account = null;
@ -311,8 +293,6 @@ public class EmailAction extends Action<EmailAction.Result> {
} else if (token == XContentParser.Token.START_OBJECT) { } else if (token == XContentParser.Token.START_OBJECT) {
if (EMAIL_FIELD.match(currentFieldName)) { if (EMAIL_FIELD.match(currentFieldName)) {
email = Email.parse(parser); email = Email.parse(parser);
} else if (Transform.Parser.TRANSFORM_RESULT_FIELD.match(currentFieldName)) {
transformResult = transformRegistry.parseResult(parser);
} else { } else {
throw new EmailException("could not parse email result. unexpected field [" + currentFieldName + "]"); throw new EmailException("could not parse email result. unexpected field [" + currentFieldName + "]");
} }
@ -325,11 +305,7 @@ public class EmailAction extends Action<EmailAction.Result> {
throw new EmailException("could not parse email result. expected field [success]"); throw new EmailException("could not parse email result. expected field [success]");
} }
Result result = success ? new Result.Success(new EmailService.EmailSent(account, email)) : new Result.Failure(reason); return success ? new Result.Success(new EmailService.EmailSent(account, email)) : new Result.Failure(reason);
if (transformResult != null) {
result.transformResult(transformResult);
}
return result;
} }
} }
@ -339,10 +315,6 @@ public class EmailAction extends Action<EmailAction.Result> {
super(type, success); super(type, success);
} }
void transformResult(Transform.Result result) {
this.transformResult = result;
}
public static class Success extends Result { public static class Success extends Result {
private final EmailService.EmailSent sent; private final EmailService.EmailSent sent;
@ -387,7 +359,7 @@ public class EmailAction extends Action<EmailAction.Result> {
} }
} }
public static class SourceBuilder implements Action.SourceBuilder { public static class SourceBuilder extends Action.SourceBuilder<SourceBuilder> {
private Email.Address from; private Email.Address from;
private Email.AddressList replyTo; private Email.AddressList replyTo;
@ -402,13 +374,17 @@ public class EmailAction extends Action<EmailAction.Result> {
private Template htmlBody; private Template htmlBody;
private Boolean attachPayload; private Boolean attachPayload;
public SourceBuilder(String id) {
super(id);
}
@Override @Override
public String type() { public String type() {
return TYPE; return TYPE;
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder actionXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
if (from != null) { if (from != null) {
builder.field(Email.FROM_FIELD.getPreferredName(), from); builder.field(Email.FROM_FIELD.getPreferredName(), from);

View File

@ -8,15 +8,6 @@ package org.elasticsearch.watcher.actions.index;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.index.IndexResponse;
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.init.proxy.ClientProxy;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry;
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;
@ -25,6 +16,12 @@ import org.elasticsearch.common.settings.Settings;
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.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.support.init.proxy.ClientProxy;
import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.WatchExecutionContext;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
@ -41,8 +38,8 @@ public class IndexAction extends Action<IndexAction.Result> {
final String index; final String index;
final String type; final String type;
public IndexAction(ESLogger logger, @Nullable Transform transform, ClientProxy client, String index, String type) { public IndexAction(ESLogger logger, ClientProxy client, String index, String type) {
super(logger, transform); super(logger);
this.client = client; this.client = client;
this.index = index; this.index = index;
this.type = type; this.type = type;
@ -54,7 +51,7 @@ public class IndexAction extends Action<IndexAction.Result> {
} }
@Override @Override
protected Result execute(WatchExecutionContext ctx, Payload payload) throws IOException { protected Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws IOException {
IndexRequest indexRequest = new IndexRequest(); IndexRequest indexRequest = new IndexRequest();
indexRequest.index(index); indexRequest.index(index);
indexRequest.type(type); indexRequest.type(type);
@ -66,8 +63,8 @@ public class IndexAction extends Action<IndexAction.Result> {
resultBuilder.endObject(); resultBuilder.endObject();
indexRequest.source(resultBuilder); indexRequest.source(resultBuilder);
} catch (IOException ioe) { } catch (IOException ioe) {
logger.error("failed to index result for watch [{}]", ioe, ctx.watch().name()); logger.error("failed to execute index action [{}] for watch [{}]", ioe, actionId, ctx.watch().name());
return new Result(null, "failed to build index request. " + ioe.getMessage(), false); return new Result(null, "failed to index payload. " + ioe.getMessage(), false);
} }
try { try {
@ -87,17 +84,11 @@ public class IndexAction extends Action<IndexAction.Result> {
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); return builder.startObject()
if (transform != null) { .field(Parser.INDEX_FIELD.getPreferredName(), index)
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName()) .field(Parser.TYPE_FIELD.getPreferredName(), type)
.field(transform.type(), transform)
.endObject(); .endObject();
} }
builder.field(Parser.INDEX_FIELD.getPreferredName(), index);
builder.field(Parser.TYPE_FIELD.getPreferredName(), type);
builder.endObject();
return builder;
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
@ -108,7 +99,6 @@ public class IndexAction extends Action<IndexAction.Result> {
if (index != null ? !index.equals(that.index) : that.index != null) return false; if (index != null ? !index.equals(that.index) : that.index != null) return false;
if (type != null ? !type.equals(that.type) : that.type != null) return false; if (type != null ? !type.equals(that.type) : that.type != null) return false;
if (transform != null ? !transform.equals(that.transform) : that.transform != null) return false;
return true; return true;
} }
@ -117,7 +107,6 @@ public class IndexAction extends Action<IndexAction.Result> {
public int hashCode() { public int hashCode() {
int result = index != null ? index.hashCode() : 0; int result = index != null ? index.hashCode() : 0;
result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (type != null ? type.hashCode() : 0);
result = 31 * result + (transform != null ? transform.hashCode() : 0);
return result; return result;
} }
@ -129,13 +118,11 @@ public class IndexAction extends Action<IndexAction.Result> {
public static final ParseField RESPONSE_FIELD = new ParseField("response"); public static final ParseField RESPONSE_FIELD = new ParseField("response");
private final ClientProxy client; private final ClientProxy client;
private final TransformRegistry transformRegistry;
@Inject @Inject
public Parser(Settings settings, ClientProxy client, TransformRegistry transformRegistry) { public Parser(Settings settings, ClientProxy client) {
super(settings); super(settings);
this.client = client; this.client = client;
this.transformRegistry = transformRegistry;
} }
@Override @Override
@ -147,7 +134,6 @@ public class IndexAction extends Action<IndexAction.Result> {
public IndexAction parse(XContentParser parser) throws IOException { public IndexAction parse(XContentParser parser) throws IOException {
String index = null; String index = null;
String type = null; String type = null;
Transform transform = null;
String currentFieldName = null; String currentFieldName = null;
XContentParser.Token token; XContentParser.Token token;
@ -162,31 +148,24 @@ public class IndexAction extends Action<IndexAction.Result> {
} else { } else {
throw new ActionSettingsException("could not parse index action. unexpected field [" + currentFieldName + "]"); throw new ActionSettingsException("could not parse index action. unexpected field [" + currentFieldName + "]");
} }
} else if (token == XContentParser.Token.START_OBJECT) {
if (Transform.Parser.TRANSFORM_FIELD.match(currentFieldName)) {
transform = transformRegistry.parse(parser);
} else {
throw new ActionSettingsException("could not parse index action. unexpected field [" + currentFieldName + "]");
}
} else { } else {
throw new ActionSettingsException("could not parse index action. unexpected token [" + token + "]"); throw new ActionSettingsException("could not parse index action. unexpected token [" + token + "]");
} }
} }
if (index == null) { if (index == null) {
throw new ActionSettingsException("could not parse index action [index] is required"); throw new ActionSettingsException("could not parse index action. [index] is required");
} }
if (type == null) { if (type == null) {
throw new ActionSettingsException("could not parse index action [type] is required"); throw new ActionSettingsException("could not parse index action. [type] is required");
} }
return new IndexAction(logger, transform, client, index, type); return new IndexAction(logger, client, index, type);
} }
@Override @Override
public Result parseResult(XContentParser parser) throws IOException { public Result parseResult(XContentParser parser) throws IOException {
Transform.Result transformResult = null;
Boolean success = null; Boolean success = null;
Payload payload = null; Payload payload = null;
String reason = null; String reason = null;
@ -211,8 +190,6 @@ public class IndexAction extends Action<IndexAction.Result> {
} else if (token == XContentParser.Token.START_OBJECT) { } else if (token == XContentParser.Token.START_OBJECT) {
if (RESPONSE_FIELD.match(currentFieldName)) { if (RESPONSE_FIELD.match(currentFieldName)) {
payload = new Payload.Simple(parser.map()); payload = new Payload.Simple(parser.map());
} else if (Transform.Parser.TRANSFORM_RESULT_FIELD.match(currentFieldName)) {
transformResult = transformRegistry.parseResult(parser);
} else { } else {
throw new ActionException("could not parse index result. unexpected object field [" + currentFieldName + "]"); throw new ActionException("could not parse index result. unexpected object field [" + currentFieldName + "]");
} }
@ -225,11 +202,7 @@ public class IndexAction extends Action<IndexAction.Result> {
throw new ActionException("could not parse index result. expected boolean field [success]"); throw new ActionException("could not parse index result. expected boolean field [success]");
} }
Result result = new Result(payload, reason, success); return new Result(payload, reason, success);
if (transformResult != null) {
result.transformResult(transformResult);
}
return result;
} }
} }
@ -244,10 +217,6 @@ public class IndexAction extends Action<IndexAction.Result> {
this.reason = reason; this.reason = reason;
} }
void transformResult(Transform.Result result) {
this.transformResult = result;
}
public Payload response() { public Payload response() {
return response; return response;
} }
@ -264,12 +233,13 @@ public class IndexAction extends Action<IndexAction.Result> {
} }
} }
public static class SourceBuilder implements Action.SourceBuilder { public static class SourceBuilder extends Action.SourceBuilder<SourceBuilder> {
private final String index; private final String index;
private final String type; private final String type;
public SourceBuilder(String index, String type) { public SourceBuilder(String id, String index, String type) {
super(id);
this.index = index; this.index = index;
this.type = type; this.type = type;
} }
@ -280,7 +250,7 @@ public class IndexAction extends Action<IndexAction.Result> {
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder actionXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject() return builder.startObject()
.field(Parser.INDEX_FIELD.getPreferredName(), index) .field(Parser.INDEX_FIELD.getPreferredName(), index)
.field(Parser.TYPE_FIELD.getPreferredName(), type) .field(Parser.TYPE_FIELD.getPreferredName(), type)

View File

@ -5,34 +5,25 @@
*/ */
package org.elasticsearch.watcher.actions.webhook; package org.elasticsearch.watcher.actions.webhook;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.base.Charsets;
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.logging.Loggers;
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.actions.Action; import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionException; import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.support.Variables; import org.elasticsearch.watcher.support.Variables;
import org.elasticsearch.watcher.support.http.HttpClient; import org.elasticsearch.watcher.support.http.HttpClient;
import org.elasticsearch.watcher.support.http.HttpRequest; import org.elasticsearch.watcher.support.http.HttpRequest;
import org.elasticsearch.watcher.support.http.HttpResponse; import org.elasticsearch.watcher.support.http.HttpResponse;
import org.elasticsearch.watcher.support.http.TemplatedHttpRequest; import org.elasticsearch.watcher.support.http.TemplatedHttpRequest;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry;
import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.elasticsearch.watcher.watch.WatchExecutionContext;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@ -45,8 +36,8 @@ public class WebhookAction extends Action<WebhookAction.Result> {
private final TemplatedHttpRequest templatedHttpRequest; private final TemplatedHttpRequest templatedHttpRequest;
public WebhookAction(ESLogger logger, @Nullable Transform transform, HttpClient httpClient, TemplatedHttpRequest templatedHttpRequest) { public WebhookAction(ESLogger logger, HttpClient httpClient, TemplatedHttpRequest templatedHttpRequest) {
super(logger, transform); super(logger);
this.httpClient = httpClient; this.httpClient = httpClient;
this.templatedHttpRequest = templatedHttpRequest; this.templatedHttpRequest = templatedHttpRequest;
} }
@ -61,38 +52,26 @@ public class WebhookAction extends Action<WebhookAction.Result> {
} }
@Override @Override
protected Result execute(WatchExecutionContext ctx, Payload payload) throws IOException { protected Result execute(String actionId, WatchExecutionContext ctx, Payload payload) throws IOException {
Map<String, Object> model = Variables.createCtxModel(ctx, payload); Map<String, Object> model = Variables.createCtxModel(ctx, payload);
HttpRequest httpRequest = templatedHttpRequest.render(model); HttpRequest request = templatedHttpRequest.render(model);
try { try {
try (HttpResponse response = httpClient.execute(httpRequest)) { HttpResponse response = httpClient.execute(request);
int status = response.status(); int status = response.status();
if (status >= 400) {
logger.warn("got status [" + status + "] when connecting to [" + httpRequest.host() + "] [" + httpRequest.path() + "]");
} else {
if (status >= 300) { if (status >= 300) {
logger.warn("a 200 range return code was expected, but got [" + status + "]"); logger.warn("received http status [{}] when connecting to [{}] [{}]", status, request.host(), request.path());
}
}
return new Result.Executed(status, httpRequest, response.body());
} }
return new Result.Executed(request, response);
} catch (IOException ioe) { } catch (IOException ioe) {
logger.error("failed to connect to [{}] for watch [{}]", ioe, httpRequest.toString(), ctx.watch().name()); logger.error("failed to execute webhook action [{}]. could not connect to [{}]", ioe, actionId, ctx.watch().name(), request.toString());
return new Result.Failure("failed to send http request. " + ioe.getMessage()); return new Result.Failure("failed to send http request. " + ioe.getMessage());
} }
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); return templatedHttpRequest.toXContent(builder, params);
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform)
.endObject();
}
builder.field(Parser.REQUEST_FIELD.getPreferredName(), templatedHttpRequest);
return builder.endObject();
} }
@Override @Override
@ -119,41 +98,29 @@ public class WebhookAction extends Action<WebhookAction.Result> {
super(type, success); super(type, success);
} }
void transformResult(Transform.Result result) {
this.transformResult = result;
}
public static class Executed extends Result { public static class Executed extends Result {
private final int httpStatus; private final HttpRequest request;
private final byte[] responseBody; private final HttpResponse response;
private final HttpRequest httpRequest;
public Executed(int httpStatus, HttpRequest httpRequest, byte[] responseBody) { public Executed(HttpRequest request, HttpResponse response) {
super(TYPE, httpStatus < 400); super(TYPE, response.status() < 400);
this.httpStatus = httpStatus; this.request = request;
this.responseBody = responseBody; this.response = response;
this.httpRequest = httpRequest;
} }
public int httpStatus() { public HttpResponse response() {
return httpStatus; return response;
} }
public byte[] responseBody() { public HttpRequest request() {
return responseBody; return request;
}
public HttpRequest httpRequest() {
return httpRequest;
} }
@Override @Override
protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException { protected XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException {
return builder.field(SUCCESS_FIELD.getPreferredName(), success()) return builder.field(Parser.REQUEST_FIELD.getPreferredName(), request)
.field(WebhookAction.Parser.HTTP_STATUS_FIELD.getPreferredName(), httpStatus) .field(Parser.RESPONSE_FIELD.getPreferredName(), response);
.field(Parser.REQUEST_FIELD.getPreferredName(), httpRequest)
.field(Parser.RESPONSE_BODY.getPreferredName(), responseBody);
} }
} }
@ -181,25 +148,22 @@ public class WebhookAction extends Action<WebhookAction.Result> {
public static class Parser extends AbstractComponent implements Action.Parser<Result, WebhookAction> { public static class Parser extends AbstractComponent implements Action.Parser<Result, WebhookAction> {
public static final ParseField REQUEST_FIELD = new ParseField("request"); public static final ParseField REQUEST_FIELD = new ParseField("request");
public static final ParseField HTTP_STATUS_FIELD = new ParseField("http_status"); public static final ParseField RESPONSE_FIELD = new ParseField("response");
public static final ParseField RESPONSE_BODY = new ParseField("response_body");
public static final ParseField REASON_FIELD = new ParseField("reason"); public static final ParseField REASON_FIELD = new ParseField("reason");
private final HttpClient httpClient; private final HttpClient httpClient;
private final TransformRegistry transformRegistry;
private final HttpRequest.Parser requestParser; private final HttpRequest.Parser requestParser;
private final TemplatedHttpRequest.Parser templatedRequestParser; private final TemplatedHttpRequest.Parser templatedRequestParser;
private final ESLogger actionLogger;
@Inject @Inject
public Parser(Settings settings, HttpClient httpClient, public Parser(Settings settings, HttpClient httpClient, HttpRequest.Parser requestParser,
TransformRegistry transformRegistry, HttpRequest.Parser requestParser,
TemplatedHttpRequest.Parser templatedRequestParser) { TemplatedHttpRequest.Parser templatedRequestParser) {
super(settings); super(settings);
this.httpClient = httpClient; this.httpClient = httpClient;
this.transformRegistry = transformRegistry;
this.requestParser = requestParser; this.requestParser = requestParser;
this.templatedRequestParser = templatedRequestParser; this.templatedRequestParser = templatedRequestParser;
this.actionLogger = Loggers.getLogger(WebhookAction.class, settings);
} }
@Override @Override
@ -209,74 +173,47 @@ public class WebhookAction extends Action<WebhookAction.Result> {
@Override @Override
public WebhookAction parse(XContentParser parser) throws IOException { public WebhookAction parse(XContentParser parser) throws IOException {
Transform transform = null; try {
TemplatedHttpRequest templatedHttpRequest = null; TemplatedHttpRequest request = templatedRequestParser.parse(parser);
return new WebhookAction(actionLogger, httpClient, request);
String currentFieldName = null; } catch (TemplatedHttpRequest.ParseException pe) {
XContentParser.Token token; throw new ActionException("could not parse webhook action", pe);
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if ((token == XContentParser.Token.START_OBJECT) && currentFieldName != null ) {
if (REQUEST_FIELD.match(currentFieldName)) {
templatedHttpRequest = templatedRequestParser.parse(parser);
} else if (Transform.Parser.TRANSFORM_FIELD.match(currentFieldName)) {
transform = transformRegistry.parse(parser);
} else {
throw new ActionSettingsException("could not parse webhook action. unexpected field [" + currentFieldName + "]");
} }
} else {
throw new ActionSettingsException("could not parse webhook action. unexpected token [" + token + "]");
}
}
if (templatedHttpRequest == null) {
throw new ActionSettingsException("could not parse webhook action. [" + REQUEST_FIELD.getPreferredName() + "] is required");
}
return new WebhookAction(logger, transform, httpClient, templatedHttpRequest);
} }
@Override @Override
public Result parseResult(XContentParser parser) throws IOException { public Result parseResult(XContentParser parser) throws IOException {
Transform.Result transformResult = null;
String currentFieldName = null; String currentFieldName = null;
XContentParser.Token token; XContentParser.Token token;
Boolean success = null; Boolean success = null;
String reason = null; String reason = null;
HttpRequest request = null; HttpRequest request = null;
byte[] responseBody = null; HttpResponse response = null;
int httpStatus = -1;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) { if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName(); currentFieldName = parser.currentName();
} else if (token.isValue()) { } else if (token == XContentParser.Token.START_OBJECT) {
if (HTTP_STATUS_FIELD.match(currentFieldName)) { if (REQUEST_FIELD.match(currentFieldName)) {
httpStatus = parser.intValue(); request = requestParser.parse(parser);
} else if (REASON_FIELD.match(currentFieldName)) { } else if (RESPONSE_FIELD.match(currentFieldName)) {
response = HttpResponse.parse(parser);
} else {
throw new ActionException("unable to parse webhook action result. unexpected object field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.VALUE_STRING) {
if (REASON_FIELD.match(currentFieldName)) {
reason = parser.text(); reason = parser.text();
} else {
throw new ActionException("unable to parse webhook action result. unexpected string field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.VALUE_BOOLEAN) { } else if (token == XContentParser.Token.VALUE_BOOLEAN) {
if (Action.Result.SUCCESS_FIELD.match(currentFieldName)) { if (Action.Result.SUCCESS_FIELD.match(currentFieldName)) {
success = parser.booleanValue(); success = parser.booleanValue();
} else { } else {
throw new ActionException("could not parse webhook result. unexpected boolean field [" + currentFieldName + "]"); throw new ActionException("unable to parse webhook action result. unexpected boolean field [" + currentFieldName + "]");
}
} else if (RESPONSE_BODY.match(currentFieldName)) {
responseBody = parser.binaryValue();
}else {
throw new ActionException("unable to parse webhook action result. unexpected field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.START_OBJECT) {
if (Transform.Parser.TRANSFORM_RESULT_FIELD.match(currentFieldName)) {
transformResult = transformRegistry.parseResult(parser);
} else if (REQUEST_FIELD.match(currentFieldName)) {
request = requestParser.parse(parser);
} else {
throw new ActionException("unable to parse webhook action result. unexpected field [" + currentFieldName + "]" );
} }
} else { } else {
throw new ActionException("unable to parse webhook action result. unexpected field [" + currentFieldName + "]" ); throw new ActionException("unable to parse webhook action result. unexpected token [" + token + "]" );
} }
} }
@ -284,42 +221,16 @@ public class WebhookAction extends Action<WebhookAction.Result> {
throw new ActionException("could not parse webhook result. expected boolean field [success]"); throw new ActionException("could not parse webhook result. expected boolean field [success]");
} }
return (reason == null) ? new Result.Executed(request, response) : new Result.Failure(reason);
Result result = (reason == null) ? new Result.Executed(httpStatus, request, responseBody) : new Result.Failure(reason);
if (transformResult != null) {
result.transformResult(transformResult);
}
return result;
} }
} }
private Object makeURLSafe(Object toSafe) throws UnsupportedEncodingException { public static class SourceBuilder extends Action.SourceBuilder<SourceBuilder> {
if (toSafe instanceof List) {
List<Object> returnObject = new ArrayList<>(((List) toSafe).size());
for (Object o : (List)toSafe) {
returnObject.add(makeURLSafe(o));
}
return returnObject;
} else if (toSafe instanceof Map) {
Map<Object, Object> returnObject = new HashMap<>(((Map) toSafe).size());
for (Object key : ((Map) toSafe).keySet()) {
returnObject.put(key, makeURLSafe(((Map) toSafe).get(key)));
}
return returnObject;
} else if (toSafe instanceof String) {
return URLEncoder.encode(toSafe.toString(), Charsets.UTF_8.name());
} else {
//Don't know how to convert anything else
return toSafe;
}
}
private final TemplatedHttpRequest.SourceBuilder httpRequest;
public static class SourceBuilder implements Action.SourceBuilder { public SourceBuilder(String id, TemplatedHttpRequest.SourceBuilder httpRequest) {
super(id);
private final TemplatedHttpRequest httpRequest;
public SourceBuilder(TemplatedHttpRequest httpRequest) {
this.httpRequest = httpRequest; this.httpRequest = httpRequest;
} }
@ -329,10 +240,9 @@ public class WebhookAction extends Action<WebhookAction.Result> {
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder actionXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); return httpRequest.toXContent(builder, params);
builder.field(Parser.REQUEST_FIELD.getPreferredName(), httpRequest);
return builder.endObject();
} }
} }
} }

View File

@ -5,14 +5,6 @@
*/ */
package org.elasticsearch.watcher.client; package org.elasticsearch.watcher.client;
import org.elasticsearch.watcher.trigger.Trigger;
import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.condition.ConditionBuilders;
import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.NoneInput;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
@ -20,6 +12,14 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.builder.SearchSourceBuilderException; import org.elasticsearch.search.builder.SearchSourceBuilderException;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.condition.ConditionBuilders;
import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.NoneInput;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.trigger.Trigger;
import org.elasticsearch.watcher.watch.Watch;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
@ -31,10 +31,6 @@ import java.util.Set;
*/ */
public class WatchSourceBuilder implements ToXContent { public class WatchSourceBuilder implements ToXContent {
public static WatchSourceBuilder watchSourceBuilder() {
return new WatchSourceBuilder();
}
private Trigger.SourceBuilder trigger; private Trigger.SourceBuilder trigger;
private Input.SourceBuilder input = NoneInput.SourceBuilder.INSTANCE; private Input.SourceBuilder input = NoneInput.SourceBuilder.INSTANCE;
private Condition.SourceBuilder condition = ConditionBuilders.alwaysTrueCondition(); private Condition.SourceBuilder condition = ConditionBuilders.alwaysTrueCondition();
@ -104,11 +100,11 @@ public class WatchSourceBuilder implements ToXContent {
builder.field(Watch.Parser.THROTTLE_PERIOD_FIELD.getPreferredName(), throttlePeriod.getMillis()); builder.field(Watch.Parser.THROTTLE_PERIOD_FIELD.getPreferredName(), throttlePeriod.getMillis());
} }
builder.startArray(Watch.Parser.ACTIONS_FIELD.getPreferredName()); builder.startObject(Watch.Parser.ACTIONS_FIELD.getPreferredName());
for (Action.SourceBuilder action : actions) { for (Action.SourceBuilder action : actions) {
builder.startObject().field(action.type(), action).endObject(); builder.field(action.type(), action);
} }
builder.endArray(); builder.endObject();
if (metadata != null) { if (metadata != null) {
builder.field(Watch.Parser.META_FIELD.getPreferredName(), metadata); builder.field(Watch.Parser.META_FIELD.getPreferredName(), metadata);

View File

@ -0,0 +1,30 @@
/*
* 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.client;
import org.elasticsearch.watcher.support.http.TemplatedHttpRequest;
import org.elasticsearch.watcher.support.template.ScriptTemplate;
/**
*
*/
public final class WatchSourceBuilders {
private WatchSourceBuilders() {
}
public static WatchSourceBuilder watchBuilder() {
return new WatchSourceBuilder();
}
public static ScriptTemplate.SourceBuilder template(String text) {
return new ScriptTemplate.SourceBuilder(text);
}
public static TemplatedHttpRequest.SourceBuilder templatedHttpRequest(String host, int port) {
return new TemplatedHttpRequest.SourceBuilder(host, port);
}
}

View File

@ -14,7 +14,7 @@ import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException; import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.support.Callback; import org.elasticsearch.watcher.support.Callback;
@ -33,6 +33,8 @@ import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
/** /**
*/ */
public class HistoryService extends AbstractComponent { public class HistoryService extends AbstractComponent {
@ -154,8 +156,8 @@ public class HistoryService extends AbstractComponent {
Transform.Result result = watch.transform().apply(ctx, inputResult.payload()); Transform.Result result = watch.transform().apply(ctx, inputResult.payload());
ctx.onTransformResult(result); ctx.onTransformResult(result);
} }
for (Action action : watch.actions()) { for (ActionWrapper action : watch.actions()) {
Action.Result actionResult = action.execute(ctx); ActionWrapper.Result actionResult = action.execute(ctx);
ctx.onActionResult(actionResult); ctx.onActionResult(actionResult);
} }
} }

View File

@ -56,20 +56,19 @@ public class HttpInput extends Input<HttpInput.Result> {
@Override @Override
public Result execute(WatchExecutionContext ctx) throws IOException { public Result execute(WatchExecutionContext ctx) throws IOException {
Map<String, Object> model = Variables.createCtxModel(ctx, null); Map<String, Object> model = Variables.createCtxModel(ctx, null);
HttpRequest httpRequest = request.render(model); HttpRequest request = this.request.render(model);
try (HttpResponse response = client.execute(httpRequest)) {
byte[] bytes = response.body(); HttpResponse response = client.execute(request);
final Payload payload; Payload payload;
if (extractKeys != null) { if (extractKeys != null) {
XContentParser parser = XContentHelper.createParser(bytes, 0, bytes.length); XContentParser parser = XContentHelper.createParser(response.body());
Map<String, Object> filteredKeys = XContentFilterKeysUtils.filterMapOrdered(extractKeys, parser); Map<String, Object> filteredKeys = XContentFilterKeysUtils.filterMapOrdered(extractKeys, parser);
payload = new Payload.Simple(filteredKeys); payload = new Payload.Simple(filteredKeys);
} else { } else {
Tuple<XContentType, Map<String, Object>> result = XContentHelper.convertToMap(bytes, true); Tuple<XContentType, Map<String, Object>> result = XContentHelper.convertToMap(response.body(), true);
payload = new Payload.Simple(result.v2()); payload = new Payload.Simple(result.v2());
} }
return new Result(TYPE, payload, httpRequest, response.status()); return new Result(payload, request, response.status());
}
} }
@Override @Override
@ -113,8 +112,8 @@ public class HttpInput extends Input<HttpInput.Result> {
private final HttpRequest request; private final HttpRequest request;
private final int statusCode; private final int statusCode;
public Result(String type, Payload payload, HttpRequest request, int statusCode) { public Result(Payload payload, HttpRequest request, int statusCode) {
super(type, payload); super(TYPE, payload);
this.request = request; this.request = request;
this.statusCode = statusCode; this.statusCode = statusCode;
} }
@ -223,7 +222,7 @@ public class HttpInput extends Input<HttpInput.Result> {
} }
} }
} }
return new Result(TYPE, payload, request, statusCode); return new Result(payload, request, statusCode);
} }
} }
@ -260,8 +259,7 @@ public class HttpInput extends Input<HttpInput.Result> {
} }
builder.endArray(); builder.endArray();
} }
builder.field(Parser.REQUEST_FIELD.getPreferredName()); builder.field(Parser.REQUEST_FIELD.getPreferredName(), request);
request.toXContent(builder, params);
return builder.endObject(); return builder.endObject();
} }
} }

View File

@ -5,12 +5,12 @@
*/ */
package org.elasticsearch.watcher.support; package org.elasticsearch.watcher.support;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
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.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.watcher.WatcherException;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@ -98,6 +98,10 @@ public class Script implements ToXContent {
} }
public static Script parse(XContentParser parser) throws IOException { public static Script parse(XContentParser parser) throws IOException {
return parse(parser, ScriptService.DEFAULT_LANG);
}
public static Script parse(XContentParser parser, String defaultLang) throws IOException {
XContentParser.Token token = parser.currentToken(); XContentParser.Token token = parser.currentToken();
if (token == XContentParser.Token.VALUE_STRING) { if (token == XContentParser.Token.VALUE_STRING) {
return new Script(parser.text()); return new Script(parser.text());
@ -108,7 +112,7 @@ public class Script implements ToXContent {
String script = null; String script = null;
ScriptService.ScriptType type = ScriptService.ScriptType.INLINE; ScriptService.ScriptType type = ScriptService.ScriptType.INLINE;
String lang = ScriptService.DEFAULT_LANG; String lang = defaultLang;
Map<String, Object> params = Collections.emptyMap(); Map<String, Object> params = Collections.emptyMap();
String currentFieldName = null; String currentFieldName = null;

View File

@ -10,6 +10,7 @@ import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.base.Charsets; import org.elasticsearch.common.base.Charsets;
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.io.Streams;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import javax.net.ssl.*; import javax.net.ssl.*;
@ -103,11 +104,12 @@ public class HttpClient extends AbstractComponent {
urlConnection.getOutputStream().write(bytes); urlConnection.getOutputStream().write(bytes);
urlConnection.getOutputStream().close(); urlConnection.getOutputStream().close();
} }
urlConnection.connect();
HttpResponse response = new HttpResponse(urlConnection.getResponseCode()); byte[] body = Streams.copyToByteArray(urlConnection.getInputStream());
response.inputStream(urlConnection.getInputStream());
HttpResponse response = new HttpResponse(urlConnection.getResponseCode(), body);
logger.debug("http status code: {}", response.status()); logger.debug("http status code: {}", response.status());
response.inputStream(urlConnection.getInputStream());
return response; return response;
} }

View File

@ -17,6 +17,7 @@ import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.support.template.Template;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class HttpRequest implements ToXContent { public class HttpRequest implements ToXContent {
@ -118,10 +119,10 @@ public class HttpRequest implements ToXContent {
builder.field(Parser.PATH_FIELD.getPreferredName(), path); builder.field(Parser.PATH_FIELD.getPreferredName(), path);
} }
if (this.params != null) { if (this.params != null) {
builder.startObject(Parser.PARAMS_FIELD.getPreferredName()).value(this.params).endObject(); builder.field(Parser.PARAMS_FIELD.getPreferredName(), this.params);
} }
if (headers != null) { if (headers != null) {
builder.startObject(Parser.HEADERS_FIELD.getPreferredName()).value(headers).endObject(); builder.field(Parser.HEADERS_FIELD.getPreferredName(), headers);
} }
if (auth != null) { if (auth != null) {
builder.field(Parser.AUTH_FIELD.getPreferredName(), auth); builder.field(Parser.AUTH_FIELD.getPreferredName(), auth);
@ -252,8 +253,8 @@ public class HttpRequest implements ToXContent {
private int port; private int port;
private String method; private String method;
private Template path; private Template path;
private Map<String, Template> params; private Map<String, Template.SourceBuilder> params = new HashMap<>();
private Map<String, Template> headers; private Map<String, Template.SourceBuilder> headers = new HashMap<>();
private HttpAuth auth; private HttpAuth auth;
private Template body; private Template body;
@ -282,16 +283,36 @@ public class HttpRequest implements ToXContent {
return this; return this;
} }
public SourceBuilder setParams(Map<String, Template> params) { public SourceBuilder setParams(Map<String, Template.SourceBuilder> params) {
this.params = params; this.params = params;
return this; return this;
} }
public SourceBuilder setHeaders(Map<String, Template> headers) { public SourceBuilder putParams(Map<String, Template.SourceBuilder> params) {
this.params.putAll(params);
return this;
}
public SourceBuilder putParam(String key, Template.SourceBuilder value) {
this.params.put(key, value);
return this;
}
public SourceBuilder setHeaders(Map<String, Template.SourceBuilder> headers) {
this.headers = headers; this.headers = headers;
return this; return this;
} }
public SourceBuilder putHeaders(Map<String, Template.SourceBuilder> headers) {
this.headers.putAll(headers);
return this;
}
public SourceBuilder putHeader(String key, Template.SourceBuilder value) {
this.headers.put(key, value);
return this;
}
public SourceBuilder setAuth(HttpAuth auth) { public SourceBuilder setAuth(HttpAuth auth) {
this.auth = auth; this.auth = auth;
return this; return this;

View File

@ -5,47 +5,125 @@
*/ */
package org.elasticsearch.watcher.support.http; package org.elasticsearch.watcher.support.http;
import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.ByteStreams; import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.WatcherException;
import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
public class HttpResponse implements Closeable { public class HttpResponse implements ToXContent {
private int status; public static final ParseField STATUS_FIELD = new ParseField("status");
private InputStream inputStream; public static final ParseField BODY_FIELD = new ParseField("body");
private byte[] body;
private final int status;
private final BytesReference body;
public HttpResponse(int status) { public HttpResponse(int status) {
this(status, BytesArray.EMPTY);
}
public HttpResponse(int status, String body) {
this(status, new BytesArray(body));
}
public HttpResponse(int status, byte[] body) {
this(status, new BytesArray(body));
}
public HttpResponse(int status, BytesReference body) {
this.status = status; this.status = status;
this.body = body;
} }
public int status() { public int status() {
return status; return status;
} }
public byte[] body() { public BytesReference body() {
if (body == null && inputStream != null) {
try {
body = ByteStreams.toByteArray(inputStream);
inputStream.close();
} catch (IOException e) {
throw ExceptionsHelper.convertToElastic(e);
}
}
return body; return body;
} }
public void inputStream(InputStream inputStream) { @Override
this.inputStream = inputStream; public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HttpResponse response = (HttpResponse) o;
if (status != response.status) return false;
return body.equals(response.body);
} }
@Override @Override
public void close() throws IOException { public int hashCode() {
if (inputStream != null) { int result = status;
inputStream.close(); result = 31 * result + body.hashCode();
return result;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.startObject()
.field(STATUS_FIELD.getPreferredName(), status)
.field(BODY_FIELD.getPreferredName(), body.toUtf8())
.endObject();
}
public static HttpResponse parse(XContentParser parser) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
int status = -1;
String body = null;
String currentFieldName = null;
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else {
if (token == XContentParser.Token.VALUE_NUMBER) {
if (STATUS_FIELD.match(currentFieldName)) {
status = parser.intValue();
} else {
throw new ParseException("could not parse http response. unknown numeric field [" + currentFieldName + "]");
}
} else if (token == XContentParser.Token.VALUE_STRING) {
if (BODY_FIELD.match(currentFieldName)) {
body = parser.text();
} else {
throw new ParseException("could not parse http response. unknown string field [" + currentFieldName + "]");
}
} else {
throw new ParseException("could not parse http response. unknown unexpected token [" + token + "]");
}
}
}
if (status < 0) {
throw new ParseException("could not parse http response. missing [status] numeric field holding the response's http status code");
}
if (body == null) {
throw new ParseException("could not parse http response. missing [status] string field holding the response's body");
}
return new HttpResponse(status, body);
}
public static class ParseException extends WatcherException {
public ParseException(String msg) {
super(msg);
}
public ParseException(String msg, Throwable cause) {
super(msg, cause);
} }
} }
} }

View File

@ -7,39 +7,40 @@ package org.elasticsearch.watcher.support.http;
import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
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.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.watcher.support.http.auth.HttpAuth; import org.elasticsearch.watcher.support.http.auth.HttpAuth;
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry; import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
import org.elasticsearch.watcher.support.template.ScriptTemplate;
import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.support.template.Template;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
/** /**
*/ */
public class TemplatedHttpRequest implements ToXContent { public class TemplatedHttpRequest implements ToXContent {
private Scheme scheme; private Scheme scheme = Scheme.HTTP;
private String host; private String host;
private int port; private int port = -1;
private HttpMethod method; private HttpMethod method = HttpMethod.GET;
private Template path; private Template path;
private Map<String, Template> params; private Map<String, Template> params = Collections.emptyMap();
private Map<String, Template> headers; private Map<String, Template> headers = Collections.emptyMap();
private HttpAuth auth; private HttpAuth auth;
private Template body; private Template body;
public TemplatedHttpRequest() {
scheme = Scheme.HTTP;
method = HttpMethod.GET;
}
public Scheme scheme() { public Scheme scheme() {
return scheme; return scheme;
} }
@ -151,10 +152,10 @@ public class TemplatedHttpRequest implements ToXContent {
builder.field(Parser.PATH_FIELD.getPreferredName(), path); builder.field(Parser.PATH_FIELD.getPreferredName(), path);
} }
if (this.params != null) { if (this.params != null) {
builder.startObject(Parser.PARAMS_FIELD.getPreferredName()).value(this.params).endObject(); builder.field(Parser.PARAMS_FIELD.getPreferredName(), this.params);
} }
if (headers != null) { if (headers != null) {
builder.startObject(Parser.HEADERS_FIELD.getPreferredName()).value(headers).endObject(); builder.field(Parser.HEADERS_FIELD.getPreferredName(), headers);
} }
if (auth != null) { if (auth != null) {
builder.field(Parser.AUTH_FIELD.getPreferredName(), auth); builder.field(Parser.AUTH_FIELD.getPreferredName(), auth);
@ -197,6 +198,10 @@ public class TemplatedHttpRequest implements ToXContent {
return result; return result;
} }
public static SourceBuilder sourceBuilder(String host, int port) {
return new SourceBuilder(host, port);
}
public static class Parser { public static class Parser {
public static final ParseField SCHEME_FIELD = new ParseField("scheme"); public static final ParseField SCHEME_FIELD = new ParseField("scheme");
@ -219,6 +224,8 @@ public class TemplatedHttpRequest implements ToXContent {
} }
public TemplatedHttpRequest parse(XContentParser parser) throws IOException { public TemplatedHttpRequest parse(XContentParser parser) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
TemplatedHttpRequest request = new TemplatedHttpRequest(); TemplatedHttpRequest request = new TemplatedHttpRequest();
XContentParser.Token token; XContentParser.Token token;
String currentFieldName = null; String currentFieldName = null;
@ -237,7 +244,7 @@ public class TemplatedHttpRequest implements ToXContent {
} else if (BODY_FIELD.match(currentFieldName)) { } else if (BODY_FIELD.match(currentFieldName)) {
request.body(templateParser.parse(parser)); request.body(templateParser.parse(parser));
} else { } else {
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]"); throw new ParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
} }
} else if (token == XContentParser.Token.VALUE_STRING) { } else if (token == XContentParser.Token.VALUE_STRING) {
if (SCHEME_FIELD.match(currentFieldName)) { if (SCHEME_FIELD.match(currentFieldName)) {
@ -251,18 +258,26 @@ public class TemplatedHttpRequest implements ToXContent {
} else if (BODY_FIELD.match(currentFieldName)) { } else if (BODY_FIELD.match(currentFieldName)) {
request.body(templateParser.parse(parser)); request.body(templateParser.parse(parser));
} else { } else {
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]"); throw new ParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
} }
} else if (token == XContentParser.Token.VALUE_NUMBER) { } else if (token == XContentParser.Token.VALUE_NUMBER) {
if (PORT_FIELD.match(currentFieldName)) { if (PORT_FIELD.match(currentFieldName)) {
request.port(parser.intValue()); request.port(parser.intValue());
} else { } else {
throw new ElasticsearchParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]"); throw new ParseException("could not parse templated http request. unexpected field [" + currentFieldName + "]");
} }
} else { } else {
throw new ElasticsearchParseException("could not parse templated http request. unexpected token [" + token + "] for field [" + currentFieldName + "]"); throw new ParseException("could not parse templated http request. unexpected token [" + token + "] for field [" + currentFieldName + "]");
} }
} }
if (request.host == null) {
throw new ParseException("could not parse templated http request. missing required [host] string field");
}
if (request.port < 0) {
throw new ParseException("could not parse templated http request. missing required [port] numeric field");
}
return request; return request;
} }
@ -287,50 +302,65 @@ public class TemplatedHttpRequest implements ToXContent {
} }
public final static class SourceBuilder implements ToXContent { public final static class SourceBuilder implements ToXContent {
private String scheme; private String scheme;
private String host; private final String host;
private int port; private final int port;
private String method; private HttpMethod method;
private Template path; private Template.SourceBuilder path;
private Map<String, Template> params; private final ImmutableMap.Builder<String, Template.SourceBuilder> params = ImmutableMap.builder();
private Map<String, Template> headers; private final ImmutableMap.Builder<String, Template.SourceBuilder> headers = ImmutableMap.builder();
private HttpAuth auth; private HttpAuth auth;
private Template body; private Template.SourceBuilder body;
public SourceBuilder(String host, int port) {
this.host = host;
this.port = port;
}
public SourceBuilder setScheme(String scheme) { public SourceBuilder setScheme(String scheme) {
this.scheme = scheme; this.scheme = scheme;
return this; return this;
} }
public SourceBuilder setHost(String host) { public SourceBuilder setMethod(HttpMethod method) {
this.host = host;
return this;
}
public SourceBuilder setPort(int port) {
this.port = port;
return this;
}
public SourceBuilder setMethod(String method) {
this.method = method; this.method = method;
return this; return this;
} }
public SourceBuilder setPath(String path) {
return setPath(new ScriptTemplate.SourceBuilder(path));
}
public SourceBuilder setPath(Template path) { public SourceBuilder setPath(Template path) {
return path != null ? setPath(new Template.InstanceSourceBuilder(path)) : setPath((Template.SourceBuilder) null);
}
public SourceBuilder setPath(Template.SourceBuilder path) {
this.path = path; this.path = path;
return this; return this;
} }
public SourceBuilder setParams(Map<String, Template> params) { public SourceBuilder putParams(Map<String, Template.SourceBuilder> params) {
this.params = params; this.params.putAll(params);
return this; return this;
} }
public SourceBuilder setHeaders(Map<String, Template> headers) { public SourceBuilder putParam(String key, Template.SourceBuilder value) {
this.headers = headers; this.params.put(key, value);
return this;
}
public SourceBuilder putHeaders(Map<String, Template.SourceBuilder> headers) {
this.headers.putAll(headers);
return this;
}
public SourceBuilder putHeader(String key, Template.SourceBuilder value) {
this.headers.put(key, value);
return this; return this;
} }
@ -339,7 +369,27 @@ public class TemplatedHttpRequest implements ToXContent {
return this; return this;
} }
public SourceBuilder setBody(String body) {
return setBody(new ScriptTemplate.SourceBuilder(body));
}
public SourceBuilder setBody(ToXContent content) {
try {
return setBody(jsonBuilder().value(content));
} catch (IOException ioe) {
throw new WatcherException("could not set http input body to given xcontent", ioe);
}
}
public SourceBuilder setBody(XContentBuilder content) {
return setBody(new ScriptTemplate.SourceBuilder(content.bytes().toUtf8()));
}
public SourceBuilder setBody(Template body) { public SourceBuilder setBody(Template body) {
return body != null ? setBody(new Template.InstanceSourceBuilder(body)) : setBody((Template.SourceBuilder) null);
}
public SourceBuilder setBody(Template.SourceBuilder body) {
this.body = body; this.body = body;
return this; return this;
} }
@ -353,16 +403,18 @@ public class TemplatedHttpRequest implements ToXContent {
builder.field(Parser.HOST_FIELD.getPreferredName(), host); builder.field(Parser.HOST_FIELD.getPreferredName(), host);
builder.field(Parser.PORT_FIELD.getPreferredName(), port); builder.field(Parser.PORT_FIELD.getPreferredName(), port);
if (method != null) { if (method != null) {
builder.field(Parser.METHOD_FIELD.getPreferredName(), method); builder.field(Parser.METHOD_FIELD.getPreferredName(), method.name().toLowerCase(Locale.ROOT));
} }
if (path != null) { if (path != null) {
builder.field(Parser.PATH_FIELD.getPreferredName(), path); builder.field(Parser.PATH_FIELD.getPreferredName(), path);
} }
if (params != null) { Map<String, Template.SourceBuilder> paramsMap = params.build();
builder.field(Parser.PARAMS_FIELD.getPreferredName(), params); if (!paramsMap.isEmpty()) {
builder.field(Parser.PARAMS_FIELD.getPreferredName(), paramsMap);
} }
if (headers != null) { Map<String, Template.SourceBuilder> headersMap = headers.build();
builder.field(Parser.HEADERS_FIELD.getPreferredName(), headers); if (!headersMap.isEmpty()) {
builder.field(Parser.HEADERS_FIELD.getPreferredName(), headersMap);
} }
if (auth != null) { if (auth != null) {
builder.field(Parser.AUTH_FIELD.getPreferredName(), auth); builder.field(Parser.AUTH_FIELD.getPreferredName(), auth);
@ -370,8 +422,18 @@ public class TemplatedHttpRequest implements ToXContent {
if (body != null) { if (body != null) {
builder.field(Parser.BODY_FIELD.getPreferredName(), body); builder.field(Parser.BODY_FIELD.getPreferredName(), body);
} }
builder.endObject(); return builder.endObject();
return builder; }
}
public static class ParseException extends WatcherException {
public ParseException(String msg) {
super(msg);
}
public ParseException(String msg, Throwable cause) {
super(msg, cause);
} }
} }

View File

@ -5,8 +5,6 @@
*/ */
package org.elasticsearch.watcher.support.template; package org.elasticsearch.watcher.support.template;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.inject.Inject;
@ -16,10 +14,13 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ExecutableScript; import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.Map; import java.util.Map;
/** /**
@ -100,7 +101,7 @@ public class ScriptTemplate implements ToXContent, Template {
return new ScriptTemplate(scriptService, parser.text()); return new ScriptTemplate(scriptService, parser.text());
} }
try { try {
Script script = Script.parse(parser); Script script = Script.parse(parser, DEFAULT_LANG);
return new ScriptTemplate(scriptService, script); return new ScriptTemplate(scriptService, script);
} catch (Script.ParseException pe) { } catch (Script.ParseException pe) {
throw new ParseException("could not parse script template", pe); throw new ParseException("could not parse script template", pe);
@ -109,4 +110,49 @@ public class ScriptTemplate implements ToXContent, Template {
} }
} }
public static class SourceBuilder implements Template.SourceBuilder {
private final String script;
private String lang;
private ScriptService.ScriptType type;
private Map<String, Object> params;
public SourceBuilder(String script) {
this.script = script;
}
public SourceBuilder lang(String lang) {
this.lang = lang;
return this;
}
public SourceBuilder setType(ScriptService.ScriptType type) {
this.type = type;
return this;
}
public SourceBuilder setParams(Map<String, Object> params) {
this.params = params;
return this;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (lang == null && type == null && params == null) {
return builder.value(script);
}
builder.startObject();
builder.field(Script.SCRIPT_FIELD.getPreferredName(), script);
if (lang != null) {
builder.field(Script.LANG_FIELD.getPreferredName(), lang);
}
if (type != null) {
builder.field(Script.TYPE_FIELD.getPreferredName(), type.name().toLowerCase(Locale.ROOT));
}
if (this.params != null) {
builder.field(Script.PARAMS_FIELD.getPreferredName(), this.params);
}
return builder.endObject();
}
}
} }

View File

@ -5,9 +5,10 @@
*/ */
package org.elasticsearch.watcher.support.template; package org.elasticsearch.watcher.support.template;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.WatcherException;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -33,6 +34,22 @@ public interface Template extends ToXContent {
super(msg, cause); super(msg, cause);
} }
} }
}
interface SourceBuilder extends ToXContent {
}
class InstanceSourceBuilder implements SourceBuilder {
private final Template template;
public InstanceSourceBuilder(Template template) {
this.template = template;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return template.toXContent(builder, params);
}
} }
} }

View File

@ -5,9 +5,15 @@
*/ */
package org.elasticsearch.watcher.watch; package org.elasticsearch.watcher.watch;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.watcher.WatcherException; import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionRegistry; import org.elasticsearch.watcher.actions.ActionRegistry;
import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.condition.ConditionRegistry; import org.elasticsearch.watcher.condition.ConditionRegistry;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
@ -15,15 +21,8 @@ import org.elasticsearch.watcher.input.InputRegistry;
import org.elasticsearch.watcher.throttle.Throttler; import org.elasticsearch.watcher.throttle.Throttler;
import org.elasticsearch.watcher.transform.Transform; import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry; import org.elasticsearch.watcher.transform.TransformRegistry;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/** /**
* *
@ -34,13 +33,13 @@ public class WatchExecution implements ToXContent {
private final Condition.Result conditionResult; private final Condition.Result conditionResult;
private final Throttler.Result throttleResult; private final Throttler.Result throttleResult;
private final @Nullable Transform.Result transformResult; private final @Nullable Transform.Result transformResult;
private final Map<String, Action.Result> actionsResults; private final Actions.Results actionsResults;
public WatchExecution(WatchExecutionContext context) { public WatchExecution(WatchExecutionContext context) {
this(context.inputResult(), context.conditionResult(), context.throttleResult(), context.transformResult(), context.actionsResults()); this(context.inputResult(), context.conditionResult(), context.throttleResult(), context.transformResult(), context.actionsResults());
} }
WatchExecution(Input.Result inputResult, Condition.Result conditionResult, Throttler.Result throttleResult, @Nullable Transform.Result transformResult, Map<String, Action.Result> actionsResults) { WatchExecution(Input.Result inputResult, Condition.Result conditionResult, Throttler.Result throttleResult, @Nullable Transform.Result transformResult, Actions.Results actionsResults) {
this.inputResult = inputResult; this.inputResult = inputResult;
this.conditionResult = conditionResult; this.conditionResult = conditionResult;
this.throttleResult = throttleResult; this.throttleResult = throttleResult;
@ -64,7 +63,7 @@ public class WatchExecution implements ToXContent {
return transformResult; return transformResult;
} }
public Map<String, Action.Result> actionsResults() { public Actions.Results actionsResults() {
return actionsResults; return actionsResults;
} }
@ -86,13 +85,11 @@ public class WatchExecution implements ToXContent {
if (transformResult != null) { if (transformResult != null) {
builder.startObject(Transform.Parser.TRANSFORM_RESULT_FIELD.getPreferredName()).field(transformResult.type(), transformResult).endObject(); builder.startObject(Transform.Parser.TRANSFORM_RESULT_FIELD.getPreferredName()).field(transformResult.type(), transformResult).endObject();
} }
builder.startArray(Parser.ACTIONS_RESULTS.getPreferredName()); builder.startObject(Parser.ACTIONS_RESULTS.getPreferredName());
for (Map.Entry<String, Action.Result> actionResult : actionsResults.entrySet()) { for (ActionWrapper.Result actionResult : actionsResults) {
builder.startObject(); builder.field(actionResult.id(), actionResult);
builder.field(actionResult.getKey(), actionResult.getValue());
builder.endObject();
} }
builder.endArray(); builder.endObject();
builder.endObject(); builder.endObject();
return builder; return builder;
} }
@ -109,7 +106,7 @@ public class WatchExecution implements ToXContent {
InputRegistry inputRegistry, TransformRegistry transformRegistry) throws IOException { InputRegistry inputRegistry, TransformRegistry transformRegistry) throws IOException {
boolean throttled = false; boolean throttled = false;
String throttleReason = null; String throttleReason = null;
Map<String, Action.Result> actionResults = new HashMap<>(); Actions.Results actionResults = null;
Input.Result inputResult = null; Input.Result inputResult = null;
Condition.Result conditionResult = null; Condition.Result conditionResult = null;
Transform.Result transformResult = null; Transform.Result transformResult = null;
@ -134,12 +131,8 @@ public class WatchExecution implements ToXContent {
conditionResult = conditionRegistry.parseResult(parser); conditionResult = conditionRegistry.parseResult(parser);
} else if (Transform.Parser.TRANSFORM_RESULT_FIELD.match(currentFieldName)) { } else if (Transform.Parser.TRANSFORM_RESULT_FIELD.match(currentFieldName)) {
transformResult = transformRegistry.parseResult(parser); transformResult = transformRegistry.parseResult(parser);
} else { } else if (ACTIONS_RESULTS.match(currentFieldName)) {
throw new WatcherException("unable to parse watch execution. unexpected field [" + currentFieldName + "]"); actionResults = actionRegistry.parseResults(parser);
}
} else if (token == XContentParser.Token.START_ARRAY) {
if (ACTIONS_RESULTS.match(currentFieldName)) {
actionResults = parseActionResults(parser, actionRegistry);
} else { } else {
throw new WatcherException("unable to parse watch execution. unexpected field [" + currentFieldName + "]"); throw new WatcherException("unable to parse watch execution. unexpected field [" + currentFieldName + "]");
} }
@ -152,15 +145,5 @@ public class WatchExecution implements ToXContent {
return new WatchExecution(inputResult, conditionResult, throttleResult, transformResult, actionResults); return new WatchExecution(inputResult, conditionResult, throttleResult, transformResult, actionResults);
} }
private static Map<String, Action.Result> parseActionResults(XContentParser parser, ActionRegistry actionRegistry) throws IOException {
Map<String, Action.Result> actionResults = new HashMap<>();
XContentParser.Token token;
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
Action.Result actionResult = actionRegistry.parseResult(parser);
actionResults.put(actionResult.type(), actionResult);
}
return actionResults;
}
} }
} }

View File

@ -6,7 +6,8 @@
package org.elasticsearch.watcher.watch; package org.elasticsearch.watcher.watch;
import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.joda.time.DateTime;
import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.throttle.Throttler; import org.elasticsearch.watcher.throttle.Throttler;
@ -30,7 +31,7 @@ public class WatchExecutionContext {
private Condition.Result conditionResult; private Condition.Result conditionResult;
private Throttler.Result throttleResult; private Throttler.Result throttleResult;
private Transform.Result transformResult; private Transform.Result transformResult;
private Map<String, Action.Result> actionsResults = new HashMap<>(); private Map<String, ActionWrapper.Result> actionsResults = new HashMap<>();
private Payload payload; private Payload payload;
@ -101,12 +102,12 @@ public class WatchExecutionContext {
return transformResult; return transformResult;
} }
public void onActionResult(Action.Result result) { public void onActionResult(ActionWrapper.Result result) {
actionsResults.put(result.type(), result); actionsResults.put(result.id(), result);
} }
public Map<String, Action.Result> actionsResults() { public Actions.Results actionsResults() {
return actionsResults; return new Actions.Results(actionsResults);
} }
public WatchExecution finish() { public WatchExecution finish() {

View File

@ -15,13 +15,10 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.ActionSettingsException; import org.elasticsearch.watcher.actions.ActionSettingsException;
import org.elasticsearch.watcher.actions.TransformMocks;
import org.elasticsearch.watcher.actions.email.service.*; import org.elasticsearch.watcher.actions.email.service.*;
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;
import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry;
import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.elasticsearch.watcher.watch.WatchExecutionContext;
import org.junit.Test; import org.junit.Test;
@ -64,8 +61,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
Template textBody = randomBoolean() ? null : mock(Template.class); Template textBody = randomBoolean() ? null : mock(Template.class);
Template htmlBody = randomBoolean() ? null : mock(Template.class); Template htmlBody = randomBoolean() ? null : mock(Template.class);
boolean attachPayload = randomBoolean(); boolean attachPayload = randomBoolean();
Transform transform = randomBoolean() ? null : mock(Transform.class); EmailAction action = new EmailAction(logger, service, email, auth, profile, account, subject, textBody, htmlBody, attachPayload);
EmailAction action = new EmailAction(logger, transform, service, email, auth, profile, account, subject, textBody, htmlBody, attachPayload);
final Map<String, Object> data = new HashMap<>(); final Map<String, Object> data = new HashMap<>();
Payload payload = new Payload() { Payload payload = new Payload() {
@ -85,16 +81,10 @@ public class EmailActionTests extends ElasticsearchTestCase {
String ctxId = randomAsciiOfLength(5); String ctxId = randomAsciiOfLength(5);
WatchExecutionContext ctx = mockExecutionContext("watch1", now, payload); WatchExecutionContext ctx = mockExecutionContext("watch1", now, payload);
when(ctx.id()).thenReturn(ctxId); when(ctx.id()).thenReturn(ctxId);
if (transform != null) {
Transform.Result transformResult = mock(Transform.Result.class);
when(transformResult.type()).thenReturn("_transform_type");
when(transformResult.payload()).thenReturn(new Payload.Simple("_key", "_value"));
when(transform.apply(ctx, payload)).thenReturn(transformResult);
}
Map<String, Object> expectedModel = ImmutableMap.<String, Object>builder() Map<String, Object> expectedModel = ImmutableMap.<String, Object>builder()
.put("ctx", ImmutableMap.<String, Object>builder() .put("ctx", ImmutableMap.<String, Object>builder()
.put("watch_name", "watch1") .put("watch_name", "watch1")
.put("payload", transform == null ? data : new Payload.Simple("_key", "_value").data()) .put("payload", data)
.put("execution_time", now) .put("execution_time", now)
.put("trigger", ImmutableMap.<String, Object>builder() .put("trigger", ImmutableMap.<String, Object>builder()
.put("triggered_time", now) .put("triggered_time", now)
@ -113,7 +103,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
when (htmlBody.render(expectedModel)).thenReturn("_html_body"); when (htmlBody.render(expectedModel)).thenReturn("_html_body");
} }
EmailAction.Result result = action.execute(ctx); EmailAction.Result result = action.execute("_id", ctx, payload);
assertThat(result, notNullValue()); assertThat(result, notNullValue());
assertThat(result, instanceOf(EmailAction.Result.Success.class)); assertThat(result, instanceOf(EmailAction.Result.Success.class));
@ -129,11 +119,6 @@ public class EmailActionTests extends ElasticsearchTestCase {
if (attachPayload) { if (attachPayload) {
assertThat(actualEmail.attachments(), hasKey("payload")); assertThat(actualEmail.attachments(), hasKey("payload"));
} }
if (transform != null) {
assertThat(result.transformResult(), notNullValue());
assertThat(result.transformResult().type(), equalTo("_transform_type"));
assertThat(result.transformResult().payload().data(), equalTo(new Payload.Simple("_key", "_value").data()));
}
} }
@Test @Repeat(iterations = 20) @Test @Repeat(iterations = 20)
@ -149,8 +134,6 @@ public class EmailActionTests extends ElasticsearchTestCase {
ScriptTemplate subject = randomBoolean() ? new ScriptTemplate(scriptService, "_subject") : null; ScriptTemplate subject = randomBoolean() ? new ScriptTemplate(scriptService, "_subject") : null;
ScriptTemplate textBody = randomBoolean() ? new ScriptTemplate(scriptService, "_text_body") : null; ScriptTemplate textBody = randomBoolean() ? new ScriptTemplate(scriptService, "_text_body") : null;
ScriptTemplate htmlBody = randomBoolean() ? new ScriptTemplate(scriptService, "_text_html") : null; ScriptTemplate htmlBody = randomBoolean() ? new ScriptTemplate(scriptService, "_text_html") : null;
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
boolean attachPayload = randomBoolean(); boolean attachPayload = randomBoolean();
XContentBuilder builder = jsonBuilder().startObject() XContentBuilder builder = jsonBuilder().startObject()
.field("account", "_account") .field("account", "_account")
@ -209,17 +192,12 @@ public class EmailActionTests extends ElasticsearchTestCase {
builder.field("html_body", htmlBody); builder.field("html_body", htmlBody);
} }
} }
if (transform != null) {
builder.startObject("transform")
.startObject("_transform").endObject()
.endObject();
}
BytesReference bytes = builder.bytes(); BytesReference bytes = builder.bytes();
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
parser.nextToken(); parser.nextToken();
EmailAction action = new EmailAction.Parser(ImmutableSettings.EMPTY, emailService, EmailAction action = new EmailAction.Parser(ImmutableSettings.EMPTY, emailService,
new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService), transformRegistry).parse(parser); new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService)).parse(parser);
assertThat(action, notNullValue()); assertThat(action, notNullValue());
assertThat(action.account, is("_account")); assertThat(action.account, is("_account"));
@ -251,10 +229,6 @@ public class EmailActionTests extends ElasticsearchTestCase {
} else { } else {
assertThat(action.emailPrototype.replyTo(), nullValue()); assertThat(action.emailPrototype.replyTo(), nullValue());
} }
if (transform != null) {
assertThat(action.transform(), notNullValue());
assertThat(action.transform(), equalTo(transform));
}
} }
@Test @Repeat(iterations = 20) @Test @Repeat(iterations = 20)
@ -284,10 +258,8 @@ public class EmailActionTests extends ElasticsearchTestCase {
Template textBody = new TemplateMock("_text_body"); Template textBody = new TemplateMock("_text_body");
Template htmlBody = randomBoolean() ? null : new TemplateMock("_html_body"); Template htmlBody = randomBoolean() ? null : new TemplateMock("_html_body");
boolean attachPayload = randomBoolean(); boolean attachPayload = randomBoolean();
Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
EmailAction action = new EmailAction(logger, transform, service, email, auth, profile, account, subject, textBody, htmlBody, attachPayload); EmailAction action = new EmailAction(logger, service, email, auth, profile, account, subject, textBody, htmlBody, attachPayload);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
action.toXContent(builder, Attachment.XContent.EMPTY_PARAMS); action.toXContent(builder, Attachment.XContent.EMPTY_PARAMS);
@ -295,7 +267,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
System.out.println(bytes.toUtf8()); System.out.println(bytes.toUtf8());
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
parser.nextToken(); parser.nextToken();
EmailAction parsed = new EmailAction.Parser(ImmutableSettings.EMPTY,service, new TemplateMock.Parser(), transformRegistry).parse(parser); EmailAction parsed = new EmailAction.Parser(ImmutableSettings.EMPTY,service, new TemplateMock.Parser()).parse(parser);
assertThat(parsed, equalTo(action)); assertThat(parsed, equalTo(action));
} }
@ -309,7 +281,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
BytesReference bytes = builder.bytes(); BytesReference bytes = builder.bytes();
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
new EmailAction.Parser(ImmutableSettings.EMPTY, emailService, new EmailAction.Parser(ImmutableSettings.EMPTY, emailService,
new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService), mock(TransformRegistry.class)).parse(parser); new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService)).parse(parser);
} }
@Test @Repeat(iterations = 20) @Test @Repeat(iterations = 20)
@ -323,25 +295,11 @@ public class EmailActionTests extends ElasticsearchTestCase {
.textBody("_text_body") .textBody("_text_body")
.build(); .build();
Transform.Result transformResult = randomBoolean() ? null : mock(Transform.Result.class);
if (transformResult != null) {
when(transformResult.type()).thenReturn("_transform_type");
when(transformResult.payload()).thenReturn(new Payload.Simple("_key", "_value"));
}
TransformRegistry transformRegistry = transformResult != null ? new TransformMocks.TransformRegistryMock(transformResult) : mock(TransformRegistry.class);
XContentBuilder builder = jsonBuilder().startObject() XContentBuilder builder = jsonBuilder().startObject()
.field("success", success); .field("success", success);
if (success) { if (success) {
builder.field("email", email); builder.field("email", email);
builder.field("account", "_account"); builder.field("account", "_account");
if (transformResult != null) {
builder.startObject("transform_result")
.startObject("_transform_type")
.field("payload", new Payload.Simple("_key", "_value").data())
.endObject()
.endObject();
}
} else { } else {
builder.field("reason", "_reason"); builder.field("reason", "_reason");
} }
@ -349,20 +307,13 @@ public class EmailActionTests extends ElasticsearchTestCase {
BytesReference bytes = builder.bytes(); BytesReference bytes = builder.bytes();
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
parser.nextToken(); parser.nextToken();
EmailAction.Result result = new EmailAction.Parser(ImmutableSettings.EMPTY, mock(EmailService.class), new TemplateMock.Parser(), transformRegistry) EmailAction.Result result = new EmailAction.Parser(ImmutableSettings.EMPTY, mock(EmailService.class), new TemplateMock.Parser())
.parseResult(parser); .parseResult(parser);
assertThat(result.success(), is(success)); assertThat(result.success(), is(success));
if (success) { if (success) {
assertThat(result, instanceOf(EmailAction.Result.Success.class)); assertThat(result, instanceOf(EmailAction.Result.Success.class));
assertThat(((EmailAction.Result.Success) result).email(), equalTo(email)); assertThat(((EmailAction.Result.Success) result).email(), equalTo(email));
assertThat(((EmailAction.Result.Success) result).account(), is("_account")); assertThat(((EmailAction.Result.Success) result).account(), is("_account"));
if (transformResult != null) {
assertThat(result.transformResult(), notNullValue());
assertThat(result.transformResult().type(), equalTo("_transform_type"));
assertThat(result.transformResult().payload().data(), equalTo(new Payload.Simple("_key", "_value").data()));
} else {
assertThat(result.transformResult(), nullValue());
}
} else { } else {
assertThat(result, instanceOf(EmailAction.Result.Failure.class)); assertThat(result, instanceOf(EmailAction.Result.Failure.class));
assertThat(((EmailAction.Result.Failure) result).reason(), is("_reason")); assertThat(((EmailAction.Result.Failure) result).reason(), is("_reason"));
@ -377,7 +328,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
BytesReference bytes = builder.bytes(); BytesReference bytes = builder.bytes();
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes); XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
parser.nextToken(); parser.nextToken();
new EmailAction.Parser(ImmutableSettings.EMPTY, mock(EmailService.class), new TemplateMock.Parser(), mock(TransformRegistry.class)) new EmailAction.Parser(ImmutableSettings.EMPTY, mock(EmailService.class), new TemplateMock.Parser())
.parseResult(parser); .parseResult(parser);
} }

View File

@ -15,7 +15,6 @@ import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.watcher.actions.ActionException; import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.TransformMocks;
import org.elasticsearch.watcher.actions.email.service.Authentication; 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;
@ -24,8 +23,6 @@ import org.elasticsearch.watcher.support.http.HttpClient;
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.test.WatcherTestUtils; import org.elasticsearch.watcher.test.WatcherTestUtils;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.Watch;
@ -38,9 +35,8 @@ import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource; import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.hamcrest.Matchers.*; import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock; import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
/** /**
*/ */
@ -49,7 +45,7 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
@Test @Test
public void testIndexActionExecute() throws Exception { public void testIndexActionExecute() throws Exception {
IndexAction action = new IndexAction(logger, null, ClientProxy.of(client()), "test-index", "test-type"); IndexAction action = new IndexAction(logger, ClientProxy.of(client()), "test-index", "test-type");
final String account = "account1"; final String account = "account1";
Watch alert = WatcherTestUtils.createTestWatch("testAlert", Watch alert = WatcherTestUtils.createTestWatch("testAlert",
ClientProxy.of(client()), ClientProxy.of(client()),
@ -71,7 +67,7 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
Map<String, Object> payloadMap = new HashMap<>(); Map<String, Object> payloadMap = new HashMap<>();
payloadMap.put("test", "foo"); payloadMap.put("test", "foo");
IndexAction.Result result = action.execute(ctx, new Payload.Simple(payloadMap)); IndexAction.Result result = action.execute("_id", ctx, new Payload.Simple(payloadMap));
assertThat(result.success(), equalTo(true)); assertThat(result.success(), equalTo(true));
Map<String, Object> responseData = result.response().data(); Map<String, Object> responseData = result.response().data();
@ -91,20 +87,13 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
@Test @Repeat(iterations = 10) @Test @Repeat(iterations = 10)
public void testParser() throws Exception { public void testParser() throws Exception {
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
builder.startObject(); builder.startObject()
{ .field(IndexAction.Parser.INDEX_FIELD.getPreferredName(), "test-index")
builder.field(IndexAction.Parser.INDEX_FIELD.getPreferredName(), "test-index"); .field(IndexAction.Parser.TYPE_FIELD.getPreferredName(), "test-type")
builder.field(IndexAction.Parser.TYPE_FIELD.getPreferredName(), "test-type"); .endObject();
if (transform != null){
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName()).field(transform.type(), transform);
}
}
builder.endObject();
IndexAction.Parser actionParser = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()), transformRegistry); IndexAction.Parser actionParser = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()));
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
@ -112,13 +101,6 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
assertThat(action.type, equalTo("test-type")); assertThat(action.type, equalTo("test-type"));
assertThat(action.index, equalTo("test-index")); assertThat(action.index, equalTo("test-index"));
if (transform != null) {
assertThat(action.transform(), notNullValue());
assertThat(action.transform(), equalTo(transform));
} else {
assertThat(action.transform(), nullValue());
}
} }
@Test @Repeat(iterations = 10) @Test @Repeat(iterations = 10)
@ -136,7 +118,7 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
} }
} }
builder.endObject(); builder.endObject();
IndexAction.Parser actionParser = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()), null); IndexAction.Parser actionParser = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()));
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
try { try {
@ -153,13 +135,6 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
public void testParser_Result() throws Exception { public void testParser_Result() throws Exception {
boolean success = randomBoolean(); boolean success = randomBoolean();
Transform.Result transformResult = randomBoolean() ? null : mock(Transform.Result.class);
if (transformResult != null) {
when(transformResult.type()).thenReturn("_transform_type");
when(transformResult.payload()).thenReturn(new Payload.Simple("_key", "_value"));
}
TransformRegistry transformRegistry = transformResult != null ? new TransformMocks.TransformRegistryMock(transformResult) : mock(TransformRegistry.class);
XContentBuilder builder = jsonBuilder().startObject() XContentBuilder builder = jsonBuilder().startObject()
.field("success", success); .field("success", success);
if (success) { if (success) {
@ -169,22 +144,14 @@ public class IndexActionTests extends ElasticsearchIntegrationTest {
data.put("version", 1); data.put("version", 1);
data.put("type", "test-type"); data.put("type", "test-type");
data.put("index", "test-index"); data.put("index", "test-index");
builder.field(IndexAction.Parser.RESPONSE_FIELD.getPreferredName(), data); builder.field(IndexAction.Parser.RESPONSE_FIELD.getPreferredName(), data);
if (transformResult != null) {
builder.startObject("transform_result")
.startObject("_transform_type")
.field("payload", new Payload.Simple("_key", "_value").data())
.endObject()
.endObject();
}
} else { } else {
builder.field("reason", "_reason"); builder.field("reason", "_reason");
} }
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
IndexAction.Result result = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()), transformRegistry) IndexAction.Result result = new IndexAction.Parser(ImmutableSettings.EMPTY, ClientProxy.of(client()))
.parseResult(parser); .parseResult(parser);
assertThat(result.success(), is(success)); assertThat(result.success(), is(success));

View File

@ -24,11 +24,7 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.ResourceWatcherService; import org.elasticsearch.watcher.ResourceWatcherService;
import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionException; import org.elasticsearch.watcher.actions.ActionException;
import org.elasticsearch.watcher.actions.TransformMocks; import org.elasticsearch.watcher.actions.email.service.*;
import org.elasticsearch.watcher.actions.email.service.Authentication;
import org.elasticsearch.watcher.actions.email.service.Email;
import org.elasticsearch.watcher.actions.email.service.EmailService;
import org.elasticsearch.watcher.actions.email.service.Profile;
import org.elasticsearch.watcher.support.http.*; import org.elasticsearch.watcher.support.http.*;
import org.elasticsearch.watcher.support.http.auth.BasicAuth; import org.elasticsearch.watcher.support.http.auth.BasicAuth;
import org.elasticsearch.watcher.support.http.auth.HttpAuth; import org.elasticsearch.watcher.support.http.auth.HttpAuth;
@ -38,8 +34,6 @@ import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
import org.elasticsearch.watcher.support.template.ScriptTemplate; import org.elasticsearch.watcher.support.template.ScriptTemplate;
import org.elasticsearch.watcher.support.template.Template; import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.test.WatcherTestUtils; import org.elasticsearch.watcher.test.WatcherTestUtils;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.TransformRegistry;
import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent; import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.Watch;
@ -51,9 +45,7 @@ import org.junit.Test;
import javax.mail.internet.AddressException; import javax.mail.internet.AddressException;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
@ -71,6 +63,7 @@ import static org.mockito.Mockito.when;
public class WebhookActionTests extends ElasticsearchTestCase { public class WebhookActionTests extends ElasticsearchTestCase {
static final String TEST_HOST = "test.com"; static final String TEST_HOST = "test.com";
static final int TEST_PORT = 8089;
private ThreadPool tp = null; private ThreadPool tp = null;
private ScriptServiceProxy scriptService; private ScriptServiceProxy scriptService;
@ -108,29 +101,37 @@ public class WebhookActionTests extends ElasticsearchTestCase {
HttpClient httpClient = scenario.client(); HttpClient httpClient = scenario.client();
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT); HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT);
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
final String account = "account1"; final String account = "account1";
TemplatedHttpRequest httpRequest = getTemplatedHttpRequest(method, TEST_HOST, testPath, testBody); TemplatedHttpRequest httpRequest = getTemplatedHttpRequest(method, TEST_HOST, TEST_PORT, testPath, testBody);
WebhookAction webhookAction = WebhookAction webhookAction = new WebhookAction(logger, httpClient, httpRequest);
new WebhookAction(logger,
transform,
httpClient,
httpRequest);
Watch watch = createWatch("test_watch", client, account); Watch watch = createWatch("test_watch", client, account);
WatchExecutionContext ctx = new WatchExecutionContext("testid", watch, new DateTime(), new ScheduleTriggerEvent(new DateTime(), new DateTime())); WatchExecutionContext ctx = new WatchExecutionContext("testid", watch, new DateTime(), new ScheduleTriggerEvent(new DateTime(), new DateTime()));
WebhookAction.Result actionResult = webhookAction.execute(ctx, new Payload.Simple()); WebhookAction.Result actionResult = webhookAction.execute("_id", ctx, new Payload.Simple());
scenario.assertResult(actionResult); scenario.assertResult(actionResult);
} }
private TemplatedHttpRequest getTemplatedHttpRequest(HttpMethod method, String host, Template path, Template body) { private TemplatedHttpRequest.SourceBuilder getTemplatedHttpRequestSourceBuilder(HttpMethod method, String host, int port, Template path, Template body) {
TemplatedHttpRequest httpRequest = new TemplatedHttpRequest(); TemplatedHttpRequest.SourceBuilder httpRequest = new TemplatedHttpRequest.SourceBuilder(host, port);
if (host != null) { if (path != null) {
httpRequest.host(host); httpRequest.setPath(path);
} }
if (body != null) {
httpRequest.setBody(body);
}
if (method != null) {
httpRequest.setMethod(method);
}
return httpRequest;
}
private TemplatedHttpRequest getTemplatedHttpRequest(HttpMethod method, String host, int port, Template path, Template body) {
TemplatedHttpRequest httpRequest = new TemplatedHttpRequest();
httpRequest.host(host);
httpRequest.port(port);
if (path != null) { if (path != null) {
httpRequest.path(path); httpRequest.path(path);
} }
@ -146,27 +147,16 @@ public class WebhookActionTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 10) @Test @Repeat(iterations = 10)
public void testParser() throws Exception { public void testParser() throws Exception {
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_subject") : null; Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_subject") : null;
Template path = new ScriptTemplate(scriptService, "_url"); Template path = new ScriptTemplate(scriptService, "_url");
String host = "test.host"; String host = "test.host";
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null); HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null);
TemplatedHttpRequest request = getTemplatedHttpRequest(method, host, path, body); TemplatedHttpRequest request = getTemplatedHttpRequest(method, host, TEST_PORT, path, body);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
builder.startObject(); request.toXContent(builder, Attachment.XContent.EMPTY_PARAMS);
{
builder.field(WebhookAction.Parser.REQUEST_FIELD.getPreferredName(), request);
if (transform != null) { WebhookAction.Parser actionParser = getParser(ExecuteScenario.Success.client());
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform);
}
}
builder.endObject();
WebhookAction.Parser actionParser = getParser(transformRegistry, ExecuteScenario.Success.client() );
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
@ -174,28 +164,22 @@ public class WebhookActionTests extends ElasticsearchTestCase {
WebhookAction action = actionParser.parse(parser); WebhookAction action = actionParser.parse(parser);
assertThat(action.templatedHttpRequest(), equalTo(request)); assertThat(action.templatedHttpRequest(), equalTo(request));
if (transform != null) {
assertThat(action.transform(), equalTo(transform));
}
} }
@Test @Repeat(iterations = 10) @Test @Repeat(iterations = 10)
public void testParser_SelfGenerated() throws Exception { public void testParser_SelfGenerated() throws Exception {
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_body") : null; Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_body") : null;
Template path = new ScriptTemplate(scriptService, "_url"); Template path = new ScriptTemplate(scriptService, "_url");
String host = "test.host"; String host = "test.host";
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null); HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null);
TemplatedHttpRequest request = getTemplatedHttpRequest(method, host, path, body); TemplatedHttpRequest request = getTemplatedHttpRequest(method, host, TEST_PORT, path, body);
WebhookAction webhookAction = new WebhookAction(logger, transform, ExecuteScenario.Success.client(), request); WebhookAction webhookAction = new WebhookAction(logger, ExecuteScenario.Success.client(), request);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
webhookAction.toXContent(builder, ToXContent.EMPTY_PARAMS); webhookAction.toXContent(builder, ToXContent.EMPTY_PARAMS);
WebhookAction.Parser actionParser = getParser(transformRegistry, ExecuteScenario.Success.client()); WebhookAction.Parser actionParser = getParser(ExecuteScenario.Success.client());
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
@ -203,93 +187,70 @@ public class WebhookActionTests extends ElasticsearchTestCase {
WebhookAction action = actionParser.parse(parser); WebhookAction action = actionParser.parse(parser);
assertThat(action.templatedHttpRequest(), equalTo(request)); assertThat(action.templatedHttpRequest(), equalTo(request));
if (transform != null) {
assertThat(action.transform(), equalTo(transform));
} }
} @Test //@Repeat(iterations = 10)
@Test @Repeat(iterations = 10)
public void testParser_SourceBuilder() throws Exception { public void testParser_SourceBuilder() throws Exception {
Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_body") : null; Template body = randomBoolean() ? new ScriptTemplate(scriptService, "_body") : null;
Template path = new ScriptTemplate(scriptService, "_url"); Template path = new ScriptTemplate(scriptService, "_url");
String host = "test.host"; String host = "test.host";
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null); HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, null);
TemplatedHttpRequest request = getTemplatedHttpRequest(method, host, path, body); TemplatedHttpRequest.SourceBuilder request = getTemplatedHttpRequestSourceBuilder(method, host, TEST_PORT, path, body);
WebhookAction.SourceBuilder sourceBuilder = new WebhookAction.SourceBuilder(request); WebhookAction.SourceBuilder sourceBuilder = new WebhookAction.SourceBuilder("_id", request);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
sourceBuilder.toXContent(builder, ToXContent.EMPTY_PARAMS); sourceBuilder.toXContent(builder, ToXContent.EMPTY_PARAMS);
WebhookAction.Parser actionParser = getParser(null, ExecuteScenario.Success.client()); WebhookAction.Parser actionParser = getParser(ExecuteScenario.Success.client());
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); assertThat(parser.nextToken(), is(XContentParser.Token.START_OBJECT));
assertThat(parser.nextToken(), is(XContentParser.Token.FIELD_NAME));
Map<String, Object> emptyModel = new HashMap<>(); assertThat(parser.currentName(), is(WebhookAction.TYPE));
assertThat(parser.nextToken(), is(XContentParser.Token.START_OBJECT));
WebhookAction parsedAction = actionParser.parse(parser); WebhookAction parsedAction = actionParser.parse(parser);
assertThat(request, equalTo(parsedAction.templatedHttpRequest())); assertThat(parsedAction.templatedHttpRequest().host(), equalTo(host));
assertThat(parsedAction.templatedHttpRequest().port(), equalTo(TEST_PORT));
assertThat(parsedAction.templatedHttpRequest().path(), equalTo(path));
assertThat(parsedAction.templatedHttpRequest().body(), equalTo(body));
} }
@Test(expected = ActionException.class) @Test(expected = ActionException.class)
public void testParser_Failure() throws Exception { public void testParser_Failure() throws Exception {
final Transform transform = randomBoolean() ? null : new TransformMocks.TransformMock();
TransformRegistry transformRegistry = transform == null ? mock(TransformRegistry.class) : new TransformMocks.TransformRegistryMock(transform);
XContentBuilder builder = jsonBuilder();
builder.startObject();
{
if (transform != null) {
builder.startObject(Transform.Parser.TRANSFORM_FIELD.getPreferredName())
.field(transform.type(), transform);
}
}
builder.endObject();
WebhookAction.Parser actionParser = getParser(transformRegistry, ExecuteScenario.Success.client());
XContentBuilder builder = jsonBuilder().startObject().endObject();
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes()); XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken(); parser.nextToken();
WebhookAction.Parser actionParser = getParser(ExecuteScenario.Success.client());
//This should fail since we are not supplying a url //This should fail since we are not supplying a url
actionParser.parse(parser); actionParser.parse(parser);
} }
@Test @Repeat(iterations = 30) @Test @Repeat(iterations = 30)
public void testParser_Result() throws Exception { public void testParser_Result() throws Exception {
Transform.Result transformResult = randomBoolean() ? null : mock(Transform.Result.class);
if (transformResult != null) {
when(transformResult.type()).thenReturn("_transform_type");
when(transformResult.payload()).thenReturn(new Payload.Simple("_key", "_value"));
}
TransformRegistry transformRegistry = transformResult != null ? new TransformMocks.TransformRegistryMock(transformResult) : mock(TransformRegistry.class);
String body = "_body"; String body = "_body";
String host = "test.host"; String host = "test.host";
String path = "/_url"; String path = "/_url";
String reason = "_reason"; String reason = "_reason";
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT); HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT);
byte[] responseBody = new byte[randomIntBetween(1,100)]; HttpRequest request = new HttpRequest();
for (int i = 0; i < responseBody.length; ++i) { request.host(host);
responseBody[i] = randomByte(); request.body(body);
} request.path(path);
request.method(method);
HttpRequest httpRequest = new HttpRequest(); HttpResponse response = new HttpResponse(randomIntBetween(200, 599), randomAsciiOfLength(10).getBytes(UTF8));
httpRequest.host(host);
httpRequest.body(body);
httpRequest.path(path);
httpRequest.method(method);
int responseCode = randomIntBetween(200, 599);
boolean error = randomBoolean(); boolean error = randomBoolean();
boolean success = !error && responseCode < 400; boolean success = !error && response.status() < 400;
HttpClient client = ExecuteScenario.Success.client(); HttpClient client = ExecuteScenario.Success.client();
WebhookAction.Parser actionParser = getParser(transformRegistry, client); WebhookAction.Parser actionParser = getParser(client);
XContentBuilder builder = jsonBuilder(); XContentBuilder builder = jsonBuilder();
@ -297,16 +258,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
{ {
builder.field(Action.Result.SUCCESS_FIELD.getPreferredName(), success); builder.field(Action.Result.SUCCESS_FIELD.getPreferredName(), success);
if (!error) { if (!error) {
builder.field(WebhookAction.Parser.HTTP_STATUS_FIELD.getPreferredName(), responseCode); builder.field(WebhookAction.Parser.REQUEST_FIELD.getPreferredName(), request);
builder.field(WebhookAction.Parser.RESPONSE_BODY.getPreferredName(), responseBody); builder.field(WebhookAction.Parser.RESPONSE_FIELD.getPreferredName(), response);
builder.field(WebhookAction.Parser.REQUEST_FIELD.getPreferredName(), httpRequest);
if (transformResult != null) {
builder.startObject("transform_result")
.startObject("_transform_type")
.field("payload", new Payload.Simple("_key", "_value").data())
.endObject()
.endObject();
}
} else { } else {
builder.field(WebhookAction.Parser.REASON_FIELD.getPreferredName(), reason); builder.field(WebhookAction.Parser.REASON_FIELD.getPreferredName(), reason);
} }
@ -322,12 +275,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
if (!error) { if (!error) {
assertThat(result, instanceOf(WebhookAction.Result.Executed.class)); assertThat(result, instanceOf(WebhookAction.Result.Executed.class));
WebhookAction.Result.Executed executedResult = (WebhookAction.Result.Executed) result; WebhookAction.Result.Executed executedResult = (WebhookAction.Result.Executed) result;
assertThat(executedResult.responseBody(), equalTo(responseBody)); assertThat(executedResult.request(), equalTo(request));
assertThat(executedResult.httpStatus(), equalTo(responseCode)); assertThat(executedResult.response(), equalTo(response));
assertThat(executedResult.httpRequest(), equalTo(httpRequest));
if (transformResult != null) {
assertThat(transformResult, equalTo(executedResult.transformResult()));
}
} else { } else {
assertThat(result, Matchers.instanceOf(WebhookAction.Result.Failure.class)); assertThat(result, Matchers.instanceOf(WebhookAction.Result.Failure.class));
WebhookAction.Result.Failure failedResult = (WebhookAction.Result.Failure) result; WebhookAction.Result.Failure failedResult = (WebhookAction.Result.Failure) result;
@ -335,9 +284,9 @@ public class WebhookActionTests extends ElasticsearchTestCase {
} }
} }
private WebhookAction.Parser getParser(TransformRegistry transformRegistry, HttpClient client) { private WebhookAction.Parser getParser(HttpClient client) {
return new WebhookAction.Parser(ImmutableSettings.EMPTY, return new WebhookAction.Parser(ImmutableSettings.EMPTY,
client, transformRegistry, new HttpRequest.Parser(authRegistry), client, new HttpRequest.Parser(authRegistry),
new TemplatedHttpRequest.Parser(new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService), new TemplatedHttpRequest.Parser(new ScriptTemplate.Parser(ImmutableSettings.EMPTY, scriptService),
authRegistry) ); authRegistry) );
} }
@ -349,20 +298,14 @@ public class WebhookActionTests extends ElasticsearchTestCase {
HttpMethod method = HttpMethod.POST; HttpMethod method = HttpMethod.POST;
Template path = new ScriptTemplate(scriptService, "/test_{{ctx.watch_name}}"); Template path = new ScriptTemplate(scriptService, "/test_{{ctx.watch_name}}");
String host = "test.host"; String host = "test.host";
TemplatedHttpRequest templatedHttpRequest = getTemplatedHttpRequest(method, host, path, testBody); TemplatedHttpRequest templatedHttpRequest = getTemplatedHttpRequest(method, host, TEST_PORT, path, testBody);
WebhookAction webhookAction =
new WebhookAction(logger,
null,
httpClient,
templatedHttpRequest);
WebhookAction webhookAction = new WebhookAction(logger, httpClient, templatedHttpRequest);
String watchName = "test_url_encode" + randomAsciiOfLength(10); String watchName = "test_url_encode" + randomAsciiOfLength(10);
Watch watch = createWatch(watchName, mock(ClientProxy.class), "account1"); Watch watch = createWatch(watchName, mock(ClientProxy.class), "account1");
WatchExecutionContext ctx = new WatchExecutionContext("testid", watch, new DateTime(), new ScheduleTriggerEvent(new DateTime(), new DateTime())); WatchExecutionContext ctx = new WatchExecutionContext("testid", watch, new DateTime(), new ScheduleTriggerEvent(new DateTime(), new DateTime()));
WebhookAction.Result result = webhookAction.execute(ctx, new Payload.Simple()); WebhookAction.Result result = webhookAction.execute("_id", ctx, new Payload.Simple());
assertThat(result, Matchers.instanceOf(WebhookAction.Result.Executed.class)); assertThat(result, Matchers.instanceOf(WebhookAction.Result.Executed.class));
} }
@ -386,13 +329,12 @@ public class WebhookActionTests extends ElasticsearchTestCase {
} }
private static enum ExecuteScenario { private enum ExecuteScenario {
ErrorCode() { ErrorCode() {
@Override @Override
public HttpClient client() throws IOException { public HttpClient client() throws IOException {
HttpClient client = mock(HttpClient.class); HttpClient client = mock(HttpClient.class);
when(client.execute(any(HttpRequest.class))) when(client.execute(any(HttpRequest.class))).thenReturn(new HttpResponse(randomIntBetween(400, 599)));
.thenReturn(new HttpResponse(randomIntBetween(400,599)));
return client; return client;
} }
@ -401,10 +343,10 @@ public class WebhookActionTests extends ElasticsearchTestCase {
assertThat(actionResult.success(), is(false)); assertThat(actionResult.success(), is(false));
assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class)); assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class));
WebhookAction.Result.Executed executedActionResult = (WebhookAction.Result.Executed) actionResult; WebhookAction.Result.Executed executedActionResult = (WebhookAction.Result.Executed) actionResult;
assertThat(executedActionResult.httpStatus(), greaterThanOrEqualTo(400)); assertThat(executedActionResult.response().status(), greaterThanOrEqualTo(400));
assertThat(executedActionResult.httpStatus(), lessThanOrEqualTo(599)); assertThat(executedActionResult.response().status(), lessThanOrEqualTo(599));
assertThat(executedActionResult.httpRequest().body(), equalTo(TEST_BODY_STRING)); assertThat(executedActionResult.request().body(), equalTo(TEST_BODY_STRING));
assertThat(executedActionResult.httpRequest().path(), equalTo(TEST_PATH_STRING)); assertThat(executedActionResult.request().path(), equalTo(TEST_PATH_STRING));
} }
}, },
@ -439,10 +381,10 @@ public class WebhookActionTests extends ElasticsearchTestCase {
assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class)); assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class));
assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class)); assertThat(actionResult, instanceOf(WebhookAction.Result.Executed.class));
WebhookAction.Result.Executed executedActionResult = (WebhookAction.Result.Executed) actionResult; WebhookAction.Result.Executed executedActionResult = (WebhookAction.Result.Executed) actionResult;
assertThat(executedActionResult.httpStatus(), greaterThanOrEqualTo(200)); assertThat(executedActionResult.response().status(), greaterThanOrEqualTo(200));
assertThat(executedActionResult.httpStatus(), lessThanOrEqualTo(399)); assertThat(executedActionResult.response().status(), lessThanOrEqualTo(399));
assertThat(executedActionResult.httpRequest().body(), equalTo(TEST_BODY_STRING)); assertThat(executedActionResult.request().body(), equalTo(TEST_BODY_STRING));
assertThat(executedActionResult.httpRequest().path(), equalTo(TEST_PATH_STRING)); assertThat(executedActionResult.request().path(), equalTo(TEST_PATH_STRING));
} }
}; };

View File

@ -12,6 +12,7 @@ import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.test.ElasticsearchTestCase; import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.Condition; import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.condition.simple.AlwaysFalseCondition; import org.elasticsearch.watcher.condition.simple.AlwaysFalseCondition;
import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
@ -67,6 +68,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
when(transformResult.payload()).thenReturn(payload); when(transformResult.payload()).thenReturn(payload);
Action.Result actionResult = mock(Action.Result.class); Action.Result actionResult = mock(Action.Result.class);
when(actionResult.type()).thenReturn("_action_type"); when(actionResult.type()).thenReturn("_action_type");
ActionWrapper.Result watchActionResult = new ActionWrapper.Result("_id", null, actionResult);
Condition condition = mock(Condition.class); Condition condition = mock(Condition.class);
when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult); when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult);
@ -74,8 +76,8 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult); when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult);
Transform transform = mock(Transform.class); Transform transform = mock(Transform.class);
when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult); when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult);
Action action = mock(Action.class); ActionWrapper action = mock(ActionWrapper.class);
when(action.execute(any(WatchExecutionContext.class))).thenReturn(actionResult); when(action.execute(any(WatchExecutionContext.class))).thenReturn(watchActionResult);
Actions actions = new Actions(Arrays.asList(action)); Actions actions = new Actions(Arrays.asList(action));
Watch.Status watchStatus = new Watch.Status(); Watch.Status watchStatus = new Watch.Status();
@ -95,7 +97,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult));
assertThat(watchExecution.transformResult(), sameInstance(transformResult)); assertThat(watchExecution.transformResult(), sameInstance(transformResult));
assertThat(watchExecution.throttleResult(), sameInstance(throttleResult)); assertThat(watchExecution.throttleResult(), sameInstance(throttleResult));
assertThat(watchExecution.actionsResults().get("_action_type"), sameInstance(actionResult)); assertThat(watchExecution.actionsResults().get("_id"), sameInstance(watchActionResult));
verify(condition, times(1)).execute(any(WatchExecutionContext.class)); verify(condition, times(1)).execute(any(WatchExecutionContext.class));
verify(throttler, times(1)).throttle(any(WatchExecutionContext.class)); verify(throttler, times(1)).throttle(any(WatchExecutionContext.class));
@ -111,8 +113,8 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
Transform.Result transformResult = mock(Transform.Result.class); Transform.Result transformResult = mock(Transform.Result.class);
when(transformResult.payload()).thenReturn(payload); when(transformResult.payload()).thenReturn(payload);
Action.Result actionResult = mock(Action.Result.class); ActionWrapper.Result actionResult = mock(ActionWrapper.Result.class);
when(actionResult.type()).thenReturn("_action_type"); when(actionResult.id()).thenReturn("_id");
Condition condition = mock(Condition.class); Condition condition = mock(Condition.class);
when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult); when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult);
@ -120,7 +122,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult); when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult);
Transform transform = mock(Transform.class); Transform transform = mock(Transform.class);
when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult); when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult);
Action action = mock(Action.class); ActionWrapper action = mock(ActionWrapper.class);
when(action.execute(any(WatchExecutionContext.class))).thenReturn(actionResult); when(action.execute(any(WatchExecutionContext.class))).thenReturn(actionResult);
Actions actions = new Actions(Arrays.asList(action)); Actions actions = new Actions(Arrays.asList(action));
@ -141,7 +143,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
assertThat(watchExecution.inputResult(), sameInstance(inputResult)); assertThat(watchExecution.inputResult(), sameInstance(inputResult));
assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult));
assertThat(watchExecution.throttleResult(), sameInstance(throttleResult)); assertThat(watchExecution.throttleResult(), sameInstance(throttleResult));
assertThat(watchExecution.actionsResults().isEmpty(), is(true)); assertThat(watchExecution.actionsResults().count(), is(0));
assertThat(watchExecution.transformResult(), nullValue()); assertThat(watchExecution.transformResult(), nullValue());
verify(condition, times(1)).execute(any(WatchExecutionContext.class)); verify(condition, times(1)).execute(any(WatchExecutionContext.class));
@ -157,8 +159,8 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
when(throttleResult.throttle()).thenReturn(true); when(throttleResult.throttle()).thenReturn(true);
Transform.Result transformResult = mock(Transform.Result.class); Transform.Result transformResult = mock(Transform.Result.class);
Action.Result actionResult = mock(Action.Result.class); ActionWrapper.Result actionResult = mock(ActionWrapper.Result.class);
when(actionResult.type()).thenReturn("_action_type"); when(actionResult.id()).thenReturn("_id");
Condition condition = mock(Condition.class); Condition condition = mock(Condition.class);
when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult); when(condition.execute(any(WatchExecutionContext.class))).thenReturn(conditionResult);
@ -166,7 +168,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult); when(throttler.throttle(any(WatchExecutionContext.class))).thenReturn(throttleResult);
Transform transform = mock(Transform.class); Transform transform = mock(Transform.class);
when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult); when(transform.apply(any(WatchExecutionContext.class), same(payload))).thenReturn(transformResult);
Action action = mock(Action.class); ActionWrapper action = mock(ActionWrapper.class);
when(action.execute(any(WatchExecutionContext.class))).thenReturn(actionResult); when(action.execute(any(WatchExecutionContext.class))).thenReturn(actionResult);
Actions actions = new Actions(Arrays.asList(action)); Actions actions = new Actions(Arrays.asList(action));
@ -188,7 +190,7 @@ public class HistoryServiceTests extends ElasticsearchTestCase {
assertThat(watchExecution.conditionResult(), sameInstance(conditionResult)); assertThat(watchExecution.conditionResult(), sameInstance(conditionResult));
assertThat(watchExecution.throttleResult(), nullValue()); assertThat(watchExecution.throttleResult(), nullValue());
assertThat(watchExecution.transformResult(), nullValue()); assertThat(watchExecution.transformResult(), nullValue());
assertThat(watchExecution.actionsResults().isEmpty(), is(true)); assertThat(watchExecution.actionsResults().count(), is(0));
verify(condition, times(1)).execute(any(WatchExecutionContext.class)); verify(condition, times(1)).execute(any(WatchExecutionContext.class));
verify(throttler, never()).throttle(any(WatchExecutionContext.class)); verify(throttler, never()).throttle(any(WatchExecutionContext.class));

View File

@ -9,6 +9,7 @@ import org.elasticsearch.common.joda.time.DateTime;
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.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.email.EmailAction; import org.elasticsearch.watcher.actions.email.EmailAction;
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;
@ -17,6 +18,7 @@ import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.simple.SimpleInput; import org.elasticsearch.watcher.input.simple.SimpleInput;
import org.elasticsearch.watcher.support.http.HttpRequest; import org.elasticsearch.watcher.support.http.HttpRequest;
import org.elasticsearch.watcher.support.http.HttpResponse;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
import org.elasticsearch.watcher.test.WatcherTestUtils; import org.elasticsearch.watcher.test.WatcherTestUtils;
import org.elasticsearch.watcher.throttle.Throttler; import org.elasticsearch.watcher.throttle.Throttler;
@ -55,13 +57,13 @@ public class WatchRecordTests extends AbstractWatcherIntegrationTests {
ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC)); ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC));
WatchRecord watchRecord = new WatchRecord(watch, event); WatchRecord watchRecord = new WatchRecord(watch, event);
WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event); WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event);
ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah")); ctx.onActionResult(new ActionWrapper.Result("_email", new EmailAction.Result.Failure("failed to send because blah")));
HttpRequest request = new HttpRequest(); HttpRequest request = new HttpRequest();
request.host("localhost"); request.host("localhost");
request.port(8000); request.port(8000);
request.path("/watchfoo"); request.path("/watchfoo");
request.body("{'awesome' : 'us'}"); request.body("{'awesome' : 'us'}");
ctx.onActionResult(new WebhookAction.Result.Executed(300, request, new byte[0])); ctx.onActionResult(new ActionWrapper.Result("_webhook", new WebhookAction.Result.Executed(request, new HttpResponse(300))));
Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple()); Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple());
Condition.Result conditionResult = AlwaysTrueCondition.RESULT; Condition.Result conditionResult = AlwaysTrueCondition.RESULT;
ctx.onThrottleResult(Throttler.NO_THROTTLE.throttle(ctx)); ctx.onThrottleResult(Throttler.NO_THROTTLE.throttle(ctx));
@ -85,13 +87,13 @@ public class WatchRecordTests extends AbstractWatcherIntegrationTests {
ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC)); ScheduleTriggerEvent event = new ScheduleTriggerEvent(DateTime.now(UTC), DateTime.now(UTC));
WatchRecord watchRecord = new WatchRecord(watch, event); WatchRecord watchRecord = new WatchRecord(watch, event);
WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event); WatchExecutionContext ctx = new WatchExecutionContext(watchRecord.id(), watch, new DateTime(), event);
ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah")); ctx.onActionResult(new ActionWrapper.Result("_email", new EmailAction.Result.Failure("failed to send because blah")));
HttpRequest request = new HttpRequest(); HttpRequest request = new HttpRequest();
request.host("localhost"); request.host("localhost");
request.port(8000); request.port(8000);
request.path("/watchfoo"); request.path("/watchfoo");
request.body("{'awesome' : 'us'}"); request.body("{'awesome' : 'us'}");
ctx.onActionResult(new WebhookAction.Result.Executed(300, request, new byte[0])); ctx.onActionResult(new ActionWrapper.Result("_webhook", new WebhookAction.Result.Executed(request, new HttpResponse(300))));
Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple()); Input.Result inputResult = new SimpleInput.Result(SimpleInput.TYPE, new Payload.Simple());
Condition.Result conditionResult = AlwaysFalseCondition.RESULT; Condition.Result conditionResult = AlwaysFalseCondition.RESULT;
ctx.onThrottleResult(Throttler.NO_THROTTLE.throttle(ctx)); ctx.onThrottleResult(Throttler.NO_THROTTLE.throttle(ctx));

View File

@ -16,8 +16,8 @@ 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.test.ElasticsearchTestCase; import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.InputBuilders; import org.elasticsearch.watcher.input.InputBuilders;
@ -34,18 +34,18 @@ import org.elasticsearch.watcher.trigger.schedule.ScheduleTriggerEvent;
import org.elasticsearch.watcher.watch.Payload; import org.elasticsearch.watcher.watch.Payload;
import org.elasticsearch.watcher.watch.Watch; import org.elasticsearch.watcher.watch.Watch;
import org.elasticsearch.watcher.watch.WatchExecutionContext; import org.elasticsearch.watcher.watch.WatchExecutionContext;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anyMap;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -82,8 +82,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
request.body(mockBody); request.body(mockBody);
HttpInput input = new HttpInput(logger, httpClient, request, null); HttpInput input = new HttpInput(logger, httpClient, request, null);
HttpResponse response = new HttpResponse(123); HttpResponse response = new HttpResponse(123, "{\"key\" : \"value\"}".getBytes(UTF8));
response.inputStream(new ByteArrayInputStream("{\"key\" : \"value\"}".getBytes(UTF8)));
when(httpClient.execute(any(HttpRequest.class))).thenReturn(response); when(httpClient.execute(any(HttpRequest.class))).thenReturn(response);
Watch watch = new Watch("test-watch", Watch watch = new Watch("test-watch",
@ -92,7 +91,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
new SimpleInput(logger, new Payload.Simple()), new SimpleInput(logger, new Payload.Simple()),
new AlwaysTrueCondition(logger), new AlwaysTrueCondition(logger),
null, null,
new Actions(new ArrayList<Action>()), new Actions(new ArrayList<ActionWrapper>()),
null, null,
null, null,
new Watch.Status()); new Watch.Status());
@ -105,40 +104,48 @@ public class HttpInputTests extends ElasticsearchTestCase {
assertThat(result.payload().data(), equalTo(MapBuilder.<String, Object>newMapBuilder().put("key", "value").map())); assertThat(result.payload().data(), equalTo(MapBuilder.<String, Object>newMapBuilder().put("key", "value").map()));
} }
@Test @Test @Repeat(iterations = 20)
@Repeat(iterations = 12)
public void testParser() throws Exception { public void testParser() throws Exception {
final String httpMethod = randomFrom("PUT", "POST", "GET", "DELETE", "HEAD", null); final HttpMethod httpMethod = rarely() ? null : randomFrom(HttpMethod.values());
String scheme = randomFrom("http", "https", null); String scheme = randomFrom("http", "https", null);
String host = randomAsciiOfLength(3); String host = randomAsciiOfLength(3);
int port = randomInt(); int port = randomIntBetween(8000, 9000);
Template path = new MockTemplate(randomAsciiOfLength(3)); String path = randomAsciiOfLength(3);
Template.SourceBuilder pathTemplate = mockTemplateSourceBuilder(path);
String body = randomBoolean() ? randomAsciiOfLength(3) : null; 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.SourceBuilder> params = randomBoolean() ? new MapBuilder<String, Template.SourceBuilder>().put("a", mockTemplateSourceBuilder("b")).map() : null;
Map<String, Template> headers = randomBoolean() ? new MapBuilder<String, Template>().put("c", new MockTemplate("d")).map() : null; Map<String, Template.SourceBuilder> headers = randomBoolean() ? new MapBuilder<String, Template.SourceBuilder>().put("c", mockTemplateSourceBuilder("d")).map() : null;
HttpAuth auth = randomBoolean() ? new BasicAuth("username", "password") : null; HttpAuth auth = randomBoolean() ? new BasicAuth("username", "password") : null;
TemplatedHttpRequest.SourceBuilder requestSource = new TemplatedHttpRequest.SourceBuilder() TemplatedHttpRequest.SourceBuilder requestSource = new TemplatedHttpRequest.SourceBuilder(host, port)
.setScheme(scheme) .setScheme(scheme)
.setMethod(httpMethod) .setMethod(httpMethod)
.setHost(host) .setPath(pathTemplate)
.setPort(port)
.setPath(path)
.setBody(body != null ? new MockTemplate(body) : null) .setBody(body != null ? new MockTemplate(body) : null)
.setParams(params)
.setHeaders(headers)
.setAuth(auth); .setAuth(auth);
if (params != null) {
requestSource.putParams(params);
}
if (headers != null) {
requestSource.putHeaders(headers);
}
XContentParser parser = XContentHelper.createParser(jsonBuilder().value(InputBuilders.httpInput(requestSource)).bytes()); XContentParser parser = XContentHelper.createParser(jsonBuilder().value(InputBuilders.httpInput(requestSource)).bytes());
parser.nextToken(); parser.nextToken();
HttpInput result = httpParser.parse(parser); HttpInput result = httpParser.parse(parser);
assertThat(result.type(), equalTo(HttpInput.TYPE)); assertThat(result.type(), equalTo(HttpInput.TYPE));
assertThat(result.getRequest().scheme().scheme(), equalTo(scheme != null ? scheme : "http")); // http is the default assertThat(result.getRequest().scheme().scheme(), equalTo(scheme != null ? scheme : "http")); // http is the default
assertThat(result.getRequest().method().method(), equalTo(httpMethod != null ? httpMethod : "GET")); // get is the default assertThat(result.getRequest().method(), equalTo(httpMethod != null ? httpMethod : HttpMethod.GET)); // get is the default
assertThat(result.getRequest().host(), equalTo(host)); assertThat(result.getRequest().host(), equalTo(host));
assertThat(result.getRequest().port(), equalTo(port)); assertThat(result.getRequest().port(), equalTo(port));
assertThat(result.getRequest().path(), equalTo(path)); assertThat(result.getRequest().path(), isTemplate(path));
assertThat(result.getRequest().params(), equalTo(params)); if (params != null) {
assertThat(result.getRequest().headers(), equalTo(headers)); assertThat(result.getRequest().params(), hasEntry(is("a"), isTemplate("b")));
}
if (headers != null) {
assertThat(result.getRequest().headers(), hasEntry(is("c"), isTemplate("d")));
}
assertThat(result.getRequest().auth(), equalTo(auth)); assertThat(result.getRequest().auth(), equalTo(auth));
if (body != null) { if (body != null) {
assertThat(result.getRequest().body().render(Collections.<String, Object>emptyMap()), equalTo(body)); assertThat(result.getRequest().body().render(Collections.<String, Object>emptyMap()), equalTo(body));
@ -149,14 +156,13 @@ public class HttpInputTests extends ElasticsearchTestCase {
@Test(expected = ElasticsearchIllegalArgumentException.class) @Test(expected = ElasticsearchIllegalArgumentException.class)
public void testParser_invalidHttpMethod() throws Exception { public void testParser_invalidHttpMethod() throws Exception {
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", new MockTemplate("b")).map(); XContentBuilder builder = jsonBuilder().startObject()
TemplatedHttpRequest.SourceBuilder requestBuilder = new TemplatedHttpRequest.SourceBuilder() .startObject("request")
.setMethod("_method") .field("method", "_method")
.setHost("_host") .field("body", "_body")
.setPort(123) .endObject()
.setBody(new MockTemplate("_body")) .endObject();
.setHeaders(headers); XContentParser parser = XContentHelper.createParser(builder.bytes());
XContentParser parser = XContentHelper.createParser(jsonBuilder().value(InputBuilders.httpInput(requestBuilder)).bytes());
parser.nextToken(); parser.nextToken();
httpParser.parse(parser); httpParser.parse(parser);
} }
@ -165,7 +171,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
public void testParseResult() throws Exception { public void testParseResult() throws Exception {
String httpMethod = "get"; String httpMethod = "get";
String body = "_body"; String body = "_body";
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", new MockTemplate("b")).map(); Map<String, Template.SourceBuilder> headers = new MapBuilder<String, Template.SourceBuilder>().put("a", mockTemplateSourceBuilder("b")).map();
HttpRequest.SourceBuilder sourceBuilder = new HttpRequest.SourceBuilder() HttpRequest.SourceBuilder sourceBuilder = new HttpRequest.SourceBuilder()
.setMethod(httpMethod) .setMethod(httpMethod)
.setHost("_host") .setHost("_host")
@ -189,14 +195,20 @@ public class HttpInputTests extends ElasticsearchTestCase {
assertThat(result.statusCode(), equalTo(123)); assertThat(result.statusCode(), equalTo(123));
assertThat(result.request().method().method(), equalTo("GET")); assertThat(result.request().method().method(), equalTo("GET"));
assertThat(result.request().headers().size(), equalTo(headers.size())); assertThat(result.request().headers().size(), equalTo(headers.size()));
for (Map.Entry<String, Template> entry : headers.entrySet()) { assertThat(result.request().headers(), hasEntry("a", (Object) "b"));
assertThat(entry.getValue().render(Collections.<String, Object>emptyMap()), equalTo(result.request().headers().get(entry.getKey())));
}
assertThat(result.request().host(), equalTo("_host")); assertThat(result.request().host(), equalTo("_host"));
assertThat(result.request().port(), equalTo(123)); assertThat(result.request().port(), equalTo(123));
assertThat(result.request().body(), equalTo("_body")); assertThat(result.request().body(), equalTo("_body"));
} }
private static Template mockTemplate(String value) {
return new MockTemplate(value);
}
private static Template.SourceBuilder mockTemplateSourceBuilder(String value) {
return new Template.InstanceSourceBuilder(new MockTemplate(value));
}
private static class MockTemplate implements Template { private static class MockTemplate implements Template {
private final String value; private final String value;
@ -240,7 +252,29 @@ public class HttpInputTests extends ElasticsearchTestCase {
return new MockTemplate(value); return new MockTemplate(value);
} }
} }
}
static MockTemplateMatcher isTemplate(String value) {
return new MockTemplateMatcher(value);
}
static class MockTemplateMatcher extends BaseMatcher<Template> {
private final String value;
public MockTemplateMatcher(String value) {
this.value = value;
}
@Override
public boolean matches(Object item) {
return item instanceof MockTemplate && ((MockTemplate) item).value.equals(value);
}
@Override
public void describeTo(Description description) {
description.appendText("is mock template [" + value + "]");
}
} }
} }

View File

@ -19,8 +19,8 @@ import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptService;
import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition; import org.elasticsearch.watcher.condition.simple.AlwaysTrueCondition;
import org.elasticsearch.watcher.input.Input; import org.elasticsearch.watcher.input.Input;
import org.elasticsearch.watcher.input.InputException; import org.elasticsearch.watcher.input.InputException;
@ -74,7 +74,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest {
new SimpleInput(logger, new Payload.Simple()), new SimpleInput(logger, new Payload.Simple()),
new AlwaysTrueCondition(logger), new AlwaysTrueCondition(logger),
null, null,
new Actions(new ArrayList<Action>()), new Actions(new ArrayList<ActionWrapper>()),
null, null,
null, null,
new Watch.Status()), new Watch.Status()),
@ -111,7 +111,7 @@ public class SearchInputTests extends ElasticsearchIntegrationTest {
new SimpleInput(logger, new Payload.Simple()), new SimpleInput(logger, new Payload.Simple()),
new AlwaysTrueCondition(logger), new AlwaysTrueCondition(logger),
null, null,
new Actions(new ArrayList<Action>()), new Actions(new ArrayList<ActionWrapper>()),
null, null,
null, null,
new Watch.Status()), new Watch.Status()),

View File

@ -82,7 +82,7 @@ public class HttpClientTest extends ElasticsearchTestCase {
RecordedRequest recordedRequest = webServer.takeRequest(); RecordedRequest recordedRequest = webServer.takeRequest();
assertThat(response.status(), equalTo(responseCode)); assertThat(response.status(), equalTo(responseCode));
assertThat(new String(response.body(), Charsets.UTF_8), equalTo(body)); assertThat(response.body().toUtf8(), equalTo(body));
assertThat(webServer.getRequestCount(), equalTo(1)); assertThat(webServer.getRequestCount(), equalTo(1));
assertThat(recordedRequest.getBody().readString(Charsets.UTF_8), equalTo(request.body())); assertThat(recordedRequest.getBody().readString(Charsets.UTF_8), equalTo(request.body()));
assertThat(recordedRequest.getPath().split("\\?")[0], equalTo(request.path())); assertThat(recordedRequest.getPath().split("\\?")[0], equalTo(request.path()));
@ -102,7 +102,7 @@ public class HttpClientTest extends ElasticsearchTestCase {
request.body("body"); request.body("body");
HttpResponse response = httpClient.execute(request); HttpResponse response = httpClient.execute(request);
assertThat(response.status(), equalTo(200)); assertThat(response.status(), equalTo(200));
assertThat(new String(response.body(), Charsets.UTF_8), equalTo("body")); assertThat(response.body().toUtf8(), equalTo("body"));
RecordedRequest recordedRequest = webServer.takeRequest(); RecordedRequest recordedRequest = webServer.takeRequest();
assertThat(recordedRequest.getHeader("Authorization"), equalTo("Basic dXNlcjpwYXNz")); assertThat(recordedRequest.getHeader("Authorization"), equalTo("Basic dXNlcjpwYXNz"));
} }
@ -127,7 +127,7 @@ public class HttpClientTest extends ElasticsearchTestCase {
request.body("body"); request.body("body");
HttpResponse response = httpClient.execute(request); HttpResponse response = httpClient.execute(request);
assertThat(response.status(), equalTo(200)); assertThat(response.status(), equalTo(200));
assertThat(new String(response.body(), Charsets.UTF_8), equalTo("body")); assertThat(response.body().toUtf8(), equalTo("body"));
RecordedRequest recordedRequest = webServer.takeRequest(); RecordedRequest recordedRequest = webServer.takeRequest();
assertThat(recordedRequest.getBody().readUtf8Line(), equalTo("body")); assertThat(recordedRequest.getBody().readUtf8Line(), equalTo("body"));
} }

View File

@ -244,18 +244,18 @@ public abstract class AbstractWatcherIntegrationTests extends ElasticsearchInteg
builder.endObject(); builder.endObject();
builder.startArray("actions"); builder.startObject("actions");
{ {
builder.startObject(); builder.startObject("_action_id");
{ {
builder.startObject("index"); builder.startObject("index")
builder.field("index", "my-index"); .field("index", "my-index")
builder.field("type", "trail"); .field("type", "trail")
builder.endObject(); .endObject();
} }
builder.endObject(); builder.endObject();
} }
builder.endArray(); builder.endObject();
} }
builder.endObject(); builder.endObject();

View File

@ -15,8 +15,8 @@ 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;
import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.email.EmailAction; import org.elasticsearch.watcher.actions.email.EmailAction;
import org.elasticsearch.watcher.actions.email.service.Authentication; import org.elasticsearch.watcher.actions.email.service.Authentication;
import org.elasticsearch.watcher.actions.email.service.Email; import org.elasticsearch.watcher.actions.email.service.Email;
@ -123,7 +123,7 @@ public final class WatcherTestUtils {
transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE); transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE);
conditionRequest.searchType(SearchInput.DEFAULT_SEARCH_TYPE); conditionRequest.searchType(SearchInput.DEFAULT_SEARCH_TYPE);
List<Action> actions = new ArrayList<>(); List<ActionWrapper> actions = new ArrayList<>();
TemplatedHttpRequest httpRequest = new TemplatedHttpRequest(); TemplatedHttpRequest httpRequest = new TemplatedHttpRequest();
@ -134,7 +134,7 @@ public final class WatcherTestUtils {
httpRequest.host("localhost"); httpRequest.host("localhost");
httpRequest.method(HttpMethod.POST); httpRequest.method(HttpMethod.POST);
actions.add(new WebhookAction(logger, null, httpClient, httpRequest)); actions.add(new ActionWrapper("_webhook", new WebhookAction(logger, httpClient, httpRequest)));
Email.Address from = new Email.Address("from@test.com"); Email.Address from = new Email.Address("from@test.com");
List<Email.Address> emailAddressList = new ArrayList<>(); List<Email.Address> emailAddressList = new ArrayList<>();
@ -147,10 +147,10 @@ public final class WatcherTestUtils {
emailBuilder.to(to); emailBuilder.to(to);
EmailAction emailAction = new EmailAction(logger, null, emailService, emailBuilder.build(), EmailAction emailAction = new EmailAction(logger, emailService, emailBuilder.build(),
new Authentication("testname", "testpassword"), Profile.STANDARD, "testaccount", body, body, null, true); new Authentication("testname", "testpassword"), Profile.STANDARD, "testaccount", body, body, null, true);
actions.add(emailAction); actions.add(new ActionWrapper("_email", emailAction));
Map<String, Object> metadata = new LinkedHashMap<>(); Map<String, Object> metadata = new LinkedHashMap<>();
metadata.put("foo", "bar"); metadata.put("foo", "bar");

View File

@ -127,7 +127,7 @@ public class WatcherBenchmark {
.addExtractKey("hits.total") .addExtractKey("hits.total")
) )
.condition(scriptCondition("1 == 1")) .condition(scriptCondition("1 == 1"))
.addAction(indexAction("index", "type"))); .addAction(indexAction("_id", "index", "type")));
putAlertRequest.setName(name); putAlertRequest.setName(name);
watcherClient.putWatch(putAlertRequest).actionGet(); watcherClient.putWatch(putAlertRequest).actionGet();
} }
@ -169,7 +169,7 @@ public class WatcherBenchmark {
final String name = "_name" + i; final String name = "_name" + i;
PutWatchRequest putAlertRequest = new PutWatchRequest(name, new WatchSourceBuilder() PutWatchRequest putAlertRequest = new PutWatchRequest(name, new WatchSourceBuilder()
.trigger(schedule(interval("5s"))) .trigger(schedule(interval("5s")))
.input(httpInput(new TemplatedHttpRequest.SourceBuilder().setHost("localhost").setPort(9200))) .input(httpInput(new TemplatedHttpRequest.SourceBuilder("localhost", 9200)))
.condition(scriptCondition("ctx.payload.tagline == \"You Know, for Search\""))); .condition(scriptCondition("ctx.payload.tagline == \"You Know, for Search\"")));
putAlertRequest.setName(name); putAlertRequest.setName(name);
watcherClient.putWatch(putAlertRequest).actionGet(); watcherClient.putWatch(putAlertRequest).actionGet();

View File

@ -35,7 +35,7 @@ import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
import static org.elasticsearch.watcher.input.InputBuilders.searchInput; import static org.elasticsearch.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.watcher.test.WatcherTestUtils.newInputSearchRequest; import static org.elasticsearch.watcher.test.WatcherTestUtils.newInputSearchRequest;
@ -56,7 +56,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
refresh(); refresh();
SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value"))); SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value")));
watcherClient.preparePutWatch("_name") watcherClient.preparePutWatch("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest)) .input(searchInput(searchRequest))
.condition(scriptCondition("ctx.payload.hits.total == 1"))) .condition(scriptCondition("ctx.payload.hits.total == 1")))
@ -79,7 +79,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
WatcherClient watcherClient = watcherClient(); WatcherClient watcherClient = watcherClient();
SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value"))); SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value")));
watcherClient.preparePutWatch("_name") watcherClient.preparePutWatch("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest)) .input(searchInput(searchRequest))
.condition(scriptCondition("ctx.payload.hits.total == 1"))) .condition(scriptCondition("ctx.payload.hits.total == 1")))
@ -110,7 +110,7 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
WatcherClient watcherClient = watcherClient(); WatcherClient watcherClient = watcherClient();
SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(matchAllQuery())); SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(matchAllQuery()));
PutWatchResponse indexResponse = watcherClient.preparePutWatch("_name") PutWatchResponse indexResponse = watcherClient.preparePutWatch("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest)) .input(searchInput(searchRequest))
.condition(scriptCondition("ctx.payload.hits.total == 1"))) .condition(scriptCondition("ctx.payload.hits.total == 1")))
@ -178,10 +178,10 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
SearchRequest searchRequest = newInputSearchRequest("idx") SearchRequest searchRequest = newInputSearchRequest("idx")
.source(searchSource().query(matchAllQuery())); .source(searchSource().query(matchAllQuery()));
WatchSourceBuilder source = watchSourceBuilder() WatchSourceBuilder source = watchBuilder()
.trigger(schedule(interval("5s"))) .trigger(schedule(interval("5s")))
.input(searchInput(searchRequest)) .input(searchInput(searchRequest))
.addAction(indexAction("idx", "action")); .addAction(indexAction("_id", "idx", "action"));
watcherClient().preparePutWatch("_name") watcherClient().preparePutWatch("_name")
.source(source.condition(scriptCondition("ctx.payload.hits.total == 1"))) .source(source.condition(scriptCondition("ctx.payload.hits.total == 1")))
@ -270,14 +270,14 @@ public class BasicWatcherTests extends AbstractWatcherIntegrationTests {
refresh(); refresh();
SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value"))); SearchRequest searchRequest = newInputSearchRequest("idx").source(searchSource().query(termQuery("field", "value")));
watcherClient.preparePutWatch("_name1") watcherClient.preparePutWatch("_name1")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest).addExtractKey("hits.total")) .input(searchInput(searchRequest).addExtractKey("hits.total"))
.condition(scriptCondition("ctx.payload.hits.total == 1"))) .condition(scriptCondition("ctx.payload.hits.total == 1")))
.get(); .get();
// in this watcher the condition will fail, because max_score isn't extracted, only total: // in this watcher the condition will fail, because max_score isn't extracted, only total:
watcherClient.preparePutWatch("_name2") watcherClient.preparePutWatch("_name2")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(searchRequest).addExtractKey("hits.total")) .input(searchInput(searchRequest).addExtractKey("hits.total"))
.condition(scriptCondition("ctx.payload.hits.max_score >= 0"))) .condition(scriptCondition("ctx.payload.hits.max_score >= 0")))

View File

@ -15,8 +15,8 @@ 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.test.junit.annotations.TestLogging; import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.condition.script.ScriptCondition; import org.elasticsearch.watcher.condition.script.ScriptCondition;
import org.elasticsearch.watcher.history.HistoryStore; import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.history.WatchRecord; import org.elasticsearch.watcher.history.WatchRecord;
@ -88,7 +88,7 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests {
new SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest, null), new SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest, null),
new ScriptCondition(logger, scriptService(), new Script("return true")), new ScriptCondition(logger, scriptService(), new Script("return true")),
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest), new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
new Actions(new ArrayList<Action>()), new Actions(new ArrayList<ActionWrapper>()),
null, // metadata null, // metadata
new TimeValue(0), new TimeValue(0),
new Watch.Status()); new Watch.Status());
@ -149,7 +149,7 @@ public class BootStrapTests extends AbstractWatcherIntegrationTests {
searchRequest, null), searchRequest, null),
new ScriptCondition(logger, scriptService(), new Script("return true")), new ScriptCondition(logger, scriptService(), new Script("return true")),
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest), new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
new Actions(new ArrayList<Action>()), new Actions(new ArrayList<ActionWrapper>()),
null, // metatdata null, // metatdata
new TimeValue(0), new TimeValue(0),
new Watch.Status()); new Watch.Status());

View File

@ -9,17 +9,14 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
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.xcontent.XContentBuilder;
import org.elasticsearch.node.internal.InternalNode; import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.watcher.client.WatchSourceBuilder;
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.input.InputBuilders;
import org.elasticsearch.watcher.support.http.TemplatedHttpRequest; import org.elasticsearch.watcher.support.http.TemplatedHttpRequest;
import org.elasticsearch.watcher.support.http.auth.BasicAuth; import org.elasticsearch.watcher.support.http.auth.BasicAuth;
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.test.AbstractWatcherIntegrationTests; import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
import org.elasticsearch.watcher.trigger.TriggerBuilders;
import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule; import org.elasticsearch.watcher.trigger.schedule.IntervalSchedule;
import org.junit.Test; import org.junit.Test;
@ -31,8 +28,11 @@ import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.client.WatchSourceBuilders.template;
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
import static org.elasticsearch.watcher.input.InputBuilders.httpInput;
import static org.elasticsearch.watcher.support.http.TemplatedHttpRequest.sourceBuilder;
import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule; import static org.elasticsearch.watcher.trigger.TriggerBuilders.schedule;
import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval; import static org.elasticsearch.watcher.trigger.schedule.Schedules.interval;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -56,26 +56,19 @@ public class HttpInputIntegrationTest extends AbstractWatcherIntegrationTests {
@Test @Test
public void testHttpInput() throws Exception { public void testHttpInput() throws Exception {
ScriptServiceProxy sc = scriptService();
createIndex("index"); createIndex("index");
client().prepareIndex("index", "type", "id").setSource("{}").setRefresh(true).get(); client().prepareIndex("index", "type", "id").setSource("{}").setRefresh(true).get();
InetSocketAddress address = internalTestCluster().httpAddresses()[0]; InetSocketAddress address = internalTestCluster().httpAddresses()[0];
TemplatedHttpRequest.SourceBuilder requestBuilder = new TemplatedHttpRequest.SourceBuilder()
.setHost(address.getHostName())
.setPort(address.getPort())
.setPath(new ScriptTemplate(sc, "/index/_search"))
.setBody(new ScriptTemplate(sc, jsonBuilder().startObject().field("size", 1).endObject().string()));
if (shieldEnabled()) {
requestBuilder.setAuth(new BasicAuth("test", "changeme"));
}
WatchSourceBuilder source = watchSourceBuilder()
.trigger(TriggerBuilders.schedule(interval("5s")))
.input(InputBuilders.httpInput(requestBuilder))
.condition(scriptCondition("ctx.payload.hits.total == 1"))
.addAction(indexAction("idx", "action"));
watcherClient().preparePutWatch("_name") watcherClient().preparePutWatch("_name")
.source(source) .source(watchBuilder()
.trigger(schedule(interval("5s")))
.input(httpInput(sourceBuilder(address.getHostName(), address.getPort())
.setPath("/index/_search")
.setBody(jsonBuilder().startObject().field("size", 1).endObject())
.setAuth(shieldEnabled() ? new BasicAuth("test", "changeme") : null)))
.condition(scriptCondition("ctx.payload.hits.total == 1"))
.addAction(indexAction("_id", "idx", "action")))
.get(); .get();
if (timeWarped()) { if (timeWarped()) {
@ -95,30 +88,28 @@ public class HttpInputIntegrationTest extends AbstractWatcherIntegrationTests {
ScriptServiceProxy sc = scriptService(); ScriptServiceProxy sc = scriptService();
InetSocketAddress address = internalTestCluster().httpAddresses()[0]; InetSocketAddress address = internalTestCluster().httpAddresses()[0];
String body = jsonBuilder().prettyPrint().startObject() XContentBuilder body = jsonBuilder().prettyPrint().startObject()
.field("query").value(termQuery("field", "value")) .field("query").value(termQuery("field", "value"))
.endObject().string(); .endObject();
TemplatedHttpRequest.SourceBuilder requestBuilder = new TemplatedHttpRequest.SourceBuilder() TemplatedHttpRequest.SourceBuilder requestBuilder = new TemplatedHttpRequest.SourceBuilder(address.getHostName(), address.getPort())
.setHost(address.getHostName()) .setPath(template("/idx/_search"))
.setPort(address.getPort()) .setBody(body);
.setPath(new ScriptTemplate(sc, "/idx/_search"))
.setBody(new ScriptTemplate(sc, body));
if (shieldEnabled()) { if (shieldEnabled()) {
requestBuilder.setAuth(new BasicAuth("test", "changeme")); requestBuilder.setAuth(new BasicAuth("test", "changeme"));
} }
watcherClient.preparePutWatch("_name1") watcherClient.preparePutWatch("_name1")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(InputBuilders.httpInput(requestBuilder).addExtractKey("hits.total")) .input(httpInput(requestBuilder).addExtractKey("hits.total"))
.condition(scriptCondition("ctx.payload.hits.total == 1"))) .condition(scriptCondition("ctx.payload.hits.total == 1")))
.get(); .get();
// in this watcher the condition will fail, because max_score isn't extracted, only total: // in this watcher the condition will fail, because max_score isn't extracted, only total:
watcherClient.preparePutWatch("_name2") watcherClient.preparePutWatch("_name2")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(InputBuilders.httpInput(requestBuilder).addExtractKey("hits.total")) .input(httpInput(requestBuilder).addExtractKey("hits.total"))
.condition(scriptCondition("ctx.payload.hits.max_score >= 0"))) .condition(scriptCondition("ctx.payload.hits.max_score >= 0")))
.get(); .get();

View File

@ -20,7 +20,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.input.InputBuilders.searchInput; import static org.elasticsearch.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.watcher.transform.TransformBuilders.searchTransform; import static org.elasticsearch.watcher.transform.TransformBuilders.searchTransform;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -50,11 +50,11 @@ public class TransformSearchTests extends AbstractWatcherIntegrationTests {
metadata.put("list", "baz"); metadata.put("list", "baz");
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("test-payload") PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("test-payload")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))) .trigger(schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS)))
.input(searchInput(inputRequest)) .input(searchInput(inputRequest))
.transform(searchTransform(transformRequest)) .transform(searchTransform(transformRequest))
.addAction(indexAction("my-payload-output", "result")) .addAction(indexAction("_id", "my-payload-output", "result"))
.metadata(metadata) .metadata(metadata)
.throttlePeriod(TimeValue.timeValueSeconds(0))) .throttlePeriod(TimeValue.timeValueSeconds(0)))
.get(); .get();

View File

@ -16,7 +16,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
import static org.elasticsearch.watcher.input.InputBuilders.searchInput; import static org.elasticsearch.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
@ -43,7 +43,7 @@ public class WatchMetadataTests extends AbstractWatcherIntegrationTests {
metadata.put("baz", metaList); metadata.put("baz", metaList);
watcherClient().preparePutWatch("_name") watcherClient().preparePutWatch("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(cron("0/5 * * * * ? *"))) .trigger(schedule(cron("0/5 * * * * ? *")))
.input(searchInput(WatcherTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery())))) .input(searchInput(WatcherTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery()))))
.condition(scriptCondition("ctx.payload.hits.total == 1")) .condition(scriptCondition("ctx.payload.hits.total == 1"))

View File

@ -10,7 +10,6 @@ import org.elasticsearch.action.index.IndexResponse;
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.joda.time.DateTimeZone;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.watcher.actions.ActionBuilders;
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;
@ -25,7 +24,8 @@ import java.util.concurrent.TimeUnit;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.watcher.client.WatchSourceBuilder.watchSourceBuilder; import static org.elasticsearch.watcher.actions.ActionBuilders.indexAction;
import static org.elasticsearch.watcher.client.WatchSourceBuilders.watchBuilder;
import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition; import static org.elasticsearch.watcher.condition.ConditionBuilders.scriptCondition;
import static org.elasticsearch.watcher.input.InputBuilders.searchInput; import static org.elasticsearch.watcher.input.InputBuilders.searchInput;
import static org.elasticsearch.watcher.test.WatcherTestUtils.matchAllRequest; import static org.elasticsearch.watcher.test.WatcherTestUtils.matchAllRequest;
@ -54,12 +54,12 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests {
PutWatchResponse putWatchResponse = watcherClient.preparePutWatch() PutWatchResponse putWatchResponse = watcherClient.preparePutWatch()
.watchName("_name") .watchName("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(cron("0/5 * * * * ? *"))) .trigger(schedule(cron("0/5 * * * * ? *")))
.input(searchInput(matchAllRequest().indices("events"))) .input(searchInput(matchAllRequest().indices("events")))
.condition(scriptCondition("ctx.payload.hits.total > 0")) .condition(scriptCondition("ctx.payload.hits.total > 0"))
.transform(searchTransform(matchAllRequest().indices("events"))) .transform(searchTransform(matchAllRequest().indices("events")))
.addAction(ActionBuilders.indexAction("actions", "action"))) .addAction(indexAction("_id", "actions", "action")))
.get(); .get();
assertThat(putWatchResponse.indexResponse().isCreated(), is(true)); assertThat(putWatchResponse.indexResponse().isCreated(), is(true));
@ -125,12 +125,12 @@ public class WatchThrottleTests extends AbstractWatcherIntegrationTests {
PutWatchResponse putWatchResponse = watcherClient.preparePutWatch() PutWatchResponse putWatchResponse = watcherClient.preparePutWatch()
.watchName("_name") .watchName("_name")
.source(watchSourceBuilder() .source(watchBuilder()
.trigger(schedule(interval("5s"))) .trigger(schedule(interval("5s")))
.input(searchInput(matchAllRequest().indices("events"))) .input(searchInput(matchAllRequest().indices("events")))
.condition(scriptCondition("ctx.payload.hits.total > 0")) .condition(scriptCondition("ctx.payload.hits.total > 0"))
.transform(searchTransform(matchAllRequest().indices("events"))) .transform(searchTransform(matchAllRequest().indices("events")))
.addAction(ActionBuilders.indexAction("actions", "action")) .addAction(indexAction("_id", "actions", "action"))
.throttlePeriod(TimeValue.timeValueSeconds(10))) .throttlePeriod(TimeValue.timeValueSeconds(10)))
.get(); .get();
assertThat(putWatchResponse.indexResponse().isCreated(), is(true)); assertThat(putWatchResponse.indexResponse().isCreated(), is(true));

View File

@ -21,6 +21,7 @@ import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.actions.Action; import org.elasticsearch.watcher.actions.Action;
import org.elasticsearch.watcher.actions.ActionRegistry; import org.elasticsearch.watcher.actions.ActionRegistry;
import org.elasticsearch.watcher.actions.Actions; import org.elasticsearch.watcher.actions.Actions;
import org.elasticsearch.watcher.actions.ActionWrapper;
import org.elasticsearch.watcher.actions.email.EmailAction; import org.elasticsearch.watcher.actions.email.EmailAction;
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;
@ -258,42 +259,43 @@ public class WatchTests extends ElasticsearchTestCase {
} }
private Actions randomActions() { private Actions randomActions() {
ImmutableList.Builder<Action> list = ImmutableList.builder(); ImmutableList.Builder<ActionWrapper> list = ImmutableList.builder();
if (randomBoolean()) { if (randomBoolean()) {
Transform transform = randomTransform(); Transform transform = randomTransform();
list.add(new EmailAction(logger, transform, emailService, Email.builder().id("prototype").build(), null, Profile.STANDARD, null, null, null, null, randomBoolean())); list.add(new ActionWrapper("_email_" + randomAsciiOfLength(8), transform, new EmailAction(logger, emailService, Email.builder().id("prototype").build(), null, Profile.STANDARD, null, null, null, null, randomBoolean())));
} }
if (randomBoolean()) { if (randomBoolean()) {
list.add(new IndexAction(logger, randomTransform(), client, "_index", "_type")); list.add(new ActionWrapper("_index_" + randomAsciiOfLength(8), randomTransform(), new IndexAction(logger, client, "_index", "_type")));
} }
if (randomBoolean()) { if (randomBoolean()) {
TemplatedHttpRequest httpRequest = new TemplatedHttpRequest(); TemplatedHttpRequest httpRequest = new TemplatedHttpRequest();
httpRequest.method(randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT)); httpRequest.method(randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT));
httpRequest.host("test.host"); httpRequest.host("test.host");
httpRequest.port(randomIntBetween(8000, 9000));
httpRequest.path(new ScriptTemplate(scriptService, "_url")); httpRequest.path(new ScriptTemplate(scriptService, "_url"));
list.add(new WebhookAction(logger, randomTransform(), httpClient, httpRequest)); list.add(new ActionWrapper("_webhook_" + randomAsciiOfLength(8), randomTransform(), new WebhookAction(logger, httpClient, httpRequest)));
} }
return new Actions(list.build()); return new Actions(list.build());
} }
private ActionRegistry registry(Actions actions, TransformRegistry transformRegistry) { private ActionRegistry registry(Actions actions, TransformRegistry transformRegistry) {
ImmutableMap.Builder<String, Action.Parser> parsers = ImmutableMap.builder(); ImmutableMap.Builder<String, Action.Parser> parsers = ImmutableMap.builder();
for (Action action : actions) { for (ActionWrapper action : actions) {
switch (action.type()) { switch (action.action().type()) {
case EmailAction.TYPE: case EmailAction.TYPE:
parsers.put(EmailAction.TYPE, new EmailAction.Parser(settings, emailService, templateParser, transformRegistry)); parsers.put(EmailAction.TYPE, new EmailAction.Parser(settings, emailService, templateParser));
break; break;
case IndexAction.TYPE: case IndexAction.TYPE:
parsers.put(IndexAction.TYPE, new IndexAction.Parser(settings, client, transformRegistry)); parsers.put(IndexAction.TYPE, new IndexAction.Parser(settings, client));
break; break;
case WebhookAction.TYPE: case WebhookAction.TYPE:
parsers.put(WebhookAction.TYPE, new WebhookAction.Parser(settings, httpClient, transformRegistry, parsers.put(WebhookAction.TYPE, new WebhookAction.Parser(settings, httpClient,
new HttpRequest.Parser(authRegistry), new HttpRequest.Parser(authRegistry),
new TemplatedHttpRequest.Parser(new ScriptTemplate.Parser(settings, scriptService), authRegistry))); new TemplatedHttpRequest.Parser(new ScriptTemplate.Parser(settings, scriptService), authRegistry)));
break; break;
} }
} }
return new ActionRegistry(parsers.build()); return new ActionRegistry(parsers.build(), transformRegistry);
} }