Change Script & Template configuration

Scripts and Templates are very much alike. There are only two main differences between them when it comes to watcher:

1. The template doesn't have a language type - it's always mustache.
2. Templates are often used to render xcontent (json/yaml). So there's build in support for  content type in it

Traditionally, in es core, the configuration of the scripts and templates was always a bit of a mess. There was no consistency between the two and when it comes to the templates configuration, they're even not future proof (future additions to the search requests body can break the templates).

After a long discussion, we've decided that we need to change the way users configure templates & scripts in es core... and align the two. These changes will only come in es 2.0. That said, it's important that watcher will be aligned with es core in how templates and scripts are configured and therefore we need to change it for that purpose.

Watcher will come with support for the scripts & templates configuration format of es 2.0. We want to future proof the configuration from day one.

here are the configuration:

Inline:

```
{
  "inline" : "script here",
  "lang" : "lang here",
  "params" : { parameters here }
}
```

File:

```
{
  "file" : "file name here",
  "lang" : "language here",
  "params" : { parameters here }
}
```

Indexed:

```
{
  "id" : "template id here",
  "lang" : "language here",
  "params" : { parameters here }
}
```

For templates it's the same configuration except there is no `lang` field. Also, for templates, there's native support for xcontent:

```
{
  "inline" : { "key" : "{{param1}}" },
  "params" : { "param1" : "value1" }
  }
}
```

Original commit: elastic/x-pack-elasticsearch@4a31114f35
This commit is contained in:
uboness 2015-05-08 01:50:05 +02:00
parent ddb5efeb25
commit a06303a894
28 changed files with 588 additions and 356 deletions

View File

@ -40,7 +40,7 @@
},
"condition" : {
"script" : {
"script" : "ctx.payload.hits.total > 1"
"inline" : "ctx.payload.hits.total > 1"
}
},
"actions" : {

View File

@ -42,7 +42,11 @@ public final class ActionBuilders {
}
public static LoggingAction.Builder loggingAction(String text) {
return loggingAction(new Template(text));
return loggingAction(Template.inline(text));
}
public static LoggingAction.Builder loggingAction(Template.Builder text) {
return loggingAction(text.build());
}
public static LoggingAction.Builder loggingAction(Template text) {

View File

@ -232,7 +232,11 @@ public class EmailTemplate implements ToXContent {
}
public Builder from(String from) {
return from(new Template(from));
return from(Template.inline(from));
}
public Builder from(Template.Builder from) {
return from(from.build());
}
public Builder from(Template from) {
@ -243,7 +247,15 @@ public class EmailTemplate implements ToXContent {
public Builder replyTo(String... replyTo) {
Template[] templates = new Template[replyTo.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = new Template(replyTo[i]);
templates[i] = Template.inline(replyTo[i]).build();
}
return replyTo(templates);
}
public Builder replyTo(Template.Builder... replyTo) {
Template[] templates = new Template[replyTo.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = replyTo[i].build();
}
return replyTo(templates);
}
@ -254,7 +266,11 @@ public class EmailTemplate implements ToXContent {
}
public Builder priority(Email.Priority priority) {
return priority(new Template(priority.name()));
return priority(Template.inline(priority.name()));
}
public Builder priority(Template.Builder priority) {
return priority(priority.build());
}
public Builder priority(Template priority) {
@ -265,7 +281,15 @@ public class EmailTemplate implements ToXContent {
public Builder to(String... to) {
Template[] templates = new Template[to.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = new Template(to[i]);
templates[i] = Template.inline(to[i]).build();
}
return to(templates);
}
public Builder to(Template.Builder... to) {
Template[] templates = new Template[to.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = to[i].build();
}
return to(templates);
}
@ -278,7 +302,15 @@ public class EmailTemplate implements ToXContent {
public Builder cc(String... cc) {
Template[] templates = new Template[cc.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = new Template(cc[i]);
templates[i] = Template.inline(cc[i]).build();
}
return cc(templates);
}
public Builder cc(Template.Builder... cc) {
Template[] templates = new Template[cc.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = cc[i].build();
}
return cc(templates);
}
@ -291,7 +323,15 @@ public class EmailTemplate implements ToXContent {
public Builder bcc(String... bcc) {
Template[] templates = new Template[bcc.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = new Template(bcc[i]);
templates[i] = Template.inline(bcc[i]).build();
}
return bcc(templates);
}
public Builder bcc(Template.Builder... bcc) {
Template[] templates = new Template[bcc.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = bcc[i].build();
}
return bcc(templates);
}
@ -302,7 +342,11 @@ public class EmailTemplate implements ToXContent {
}
public Builder subject(String subject) {
return subject(new Template(subject));
return subject(Template.inline(subject));
}
public Builder subject(Template.Builder subject) {
return subject(subject.build());
}
public Builder subject(Template subject) {
@ -311,7 +355,11 @@ public class EmailTemplate implements ToXContent {
}
public Builder textBody(String text) {
return textBody(new Template(text));
return textBody(Template.inline(text));
}
public Builder textBody(Template.Builder text) {
return textBody(text.build());
}
public Builder textBody(Template text) {
@ -320,7 +368,11 @@ public class EmailTemplate implements ToXContent {
}
public Builder htmlBody(String html, boolean sanitizeHtmlBody) {
return htmlBody(new Template(html), sanitizeHtmlBody);
return htmlBody(Template.inline(html), sanitizeHtmlBody);
}
public Builder htmlBody(Template.Builder html, boolean sanitizeHtmlBody) {
return htmlBody(html.build(), sanitizeHtmlBody);
}
public Builder htmlBody(Template html, boolean sanitizeHtmlBody) {
@ -332,7 +384,6 @@ public class EmailTemplate implements ToXContent {
public EmailTemplate build() {
return new EmailTemplate(from, replyTo, priority, to, cc, bcc, subject, textBody, htmlBody, sanitizeHtmlBody);
}
}
public static class Parser {

View File

@ -7,10 +7,8 @@ package org.elasticsearch.watcher.condition;
import org.elasticsearch.watcher.condition.always.AlwaysCondition;
import org.elasticsearch.watcher.condition.never.NeverCondition;
import org.elasticsearch.watcher.condition.script.ExecutableScriptCondition;
import org.elasticsearch.watcher.condition.never.ExecutableNeverCondition;
import org.elasticsearch.watcher.condition.always.ExecutableAlwaysCondition;
import org.elasticsearch.watcher.condition.script.ScriptCondition;
import org.elasticsearch.watcher.support.Script;
/**
*
@ -29,6 +27,14 @@ public final class ConditionBuilders {
}
public static ScriptCondition.Builder scriptCondition(String script) {
return scriptCondition(Script.inline(script));
}
public static ScriptCondition.Builder scriptCondition(Script.Builder script) {
return scriptCondition(script.build());
}
public static ScriptCondition.Builder scriptCondition(Script script) {
return ScriptCondition.builder(script);
}
}

View File

@ -5,15 +5,12 @@
*/
package org.elasticsearch.watcher.condition.script;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.watcher.condition.Condition;
import org.elasticsearch.watcher.support.Script;
import java.io.IOException;
import java.util.Map;
/**
*
@ -66,7 +63,7 @@ public class ScriptCondition implements Condition {
}
}
public static Builder builder(String script) {
public static Builder builder(Script script) {
return new Builder(script);
}
@ -115,38 +112,15 @@ public class ScriptCondition implements Condition {
public static class Builder implements Condition.Builder<ScriptCondition> {
private final String script;
private ScriptService.ScriptType type = Script.DEFAULT_TYPE;
private String lang = Script.DEFAULT_LANG;
private ImmutableMap.Builder<String, Object> vars = ImmutableMap.builder();
private final Script script;
private Builder(String script) {
private Builder(Script script) {
this.script = script;
}
public Builder setType(ScriptService.ScriptType type) {
this.type = type;
return this;
}
public Builder setLang(String lang) {
this.lang = lang;
return this;
}
public Builder addVars(Map<String, Object> vars) {
this.vars.putAll(vars);
return this;
}
public Builder setVar(String name, Object value) {
this.vars.put(name, value);
return this;
}
@Override
public ScriptCondition build() {
return new ScriptCondition(new Script(this.script, type, lang, vars.build()));
return new ScriptCondition(script);
}
}
}

View File

@ -12,11 +12,10 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.watcher.WatcherException;
import java.io.IOException;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
/**
@ -24,28 +23,19 @@ import java.util.Map;
*/
public class Script implements ToXContent {
public static final ScriptService.ScriptType DEFAULT_TYPE = ScriptService.ScriptType.INLINE;
public static final ScriptType DEFAULT_TYPE = ScriptType.INLINE;
public static final String DEFAULT_LANG = ScriptService.DEFAULT_LANG;
public static final ParseField SCRIPT_FIELD = new ParseField("script");
public static final ParseField TYPE_FIELD = new ParseField("type");
public static final ParseField LANG_FIELD = new ParseField("lang");
public static final ParseField PARAMS_FIELD = new ParseField("params");
private final String script;
private final @Nullable ScriptService.ScriptType type;
private final @Nullable ScriptType type;
private final @Nullable String lang;
private final @Nullable Map<String, Object> params;
public Script(String script) {
Script(String script) {
this(script, null, null, null);
}
public Script(String script, ScriptService.ScriptType type, String lang) {
this(script, type, lang, null);
}
public Script(String script, ScriptService.ScriptType type, String lang, Map<String, Object> params) {
Script(String script, @Nullable ScriptType type, @Nullable String lang, @Nullable Map<String, Object> params) {
this.script = script;
this.type = type;
this.lang = lang;
@ -56,8 +46,8 @@ public class Script implements ToXContent {
return script;
}
public ScriptService.ScriptType type() {
return type != null ? type : ScriptService.ScriptType.INLINE;
public ScriptType type() {
return type != null ? type : ScriptType.INLINE;
}
public String lang() {
@ -92,19 +82,28 @@ public class Script implements ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (type == null && lang == null && params == null) {
if (type == null) {
return builder.value(script);
}
builder.startObject();
builder.field(SCRIPT_FIELD.getPreferredName(), script);
if (type != null) {
builder.field(TYPE_FIELD.getPreferredName(), type.name().toLowerCase(Locale.ROOT));
switch (type) {
case INLINE:
builder.field(Field.INLINE.getPreferredName(), script);
break;
case FILE:
builder.field(Field.FILE.getPreferredName(), script);
break;
case INDEXED:
builder.field(Field.ID.getPreferredName(), script);
break;
default:
throw new WatcherException("unsupported script type [{}]", type());
}
if (lang != null) {
builder.field(LANG_FIELD.getPreferredName(), lang);
builder.field(Field.LANG.getPreferredName(), lang);
}
if (this.params != null) {
builder.field(PARAMS_FIELD.getPreferredName(), this.params);
builder.field(Field.PARAMS.getPreferredName(), this.params);
}
return builder.endObject();
}
@ -119,7 +118,7 @@ public class Script implements ToXContent {
}
String script = null;
ScriptService.ScriptType type = null;
ScriptType type = null;
String lang = null;
Map<String, Object> params = null;
@ -127,28 +126,34 @@ public class Script implements ToXContent {
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (SCRIPT_FIELD.match(currentFieldName)) {
} else if (Field.INLINE.match(currentFieldName)) {
type = ScriptType.INLINE;
if (token == XContentParser.Token.VALUE_STRING) {
script = parser.text();
} else {
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (TYPE_FIELD.match(currentFieldName)) {
} else if (Field.FILE.match(currentFieldName)) {
type = ScriptType.FILE;
if (token == XContentParser.Token.VALUE_STRING) {
String value = parser.text();
try {
type = ScriptService.ScriptType.valueOf(value.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException iae) {
throw new ParseException("unknown script type [{}]", value);
}
script = parser.text();
} else {
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (LANG_FIELD.match(currentFieldName)) {
} else if (Field.ID.match(currentFieldName)) {
type = ScriptType.INDEXED;
if (token == XContentParser.Token.VALUE_STRING) {
script = parser.text();
} else {
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (Field.LANG.match(currentFieldName)) {
if (token == XContentParser.Token.VALUE_STRING) {
lang = parser.text();
} else {
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (PARAMS_FIELD.match(currentFieldName)) {
} else if (Field.PARAMS.match(currentFieldName)) {
if (token == XContentParser.Token.START_OBJECT) {
params = parser.map();
} else {
@ -159,11 +164,101 @@ public class Script implements ToXContent {
}
}
if (script == null) {
throw new ParseException("missing required string field [{}]", SCRIPT_FIELD.getPreferredName());
throw new ParseException("expected one of [{}], [{}] or [{}] fields, but found none", Field.INLINE.getPreferredName(), Field.FILE.getPreferredName(), Field.ID.getPreferredName());
}
assert type != null : "if script is not null, type should definitely not be null";
return new Script(script, type, lang, params);
}
public static Builder.Inline inline(String script) {
return new Builder.Inline(script);
}
public static Builder.File file(String file) {
return new Builder.File(file);
}
public static Builder.Indexed indexed(String id) {
return new Builder.Indexed(id);
}
public static Builder.DefaultType defaultType(String text) {
return new Builder.DefaultType(text);
}
public static abstract class Builder<B extends Builder> {
protected final ScriptType type;
protected final String script;
protected String lang;
protected Map<String, Object> params;
protected Builder(String script, ScriptType type) {
this.script = script;
this.type = type;
}
public B lang(String lang) {
this.lang = lang;
return (B) this;
}
public B params(Map<String, Object> params) {
this.params = params;
return (B) this;
}
public abstract Script build();
public static class Inline extends Builder<Inline> {
public Inline(String script) {
super(script, ScriptType.INLINE);
}
@Override
public Script build() {
return new Script(script, type, lang, params);
}
}
public static class File extends Builder<File> {
public File(String file) {
super(file, ScriptType.FILE);
}
@Override
public Script build() {
return new Script(script, type, lang, params);
}
}
public static class Indexed extends Builder<Indexed> {
public Indexed(String id) {
super(id, ScriptType.INDEXED);
}
@Override
public Script build() {
return new Script(script, type, lang, params);
}
}
public static class DefaultType extends Builder<DefaultType> {
public DefaultType(String text) {
super(text, null);
}
@Override
public Script build() {
return new Script(script, type, lang, params);
}
}
}
public static class ParseException extends WatcherException {
public ParseException(String msg, Object... args) {
@ -174,4 +269,14 @@ public class Script implements ToXContent {
super(msg, cause, args);
}
}
interface Field {
ParseField INLINE = new ParseField("inline");
ParseField FILE = new ParseField("file");
ParseField ID = new ParseField("id");
ParseField LANG = new ParseField("lang");
ParseField PARAMS = new ParseField("params");
}
}

View File

@ -7,12 +7,13 @@ package org.elasticsearch.watcher.support.http;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.netty.handler.codec.http.HttpHeaders;
import org.elasticsearch.common.xcontent.*;
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.support.http.auth.HttpAuth;
import org.elasticsearch.watcher.support.http.auth.HttpAuthRegistry;
@ -38,11 +39,10 @@ public class HttpRequestTemplate implements ToXContent {
private final ImmutableMap<String, Template> headers;
private final HttpAuth auth;
private final Template body;
private final XContentType xContentType;
public HttpRequestTemplate(String host, int port, @Nullable Scheme scheme, @Nullable HttpMethod method, @Nullable Template path,
Map<String, Template> params, Map<String, Template> headers, HttpAuth auth,
Template body, XContentType xContentType) {
Template body) {
this.host = host;
this.port = port;
this.scheme = scheme != null ? scheme :Scheme.HTTP;
@ -52,7 +52,6 @@ public class HttpRequestTemplate implements ToXContent {
this.headers = headers != null ? ImmutableMap.copyOf(headers) : ImmutableMap.<String, Template>of();
this.auth = auth;
this.body = body;
this.xContentType = xContentType;
}
public Scheme scheme() {
@ -105,13 +104,13 @@ public class HttpRequestTemplate implements ToXContent {
}
request.setParams(mapBuilder.map());
}
if ((headers == null || headers.isEmpty()) && xContentType != null) {
request.setHeaders(ImmutableMap.of(HttpHeaders.Names.CONTENT_TYPE, xContentType.restContentType()));
if ((headers == null || headers.isEmpty()) && body != null && body.getContentType() != null) {
request.setHeaders(ImmutableMap.of(HttpHeaders.Names.CONTENT_TYPE, body.getContentType().restContentType()));
} else if (headers != null && !headers.isEmpty()) {
MapBuilder<String, String> mapBuilder = MapBuilder.newMapBuilder();
if (xContentType != null) {
if (body != null && body.getContentType() != null) {
// putting the content type first, so it can be overridden by custom headers
mapBuilder.put(HttpHeaders.Names.CONTENT_TYPE, xContentType.restContentType());
mapBuilder.put(HttpHeaders.Names.CONTENT_TYPE, body.getContentType().restContentType());
}
for (Map.Entry<String, Template> entry : headers.entrySet()) {
mapBuilder.put(entry.getKey(), engine.render(entry.getValue(), model));
@ -156,11 +155,7 @@ public class HttpRequestTemplate implements ToXContent {
.endObject();
}
if (body != null) {
if (xContentType != null) {
builder.rawField(Parser.XBODY_FIELD.getPreferredName(), new BytesArray(body.getTemplate()));
} else {
builder.field(Parser.BODY_FIELD.getPreferredName(), body, params);
}
builder.field(Parser.BODY_FIELD.getPreferredName(), body, params);
}
return builder.endObject();
}
@ -180,8 +175,7 @@ public class HttpRequestTemplate implements ToXContent {
if (params != null ? !params.equals(that.params) : that.params != null) return false;
if (headers != null ? !headers.equals(that.headers) : that.headers != null) return false;
if (auth != null ? !auth.equals(that.auth) : that.auth != null) return false;
if (body != null ? !body.equals(that.body) : that.body != null) return false;
return xContentType == that.xContentType;
return body != null ? body.equals(that.body) : that.body == null;
}
@Override
@ -195,7 +189,6 @@ public class HttpRequestTemplate implements ToXContent {
result = 31 * result + (headers != null ? headers.hashCode() : 0);
result = 31 * result + (auth != null ? auth.hashCode() : 0);
result = 31 * result + (body != null ? body.hashCode() : 0);
result = 31 * result + (xContentType != null ? xContentType.hashCode() : 0);
return result;
}
@ -226,8 +219,6 @@ public class HttpRequestTemplate implements ToXContent {
public HttpRequestTemplate parse(XContentParser parser) throws IOException {
assert parser.currentToken() == XContentParser.Token.START_OBJECT;
boolean seenBody = false;
boolean seenXBody = false;
Builder builder = new Builder();
XContentParser.Token token;
String currentFieldName = null;
@ -241,19 +232,7 @@ public class HttpRequestTemplate implements ToXContent {
} else if (PARAMS_FIELD.match(currentFieldName)) {
builder.putParams(parseFieldTemplates(currentFieldName, parser));
} else if (BODY_FIELD.match(currentFieldName)) {
if (seenXBody) {
throw new ParseException("could not parse http request template. both [{}] and [{}] are set, only one of the two is allowed", XBODY_FIELD.getPreferredName(), BODY_FIELD.getPreferredName());
}
seenBody = true;
builder.body(parseFieldTemplate(currentFieldName, parser));
} else if (XBODY_FIELD.match(currentFieldName)) {
if (seenBody) {
throw new ParseException("could not parse http request template. both [{}] and [{}] are set, only one of the two is allowed", XBODY_FIELD.getPreferredName(), BODY_FIELD.getPreferredName());
}
seenXBody = true;
XContentBuilder contentBuilder = XContentBuilder.builder(parser.contentType().xContent());
XContentHelper.copyCurrentStructure(contentBuilder.generator(), parser);
builder.body(contentBuilder);
} else if (token == XContentParser.Token.START_OBJECT) {
if (AUTH_FIELD.match(currentFieldName)) {
builder.auth(httpAuthRegistry.parse(parser));
@ -338,7 +317,6 @@ public class HttpRequestTemplate implements ToXContent {
private final ImmutableMap.Builder<String, Template> headers = ImmutableMap.builder();
private HttpAuth auth;
private Template body;
private XContentType xContentType;
private Builder() {
}
@ -359,7 +337,11 @@ public class HttpRequestTemplate implements ToXContent {
}
public Builder path(String path) {
return path(new Template(path));
return path(Template.inline(path));
}
public Builder path(Template.Builder path) {
return path(path.build());
}
public Builder path(Template path) {
@ -372,6 +354,10 @@ public class HttpRequestTemplate implements ToXContent {
return this;
}
public Builder putParam(String key, Template.Builder value) {
return putParam(key, value.build());
}
public Builder putParam(String key, Template value) {
this.params.put(key, value);
return this;
@ -382,6 +368,10 @@ public class HttpRequestTemplate implements ToXContent {
return this;
}
public Builder putHeader(String key, Template.Builder value) {
return putHeader(key, value.build());
}
public Builder putHeader(String key, Template value) {
this.headers.put(key, value);
return this;
@ -393,20 +383,15 @@ public class HttpRequestTemplate implements ToXContent {
}
public Builder body(String body) {
return body(body, null);
return body(Template.inline(body));
}
public Builder body(Template.Builder body) {
return body(body.build());
}
public Builder body(Template body) {
return body(body, null);
}
public Builder body(String body, XContentType xContentType) {
return body(new Template(body), xContentType);
}
public Builder body(Template body, XContentType xContentType) {
this.body = body;
this.xContentType = xContentType;
return this;
}
@ -419,11 +404,11 @@ public class HttpRequestTemplate implements ToXContent {
}
public Builder body(XContentBuilder content) {
return body(content.bytes().toUtf8(), content.contentType());
return body(Template.inline(content));
}
public HttpRequestTemplate build() {
return new HttpRequestTemplate(host, port, scheme, method, path, params.build(), headers.build(), auth, body, xContentType);
return new HttpRequestTemplate(host, port, scheme, method, path, params.build(), headers.build(), auth, body);
}
}

View File

@ -7,16 +7,13 @@ package org.elasticsearch.watcher.support.template;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.*;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.watcher.WatcherException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
/**
@ -25,15 +22,17 @@ import java.util.Map;
public class Template implements ToXContent {
private final String template;
private final @Nullable XContentType contentType;
private final @Nullable ScriptType type;
private final @Nullable Map<String, Object> params;
public Template(String template) {
this(template, null, null);
Template(String template) {
this(template, null, null, null);
}
public Template(String template, @Nullable ScriptType type, @Nullable Map<String, Object> params) {
Template(String template, @Nullable XContentType contentType, @Nullable ScriptType type, @Nullable Map<String, Object> params) {
this.template = template;
this.contentType = contentType;
this.type = type;
this.params = params;
}
@ -42,6 +41,10 @@ public class Template implements ToXContent {
return template;
}
public XContentType getContentType() {
return contentType;
}
public ScriptType getType() {
return type != null ? type : ScriptType.INLINE;
}
@ -58,13 +61,16 @@ public class Template implements ToXContent {
Template template1 = (Template) o;
if (!template.equals(template1.template)) return false;
if (contentType != template1.contentType) return false;
if (type != template1.type) return false;
return !(params != null ? !params.equals(template1.params) : template1.params != null);
}
@Override
public int hashCode() {
int result = template.hashCode();
result = 31 * result + (contentType != null ? contentType.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
result = 31 * result + (params != null ? params.hashCode() : 0);
return result;
@ -72,13 +78,26 @@ public class Template implements ToXContent {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (type == null && this.params == null) {
if (type == null) {
return builder.value(template);
}
builder.startObject();
builder.field(Field.TEMPLATE.getPreferredName(), template);
if (type != null) {
builder.field(Field.TYPE.getPreferredName(), type.name().toLowerCase(Locale.ROOT));
switch (type) {
case INLINE:
if (contentType != null && builder.contentType() == contentType) {
builder.rawField(Field.INLINE.getPreferredName(), new BytesArray(template));
} else {
builder.field(Field.INLINE.getPreferredName(), template);
}
break;
case FILE:
builder.field(Field.FILE.getPreferredName(), template);
break;
case INDEXED:
builder.field(Field.ID.getPreferredName(), template);
break;
default:
throw new WatcherException("unsupported script type [{}]", type);
}
if (this.params != null) {
builder.field(Field.PARAMS.getPreferredName(), this.params);
@ -92,31 +111,40 @@ public class Template implements ToXContent {
return new Template(String.valueOf(parser.objectText()));
}
if (token != XContentParser.Token.START_OBJECT) {
throw new ParseException("expected a string value or an object, but found [{}]instead", token);
throw new ParseException("expected a string value or an object, but found [{}] instead", token);
}
String template = null;
ScriptType type = ScriptType.INLINE;
Map<String, Object> params = ImmutableMap.of();
XContentType contentType = null;
ScriptType type = null;
Map<String, Object> params = null;
String currentFieldName = null;
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
if (token == XContentParser.Token.FIELD_NAME) {
currentFieldName = parser.currentName();
} else if (Field.TEMPLATE.match(currentFieldName)) {
} else if (Field.INLINE.match(currentFieldName)) {
type = ScriptType.INLINE;
if (token.isValue()) {
template = String.valueOf(parser.objectText());
} else {
contentType = parser.contentType();
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
template = builder.copyCurrentStructure(parser).bytes().toUtf8();
}
} else if (Field.FILE.match(currentFieldName)) {
type = ScriptType.FILE;
if (token == XContentParser.Token.VALUE_STRING) {
template = parser.text();
} else {
throw new ParseException("expected a string field [{}], but found [{}]", currentFieldName, token);
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (Field.TYPE.match(currentFieldName)) {
} else if (Field.ID.match(currentFieldName)) {
type = ScriptType.INDEXED;
if (token == XContentParser.Token.VALUE_STRING) {
String value = parser.text();
try {
type = ScriptType.valueOf(value.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException iae) {
throw new ParseException("unknown template type [{}]", value);
}
template = parser.text();
} else {
throw new ParseException("expected a string value for field [{}], but found [{}]", currentFieldName, token);
}
} else if (Field.PARAMS.match(currentFieldName)) {
if (token == XContentParser.Token.START_OBJECT) {
@ -129,48 +157,103 @@ public class Template implements ToXContent {
}
}
if (template == null) {
throw new ParseException("missing required string field [{}]", Field.TEMPLATE.getPreferredName());
throw new ParseException("expected one of [{}], [{}] or [{}] fields, but found none", Field.INLINE.getPreferredName(), Field.FILE.getPreferredName(), Field.ID.getPreferredName());
}
return new Template(template, type, params);
assert type != null : "if template is not null, type should definitely not be null";
return new Template(template, contentType, type, params);
}
public static Builder builder(String text) {
return new Builder(text);
public static Builder inline(XContentBuilder template) {
return new Builder.Inline(template.bytes().toUtf8()).contentType(template.contentType());
}
public static class Builder {
public static Builder inline(String text) {
return new Builder.Inline(text);
}
private final String template;
private ScriptType type;
private HashMap<String, Object> params;
public static Builder file(String file) {
return new Builder.File(file);
}
private Builder(String template) {
public static Builder indexed(String id) {
return new Builder.Indexed(id);
}
public static Builder.DefaultType defaultType(String text) {
return new Builder.DefaultType(text);
}
public static abstract class Builder<B extends Builder> {
protected final ScriptType type;
protected final String template;
protected Map<String, Object> params;
protected Builder(String template, ScriptType type) {
this.template = template;
}
public Builder setType(ScriptType type) {
this.type = type;
return null;
}
public Builder putParams(Map<String, Object> params) {
if (params == null) {
params = new HashMap<>();
public B params(Map<String, Object> params) {
this.params = params;
return (B) this;
}
public abstract Template build();
public static class Inline extends Builder<Inline> {
private XContentType contentType;
public Inline(String script) {
super(script, ScriptType.INLINE);
}
this.params.putAll(params);
return this;
}
public Builder putParam(String key, Object value) {
if (params == null) {
params = new HashMap<>();
public Inline contentType(XContentType contentType) {
this.contentType = contentType;
return this;
}
@Override
public Template build() {
return new Template(template, contentType, type, params);
}
params.put(key, value);
return this;
}
public Template build() {
return new Template(template, type, params);
public static class File extends Builder<File> {
public File(String file) {
super(file, ScriptType.FILE);
}
@Override
public Template build() {
return new Template(template, null, type, params);
}
}
public static class Indexed extends Builder<Indexed> {
public Indexed(String id) {
super(id, ScriptType.INDEXED);
}
@Override
public Template build() {
return new Template(template, null, type, params);
}
}
public static class DefaultType extends Builder<DefaultType> {
public DefaultType(String text) {
super(text, null);
}
@Override
public Template build() {
return new Template(template, null, type, params);
}
}
}
@ -186,8 +269,9 @@ public class Template implements ToXContent {
}
public interface Field {
ParseField TEMPLATE = new ParseField("template");
ParseField TYPE = new ParseField("type");
ParseField INLINE = new ParseField("inline");
ParseField FILE = new ParseField("file");
ParseField ID = new ParseField("id");
ParseField PARAMS = new ParseField("params");
}
}

View File

@ -29,7 +29,11 @@ public final class TransformBuilders {
}
public static ScriptTransform.Builder scriptTransform(String script) {
return scriptTransform(new Script(script));
return scriptTransform(Script.inline(script));
}
public static ScriptTransform.Builder scriptTransform(Script.Builder script) {
return scriptTransform(script.build());
}
public static ScriptTransform.Builder scriptTransform(Script script) {

View File

@ -61,17 +61,17 @@ public class EmailActionTests extends ElasticsearchTestCase {
EmailTemplate.Builder emailBuilder = EmailTemplate.builder();
Template subject = null;
if (randomBoolean()) {
subject = new Template("_subject");
subject = Template.inline("_subject").build();
emailBuilder.subject(subject);
}
Template textBody = null;
if (randomBoolean()) {
textBody = new Template("_text_body");
textBody = Template.inline("_text_body").build();
emailBuilder.textBody(textBody);
}
Template htmlBody = null;
if (randomBoolean()) {
htmlBody = new Template("_html_body");
htmlBody = Template.inline("_html_body").build();
emailBuilder.htmlBody(htmlBody, true);
}
EmailTemplate email = emailBuilder.build();
@ -148,9 +148,9 @@ public class EmailActionTests extends ElasticsearchTestCase {
Email.Address[] cc = rarely() ? null : Email.AddressList.parse(randomBoolean() ? "cc@domain" : "cc1@domain,cc2@domain").toArray();
Email.Address[] bcc = rarely() ? null : Email.AddressList.parse(randomBoolean() ? "bcc@domain" : "bcc1@domain,bcc2@domain").toArray();
Email.Address[] replyTo = rarely() ? null : Email.AddressList.parse(randomBoolean() ? "reply@domain" : "reply1@domain,reply2@domain").toArray();
Template subject = randomBoolean() ? new Template("_subject") : null;
Template textBody = randomBoolean() ? new Template("_text_body") : null;
Template htmlBody = randomBoolean() ? new Template("_text_html") : null;
Template subject = randomBoolean() ? Template.inline("_subject").build() : null;
Template textBody = randomBoolean() ? Template.inline("_text_body").build() : null;
Template htmlBody = randomBoolean() ? Template.inline("_text_html").build() : null;
boolean attachData = randomBoolean();
XContentBuilder builder = jsonBuilder().startObject()
.field("account", "_account")
@ -223,7 +223,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
assertThat(executable.action().getAuth(), notNullValue());
assertThat(executable.action().getAuth().user(), is("_user"));
assertThat(executable.action().getAuth().password(), is(new Secret("_passwd".toCharArray())));
assertThat(executable.action().getEmail().priority(), is(new Template(priority.name())));
assertThat(executable.action().getEmail().priority(), is(Template.defaultType(priority.name()).build()));
if (to != null) {
assertThat(executable.action().getEmail().to(), arrayContainingInAnyOrder(addressesToTemplates(to)));
} else {
@ -249,7 +249,7 @@ public class EmailActionTests extends ElasticsearchTestCase {
private static Template[] addressesToTemplates(Email.Address[] addresses) {
Template[] templates = new Template[addresses.length];
for (int i = 0; i < templates.length; i++) {
templates[i] = new Template(addresses[i].toString());
templates[i] = Template.defaultType(addresses[i].toString()).build();
}
return templates;
}

View File

@ -32,29 +32,29 @@ public class EmailTemplateTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 100)
public void testEmailTemplate_Parser_SelfGenerated() throws Exception {
Template from = randomFrom(new Template("from@from.com"), null);
Template from = randomFrom(Template.inline("from@from.com").build(), null);
List<Template> addresses = new ArrayList<>();
for( int i = 0; i < randomIntBetween(1, 5); ++i){
addresses.add(new Template("address" + i + "@test.com"));
addresses.add(Template.inline("address" + i + "@test.com").build());
}
Template[] possibleList = addresses.toArray(new Template[addresses.size()]);
Template[] replyTo = randomFrom(possibleList, null);
Template[] to = randomFrom(possibleList, null);
Template[] cc = randomFrom(possibleList, null);
Template[] bcc = randomFrom(possibleList, null);
Template priority = new Template(randomFrom(Email.Priority.values()).name());
Template priority = Template.inline(randomFrom(Email.Priority.values()).name()).build();
boolean sanitizeHtml = randomBoolean();
Template templatedSubject = new Template("Templated Subject {{foo}}");
Template templatedSubject = Template.inline("Templated Subject {{foo}}").build();
String renderedTemplatedSubject = "Templated Subject bar";
Template templatedBody = new Template("Templated Body {{foo}}");
Template templatedBody = Template.inline("Templated Body {{foo}}").build();
String renderedTemplatedBody = "Templated Body bar";
Template templatedHtmlBodyGood = new Template("Templated Html Body <hr />");
Template templatedHtmlBodyGood = Template.inline("Templated Html Body <hr />").build();
String renderedTemplatedHtmlBodyGood = "Templated Html Body <hr /> bar";
Template templatedHtmlBodyBad = new Template("Templated Html Body <script>nefarious scripting</script>");
Template templatedHtmlBodyBad = Template.inline("Templated Html Body <script>nefarious scripting</script>").build();
String renderedTemplatedHtmlBodyBad = "Templated Html Body<script>nefarious scripting</script>";
String renderedSanitizedHtmlBodyBad = "Templated Html Body";

View File

@ -75,7 +75,7 @@ public class LoggingActionTests extends ElasticsearchTestCase {
.build();
String text = randomAsciiOfLength(10);
Template template = new Template(text);
Template template = Template.inline(text).build();
LoggingAction action = new LoggingAction(template, level, "_category");
ExecutableLoggingAction executable = new ExecutableLoggingAction(action, logger, actionLogger, engine);
when(engine.render(template, expectedModel)).thenReturn(text);
@ -99,7 +99,7 @@ public class LoggingActionTests extends ElasticsearchTestCase {
LoggingActionFactory parser = new LoggingActionFactory(settings, engine);
String text = randomAsciiOfLength(10);
Template template = new Template(text);
Template template = Template.inline(text).build();
XContentBuilder builder = jsonBuilder().startObject();
builder.field("text", template);
@ -134,7 +134,7 @@ public class LoggingActionTests extends ElasticsearchTestCase {
LoggingActionFactory parser = new LoggingActionFactory(settings, engine);
String text = randomAsciiOfLength(10);
Template template = new Template(text);
Template template = Template.inline(text).build();
String category = randomAsciiOfLength(10);
LoggingAction action = new LoggingAction(template, level, category);
ExecutableLoggingAction executable = new ExecutableLoggingAction(action, logger, settings, engine);
@ -155,7 +155,7 @@ public class LoggingActionTests extends ElasticsearchTestCase {
LoggingActionFactory parser = new LoggingActionFactory(settings, engine);
String text = randomAsciiOfLength(10);
Template template = new Template(text);
Template template = Template.inline(text).build();
LoggingAction.Builder actionBuilder = loggingAction(template);
String category = null;
if (randomBoolean()) {

View File

@ -83,8 +83,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
scriptService = WatcherTestUtils.getScriptServiceProxy(tp);
templateEngine = new XMustacheTemplateEngine(settings, scriptService);
secretService = mock(SecretService.class);
testBody = new Template(TEST_BODY_STRING );
testPath = new Template(TEST_PATH_STRING);
testBody = Template.inline(TEST_BODY_STRING).build();
testPath = Template.inline(TEST_PATH_STRING).build();
authRegistry = new HttpAuthRegistry(ImmutableMap.of("basic", (HttpAuthFactory) new BasicAuthFactory(secretService)));
}
@ -134,8 +134,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 10)
public void testParser() throws Exception {
Template body = randomBoolean() ? new Template("_subject") : null;
Template path = new Template("_url");
Template body = randomBoolean() ? Template.inline("_subject").build() : null;
Template path = Template.inline("_url").build();
String host = "test.host";
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, HttpMethod.HEAD, null);
HttpRequestTemplate request = getHttpRequestTemplate(method, host, TEST_PORT, path, body, null);
@ -155,8 +155,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 10)
public void testParser_SelfGenerated() throws Exception {
Template body = randomBoolean() ? new Template("_body") : null;
Template path = new Template("_url");
Template body = randomBoolean() ? Template.inline("_body").build() : null;
Template path = Template.inline("_url").build();
String host = "test.host";
String watchId = "_watch";
String actionId = randomAsciiOfLength(5);
@ -182,8 +182,8 @@ public class WebhookActionTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 10)
public void testParser_Builder() throws Exception {
Template body = randomBoolean() ? new Template("_body") : null;
Template path = new Template("_url");
Template body = randomBoolean() ? Template.inline("_body").build() : null;
Template path = Template.inline("_url").build();
String host = "test.host";
String watchId = "_watch";
@ -365,10 +365,10 @@ public class WebhookActionTests extends ElasticsearchTestCase {
String path = randomFrom("{{ctx.execution_time}}", "{{ctx.trigger.scheduled_time}}", "{{ctx.trigger.triggered_time}}");
Map<String, Template> params = new HashMap<>();
params.put("foo", new Template(randomFrom("{{ctx.execution_time}}", "{{ctx.trigger.scheduled_time}}", "{{ctx.trigger.triggered_time}}")));
params.put("foo", Template.inline(randomFrom("{{ctx.execution_time}}", "{{ctx.trigger.scheduled_time}}", "{{ctx.trigger.triggered_time}}")).build());
HttpMethod method = randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT);
HttpRequestTemplate request = getHttpRequestTemplate(method, host, TEST_PORT, new Template(path), new Template(body), params);
HttpRequestTemplate request = getHttpRequestTemplate(method, host, TEST_PORT, Template.inline(path).build(), Template.inline(body).build(), params);
String watchId = "_watch";
String actionId = randomAsciiOfLength(5);
@ -395,7 +395,7 @@ public class WebhookActionTests extends ElasticsearchTestCase {
HttpClient httpClient = ExecuteScenario.Success.client();
HttpMethod method = HttpMethod.POST;
Template path = new Template("/test_{{ctx.watch_id}}");
Template path = Template.inline("/test_{{ctx.watch_id}}").build();
String host = "test.host";
HttpRequestTemplate requestTemplate = getHttpRequestTemplate(method, host, TEST_PORT, path, testBody, null);
WebhookAction action = new WebhookAction(requestTemplate);

View File

@ -82,7 +82,7 @@ public class ScriptConditionSearchTests extends AbstractWatcherIntegrationTests
.addAggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp").interval(DateHistogram.Interval.HOUR).order(Histogram.Order.COUNT_DESC))
.get();
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("ctx.payload.aggregations.rate.buckets[0]?.doc_count >= 5")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("ctx.payload.aggregations.rate.buckets[0]?.doc_count >= 5").build()), logger, scriptService);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met());
@ -100,7 +100,7 @@ public class ScriptConditionSearchTests extends AbstractWatcherIntegrationTests
@Test
public void testExecute_accessHits() throws Exception {
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("ctx.payload.hits?.hits[0]?._score == 1.0")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("ctx.payload.hits?.hits[0]?._score == 1.0").build()), logger, scriptService);
InternalSearchHit hit = new InternalSearchHit(0, "1", new StringText("type"), null);
hit.score(1f);
hit.shard(new SearchShardTarget("a", "a", 0));

View File

@ -6,6 +6,7 @@
package org.elasticsearch.watcher.condition.script;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import com.carrotsearch.randomizedtesting.annotations.Seed;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.ShardSearchFailure;
import org.elasticsearch.common.collect.ImmutableMap;
@ -16,9 +17,11 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.search.internal.InternalSearchResponse;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.watcher.execution.WatchExecutionContext;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
@ -55,7 +58,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test
public void testExecute() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("ctx.payload.hits.total > 1")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("ctx.payload.hits.total > 1").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500l, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(condition.execute(ctx).met());
@ -64,29 +67,18 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test
public void testExecute_MergedParams() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
Script script = new Script("ctx.payload.hits.total > threshold", ScriptService.ScriptType.INLINE, ScriptService.DEFAULT_LANG, ImmutableMap.<String, Object>of("threshold", 1));
Script script = Script.inline("ctx.payload.hits.total > threshold").lang(ScriptService.DEFAULT_LANG).params(ImmutableMap.<String, Object>of("threshold", 1)).build();
ExecutableScriptCondition executable = new ExecutableScriptCondition(new ScriptCondition(script), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500l, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
assertFalse(executable.execute(ctx).met());
}
@Test
@Repeat(iterations = 5)
@Test @Repeat(iterations = 5)
public void testParser_Valid() throws Exception {
ScriptConditionFactory factory = new ScriptConditionFactory(ImmutableSettings.settingsBuilder().build(), getScriptServiceProxy(tp));
XContentBuilder builder;
if (randomBoolean()) {
//Create structure
builder = createConditionContent("ctx.payload.hits.total > 1", null, null);
} else {
//Create simple { "script : "ctx.payload.hits.total" } which should parse
builder = XContentFactory.jsonBuilder();
builder.startObject();
builder.field("script", "ctx.payload.hits.total > 1");
builder.endObject();
}
XContentBuilder builder = createConditionContent("ctx.payload.hits.total > 1", null, ScriptType.INLINE);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
@ -99,7 +91,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
assertFalse(executable.execute(ctx).met());
builder = createConditionContent("return true", null, null);
builder = createConditionContent("return true", null, ScriptType.INLINE);
parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
parser.nextToken();
condition = factory.parseCondition("_watch", parser);
@ -162,7 +154,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Repeat(iterations = 3)
public void testScriptConditionParser_badScript() throws Exception {
ScriptConditionFactory conditionParser = new ScriptConditionFactory(ImmutableSettings.settingsBuilder().build(), getScriptServiceProxy(tp));
ScriptService.ScriptType scriptType = randomFrom(ScriptService.ScriptType.values());
ScriptType scriptType = randomFrom(ScriptType.values());
String script;
switch (scriptType) {
case INDEXED:
@ -184,7 +176,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test(expected = ScriptConditionValidationException.class)
public void testScriptConditionParser_badLang() throws Exception {
ScriptConditionFactory conditionParser = new ScriptConditionFactory(ImmutableSettings.settingsBuilder().build(), getScriptServiceProxy(tp));
ScriptService.ScriptType scriptType = ScriptService.ScriptType.INLINE;
ScriptType scriptType = ScriptType.INLINE;
String script = "return true";
XContentBuilder builder = createConditionContent(script, "not_a_valid_lang", scriptType);
XContentParser parser = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
@ -197,7 +189,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test(expected = ScriptConditionException.class)
public void testScriptCondition_throwException() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("assert false")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("assert false").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500l, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
condition.execute(ctx);
@ -207,7 +199,7 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test(expected = ScriptConditionException.class)
public void testScriptCondition_returnObject() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("return new Object()")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("return new Object()").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500l, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new Payload.XContent(response));
condition.execute(ctx);
@ -218,22 +210,35 @@ public class ScriptConditionTests extends ElasticsearchTestCase {
@Test
public void testScriptCondition_accessCtx() throws Exception {
ScriptServiceProxy scriptService = getScriptServiceProxy(tp);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(new Script("ctx.trigger.scheduled_time.getMillis() < System.currentTimeMillis() ")), logger, scriptService);
ExecutableScriptCondition condition = new ExecutableScriptCondition(new ScriptCondition(Script.inline("ctx.trigger.scheduled_time.getMillis() < System.currentTimeMillis() ").build()), logger, scriptService);
SearchResponse response = new SearchResponse(InternalSearchResponse.empty(), "", 3, 3, 500l, new ShardSearchFailure[0]);
WatchExecutionContext ctx = mockExecutionContext("_name", new DateTime(UTC), new Payload.XContent(response));
Thread.sleep(10);
assertThat(condition.execute(ctx).met(), is(true));
}
private static XContentBuilder createConditionContent(String script, String scriptLang, ScriptService.ScriptType scriptType) throws IOException {
XContentBuilder builder = jsonBuilder().startObject();
builder.field("script", script);
private static XContentBuilder createConditionContent(String script, String scriptLang, ScriptType scriptType) throws IOException {
XContentBuilder builder = jsonBuilder();
if (scriptType == null) {
return builder.value(script);
}
builder.startObject();
switch (scriptType) {
case INLINE:
builder.field("inline", script);
break;
case FILE:
builder.field("file", script);
break;
case INDEXED:
builder.field("id", script);
break;
default:
throw new WatcherException("unsupported script type [{}]", scriptType);
}
if (scriptLang != null) {
builder.field("lang", scriptLang);
}
if (scriptType != null) {
builder.field("type", scriptType.toString());
}
return builder.endObject();
}

View File

@ -85,7 +85,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
HttpResponse response = new HttpResponse(123, "{\"key\" : \"value\"}".getBytes(UTF8));
when(httpClient.execute(any(HttpRequest.class))).thenReturn(response);
when(templateEngine.render(eq(new Template("_body")), any(Map.class))).thenReturn("_body");
when(templateEngine.render(eq(Template.inline("_body").build()), any(Map.class))).thenReturn("_body");
Watch watch = new Watch("test-watch",
new ClockMock(),
@ -113,16 +113,16 @@ public class HttpInputTests extends ElasticsearchTestCase {
String host = randomAsciiOfLength(3);
int port = randomIntBetween(8000, 9000);
String path = randomAsciiOfLength(3);
Template pathTemplate = new Template(path);
Template pathTemplate = Template.inline(path).build();
String body = randomBoolean() ? randomAsciiOfLength(3) : null;
Map<String, Template> params = randomBoolean() ? new MapBuilder<String, Template>().put("a", new Template("b")).map() : null;
Map<String, Template> headers = randomBoolean() ? new MapBuilder<String, Template>().put("c", new Template("d")).map() : null;
Map<String, Template> params = randomBoolean() ? new MapBuilder<String, Template>().put("a", Template.inline("b").build()).map() : null;
Map<String, Template> headers = randomBoolean() ? new MapBuilder<String, Template>().put("c", Template.inline("d").build()).map() : null;
HttpAuth auth = randomBoolean() ? new BasicAuth("username", "password".toCharArray()) : null;
HttpRequestTemplate.Builder requestBuilder = HttpRequestTemplate.builder(host, port)
.scheme(scheme)
.method(httpMethod)
.path(pathTemplate)
.body(body != null ? new Template(body) : null)
.body(body != null ? Template.inline(body).build() : null)
.auth(auth);
if (params != null) {
@ -142,16 +142,16 @@ public class HttpInputTests extends ElasticsearchTestCase {
assertThat(result.getRequest().method(), equalTo(httpMethod != null ? httpMethod : HttpMethod.GET)); // get is the default
assertThat(result.getRequest().host(), equalTo(host));
assertThat(result.getRequest().port(), equalTo(port));
assertThat(result.getRequest().path(), is(new Template(path)));
assertThat(result.getRequest().path(), is(Template.inline(path).build()));
if (params != null) {
assertThat(result.getRequest().params(), hasEntry(is("a"), is(new Template("b"))));
assertThat(result.getRequest().params(), hasEntry(is("a"), is(Template.inline("b").build())));
}
if (headers != null) {
assertThat(result.getRequest().headers(), hasEntry(is("c"), is(new Template("d"))));
assertThat(result.getRequest().headers(), hasEntry(is("c"), is(Template.inline("d").build())));
}
assertThat(result.getRequest().auth(), equalTo(auth));
if (body != null) {
assertThat(result.getRequest().body(), is(new Template(body)));
assertThat(result.getRequest().body(), is(Template.inline(body).build()));
} else {
assertThat(result.getRequest().body(), nullValue());
}
@ -174,7 +174,7 @@ public class HttpInputTests extends ElasticsearchTestCase {
public void testParseResult() throws Exception {
HttpMethod httpMethod = HttpMethod.GET;
String body = "_body";
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", new Template("b")).map();
Map<String, Template> headers = new MapBuilder<String, Template>().put("a", Template.inline("b").build()).map();
HttpRequest request = HttpRequest.builder("_host", 123)
.method(httpMethod)
.body(body)

View File

@ -26,9 +26,7 @@ import org.junit.Test;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.*;
/**
*
@ -36,7 +34,7 @@ import static org.hamcrest.Matchers.is;
public class HttpRequestTemplateTests extends ElasticsearchTestCase {
@Test @Repeat(iterations = 5)
public void testXBody() throws Exception {
public void testBody_WithXContent() throws Exception {
XContentType type = randomFrom(XContentType.JSON, XContentType.YAML);
HttpRequestTemplate template = HttpRequestTemplate.builder("_host", 1234)
.body(XContentBuilder.builder(type.xContent()).startObject().endObject())
@ -54,23 +52,6 @@ public class HttpRequestTemplateTests extends ElasticsearchTestCase {
assertThat(request.headers.size(), is(0));
}
@Test(expected = HttpRequestTemplate.ParseException.class)
public void testParse_BothBodyAndXBody() throws Exception {
XContentBuilder builder = jsonBuilder()
.startObject()
.field("body", "_body")
.field("xbody", "{}")
.endObject();
XContentParser xContentParser = JsonXContent.jsonXContent.createParser(builder.bytes());
HttpAuthRegistry registry = new HttpAuthRegistry(ImmutableMap.<String, HttpAuthFactory>of(BasicAuth.TYPE, new BasicAuthFactory(new SecretService.PlainText())));
HttpRequestTemplate.Parser parser = new HttpRequestTemplate.Parser(registry);
xContentParser.nextToken();
HttpRequestTemplate parsed = parser.parse(xContentParser);
}
@Test @Repeat(iterations = 20)
public void testParse_SelfGenerated() throws Exception {
HttpRequestTemplate.Builder builder = HttpRequestTemplate.builder("_host", 1234);
@ -93,10 +74,10 @@ public class HttpRequestTemplateTests extends ElasticsearchTestCase {
builder.auth(new BasicAuth("_username", "_password".toCharArray()));
}
if (randomBoolean()) {
builder.putParam("_key", new Template("_value"));
builder.putParam("_key", Template.inline("_value"));
}
if (randomBoolean()) {
builder.putHeader("_key", new Template("_value"));
builder.putHeader("_key", Template.inline("_value"));
}
HttpRequestTemplate template = builder.build();

View File

@ -5,6 +5,8 @@
*/
package org.elasticsearch.watcher.support.template;
import com.carrotsearch.randomizedtesting.annotations.Repeat;
import com.carrotsearch.randomizedtesting.annotations.Seed;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableMap;
import org.elasticsearch.common.settings.ImmutableSettings;
@ -12,8 +14,9 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
import org.elasticsearch.watcher.support.template.xmustache.XMustacheTemplateEngine;
import org.junit.Before;
@ -49,12 +52,12 @@ public class TemplateTests extends ElasticsearchTestCase {
Map<String, Object> params = ImmutableMap.<String, Object>of("param_key", "param_val");
Map<String, Object> model = ImmutableMap.<String, Object>of("model_key", "model_val");
Map<String, Object> merged = ImmutableMap.<String, Object>builder().putAll(params).putAll(model).build();
ScriptService.ScriptType scriptType = ScriptService.ScriptType.values()[randomIntBetween(0, ScriptService.ScriptType.values().length - 1)];
ScriptType type = randomFrom(ScriptType.values());
when(proxy.executable(lang, templateText, scriptType, merged)).thenReturn(script);
when(proxy.executable(lang, templateText, type, merged)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");
Template template = new Template(templateText, scriptType, params);
Template template = templateBuilder(type, templateText).params(params).build();
assertThat(engine.render(template, model), is("rendered_text"));
}
@ -63,13 +66,12 @@ public class TemplateTests extends ElasticsearchTestCase {
String templateText = "_template";
Map<String, Object> params = ImmutableMap.<String, Object>of("key", "param_val");
Map<String, Object> model = ImmutableMap.<String, Object>of("key", "model_val");
ScriptService.ScriptType scriptType = randomScriptType();
ScriptType scriptType = randomFrom(ScriptType.values());
when(proxy.executable(lang, templateText, scriptType, model)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");
Template template = new Template(templateText, scriptType, params);
Template template = templateBuilder(scriptType, templateText).params(params).build();
assertThat(engine.render(template, model), is("rendered_text"));
}
@ -78,22 +80,30 @@ public class TemplateTests extends ElasticsearchTestCase {
String templateText = "_template";
Map<String, Object> model = ImmutableMap.<String, Object>of("key", "model_val");
when(proxy.executable(lang, templateText, ScriptService.ScriptType.INLINE, model)).thenReturn(script);
when(proxy.executable(lang, templateText, ScriptType.INLINE, model)).thenReturn(script);
when(script.run()).thenReturn("rendered_text");
Template template = new Template(templateText);
assertThat(engine.render(template, model), is("rendered_text"));
}
@Test
@Test @Repeat(iterations = 5)
public void testParser() throws Exception {
Template template = new Template("_template", randomScriptType(), ImmutableMap.<String, Object>of("param_key", "param_val"));
XContentBuilder builder = jsonBuilder().startObject()
.field(randomFrom("template"), template.getTemplate())
.field(randomFrom("type"), template.getType().name())
.field(randomFrom("params"), template.getParams())
.endObject();
ScriptType type = randomScriptType();
Template template = templateBuilder(type, "_template").params(ImmutableMap.<String, Object>of("param_key", "param_val")).build();
XContentBuilder builder = jsonBuilder().startObject();
switch (type) {
case INLINE:
builder.field("inline", template.getTemplate());
break;
case FILE:
builder.field("file", template.getTemplate());
break;
case INDEXED:
builder.field("id", template.getTemplate());
}
builder.field("params", template.getParams());
builder.endObject();
BytesReference bytes = builder.bytes();
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
parser.nextToken();
@ -104,7 +114,7 @@ public class TemplateTests extends ElasticsearchTestCase {
@Test
public void testParser_ParserSelfGenerated() throws Exception {
Template template = new Template("_template", randomScriptType(), ImmutableMap.<String, Object>of("param_key", "param_val"));
Template template = templateBuilder(randomScriptType(), "_template").params(ImmutableMap.<String, Object>of("param_key", "param_val")).build();
XContentBuilder builder = jsonBuilder().value(template);
BytesReference bytes = builder.bytes();
@ -144,7 +154,7 @@ public class TemplateTests extends ElasticsearchTestCase {
@Test(expected = Template.ParseException.class)
public void testParser_Invalid_MissingText() throws Exception {
XContentBuilder builder = jsonBuilder().startObject()
.field("type", ScriptService.ScriptType.INDEXED)
.field("type", ScriptType.INDEXED)
.startObject("params").endObject()
.endObject();
BytesReference bytes = builder.bytes();
@ -154,7 +164,17 @@ public class TemplateTests extends ElasticsearchTestCase {
fail("expected parse exception when template text is missing");
}
private static ScriptService.ScriptType randomScriptType() {
return randomFrom(ScriptService.ScriptType.values());
private Template.Builder templateBuilder(ScriptType type, String text) {
switch (type) {
case INLINE: return Template.inline(text);
case FILE: return Template.file(text);
case INDEXED: return Template.indexed(text);
default:
throw new WatcherException("unsupported script type [{}]", type);
}
}
private static ScriptType randomScriptType() {
return randomFrom(ScriptType.values());
}
}

View File

@ -150,9 +150,9 @@ public final class WatcherTestUtils {
HttpRequestTemplate.Builder httpRequest = HttpRequestTemplate.builder("localhost", 80);
httpRequest.method(HttpMethod.POST);
Template path = new Template("/foobarbaz/{{ctx.watch_id}}");
Template path = Template.inline("/foobarbaz/{{ctx.watch_id}}").build();
httpRequest.path(path);
Template body = new Template("{{ctx.watch_id}} executed with {{ctx.payload.response.hits.total_hits}} hits");
Template body = Template.inline("{{ctx.watch_id}} executed with {{ctx.payload.response.hits.total_hits}} hits").build();
httpRequest.body(body);
TemplateEngine engine = new XMustacheTemplateEngine(ImmutableSettings.EMPTY, scriptService);
@ -191,7 +191,7 @@ public final class WatcherTestUtils {
licenseService,
new ScheduleTrigger(new CronSchedule("0/5 * * * * ? *")),
new ExecutableSimpleInput(new SimpleInput(new Payload.Simple(inputData)), logger),
new ExecutableScriptCondition(new ScriptCondition(new Script("return true")), logger, scriptService),
new ExecutableScriptCondition(new ScriptCondition(Script.inline("return true").build()), logger, scriptService),
new ExecutableSearchTransform(new SearchTransform(transformRequest), logger, scriptService, client),
new ExecutableActions(actions),
metadata,

View File

@ -15,7 +15,6 @@ import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.watcher.client.WatcherClient;
import org.elasticsearch.watcher.history.HistoryStore;
import org.elasticsearch.watcher.support.http.HttpRequestTemplate;
import org.elasticsearch.watcher.support.http.auth.basic.ApplicableBasicAuth;
import org.elasticsearch.watcher.support.http.auth.basic.BasicAuth;
import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
@ -107,7 +106,7 @@ public class HttpInputIntegrationTest extends AbstractWatcherIntegrationTests {
.field("query").value(termQuery("field", "value"))
.endObject();
HttpRequestTemplate.Builder requestBuilder = HttpRequestTemplate.builder(address.getHostName(), address.getPort())
.path(new Template("/idx/_search"))
.path(Template.inline("/idx/_search"))
.body(body);
if (shieldEnabled()) {
requestBuilder.auth(new BasicAuth("test", "changeme".toCharArray()));

View File

@ -9,7 +9,6 @@ import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
import org.elasticsearch.watcher.test.WatcherTestUtils;
@ -53,14 +52,14 @@ public class TransformSearchTests extends AbstractWatcherIntegrationTests {
final Script script;
if (randomBoolean()) {
logger.info("testing script transform with an inline script");
script = new Script("return [key3 : ctx.payload.key1 + ctx.payload.key2]", ScriptService.ScriptType.INLINE, "groovy");
script = Script.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
} else if (randomBoolean()) {
logger.info("testing script transform with an indexed script");
client().preparePutIndexedScript("groovy", "_id", "{\"script\" : \"return [key3 : ctx.payload.key1 + ctx.payload.key2]\"}").get();
script = new Script("_id", ScriptService.ScriptType.INDEXED, "groovy");
script = Script.indexed("_id").lang("groovy").build();
} else {
logger.info("testing script transform with a file script");
script = new Script("my-script", ScriptService.ScriptType.FILE, "groovy");
script = Script.file("my-script").lang("groovy").build();
}
// put a watch that has watch level transform:
@ -156,8 +155,8 @@ public class TransformSearchTests extends AbstractWatcherIntegrationTests {
@Test
public void testChainTransform() throws Exception {
final Script script1 = new Script("return [key3 : ctx.payload.key1 + ctx.payload.key2]", ScriptService.ScriptType.INLINE, "groovy");
final Script script2 = new Script("return [key4 : ctx.payload.key3 + 10]", ScriptService.ScriptType.INLINE, "groovy");
final Script script1 = Script.inline("return [key3 : ctx.payload.key1 + ctx.payload.key2]").lang("groovy").build();
final Script script2 = Script.inline("return [key4 : ctx.payload.key3 + 10]").lang("groovy").build();
// put a watch that has watch level transform:
PutWatchResponse putWatchResponse = watcherClient().preparePutWatch("_id1")
.setSource(watchBuilder()

View File

@ -80,7 +80,7 @@ public class WatchMetadataTests extends AbstractWatcherIntegrationTests {
metadata.put("foo", "bar");
metadata.put("logtext", "This is a test");
LoggingAction loggingAction = new LoggingAction(new Template("{{ctx.metadata.logtext}}"), LoggingLevel.DEBUG, "test");
LoggingAction loggingAction = new LoggingAction(Template.inline("{{ctx.metadata.logtext}}").build(), LoggingLevel.DEBUG, "test");
watcherClient().preparePutWatch("_name")
.setSource(watchBuilder()

View File

@ -93,8 +93,8 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
HttpRequestTemplate.Builder builder = HttpRequestTemplate.builder("localhost", webPort)
.scheme(Scheme.HTTPS)
.path(Template.builder("/test/{{ctx.watch_id}}").build())
.body(Template.builder("{{ctx.payload}}").build());
.path(Template.inline("/test/{{ctx.watch_id}}").build())
.body(Template.inline("{{ctx.payload}}").build());
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder()
@ -128,8 +128,8 @@ public class WebhookHttpsIntegrationTests extends AbstractWatcherIntegrationTest
HttpRequestTemplate.Builder builder = HttpRequestTemplate.builder("localhost", webPort)
.scheme(Scheme.HTTPS)
.auth(new BasicAuth("_username", "_password".toCharArray()))
.path(Template.builder("/test/{{ctx.watch_id}}").build())
.body(Template.builder("{{ctx.payload}}").build());
.path(Template.inline("/test/{{ctx.watch_id}}").build())
.body(Template.inline("{{ctx.payload}}").build());
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder()

View File

@ -12,7 +12,6 @@ import com.squareup.okhttp.mockwebserver.QueueDispatcher;
import com.squareup.okhttp.mockwebserver.RecordedRequest;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.watcher.actions.ActionBuilders;
import org.elasticsearch.watcher.history.HistoryStore;
@ -20,6 +19,7 @@ import org.elasticsearch.watcher.history.WatchRecord;
import org.elasticsearch.watcher.support.http.HttpRequestTemplate;
import org.elasticsearch.watcher.support.http.auth.basic.BasicAuth;
import org.elasticsearch.watcher.support.template.Template;
import org.elasticsearch.watcher.support.xcontent.XContentSource;
import org.elasticsearch.watcher.test.AbstractWatcherIntegrationTests;
import org.junit.After;
import org.junit.Before;
@ -69,10 +69,10 @@ public class WebhookIntegrationTests extends AbstractWatcherIntegrationTests {
public void testWebhook() throws Exception {
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
HttpRequestTemplate.Builder builder = HttpRequestTemplate.builder("localhost", webPort)
.path(Template.builder("/test/{{ctx.watch_id}}").build())
.putParam("param1", Template.builder("value1").build())
.putParam("watch_id", Template.builder("{{ctx.watch_id}}").build())
.body(Template.builder("{{ctx.payload}}").build());
.path(Template.inline("/test/{{ctx.watch_id}}"))
.putParam("param1", Template.inline("value1"))
.putParam("watch_id", Template.inline("{{ctx.watch_id}}"))
.body(Template.inline("{{ctx.payload}}"));
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder()
@ -95,9 +95,11 @@ public class WebhookIntegrationTests extends AbstractWatcherIntegrationTests {
SearchResponse response = client().prepareSearch(HistoryStore.INDEX_PREFIX + "*")
.setQuery(QueryBuilders.termQuery(WatchRecord.Parser.STATE_FIELD.getPreferredName(), "executed"))
.get();
assertNoFailures(response);
assertThat(XContentMapValues.extractValue("watch_execution.actions_results._id.webhook.response.body", response.getHits().getAt(0).sourceAsMap()).toString(), equalTo("body"));
assertThat(XContentMapValues.extractValue("watch_execution.actions_results._id.webhook.response.status", response.getHits().getAt(0).sourceAsMap()).toString(), equalTo("200"));
XContentSource source = new XContentSource(response.getHits().getAt(0).getSourceRef());
assertThat(source.getValue("watch_execution.actions_results._id.webhook.response.body"), equalTo((Object) "body"));
assertThat(source.getValue("watch_execution.actions_results._id.webhook.response.status"), equalTo((Object) 200));
}
@Test
@ -105,10 +107,10 @@ public class WebhookIntegrationTests extends AbstractWatcherIntegrationTests {
webServer.enqueue(new MockResponse().setResponseCode(200).setBody("body"));
HttpRequestTemplate.Builder builder = HttpRequestTemplate.builder("localhost", webPort)
.auth(new BasicAuth("_username", "_password".toCharArray()))
.path(Template.builder("/test/{{ctx.watch_id}}").build())
.putParam("param1", Template.builder("value1").build())
.putParam("watch_id", Template.builder("{{ctx.watch_id}}").build())
.body(Template.builder("{{ctx.payload}}").build());
.path(Template.inline("/test/{{ctx.watch_id}}").build())
.putParam("param1", Template.inline("value1").build())
.putParam("watch_id", Template.inline("{{ctx.watch_id}}").build())
.body(Template.inline("{{ctx.payload}}").build());
watcherClient().preparePutWatch("_id")
.setSource(watchBuilder()

View File

@ -14,6 +14,7 @@ import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.test.rest.RestTestCandidate;
import org.elasticsearch.watcher.WatcherPlugin;
import org.elasticsearch.watcher.license.LicenseIntegrationTests;
import org.elasticsearch.watcher.license.LicenseIntegrationTests.MockLicenseService;
import org.junit.Test;
import java.io.IOException;
@ -24,7 +25,6 @@ import static org.hamcrest.Matchers.is;
*/
public class WatcherDisabledLicenseRestTests extends WatcherRestTests {
@Override
protected Settings nodeSettings(int nodeOrdinal) {
ImmutableSettings.Builder builder = ImmutableSettings.builder()
@ -42,7 +42,6 @@ public class WatcherDisabledLicenseRestTests extends WatcherRestTests {
return LicenseIntegrationTests.MockLicensePlugin.class;
}
public WatcherDisabledLicenseRestTests(@Name("yaml") RestTestCandidate testCandidate) {
super(testCandidate);
}
@ -64,7 +63,7 @@ public class WatcherDisabledLicenseRestTests extends WatcherRestTests {
}
public static void disableLicensing() {
for (LicenseIntegrationTests.MockLicenseService service : internalCluster().getInstances(LicenseIntegrationTests.MockLicenseService.class)) {
for (MockLicenseService service : internalCluster().getInstances(MockLicenseService.class)) {
service.disable();
}
}

View File

@ -6,7 +6,7 @@
package org.elasticsearch.watcher.test.rest;
import com.carrotsearch.randomizedtesting.annotations.Name;
import org.apache.lucene.util.AbstractRandomizedTest;
import org.apache.lucene.util.AbstractRandomizedTest.Rest;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.base.Charsets;
import org.elasticsearch.common.io.FileSystemUtils;
@ -17,7 +17,7 @@ import org.elasticsearch.license.plugin.LicensePlugin;
import org.elasticsearch.node.internal.InternalNode;
import org.elasticsearch.shield.ShieldPlugin;
import org.elasticsearch.shield.authc.esusers.ESUsersRealm;
import org.elasticsearch.test.ElasticsearchIntegrationTest;
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
import org.elasticsearch.test.junit.annotations.TestLogging;
import org.elasticsearch.test.rest.ElasticsearchRestTests;
import org.elasticsearch.test.rest.RestTestCandidate;
@ -27,9 +27,11 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
@AbstractRandomizedTest.Rest
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numClientNodes = 1, transportClientRatio = 0, numDataNodes = 1, randomDynamicTemplates = false)
@Rest
@ClusterScope(scope = SUITE, numClientNodes = 1, transportClientRatio = 0, numDataNodes = 1, randomDynamicTemplates = false)
@TestLogging("_root:DEBUG")
public class WatcherRestTests extends ElasticsearchRestTests {
@ -101,7 +103,6 @@ public class WatcherRestTests extends ElasticsearchRestTests {
}
/** Shield related settings */
public static class ShieldSettings {
@ -182,5 +183,4 @@ public class WatcherRestTests extends ElasticsearchRestTests {
}
}
}

View File

@ -16,18 +16,15 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.script.ScriptService.ScriptType;
import org.elasticsearch.test.ElasticsearchTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.watcher.WatcherException;
import org.elasticsearch.watcher.execution.WatchExecutionContext;
import org.elasticsearch.watcher.support.Script;
import org.elasticsearch.watcher.support.Variables;
import org.elasticsearch.watcher.support.init.proxy.ScriptServiceProxy;
import org.elasticsearch.watcher.transform.Transform;
import org.elasticsearch.watcher.transform.script.ExecutableScriptTransform;
import org.elasticsearch.watcher.transform.script.ScriptTransform;
import org.elasticsearch.watcher.transform.script.ScriptTransformFactory;
import org.elasticsearch.watcher.transform.script.ScriptTransformValidationException;
import org.elasticsearch.watcher.watch.Payload;
import org.junit.After;
import org.junit.Before;
@ -63,9 +60,9 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
@Test
public void testApply_MapValue() throws Exception {
ScriptServiceProxy service = mock(ScriptServiceProxy.class);
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
ScriptType type = randomFrom(ScriptType.values());
Map<String, Object> params = Collections.emptyMap();
Script script = new Script("_script", type, "_lang", params);
Script script = scriptBuilder(type, "_script").lang("_lang").params(params).build();
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(script)).thenReturn(compiledScript);
ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service);
@ -94,9 +91,9 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
public void testApply_NonMapValue() throws Exception {
ScriptServiceProxy service = mock(ScriptServiceProxy.class);
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
ScriptType type = randomFrom(ScriptType.values());
Map<String, Object> params = Collections.emptyMap();
Script script = new Script("_script", type, "_lang", params);
Script script = scriptBuilder(type, "_script").lang("_lang").params(params).build();
CompiledScript compiledScript = mock(CompiledScript.class);
when(service.compile(script)).thenReturn(compiledScript);
ExecutableScriptTransform transform = new ExecutableScriptTransform(new ScriptTransform(script), logger, service);
@ -108,7 +105,7 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
Map<String, Object> model = Variables.createCtxModel(ctx, payload);
ExecutableScript executable = mock(ExecutableScript.class);
Object value = randomFrom("value", 1, new String[]{"value"}, ImmutableList.of("value"), ImmutableSet.of("value"));
Object value = randomFrom("value", 1, new String[] { "value" }, ImmutableList.of("value"), ImmutableSet.of("value"));
when(executable.run()).thenReturn(value);
when(service.executable(compiledScript, model)).thenReturn(executable);
@ -122,18 +119,18 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
@Test
public void testParser() throws Exception {
ScriptServiceProxy service = mock(ScriptServiceProxy.class);
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
XContentBuilder builder = jsonBuilder().startObject()
.field("script", "_script")
.field("lang", "_lang")
.field("type", type.name())
.startObject("params").field("key", "value").endObject()
.endObject();
ScriptType type = randomFrom(ScriptType.values());
XContentBuilder builder = jsonBuilder().startObject();
builder.field(scriptTypeField(type), "_script");
builder.field("lang", "_lang");
builder.startObject("params").field("key", "value").endObject();
builder.endObject();
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken();
ExecutableScriptTransform transform = new ScriptTransformFactory(ImmutableSettings.EMPTY, service).parseExecutable("_id", parser);
assertThat(transform.transform().getScript(), equalTo(new Script("_script", type, "_lang", ImmutableMap.<String, Object>builder().put("key", "value").build())));
Script script = scriptBuilder(type, "_script").lang("_lang").params(ImmutableMap.<String, Object>builder().put("key", "value").build()).build();
assertThat(transform.transform().getScript(), equalTo(script));
}
@Test
@ -144,7 +141,7 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
parser.nextToken();
ExecutableScriptTransform transform = new ScriptTransformFactory(ImmutableSettings.EMPTY, service).parseExecutable("_id", parser);
assertThat(transform.transform().getScript(), equalTo(new Script("_script")));
assertThat(transform.transform().getScript(), equalTo(Script.defaultType("_script").build()));
}
@ -152,7 +149,7 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
@Repeat(iterations = 3)
public void testScriptConditionParser_badScript() throws Exception {
ScriptTransformFactory transformFactory = new ScriptTransformFactory(ImmutableSettings.settingsBuilder().build(), getScriptServiceProxy(tp));
ScriptService.ScriptType scriptType = randomFrom(ScriptService.ScriptType.values());
ScriptType scriptType = randomFrom(ScriptType.values());
String script;
switch (scriptType) {
case INDEXED:
@ -165,9 +162,8 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
}
XContentBuilder builder = jsonBuilder().startObject()
.field("script", script)
.field(scriptTypeField(scriptType), script)
.field("lang", "groovy")
.field("type", scriptType.name())
.startObject("params").field("key", "value").endObject()
.endObject();
@ -181,12 +177,11 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
@Test(expected = ScriptTransformValidationException.class)
public void testScriptConditionParser_badLang() throws Exception {
ScriptTransformFactory transformFactory = new ScriptTransformFactory(ImmutableSettings.settingsBuilder().build(), getScriptServiceProxy(tp));
ScriptService.ScriptType scriptType = ScriptService.ScriptType.INLINE;
ScriptType scriptType = randomFrom(ScriptType.values());
String script = "return true";
XContentBuilder builder = jsonBuilder().startObject()
.field("script", script)
.field(scriptTypeField(scriptType), script)
.field("lang", "not_a_valid_lang")
.field("type", scriptType.name())
.startObject("params").field("key", "value").endObject()
.endObject();
@ -198,4 +193,23 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
fail("expected a transform validation exception trying to create an executable with an invalid language");
}
static Script.Builder scriptBuilder(ScriptType type, String script) {
switch (type) {
case INLINE: return Script.inline(script);
case FILE: return Script.file(script);
case INDEXED: return Script.indexed(script);
default:
throw new WatcherException("unsupported script type [{}]", type);
}
}
static String scriptTypeField(ScriptType type) {
switch (type) {
case INLINE: return "inline";
case FILE: return "file";
case INDEXED: return "id";
default:
throw new WatcherException("unsupported script type [{}]", type);
}
}
}

View File

@ -285,7 +285,7 @@ public class WatchTests extends ElasticsearchTestCase {
String type = randomFrom(ScriptCondition.TYPE, AlwaysCondition.TYPE);
switch (type) {
case ScriptCondition.TYPE:
return new ExecutableScriptCondition(new ScriptCondition(new Script("_script")), logger, scriptService);
return new ExecutableScriptCondition(new ScriptCondition(Script.inline("_script").build()), logger, scriptService);
default:
return new ExecutableAlwaysCondition(logger);
}
@ -307,16 +307,16 @@ public class WatchTests extends ElasticsearchTestCase {
String type = randomFrom(ScriptTransform.TYPE, SearchTransform.TYPE, ChainTransform.TYPE);
switch (type) {
case ScriptTransform.TYPE:
return new ExecutableScriptTransform(new ScriptTransform(new Script("_script")), logger, scriptService);
return new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService);
case SearchTransform.TYPE:
return new ExecutableSearchTransform(new SearchTransform(matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS)), logger, scriptService, client);
default: // chain
ChainTransform chainTransform = new ChainTransform(ImmutableList.of(
new SearchTransform(matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS)),
new ScriptTransform(new Script("_script"))));
new ScriptTransform(Script.inline("_script").build())));
return new ExecutableChainTransform(chainTransform, logger, ImmutableList.<ExecutableTransform>of(
new ExecutableSearchTransform(new SearchTransform(matchAllRequest(WatcherUtils.DEFAULT_INDICES_OPTIONS)), logger, scriptService, client),
new ExecutableScriptTransform(new ScriptTransform(new Script("_script")), logger, scriptService)));
new ExecutableScriptTransform(new ScriptTransform(Script.inline("_script").build()), logger, scriptService)));
}
}
@ -345,7 +345,7 @@ public class WatchTests extends ElasticsearchTestCase {
if (randomBoolean()) {
HttpRequestTemplate httpRequest = HttpRequestTemplate.builder("test.host", randomIntBetween(8000, 9000))
.method(randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT))
.path(new Template("_url"))
.path(Template.inline("_url").build())
.build();
WebhookAction action = new WebhookAction(httpRequest);
list.add(new ActionWrapper("_webhook_" + randomAsciiOfLength(8), randomTransform(), new ExecutableWebhookAction(action, logger, httpClient, templateEngine)));