[client] reorganized tests and added alert source builder
The `AlertSourceBuilder` along with a set of source builder for all the different constructs that make an alert (condition, input, transform and action), provides a structured approach for building an alert from the client side (instead of forcing the clients to use xcontent directory) - fixed some of the tests to already use these builders (I reckon there are still quite a few that need to be converted.. but we'll do that over time). - moved all integration tests under `test/integration` package. - changed the `AlertsTests` to **not** be an integration test... it randomizes the alert structure and makes sure that it can serialize & deserialize itself to/from xcontent. - fixed small bugs found by the tests Original commit: elastic/x-pack-elasticsearch@94b76b6fc7
This commit is contained in:
parent
b76b0e7129
commit
aae6ff834f
|
@ -7,11 +7,13 @@ package org.elasticsearch.alerts;
|
|||
|
||||
import org.elasticsearch.alerts.actions.ActionRegistry;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.scheduler.Scheduler;
|
||||
import org.elasticsearch.alerts.condition.Condition;
|
||||
import org.elasticsearch.alerts.condition.ConditionRegistry;
|
||||
import org.elasticsearch.alerts.condition.simple.AlwaysTrueCondition;
|
||||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.InputRegistry;
|
||||
import org.elasticsearch.alerts.input.NoneInput;
|
||||
import org.elasticsearch.alerts.scheduler.Scheduler;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.Schedule;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.ScheduleRegistry;
|
||||
import org.elasticsearch.alerts.throttle.AlertThrottler;
|
||||
|
@ -27,6 +29,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
|
|||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Streamable;
|
||||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
import org.elasticsearch.common.joda.time.DateTimeZone;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
|
@ -57,7 +60,7 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
@Nullable
|
||||
private final Transform transform;
|
||||
|
||||
public Alert(String name, Schedule schedule, Input input, Condition condition, Transform transform, Actions actions, Map<String, Object> metadata, Status status, TimeValue throttlePeriod) {
|
||||
public Alert(String name, Schedule schedule, Input input, Condition condition, @Nullable Transform transform, Actions actions, @Nullable Map<String, Object> metadata, @Nullable TimeValue throttlePeriod, @Nullable Status status) {
|
||||
this.name = name;
|
||||
this.schedule = schedule;
|
||||
this.input = input;
|
||||
|
@ -67,7 +70,6 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
this.throttlePeriod = throttlePeriod;
|
||||
this.metadata = metadata;
|
||||
this.transform = transform != null ? transform : Transform.NOOP;
|
||||
|
||||
throttler = new AlertThrottler(throttlePeriod);
|
||||
}
|
||||
|
||||
|
@ -174,6 +176,9 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
private final ActionRegistry actionRegistry;
|
||||
private final InputRegistry inputRegistry;
|
||||
|
||||
private final Input defaultInput;
|
||||
private final Condition defaultCondition;
|
||||
|
||||
@Inject
|
||||
public Parser(Settings settings, ConditionRegistry conditionRegistry, ScheduleRegistry scheduleRegistry,
|
||||
TransformRegistry transformRegistry, ActionRegistry actionRegistry,
|
||||
|
@ -185,6 +190,9 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
this.transformRegistry = transformRegistry;
|
||||
this.actionRegistry = actionRegistry;
|
||||
this.inputRegistry = inputRegistry;
|
||||
|
||||
this.defaultInput = new NoneInput(logger);
|
||||
this.defaultCondition = new AlwaysTrueCondition(logger);
|
||||
}
|
||||
|
||||
public Alert parse(String name, boolean includeStatus, BytesReference source) {
|
||||
|
@ -200,8 +208,8 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
|
||||
public Alert parse(String name, boolean includeStatus, XContentParser parser) throws IOException {
|
||||
Schedule schedule = null;
|
||||
Input input = null;
|
||||
Condition condition = null;
|
||||
Input input = defaultInput;
|
||||
Condition condition = defaultCondition;
|
||||
Actions actions = null;
|
||||
Transform transform = null;
|
||||
Map<String, Object> metatdata = null;
|
||||
|
@ -244,30 +252,24 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
if (schedule == null) {
|
||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert schedule");
|
||||
}
|
||||
if (input == null) {
|
||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert input");
|
||||
}
|
||||
if (condition == null) {
|
||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert condition");
|
||||
}
|
||||
if (actions == null) {
|
||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert actions");
|
||||
}
|
||||
|
||||
return new Alert(name, schedule, input, condition, transform, actions, metatdata, status, throttlePeriod);
|
||||
return new Alert(name, schedule, input, condition, transform, actions, metatdata, throttlePeriod, status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Status implements ToXContent, Streamable {
|
||||
|
||||
public static final ParseField TIMESTAMP_FIELD = new ParseField("last_throttled");
|
||||
public static final ParseField LAST_CHECKED_FIELD = new ParseField("last_checked");
|
||||
public static final ParseField LAST_MET_CONDITION_FIELD = new ParseField("last_met_condition");
|
||||
public static final ParseField LAST_THROTTLED_FIELD = new ParseField("last_throttled");
|
||||
public static final ParseField LAST_EXECUTED_FIELD = new ParseField("last_executed");
|
||||
public static final ParseField ACK_FIELD = new ParseField("ack");
|
||||
public static final ParseField STATE_FIELD = new ParseField("state");
|
||||
public static final ParseField TIMESTAMP_FIELD = new ParseField("timestamp");
|
||||
public static final ParseField REASON_FIELD = new ParseField("reason");
|
||||
|
||||
private transient long version;
|
||||
|
@ -335,6 +337,38 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
return ackStatus;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Status status = (Status) o;
|
||||
|
||||
if (version != status.version) return false;
|
||||
if (!ackStatus.equals(status.ackStatus)) return false;
|
||||
if (lastChecked != null ? !lastChecked.equals(status.lastChecked) : status.lastChecked != null)
|
||||
return false;
|
||||
if (lastExecuted != null ? !lastExecuted.equals(status.lastExecuted) : status.lastExecuted != null)
|
||||
return false;
|
||||
if (lastMetCondition != null ? !lastMetCondition.equals(status.lastMetCondition) : status.lastMetCondition != null)
|
||||
return false;
|
||||
if (lastThrottle != null ? !lastThrottle.equals(status.lastThrottle) : status.lastThrottle != null)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) (version ^ (version >>> 32));
|
||||
result = 31 * result + (lastChecked != null ? lastChecked.hashCode() : 0);
|
||||
result = 31 * result + (lastMetCondition != null ? lastMetCondition.hashCode() : 0);
|
||||
result = 31 * result + (lastThrottle != null ? lastThrottle.hashCode() : 0);
|
||||
result = 31 * result + (lastExecuted != null ? lastExecuted.hashCode() : 0);
|
||||
result = 31 * result + ackStatus.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called whenever an alert is checked, ie. the condition of the alert is evaluated to see if
|
||||
* the alert should be executed.
|
||||
|
@ -534,7 +568,7 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
private final DateTime timestamp;
|
||||
|
||||
public AckStatus() {
|
||||
this(State.AWAITS_EXECUTION, new DateTime());
|
||||
this(State.AWAITS_EXECUTION, new DateTime(DateTimeZone.UTC));
|
||||
}
|
||||
|
||||
public AckStatus(State state, DateTime timestamp) {
|
||||
|
@ -550,6 +584,25 @@ public class Alert implements Scheduler.Job, ToXContent {
|
|||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
AckStatus ackStatus = (AckStatus) o;
|
||||
|
||||
if (state != ackStatus.state) return false;
|
||||
if (!timestamp.equals(ackStatus.timestamp)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = state.hashCode();
|
||||
result = 31 * result + timestamp.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Throttle {
|
||||
|
|
|
@ -43,6 +43,23 @@ public interface Payload extends ToXContent {
|
|||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.value(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Simple simple = (Simple) o;
|
||||
|
||||
if (!data.equals(simple.data)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return data.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
static class ActionResponse extends Simple {
|
||||
|
@ -50,7 +67,6 @@ public interface Payload extends ToXContent {
|
|||
public ActionResponse(org.elasticsearch.action.ActionResponse response) {
|
||||
super(responseToData(response));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class XContent extends Simple {
|
||||
|
|
|
@ -48,7 +48,7 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
|
|||
/**
|
||||
* Parses xcontent to a concrete action of the same type.
|
||||
*/
|
||||
protected static interface Parser<R extends Result, T extends Action<R>> {
|
||||
public static interface Parser<R extends Result, T extends Action<R>> {
|
||||
|
||||
/**
|
||||
* @return The type of the action
|
||||
|
@ -92,5 +92,12 @@ public abstract class Action<R extends Action.Result> implements ToXContent {
|
|||
}
|
||||
|
||||
protected abstract XContentBuilder xContentBody(XContentBuilder builder, Params params) throws IOException;
|
||||
|
||||
}
|
||||
|
||||
public static interface SourceBuilder extends ToXContent {
|
||||
|
||||
String type();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.alerts.actions;
|
||||
|
||||
import org.elasticsearch.alerts.actions.email.EmailAction;
|
||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
||||
import org.elasticsearch.alerts.actions.webhook.WebhookAction;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class ActionBuilders {
|
||||
|
||||
private ActionBuilders() {
|
||||
}
|
||||
|
||||
public static EmailAction.SourceBuilder emailAction() {
|
||||
return new EmailAction.SourceBuilder();
|
||||
}
|
||||
|
||||
public static IndexAction.SourceBuilder indexAction(String index, String type) {
|
||||
return new IndexAction.SourceBuilder(index, type);
|
||||
}
|
||||
|
||||
public static WebhookAction.SourceBuilder webhookAction(String url) {
|
||||
return new WebhookAction.SourceBuilder(url);
|
||||
}
|
||||
|
||||
public static WebhookAction.SourceBuilder webhookAction(Script url) {
|
||||
return new WebhookAction.SourceBuilder(url);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,10 @@ public class Actions implements Iterable<Action>, ToXContent {
|
|||
this.actions = actions;
|
||||
}
|
||||
|
||||
public int count() {
|
||||
return actions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Action> iterator() {
|
||||
return actions.iterator();
|
||||
|
@ -38,4 +42,20 @@ public class Actions implements Iterable<Action>, ToXContent {
|
|||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Actions actions1 = (Actions) o;
|
||||
|
||||
if (!actions.equals(actions1.actions)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return actions.hashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -358,6 +358,68 @@ public class EmailAction extends Action<EmailAction.Result> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Action.SourceBuilder {
|
||||
|
||||
private Email.Address from;
|
||||
private Email.AddressList replyTo;
|
||||
private Email.AddressList to;
|
||||
private Email.AddressList cc;
|
||||
private Email.AddressList bcc;
|
||||
private Authentication auth = null;
|
||||
private Profile profile = null;
|
||||
private String account = null;
|
||||
private Template subject;
|
||||
private Template textBody;
|
||||
private Template htmlBody;
|
||||
private Boolean attachPayload;
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
if (from != null) {
|
||||
builder.field(Email.FROM_FIELD.getPreferredName(), from);
|
||||
}
|
||||
if (replyTo != null && replyTo.size() != 0) {
|
||||
builder.field(Email.REPLY_TO_FIELD.getPreferredName(), (ToXContent) replyTo);
|
||||
}
|
||||
if (to != null && to.size() != 0) {
|
||||
builder.field(Email.TO_FIELD.getPreferredName(), (ToXContent) to);
|
||||
}
|
||||
if (cc != null && cc.size() != 0) {
|
||||
builder.field(Email.CC_FIELD.getPreferredName(), (ToXContent) cc);
|
||||
}
|
||||
if (bcc != null && bcc.size() != 0) {
|
||||
builder.field(Email.BCC_FIELD.getPreferredName(), (ToXContent) bcc);
|
||||
}
|
||||
if (auth != null) {
|
||||
builder.field(Parser.USER_FIELD.getPreferredName(), auth.user());
|
||||
builder.field(Parser.PASSWORD_FIELD.getPreferredName(), auth.password());
|
||||
}
|
||||
if (profile != null) {
|
||||
builder.field(Parser.PROFILE_FIELD.getPreferredName(), profile);
|
||||
}
|
||||
if (account != null) {
|
||||
builder.field(Parser.ACCOUNT_FIELD.getPreferredName(), account);
|
||||
}
|
||||
if (subject != null) {
|
||||
builder.field(Email.SUBJECT_FIELD.getPreferredName(), subject);
|
||||
}
|
||||
if (textBody != null) {
|
||||
builder.field(Email.TEXT_BODY_FIELD.getPreferredName(), textBody);
|
||||
}
|
||||
if (htmlBody != null) {
|
||||
builder.field(Email.HTML_BODY_FIELD.getPreferredName(), htmlBody);
|
||||
}
|
||||
if (attachPayload != null) {
|
||||
builder.field(Parser.ATTACH_PAYLOAD_FIELD.getPreferredName(), attachPayload);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -233,7 +233,32 @@ public class IndexAction extends Action<IndexAction.Result> {
|
|||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Action.SourceBuilder {
|
||||
|
||||
private final String index;
|
||||
private final String type;
|
||||
|
||||
public SourceBuilder(String index, String type) {
|
||||
this.index = index;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.field(Parser.INDEX_FIELD.getPreferredName(), index)
|
||||
.field(Parser.TYPE_FIELD.getPreferredName(), type)
|
||||
.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.alerts.Payload;
|
|||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.ActionException;
|
||||
import org.elasticsearch.alerts.actions.ActionSettingsException;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.template.Template;
|
||||
import org.elasticsearch.alerts.support.template.XContentTemplate;
|
||||
import org.elasticsearch.common.Nullable;
|
||||
|
@ -25,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
|||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
*/
|
||||
|
@ -75,13 +77,12 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||
logger.error("failed to connect to [{}] for alert [{}]", ioe, urlText, ctx.alert().name());
|
||||
return new Result.Failure("failed to send http request. " + ioe.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.getName());
|
||||
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.getName().toLowerCase(Locale.ROOT));
|
||||
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
||||
if (body != null) {
|
||||
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||
|
@ -96,7 +97,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||
|
||||
WebhookAction that = (WebhookAction) o;
|
||||
|
||||
if (!body.equals(that.body)) return false;
|
||||
if (body != null ? !body.equals(that.body) : that.body != null) return false;
|
||||
if (!method.equals(that.method)) return false;
|
||||
if (!url.equals(that.url)) return false;
|
||||
|
||||
|
@ -107,7 +108,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||
public int hashCode() {
|
||||
int result = method.hashCode();
|
||||
result = 31 * result + url.hashCode();
|
||||
result = 31 * result + body.hashCode();
|
||||
result = 31 * result + (body != null ? body.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -205,7 +206,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||
currentFieldName = parser.currentName();
|
||||
} else if ((token.isValue() || token == XContentParser.Token.START_OBJECT) && currentFieldName != null ) {
|
||||
if (METHOD_FIELD.match(currentFieldName)) {
|
||||
method = HttpMethod.valueOf(parser.text());
|
||||
method = HttpMethod.valueOf(parser.text().toUpperCase(Locale.ROOT));
|
||||
if (method != HttpMethod.POST && method != HttpMethod.GET && method != HttpMethod.PUT) {
|
||||
throw new ActionSettingsException("could not parse webhook action. unsupported http method [" + method.getName() + "]");
|
||||
}
|
||||
|
@ -279,4 +280,46 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Action.SourceBuilder {
|
||||
|
||||
private final Script url;
|
||||
private HttpMethod method;
|
||||
private Script body = null;
|
||||
|
||||
public SourceBuilder(String url) {
|
||||
this(new Script(url));
|
||||
}
|
||||
|
||||
public SourceBuilder(Script url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public SourceBuilder method(HttpMethod method) {
|
||||
this.method = method;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceBuilder body(Script body) {
|
||||
this.body = body;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
||||
if (method != null) {
|
||||
builder.field(Parser.METHOD_FIELD.getPreferredName(), method.getName().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
if (body != null) {
|
||||
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||
}
|
||||
return builder.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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.alerts.client;
|
||||
|
||||
import org.elasticsearch.alerts.Alert;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.condition.Condition;
|
||||
import org.elasticsearch.alerts.condition.ConditionBuilders;
|
||||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.NoneInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.Schedule;
|
||||
import org.elasticsearch.alerts.transform.Transform;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilderException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class AlertSourceBuilder implements ToXContent {
|
||||
|
||||
public static AlertSourceBuilder alertSourceBuilder() {
|
||||
return new AlertSourceBuilder();
|
||||
}
|
||||
|
||||
private Schedule schedule;
|
||||
private Input.SourceBuilder input = NoneInput.SourceBuilder.INSTANCE;
|
||||
private Condition.SourceBuilder condition = ConditionBuilders.alwaysTrueCondition();
|
||||
private Transform.SourceBuilder transform = null;
|
||||
private Set<Action.SourceBuilder> actions = new HashSet<>();
|
||||
private TimeValue throttlePeriod = null;
|
||||
private Map<String, Object> metadata;
|
||||
|
||||
public AlertSourceBuilder schedule(Schedule schedule) {
|
||||
this.schedule = schedule;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder input(Input.SourceBuilder input) {
|
||||
this.input = input;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder condition(Condition.SourceBuilder condition) {
|
||||
this.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder transform(Transform.SourceBuilder transform) {
|
||||
this.transform = transform;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder throttlePeriod(TimeValue throttlePeriod) {
|
||||
this.throttlePeriod = throttlePeriod;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder addAction(Action.SourceBuilder action) {
|
||||
actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public AlertSourceBuilder metadata(Map<String, Object> metadata) {
|
||||
this.metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
|
||||
builder.startObject(Alert.Parser.SCHEDULE_FIELD.getPreferredName())
|
||||
.field(schedule.type(), schedule)
|
||||
.endObject();
|
||||
|
||||
builder.startObject(Alert.Parser.INPUT_FIELD.getPreferredName())
|
||||
.field(input.type(), input)
|
||||
.endObject();
|
||||
|
||||
builder.startObject(Alert.Parser.CONDITION_FIELD.getPreferredName())
|
||||
.field(condition.type(), condition)
|
||||
.endObject();
|
||||
|
||||
if (transform != null) {
|
||||
builder.startObject(Alert.Parser.TRANSFORM_FIELD.getPreferredName())
|
||||
.field(transform.type(), transform)
|
||||
.endObject();
|
||||
}
|
||||
|
||||
if (throttlePeriod != null) {
|
||||
builder.field(Alert.Parser.THROTTLE_PERIOD_FIELD.getPreferredName(), throttlePeriod.getMillis());
|
||||
}
|
||||
|
||||
builder.startArray(Alert.Parser.ACTIONS_FIELD.getPreferredName());
|
||||
for (Action.SourceBuilder action : actions) {
|
||||
builder.startObject().field(action.type(), action).endObject();
|
||||
}
|
||||
builder.endArray();
|
||||
|
||||
if (metadata != null) {
|
||||
builder.field(Alert.Parser.META_FIELD.getPreferredName(), metadata);
|
||||
}
|
||||
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
public BytesReference buildAsBytes(XContentType contentType) throws SearchSourceBuilderException {
|
||||
try {
|
||||
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
|
||||
toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
return builder.bytes();
|
||||
} catch (Exception e) {
|
||||
throw new SearchSourceBuilderException("Failed to build search source", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -75,4 +75,10 @@ public abstract class Condition<R extends Condition.Result> implements ToXConten
|
|||
public boolean met() { return met; }
|
||||
|
||||
}
|
||||
|
||||
public static interface SourceBuilder extends ToXContent {
|
||||
|
||||
public String type();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.alerts.condition;
|
||||
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.condition.simple.AlwaysTrueCondition;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class ConditionBuilders {
|
||||
|
||||
private ConditionBuilders() {
|
||||
}
|
||||
|
||||
public static AlwaysTrueCondition.SourceBuilder alwaysTrueCondition() {
|
||||
return AlwaysTrueCondition.SourceBuilder.INSTANCE;
|
||||
}
|
||||
|
||||
public static ScriptCondition.SourceBuilder scriptCondition() {
|
||||
return new ScriptCondition.SourceBuilder();
|
||||
}
|
||||
|
||||
public static ScriptCondition.SourceBuilder scriptCondition(String script) {
|
||||
return new ScriptCondition.SourceBuilder().script(script);
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -24,6 +25,10 @@ public class ConditionRegistry {
|
|||
this.parsers = ImmutableMap.copyOf(parsers);
|
||||
}
|
||||
|
||||
public Set<String> types() {
|
||||
return parsers.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the contents of parser to create the correct Condition
|
||||
*
|
||||
|
|
|
@ -18,8 +18,11 @@ import org.elasticsearch.common.settings.Settings;
|
|||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.script.ExecutableScript;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class executes a script against the ctx payload and returns a boolean
|
||||
|
@ -61,6 +64,23 @@ public class ScriptCondition extends Condition<ScriptCondition.Result> {
|
|||
return script.toXContent(builder, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ScriptCondition that = (ScriptCondition) o;
|
||||
|
||||
if (!script.equals(that.script)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return script.hashCode();
|
||||
}
|
||||
|
||||
public static class Parser extends AbstractComponent implements Condition.Parser<Result, ScriptCondition> {
|
||||
|
||||
private final ScriptServiceProxy scriptService;
|
||||
|
@ -131,6 +151,43 @@ public class ScriptCondition extends Condition<ScriptCondition.Result> {
|
|||
.field(MET_FIELD.getPreferredName(), met())
|
||||
.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Condition.SourceBuilder {
|
||||
|
||||
private String script;
|
||||
private String lang = ScriptService.DEFAULT_LANG;
|
||||
private ScriptService.ScriptType type = ScriptService.ScriptType.INLINE;
|
||||
private Map<String, Object> params = Collections.emptyMap();
|
||||
|
||||
public SourceBuilder script(String script) {
|
||||
this.script = script;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceBuilder lang(String lang) {
|
||||
this.lang = lang;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceBuilder type(ScriptService.ScriptType type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SourceBuilder type(Map<String, Object> params) {
|
||||
this.params = params;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return new Script(script, type, lang, this.params).toXContent(builder, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.common.component.AbstractComponent;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
|
@ -22,6 +23,7 @@ import java.io.IOException;
|
|||
public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
||||
|
||||
public static final String TYPE = "always_false";
|
||||
|
||||
public static final Result RESULT = new Result(TYPE, false) {
|
||||
|
||||
@Override
|
||||
|
@ -50,6 +52,11 @@ public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
|||
return builder.startObject().endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof AlwaysFalseCondition;
|
||||
}
|
||||
|
||||
public static class Parser extends AbstractComponent implements Condition.Parser<Result, AlwaysFalseCondition> {
|
||||
|
||||
@Inject
|
||||
|
@ -80,4 +87,22 @@ public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Condition.SourceBuilder {
|
||||
|
||||
public static final SourceBuilder INSTANCE = new SourceBuilder();
|
||||
|
||||
private SourceBuilder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.io.IOException;
|
|||
public class AlwaysTrueCondition extends Condition<Condition.Result> {
|
||||
|
||||
public static final String TYPE = "always_true";
|
||||
|
||||
public static final Result RESULT = new Result(TYPE, true) {
|
||||
|
||||
@Override
|
||||
|
@ -49,6 +50,10 @@ public class AlwaysTrueCondition extends Condition<Condition.Result> {
|
|||
return builder.startObject().endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof AlwaysTrueCondition;
|
||||
}
|
||||
|
||||
public static class Parser extends AbstractComponent implements Condition.Parser<Result, AlwaysTrueCondition> {
|
||||
|
||||
|
@ -87,4 +92,21 @@ public class AlwaysTrueCondition extends Condition<Condition.Result> {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Condition.SourceBuilder {
|
||||
|
||||
public static final SourceBuilder INSTANCE = new SourceBuilder();
|
||||
|
||||
private SourceBuilder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.elasticsearch.alerts.support.TemplateUtils;
|
|||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
|
@ -74,8 +75,9 @@ public class HistoryStore extends AbstractComponent {
|
|||
public void update(FiredAlert firedAlert) throws HistoryException {
|
||||
logger.debug("updating fired alert [{}]", firedAlert);
|
||||
try {
|
||||
BytesReference bytes = XContentFactory.jsonBuilder().value(firedAlert).bytes();
|
||||
IndexResponse response = client.prepareIndex(getAlertHistoryIndexNameForTime(firedAlert.scheduledTime()), ALERT_HISTORY_TYPE, firedAlert.id())
|
||||
.setSource(XContentFactory.jsonBuilder().value(firedAlert))
|
||||
.setSource(bytes)
|
||||
.setVersion(firedAlert.version())
|
||||
.get();
|
||||
firedAlert.version(response.getVersion());
|
||||
|
|
|
@ -88,4 +88,10 @@ public abstract class Input<R extends Input.Result> implements ToXContent {
|
|||
|
||||
protected abstract XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException;
|
||||
}
|
||||
|
||||
public static interface SourceBuilder extends ToXContent {
|
||||
|
||||
String type();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.alerts.input;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.input.simple.SimpleInput;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class InputBuilders {
|
||||
|
||||
private InputBuilders() {
|
||||
}
|
||||
|
||||
public static SearchInput.SourceBuilder searchInput(SearchRequest request) {
|
||||
return new SearchInput.SourceBuilder(request);
|
||||
}
|
||||
|
||||
public static SearchInput.SourceBuilder searchInput(SearchRequestBuilder builder) {
|
||||
return searchInput(builder.request());
|
||||
}
|
||||
|
||||
public static SimpleInput.SourceBuilder simpleInput() {
|
||||
return simpleInput(new HashMap<String, Object>());
|
||||
}
|
||||
|
||||
public static SimpleInput.SourceBuilder simpleInput(Map<String, Object> data) {
|
||||
return new SimpleInput.SourceBuilder(data);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* 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.alerts.input;
|
||||
|
||||
import org.elasticsearch.alerts.ExecutionContext;
|
||||
import org.elasticsearch.alerts.Payload;
|
||||
import org.elasticsearch.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.common.component.AbstractComponent;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class NoneInput extends Input<NoneInput.Result> {
|
||||
|
||||
public static final String TYPE = "none";
|
||||
|
||||
private static final Payload EMPTY_PAYLOAD = new Payload() {
|
||||
@Override
|
||||
public Map<String, Object> data() {
|
||||
return ImmutableMap.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
};
|
||||
|
||||
public NoneInput(ESLogger logger) {
|
||||
super(logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result execute(ExecutionContext ctx) throws IOException {
|
||||
return Result.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
|
||||
public static class Result extends Input.Result {
|
||||
|
||||
static final Result INSTANCE = new Result();
|
||||
|
||||
private Result() {
|
||||
super(TYPE, EMPTY_PAYLOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
}
|
||||
|
||||
public static class Parser extends AbstractComponent implements Input.Parser<Result, NoneInput> {
|
||||
|
||||
private final NoneInput input;
|
||||
|
||||
public Parser(Settings settings) {
|
||||
super(settings);
|
||||
this.input = new NoneInput(logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NoneInput parse(XContentParser parser) throws IOException {
|
||||
if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
|
||||
|
||||
}
|
||||
parser.nextToken();
|
||||
if (parser.currentToken() != XContentParser.Token.END_OBJECT) {
|
||||
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result parseResult(XContentParser parser) throws IOException {
|
||||
if (parser.currentToken() != XContentParser.Token.START_OBJECT) {
|
||||
|
||||
}
|
||||
parser.nextToken();
|
||||
if (parser.currentToken() != XContentParser.Token.END_OBJECT) {
|
||||
|
||||
}
|
||||
return Result.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Input.SourceBuilder {
|
||||
|
||||
public static final SourceBuilder INSTANCE = new SourceBuilder();
|
||||
|
||||
private SourceBuilder() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject().endObject();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.alerts.Payload;
|
|||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.InputException;
|
||||
import org.elasticsearch.alerts.support.AlertUtils;
|
||||
import org.elasticsearch.alerts.support.SearchRequestEquivalence;
|
||||
import org.elasticsearch.alerts.support.Variables;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ScriptServiceProxy;
|
||||
|
@ -44,6 +45,7 @@ import static org.elasticsearch.alerts.support.AlertsDateUtils.formatDate;
|
|||
public class SearchInput extends Input<SearchInput.Result> {
|
||||
|
||||
public static final String TYPE = "search";
|
||||
|
||||
public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.COUNT;
|
||||
|
||||
private final SearchRequest searchRequest;
|
||||
|
@ -86,12 +88,25 @@ public class SearchInput extends Input<SearchInput.Result> {
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject();
|
||||
builder.field(Parser.REQUEST_FIELD.getPreferredName());
|
||||
AlertUtils.writeSearchRequest(searchRequest, builder, params);
|
||||
return builder.endObject();
|
||||
return AlertUtils.writeSearchRequest(searchRequest, builder, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
SearchInput that = (SearchInput) o;
|
||||
|
||||
if (!SearchRequestEquivalence.INSTANCE.equivalent(searchRequest, that.searchRequest)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return SearchRequestEquivalence.INSTANCE.hash(searchRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new search request applying the scheduledFireTime and fireTime to the original request
|
||||
|
@ -136,11 +151,8 @@ public class SearchInput extends Input<SearchInput.Result> {
|
|||
|
||||
@Override
|
||||
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
|
||||
if (request != null) {
|
||||
builder.field(Parser.REQUEST_FIELD.getPreferredName());
|
||||
AlertUtils.writeSearchRequest(request, builder, params);
|
||||
}
|
||||
return builder;
|
||||
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -164,27 +176,10 @@ public class SearchInput extends Input<SearchInput.Result> {
|
|||
|
||||
@Override
|
||||
public SearchInput parse(XContentParser parser) throws IOException {
|
||||
SearchRequest request = 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.START_OBJECT && currentFieldName != null) {
|
||||
if (REQUEST_FIELD.match(currentFieldName)) {
|
||||
request = AlertUtils.readSearchRequest(parser, DEFAULT_SEARCH_TYPE);
|
||||
} else {
|
||||
throw new InputException("unable to parse [" + TYPE + "] input. unexpected field [" + currentFieldName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SearchRequest request = AlertUtils.readSearchRequest(parser, DEFAULT_SEARCH_TYPE);
|
||||
if (request == null) {
|
||||
throw new InputException("search request is missing or null for [" + TYPE + "] input");
|
||||
throw new InputException("could not parse [search] input. search request is missing or null.");
|
||||
}
|
||||
|
||||
return new SearchInput(logger, scriptService, client, request);
|
||||
}
|
||||
|
||||
|
@ -222,4 +217,23 @@ public class SearchInput extends Input<SearchInput.Result> {
|
|||
return new Result(TYPE, payload, request);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Input.SourceBuilder {
|
||||
|
||||
private final SearchRequest request;
|
||||
|
||||
public SourceBuilder(SearchRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,14 @@ import org.elasticsearch.common.component.AbstractComponent;
|
|||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class just defines a simple xcontent map as an input
|
||||
|
@ -24,6 +28,7 @@ import java.io.IOException;
|
|||
public class SimpleInput extends Input<SimpleInput.Result> {
|
||||
|
||||
public static final String TYPE = "simple";
|
||||
|
||||
private final Payload payload;
|
||||
|
||||
public SimpleInput(ESLogger logger, Payload payload) {
|
||||
|
@ -48,6 +53,23 @@ public class SimpleInput extends Input<SimpleInput.Result> {
|
|||
return builder.endObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final SimpleInput other = (SimpleInput) obj;
|
||||
return Objects.equals(this.payload.data(), other.payload.data());
|
||||
}
|
||||
|
||||
public static class Result extends Input.Result {
|
||||
|
||||
public Result(String type, Payload payload) {
|
||||
|
@ -122,4 +144,29 @@ public class SimpleInput extends Input<SimpleInput.Result> {
|
|||
return new Result(TYPE, payload);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Input.SourceBuilder {
|
||||
|
||||
private Map<String, Object> data;
|
||||
|
||||
public SourceBuilder(Map<String, Object> data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Input.SourceBuilder put(String key, Object value) {
|
||||
data.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.map(data);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class RestPutAlertAction extends BaseRestHandler {
|
|||
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||
PutAlertRequest putAlertRequest = new PutAlertRequest();
|
||||
putAlertRequest.setAlertName(request.param("name"));
|
||||
putAlertRequest.setAlertSource(request.content(), request.contentUnsafe());
|
||||
putAlertRequest.source(request.content(), request.contentUnsafe());
|
||||
alertsClient.putAlert(putAlertRequest, new RestBuilderListener<PutAlertResponse>(channel) {
|
||||
@Override
|
||||
public RestResponse buildResponse(PutAlertResponse response, XContentBuilder builder) throws Exception {
|
||||
|
|
|
@ -12,6 +12,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,6 +26,10 @@ public class ScheduleRegistry {
|
|||
this.parsers = ImmutableMap.copyOf(parsers);
|
||||
}
|
||||
|
||||
public Set<String> types() {
|
||||
return parsers.keySet();
|
||||
}
|
||||
|
||||
public Schedule parse(XContentParser parser) throws IOException {
|
||||
String type = null;
|
||||
XContentParser.Token token;
|
||||
|
|
|
@ -155,13 +155,19 @@ public final class AlertUtils {
|
|||
/**
|
||||
* Writes the searchRequest to the specified builder.
|
||||
*/
|
||||
public static void writeSearchRequest(SearchRequest searchRequest, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
public static XContentBuilder writeSearchRequest(SearchRequest searchRequest, XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
if (searchRequest == null) {
|
||||
builder.nullValue();
|
||||
return;
|
||||
return builder;
|
||||
}
|
||||
|
||||
builder.startObject();
|
||||
if (searchRequest.searchType() != null) {
|
||||
builder.field("search_type", searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
if (searchRequest.indices() != null) {
|
||||
builder.array("indices", searchRequest.indices());
|
||||
}
|
||||
if (Strings.hasLength(searchRequest.source())) {
|
||||
XContentHelper.writeRawField("body", searchRequest.source(), builder, params);
|
||||
}
|
||||
|
@ -171,11 +177,6 @@ public final class AlertUtils {
|
|||
if (searchRequest.templateType() != null) {
|
||||
builder.field("template_type", searchRequest.templateType().name().toLowerCase(Locale.ROOT));
|
||||
}
|
||||
builder.startArray("indices");
|
||||
for (String index : searchRequest.indices()) {
|
||||
builder.value(index);
|
||||
}
|
||||
builder.endArray();
|
||||
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||
IndicesOptions options = searchRequest.indicesOptions();
|
||||
builder.startObject("indices_options");
|
||||
|
@ -194,10 +195,7 @@ public final class AlertUtils {
|
|||
builder.field("allow_no_indices", options.allowNoIndices());
|
||||
builder.endObject();
|
||||
}
|
||||
if (searchRequest.searchType() != null) {
|
||||
builder.field("search_type", searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
builder.endObject();
|
||||
return builder.endObject();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class Script implements ToXContent {
|
|||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return builder.startObject()
|
||||
.field(SCRIPT_FIELD.getPreferredName(), script)
|
||||
.field(TYPE_FIELD.getPreferredName(), type)
|
||||
.field(TYPE_FIELD.getPreferredName(), type.name().toLowerCase(Locale.ROOT))
|
||||
.field(LANG_FIELD.getPreferredName(), lang)
|
||||
.field(PARAMS_FIELD.getPreferredName(), this.params)
|
||||
.endObject();
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.alerts.support;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.AlertsException;
|
||||
import org.elasticsearch.common.base.Equivalence;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.stream.BytesStreamOutput;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* The only true way today to compare search request object (outside of core) is to
|
||||
* serialize it and compare the serialized output. this is heavy obviously, but luckily we
|
||||
* don't compare search requests in normal runtime... we only do it in the tests. The is here basically
|
||||
* due to the lack of equals/hashcode support in SearchRequest in core.
|
||||
*/
|
||||
public final class SearchRequestEquivalence extends Equivalence<SearchRequest> {
|
||||
|
||||
public static final SearchRequestEquivalence INSTANCE = new SearchRequestEquivalence();
|
||||
|
||||
private SearchRequestEquivalence() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doEquivalent(SearchRequest r1, SearchRequest r2) {
|
||||
try {
|
||||
BytesStreamOutput output1 = new BytesStreamOutput();
|
||||
r1.writeTo(output1);
|
||||
BytesReference bytes1 = output1.bytes();
|
||||
BytesStreamOutput output2 = new BytesStreamOutput(bytes1.length());
|
||||
r2.writeTo(output2);
|
||||
BytesReference bytes2 = output2.bytes();
|
||||
return Arrays.equals(bytes1.toBytes(), bytes2.toBytes());
|
||||
} catch (IOException ioe) {
|
||||
throw new AlertsException("could not compare search requests", ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int doHash(SearchRequest request) {
|
||||
try {
|
||||
BytesStreamOutput output = new BytesStreamOutput();
|
||||
request.writeTo(output);
|
||||
return Arrays.hashCode(output.bytes().toBytes());
|
||||
} catch (IOException ioe) {
|
||||
throw new AlertsException("could not compute hashcode for search request", ioe);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.alerts.support.template;
|
|||
|
||||
import org.elasticsearch.common.xcontent.XContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -18,6 +19,7 @@ import java.util.Map;
|
|||
public class XContentTemplate implements Template {
|
||||
|
||||
public static XContentTemplate YAML = new XContentTemplate(YamlXContent.yamlXContent);
|
||||
public static XContentTemplate JSON = new XContentTemplate(JsonXContent.jsonXContent);
|
||||
|
||||
private final XContent xContent;
|
||||
|
||||
|
|
|
@ -72,7 +72,11 @@ public class ChainTransform extends Transform {
|
|||
|
||||
@Override
|
||||
public void init(Injector injector) {
|
||||
this.registry = injector.getInstance(TransformRegistry.class);
|
||||
init(injector.getInstance(TransformRegistry.class));
|
||||
}
|
||||
|
||||
public void init(TransformRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,8 +110,36 @@ public class ChainTransform extends Transform {
|
|||
}
|
||||
return new ChainTransform(builder.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Transform.SourceBuilder {
|
||||
|
||||
private final ImmutableList.Builder<Transform.SourceBuilder> builders = ImmutableList.builder();
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
public SourceBuilder(Transform.SourceBuilder... builders) {
|
||||
this.builders.add(builders);
|
||||
}
|
||||
|
||||
public SourceBuilder add(Transform.SourceBuilder builder) {
|
||||
builders.add(builder);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startArray();
|
||||
for (Transform.SourceBuilder transBuilder : builders.build()) {
|
||||
builder.startObject()
|
||||
.field(TYPE, transBuilder)
|
||||
.endObject();
|
||||
}
|
||||
return builder.endArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,12 +26,12 @@ public class ScriptTransform extends Transform {
|
|||
|
||||
public static final String TYPE = "script";
|
||||
|
||||
private final Script script;
|
||||
private final ScriptServiceProxy scriptService;
|
||||
private final Script script;
|
||||
|
||||
public ScriptTransform(Script script, ScriptServiceProxy scriptService) {
|
||||
this.script = script;
|
||||
public ScriptTransform(ScriptServiceProxy scriptService, Script script) {
|
||||
this.scriptService = scriptService;
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,7 +83,30 @@ public class ScriptTransform extends Transform {
|
|||
} catch (Script.ParseException pe) {
|
||||
throw new AlertsSettingsException("could not parse [script] transform", pe);
|
||||
}
|
||||
return new ScriptTransform(script, scriptService);
|
||||
return new ScriptTransform(scriptService, script);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Transform.SourceBuilder {
|
||||
|
||||
private final Script script;
|
||||
|
||||
public SourceBuilder(String script) {
|
||||
this(new Script(script));
|
||||
}
|
||||
|
||||
public SourceBuilder(Script script) {
|
||||
this.script = script;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return script.toXContent(builder, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ public class SearchTransform extends Transform {
|
|||
protected final ESLogger logger;
|
||||
protected final ScriptServiceProxy scriptService;
|
||||
protected final ClientProxy client;
|
||||
|
||||
protected final SearchRequest request;
|
||||
|
||||
public SearchTransform(ESLogger logger, ScriptServiceProxy scriptService, ClientProxy client, SearchRequest request) {
|
||||
|
@ -71,8 +72,7 @@ public class SearchTransform extends Transform {
|
|||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||
AlertUtils.writeSearchRequest(request, builder, params);
|
||||
return builder;
|
||||
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||
}
|
||||
|
||||
public SearchRequest createRequest(SearchRequest requestPrototype, ExecutionContext ctx, Payload payload) throws IOException {
|
||||
|
@ -160,4 +160,23 @@ public class SearchTransform extends Transform {
|
|||
}
|
||||
}
|
||||
|
||||
public static class SourceBuilder implements Transform.SourceBuilder {
|
||||
|
||||
private final SearchRequest request;
|
||||
|
||||
public SourceBuilder(SearchRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public abstract class Transform implements ToXContent {
|
|||
}
|
||||
}
|
||||
|
||||
static interface Parser<T extends Transform> {
|
||||
public static interface Parser<T extends Transform> {
|
||||
|
||||
String type();
|
||||
|
||||
|
@ -77,4 +77,9 @@ public abstract class Transform implements ToXContent {
|
|||
|
||||
}
|
||||
|
||||
public static interface SourceBuilder extends ToXContent {
|
||||
|
||||
String type();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.alerts.transform;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.transform.ChainTransform;
|
||||
import org.elasticsearch.alerts.transform.ScriptTransform;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.transform.Transform;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class TransformBuilders {
|
||||
|
||||
private TransformBuilders() {
|
||||
}
|
||||
|
||||
public static SearchTransform.SourceBuilder searchTransform(SearchRequest request) {
|
||||
return new SearchTransform.SourceBuilder(request);
|
||||
}
|
||||
|
||||
public static ScriptTransform.SourceBuilder scriptTransform(String script) {
|
||||
return new ScriptTransform.SourceBuilder(script);
|
||||
}
|
||||
|
||||
public static ScriptTransform.SourceBuilder scriptTransform(Script script) {
|
||||
return new ScriptTransform.SourceBuilder(script);
|
||||
}
|
||||
|
||||
public static ChainTransform.SourceBuilder chainTransform(Transform.SourceBuilder... transforms) {
|
||||
return new ChainTransform.SourceBuilder(transforms);
|
||||
}
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ public class TransformRegistry {
|
|||
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) {
|
||||
} else if (type != null) {
|
||||
Transform.Parser transformParser = parsers.get(type);
|
||||
if (transformParser == null) {
|
||||
throw new AlertsSettingsException("unknown transform type [" + type + "]");
|
||||
|
|
|
@ -9,9 +9,12 @@ package org.elasticsearch.alerts.transport.actions.put;
|
|||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.ValidateActions;
|
||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequest;
|
||||
import org.elasticsearch.alerts.client.AlertSourceBuilder;
|
||||
import org.elasticsearch.client.Requests;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.xcontent.XContentType;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
|
@ -59,7 +62,14 @@ public class PutAlertRequest extends MasterNodeOperationRequest<PutAlertRequest>
|
|||
/**
|
||||
* Set the source of the alert
|
||||
*/
|
||||
public void setAlertSource(BytesReference alertSource) {
|
||||
public void source(AlertSourceBuilder source) {
|
||||
source(source.buildAsBytes(XContentType.JSON));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the source of the alert
|
||||
*/
|
||||
public void source(BytesReference alertSource) {
|
||||
this.alertSource = alertSource;
|
||||
this.alertSourceUnsafe = false;
|
||||
}
|
||||
|
@ -67,7 +77,7 @@ public class PutAlertRequest extends MasterNodeOperationRequest<PutAlertRequest>
|
|||
/**
|
||||
* Set the source of the alert with boolean to control source safety
|
||||
*/
|
||||
public void setAlertSource(BytesReference alertSource, boolean alertSourceUnsafe) {
|
||||
public void source(BytesReference alertSource, boolean alertSourceUnsafe) {
|
||||
this.alertSource = alertSource;
|
||||
this.alertSourceUnsafe = alertSourceUnsafe;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.alerts.transport.actions.put;
|
|||
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||
import org.elasticsearch.alerts.client.AlertSourceBuilder;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
|
@ -28,19 +29,26 @@ public class PutAlertRequestBuilder extends MasterNodeOperationRequestBuilder<Pu
|
|||
/**
|
||||
* @param alertName The alert name to be created
|
||||
*/
|
||||
public PutAlertRequestBuilder setAlertName(String alertName){
|
||||
public PutAlertRequestBuilder alertName(String alertName){
|
||||
request.setAlertName(alertName);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param alertSource the source of the alert to be created
|
||||
* @param source the source of the alert to be created
|
||||
*/
|
||||
public PutAlertRequestBuilder setAlertSource(BytesReference alertSource) {
|
||||
request.setAlertSource(alertSource);
|
||||
public PutAlertRequestBuilder source(BytesReference source) {
|
||||
request.source(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source the source of the alert to be created
|
||||
*/
|
||||
public PutAlertRequestBuilder source(AlertSourceBuilder source) {
|
||||
request.source(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(ActionListener<PutAlertResponse> listener) {
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.alerts;
|
||||
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class AlertSerializationTest extends AbstractAlertingTests {
|
||||
|
||||
@Test
|
||||
public void testAlertSerialization() throws Exception {
|
||||
|
||||
Alert alert = createTestAlert("test-serialization");
|
||||
|
||||
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
final Alert.Parser alertParser =
|
||||
internalTestCluster().getInstance(Alert.Parser.class, internalTestCluster().getMasterName());
|
||||
|
||||
Alert parsedAlert = alertParser.parse("test-serialization", true, jsonBuilder.bytes());
|
||||
|
||||
long parsedActionCount = 0;
|
||||
|
||||
long alertActionCount = 0;
|
||||
for (Action action : parsedAlert.actions()) {
|
||||
boolean found = false;
|
||||
++parsedActionCount;
|
||||
alertActionCount = 0;
|
||||
for (Action action1 : alert.actions()) {
|
||||
++alertActionCount;
|
||||
if (action.type().equals(action1.type())) {
|
||||
assertEqualByGeneratedXContent(action, action1);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
assertTrue(found);
|
||||
}
|
||||
assertEquals(parsedActionCount, alertActionCount);
|
||||
|
||||
assertEquals(parsedAlert,alert);
|
||||
|
||||
assertEquals(parsedAlert.status().version(), alert.status().version());
|
||||
if (parsedAlert.status().lastExecuted() == null ) {
|
||||
assertNull(alert.status().lastExecuted());
|
||||
} else {
|
||||
assertEquals(parsedAlert.status().lastExecuted().getMillis(), alert.status().lastExecuted().getMillis());
|
||||
}
|
||||
assertEqualByGeneratedXContent(parsedAlert.schedule(), alert.schedule());
|
||||
assertEqualByGeneratedXContent(parsedAlert.condition(), alert.condition());
|
||||
assertEquals(parsedAlert.throttlePeriod().getMillis(), alert.throttlePeriod().getMillis());
|
||||
assertEquals(parsedAlert.status().ackStatus().state(), alert.status().ackStatus().state());
|
||||
assertEquals(parsedAlert.metadata().get("foo"), "bar");
|
||||
}
|
||||
|
||||
|
||||
private void assertEqualByGeneratedXContent(ToXContent xCon1, ToXContent xCon2) throws IOException {
|
||||
XContentBuilder builder1 = XContentFactory.jsonBuilder();
|
||||
XContentBuilder builder2 = XContentFactory.jsonBuilder();
|
||||
xCon1.toXContent(builder1, ToXContent.EMPTY_PARAMS);
|
||||
xCon2.toXContent(builder2, ToXContent.EMPTY_PARAMS);
|
||||
assertEquals(builder1.bytes().toUtf8(), builder2.bytes().toUtf8());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* 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.alerts;
|
||||
|
||||
import com.carrotsearch.randomizedtesting.annotations.Repeat;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.ActionRegistry;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.actions.email.EmailAction;
|
||||
import org.elasticsearch.alerts.actions.email.service.Email;
|
||||
import org.elasticsearch.alerts.actions.email.service.EmailService;
|
||||
import org.elasticsearch.alerts.actions.email.service.Profile;
|
||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
||||
import org.elasticsearch.alerts.actions.webhook.HttpClient;
|
||||
import org.elasticsearch.alerts.actions.webhook.WebhookAction;
|
||||
import org.elasticsearch.alerts.condition.Condition;
|
||||
import org.elasticsearch.alerts.condition.ConditionRegistry;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.condition.simple.AlwaysTrueCondition;
|
||||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.InputRegistry;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.input.simple.SimpleInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.*;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.support.*;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ScriptServiceProxy;
|
||||
import org.elasticsearch.alerts.support.template.ScriptTemplate;
|
||||
import org.elasticsearch.alerts.support.template.Template;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transform.*;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.collect.ImmutableList;
|
||||
import org.elasticsearch.common.collect.ImmutableMap;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.alerts.test.AlertsTestUtils.matchAllRequest;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class AlertTests extends ElasticsearchTestCase {
|
||||
|
||||
private ScriptServiceProxy scriptService;
|
||||
private ClientProxy client;
|
||||
private HttpClient httpClient;
|
||||
private EmailService emailService;
|
||||
private Template.Parser templateParser;
|
||||
private ESLogger logger;
|
||||
private Settings settings = ImmutableSettings.EMPTY;
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
scriptService = mock(ScriptServiceProxy.class);
|
||||
client = mock(ClientProxy.class);
|
||||
httpClient = mock(HttpClient.class);
|
||||
emailService = mock(EmailService.class);
|
||||
templateParser = new ScriptTemplate.Parser(settings, scriptService);
|
||||
logger = Loggers.getLogger(AlertTests.class);
|
||||
}
|
||||
|
||||
@Test @Repeat(iterations = 20)
|
||||
public void testParser_SelfGenerated() throws Exception {
|
||||
|
||||
Schedule schedule = randomSchedule();
|
||||
ScheduleRegistry scheduleRegistry = registry(schedule);
|
||||
|
||||
Input input = randomInput();
|
||||
InputRegistry inputRegistry = registry(input);
|
||||
|
||||
Condition condition = randomCondition();
|
||||
ConditionRegistry conditionRegistry = registry(condition);
|
||||
|
||||
Transform transform = randomTransform();
|
||||
TransformRegistry transformRegistry = registry(transform);
|
||||
|
||||
Actions actions = randomActions();
|
||||
ActionRegistry actionRegistry = registry(actions);
|
||||
|
||||
Map<String, Object> metadata = ImmutableMap.<String, Object>of("_key", "_val");
|
||||
|
||||
Alert.Status status = new Alert.Status();
|
||||
|
||||
TimeValue throttlePeriod = randomBoolean() ? null : TimeValue.timeValueSeconds(randomIntBetween(5, 10));
|
||||
|
||||
Alert alert = new Alert("_name", schedule, input, condition, transform, actions, metadata, throttlePeriod, status);
|
||||
|
||||
BytesReference bytes = XContentFactory.jsonBuilder().value(alert).bytes();
|
||||
logger.info(bytes.toUtf8());
|
||||
Alert.Parser alertParser = new Alert.Parser(settings, conditionRegistry, scheduleRegistry, transformRegistry, actionRegistry, inputRegistry);
|
||||
|
||||
boolean includeStatus = randomBoolean();
|
||||
Alert parsedAlert = alertParser.parse("_name", includeStatus, bytes);
|
||||
|
||||
if (includeStatus) {
|
||||
assertThat(parsedAlert.status(), equalTo(status));
|
||||
}
|
||||
assertThat(parsedAlert.schedule(), equalTo(schedule));
|
||||
assertThat(parsedAlert.input(), equalTo(input));
|
||||
assertThat(parsedAlert.condition(), equalTo(condition));
|
||||
if (throttlePeriod != null) {
|
||||
assertThat(parsedAlert.throttlePeriod().millis(), equalTo(throttlePeriod.millis()));
|
||||
}
|
||||
assertThat(parsedAlert.metadata(), equalTo(metadata));
|
||||
assertThat(parsedAlert.actions(), equalTo(actions));
|
||||
}
|
||||
|
||||
private static Schedule randomSchedule() {
|
||||
String type = randomFrom(CronSchedule.TYPE, HourlySchedule.TYPE, DailySchedule.TYPE, WeeklySchedule.TYPE, MonthlySchedule.TYPE, YearlySchedule.TYPE, IntervalSchedule.TYPE);
|
||||
switch (type) {
|
||||
case CronSchedule.TYPE:
|
||||
return new CronSchedule("0/5 * * * * ? *");
|
||||
case HourlySchedule.TYPE:
|
||||
return HourlySchedule.builder().minutes(30).build();
|
||||
case DailySchedule.TYPE:
|
||||
return DailySchedule.builder().atNoon().build();
|
||||
case WeeklySchedule.TYPE:
|
||||
return WeeklySchedule.builder().time(WeekTimes.builder().on(DayOfWeek.FRIDAY).atMidnight()).build();
|
||||
case MonthlySchedule.TYPE:
|
||||
return MonthlySchedule.builder().time(MonthTimes.builder().on(1).atNoon()).build();
|
||||
case YearlySchedule.TYPE:
|
||||
return YearlySchedule.builder().time(YearTimes.builder().in(Month.JANUARY).on(1).atMidnight()).build();
|
||||
default:
|
||||
return new IntervalSchedule(IntervalSchedule.Interval.seconds(5));
|
||||
}
|
||||
}
|
||||
|
||||
private static ScheduleRegistry registry(Schedule schedule) {
|
||||
ImmutableMap.Builder<String, Schedule.Parser> parsers = ImmutableMap.builder();
|
||||
switch (schedule.type()) {
|
||||
case CronSchedule.TYPE:
|
||||
parsers.put(CronSchedule.TYPE, new CronSchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case HourlySchedule.TYPE:
|
||||
parsers.put(HourlySchedule.TYPE, new HourlySchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case DailySchedule.TYPE:
|
||||
parsers.put(DailySchedule.TYPE, new DailySchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case WeeklySchedule.TYPE:
|
||||
parsers.put(WeeklySchedule.TYPE, new WeeklySchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case MonthlySchedule.TYPE:
|
||||
parsers.put(MonthlySchedule.TYPE, new MonthlySchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case YearlySchedule.TYPE:
|
||||
parsers.put(YearlySchedule.TYPE, new YearlySchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
case IntervalSchedule.TYPE:
|
||||
parsers.put(IntervalSchedule.TYPE, new IntervalSchedule.Parser());
|
||||
return new ScheduleRegistry(parsers.build());
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown schedule [" + schedule + "]");
|
||||
}
|
||||
}
|
||||
|
||||
private Input randomInput() {
|
||||
String type = randomFrom(SearchInput.TYPE, SimpleInput.TYPE);
|
||||
switch (type) {
|
||||
case SearchInput.TYPE:
|
||||
return new SearchInput(logger, scriptService, client, AlertsTestUtils.newInputSearchRequest("idx"));
|
||||
default:
|
||||
return new SimpleInput(logger, new Payload.Simple(ImmutableMap.<String, Object>builder().put("_key", "_val").build()));
|
||||
}
|
||||
}
|
||||
|
||||
private InputRegistry registry(Input input) {
|
||||
ImmutableMap.Builder<String, Input.Parser> parsers = ImmutableMap.builder();
|
||||
switch (input.type()) {
|
||||
case SearchInput.TYPE:
|
||||
parsers.put(SearchInput.TYPE, new SearchInput.Parser(settings, scriptService, client));
|
||||
return new InputRegistry(parsers.build());
|
||||
default:
|
||||
parsers.put(SimpleInput.TYPE, new SimpleInput.Parser(settings));
|
||||
return new InputRegistry(parsers.build());
|
||||
}
|
||||
}
|
||||
|
||||
private Condition randomCondition() {
|
||||
String type = randomFrom(ScriptCondition.TYPE, AlwaysTrueCondition.TYPE);
|
||||
switch (type) {
|
||||
case ScriptCondition.TYPE:
|
||||
return new ScriptCondition(logger, scriptService, new Script("_script"));
|
||||
default:
|
||||
return new AlwaysTrueCondition(logger);
|
||||
}
|
||||
}
|
||||
|
||||
private ConditionRegistry registry(Condition condition) {
|
||||
ImmutableMap.Builder<String, Condition.Parser> parsers = ImmutableMap.builder();
|
||||
switch (condition.type()) {
|
||||
case ScriptCondition.TYPE:
|
||||
parsers.put(ScriptCondition.TYPE, new ScriptCondition.Parser(settings, scriptService));
|
||||
return new ConditionRegistry(parsers.build());
|
||||
default:
|
||||
parsers.put(AlwaysTrueCondition.TYPE, new AlwaysTrueCondition.Parser(settings));
|
||||
return new ConditionRegistry(parsers.build());
|
||||
}
|
||||
}
|
||||
|
||||
private Transform randomTransform() {
|
||||
String type = randomFrom(ScriptTransform.TYPE, SearchTransform.TYPE, ChainTransform.TYPE);
|
||||
switch (type) {
|
||||
case ScriptTransform.TYPE:
|
||||
return new ScriptTransform(scriptService, new Script("_script"));
|
||||
case SearchTransform.TYPE:
|
||||
return new SearchTransform(logger, scriptService, client, matchAllRequest());
|
||||
default: // chain
|
||||
return new ChainTransform(ImmutableList.of(
|
||||
new SearchTransform(logger, scriptService, client, matchAllRequest()),
|
||||
new ScriptTransform(scriptService, new Script("_script"))));
|
||||
}
|
||||
}
|
||||
|
||||
private TransformRegistry registry(Transform transform) {
|
||||
ImmutableMap.Builder<String, Transform.Parser> parsers = ImmutableMap.builder();
|
||||
switch (transform.type()) {
|
||||
case ScriptTransform.TYPE:
|
||||
parsers.put(ScriptTransform.TYPE, new ScriptTransform.Parser(scriptService));
|
||||
return new TransformRegistry(parsers.build());
|
||||
case SearchTransform.TYPE:
|
||||
parsers.put(SearchTransform.TYPE, new SearchTransform.Parser(settings, scriptService, client));
|
||||
return new TransformRegistry(parsers.build());
|
||||
default:
|
||||
ChainTransform.Parser parser = new ChainTransform.Parser();
|
||||
parsers.put(ChainTransform.TYPE, parser);
|
||||
parsers.put(ScriptTransform.TYPE, new ScriptTransform.Parser(scriptService));
|
||||
parsers.put(SearchTransform.TYPE, new SearchTransform.Parser(settings, scriptService, client));
|
||||
TransformRegistry registry = new TransformRegistry(parsers.build());
|
||||
parser.init(registry);
|
||||
return registry;
|
||||
}
|
||||
}
|
||||
|
||||
private Actions randomActions() {
|
||||
ImmutableList.Builder<Action> list = ImmutableList.builder();
|
||||
if (randomBoolean()) {
|
||||
list.add(new EmailAction(logger, emailService, Email.builder().id("prototype").build(), null, Profile.STANDARD, null, null, null, null, randomBoolean()));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
list.add(new IndexAction(logger, client, "_index", "_type"));
|
||||
}
|
||||
if (randomBoolean()) {
|
||||
list.add(new WebhookAction(logger, httpClient, randomFrom(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT), new ScriptTemplate(scriptService, "_url"), null));
|
||||
}
|
||||
return new Actions(list.build());
|
||||
}
|
||||
|
||||
private ActionRegistry registry(Actions actions) {
|
||||
ImmutableMap.Builder<String, Action.Parser> parsers = ImmutableMap.builder();
|
||||
for (Action action : actions) {
|
||||
switch (action.type()) {
|
||||
case EmailAction.TYPE:
|
||||
parsers.put(EmailAction.TYPE, new EmailAction.Parser(settings, emailService, templateParser));
|
||||
break;
|
||||
case IndexAction.TYPE:
|
||||
parsers.put(IndexAction.TYPE, new IndexAction.Parser(settings, client));
|
||||
break;
|
||||
case WebhookAction.TYPE:
|
||||
parsers.put(WebhookAction.TYPE, new WebhookAction.Parser(settings, templateParser, httpClient));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new ActionRegistry(parsers.build());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
package org.elasticsearch.alerts.actions;
|
||||
|
||||
|
||||
import org.elasticsearch.alerts.AbstractAlertingTests;
|
||||
import org.elasticsearch.alerts.Alert;
|
||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
||||
import org.elasticsearch.alerts.condition.Condition;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class ActionsTest extends AbstractAlertingTests {
|
||||
|
||||
@Test
|
||||
public void testAlertActions() throws Exception {
|
||||
//TODO: Consider deleting this test or making it do something useful
|
||||
createIndex("my-index");
|
||||
|
||||
ensureGreen("my-index");
|
||||
|
||||
client().preparePutIndexedScript()
|
||||
.setScriptLang("mustache")
|
||||
.setId("query")
|
||||
.setSource(jsonBuilder().startObject().startObject("template").startObject("match_all").endObject().endObject().endObject())
|
||||
.get();
|
||||
|
||||
ensureAlertingStarted();
|
||||
|
||||
final Action alertAction = new IndexAction(logger, ClientProxy.of(client()), "testindex", "testtype");
|
||||
final List<Action> actionList = new ArrayList<>();
|
||||
actionList.add(alertAction);
|
||||
|
||||
Input alertInput = new SearchInput(logger, scriptService(), ClientProxy.of(client()),
|
||||
createConditionSearchRequest());
|
||||
Condition alertCondition = new ScriptCondition(logger, scriptService(), new Script("return true"));
|
||||
|
||||
|
||||
|
||||
Alert alert = new Alert(
|
||||
"my-first-alert",
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
alertInput,
|
||||
alertCondition,
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), createConditionSearchRequest()),
|
||||
new Actions(actionList), null, new Alert.Status(), new TimeValue(0)
|
||||
);
|
||||
|
||||
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
PutAlertRequest alertRequest = alertClient().preparePutAlert().setAlertName("my-first-alert").setAlertSource(jsonBuilder.bytes()).request();
|
||||
PutAlertResponse alertsResponse = alertClient().putAlert(alertRequest).actionGet();
|
||||
assertNotNull(alertsResponse.indexResponse());
|
||||
assertTrue(alertsResponse.indexResponse().isCreated());
|
||||
|
||||
GetAlertRequest getAlertRequest = new GetAlertRequest(alert.name());
|
||||
GetAlertResponse getAlertResponse = alertClient().getAlert(getAlertRequest).actionGet();
|
||||
assertTrue(getAlertResponse.getResponse().isExists());
|
||||
assertEquals(((Map<String,Object>)getAlertResponse.getResponse().getSourceAsMap().get("schedule")).get("cron").toString(), "0/5 * * * * ? *");
|
||||
|
||||
DeleteAlertRequest deleteAlertRequest = new DeleteAlertRequest(alert.name());
|
||||
DeleteAlertResponse deleteAlertResponse = alertClient().deleteAlert(deleteAlertRequest).actionGet();
|
||||
assertNotNull(deleteAlertResponse.deleteResponse());
|
||||
assertTrue(deleteAlertResponse.deleteResponse().isFound());
|
||||
|
||||
getAlertResponse = alertClient().getAlert(getAlertRequest).actionGet();
|
||||
assertFalse(getAlertResponse.getResponse().isExists());
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,8 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
||||
public class AlwaysFalseConditionTests extends ElasticsearchTestCase {
|
||||
|
||||
|
||||
@Test
|
||||
public void testExecute() throws Exception {
|
||||
|
@ -34,6 +35,7 @@ public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
|||
builder.endObject();
|
||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||
xp.nextToken();
|
||||
|
||||
Condition alwaysTrue = p.parse(xp);
|
||||
assertTrue(alwaysTrue.execute(null).met());
|
||||
}
|
||||
|
@ -47,6 +49,7 @@ public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
|||
builder.endObject();
|
||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||
xp.nextToken();
|
||||
|
||||
p.parse(xp);
|
||||
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
||||
+ AlwaysTrueCondition.TYPE + "] condition should not parse with a body");
|
||||
|
@ -80,5 +83,4 @@ public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
|||
fail("expected a condition exception trying to parse an invalid condition result XContent, ["
|
||||
+ AlwaysTrueCondition.TYPE + "] condition result should not parse with a [met] field");
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,7 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
||||
|
||||
public class AlwaysTrueConditionTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testExecute() throws Exception {
|
||||
|
@ -35,7 +34,6 @@ public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
|||
builder.endObject();
|
||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||
xp.nextToken();
|
||||
|
||||
Condition alwaysTrue = p.parse(xp);
|
||||
assertTrue(alwaysTrue.execute(null).met());
|
||||
}
|
||||
|
@ -49,7 +47,6 @@ public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
|||
builder.endObject();
|
||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||
xp.nextToken();
|
||||
|
||||
p.parse(xp);
|
||||
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
||||
+ AlwaysTrueCondition.TYPE + "] condition should not parse with a body");
|
||||
|
@ -83,4 +80,5 @@ public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
|||
fail("expected a condition exception trying to parse an invalid condition result XContent, ["
|
||||
+ AlwaysTrueCondition.TYPE + "] condition result should not parse with a [met] field");
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,8 @@ import org.elasticsearch.alerts.condition.simple.AlwaysFalseCondition;
|
|||
import org.elasticsearch.alerts.condition.simple.AlwaysTrueCondition;
|
||||
import org.elasticsearch.alerts.input.Input;
|
||||
import org.elasticsearch.alerts.input.simple.SimpleInput;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.throttle.Throttler;
|
||||
import org.elasticsearch.common.joda.time.DateTime;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
|
@ -22,12 +24,12 @@ import org.junit.Test;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class FiredAlertTest extends AbstractAlertingTests {
|
||||
public class FiredAlertTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testParser() throws Exception {
|
||||
|
||||
Alert alert = createTestAlert("fired_test");
|
||||
Alert alert = AlertsTestUtils.createTestAlert("fired_test", scriptService(), httpClient(), noopEmailService(), logger);
|
||||
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
firedAlert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
@ -43,7 +45,7 @@ public class FiredAlertTest extends AbstractAlertingTests {
|
|||
|
||||
@Test
|
||||
public void testParser_WithSealedFiredAlert() throws Exception {
|
||||
Alert alert = createTestAlert("fired_test");
|
||||
Alert alert = AlertsTestUtils.createTestAlert("fired_test", scriptService(), httpClient(), noopEmailService(), logger);
|
||||
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||
ExecutionContext ctx = new ExecutionContext(firedAlert.id(), alert, new DateTime(), new DateTime());
|
||||
ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah"));
|
||||
|
@ -65,7 +67,7 @@ public class FiredAlertTest extends AbstractAlertingTests {
|
|||
|
||||
@Test
|
||||
public void testParser_WithSealedFiredAlert_WithScriptSearchCondition() throws Exception {
|
||||
Alert alert = createTestAlert("fired_test");
|
||||
Alert alert = AlertsTestUtils.createTestAlert("fired_test", scriptService(), httpClient(), noopEmailService(), logger);
|
||||
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||
ExecutionContext ctx = new ExecutionContext(firedAlert.id(), alert, new DateTime(), new DateTime());
|
||||
ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah"));
|
|
@ -14,10 +14,10 @@ import static org.hamcrest.core.IsEqual.equalTo;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class ActionHistoryIndexNameTest extends ElasticsearchTestCase {
|
||||
public class HistoryStoreTests extends ElasticsearchTestCase {
|
||||
|
||||
@Test
|
||||
public void testActionHistoryNameTest() {
|
||||
public void testIndexNameGeneration() {
|
||||
assertThat(HistoryStore.getAlertHistoryIndexNameForTime(new DateTime(0, DateTimeZone.UTC)), equalTo(".alert_history_1970-01-01"));
|
||||
assertThat(HistoryStore.getAlertHistoryIndexNameForTime(new DateTime(100000000000L, DateTimeZone.UTC)), equalTo(".alert_history_1973-03-03"));
|
||||
assertThat(HistoryStore.getAlertHistoryIndexNameForTime(new DateTime(1416582852000L, DateTimeZone.UTC)), equalTo(".alert_history_2014-11-21"));
|
|
@ -19,6 +19,8 @@ import org.elasticsearch.common.settings.ImmutableSettings;
|
|||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
|
@ -70,27 +72,21 @@ public class SearchInputTests extends ElasticsearchIntegrationTest {
|
|||
|
||||
@Test
|
||||
public void testParser_Valid() throws Exception {
|
||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
||||
filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}"))
|
||||
);
|
||||
SearchRequest request = client()
|
||||
.prepareSearch()
|
||||
SearchRequest request = client().prepareSearch()
|
||||
.setSearchType(SearchInput.DEFAULT_SEARCH_TYPE)
|
||||
.request()
|
||||
.source(searchSourceBuilder);
|
||||
.source(searchSource()
|
||||
.query(filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}"))));
|
||||
|
||||
XContentBuilder jsonBuilder = jsonBuilder();
|
||||
XContentBuilder builder = AlertUtils.writeSearchRequest(request, jsonBuilder(), ToXContent.EMPTY_PARAMS);
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(builder.bytes());
|
||||
parser.nextToken();
|
||||
|
||||
jsonBuilder.startObject();
|
||||
jsonBuilder.field(SearchInput.Parser.REQUEST_FIELD.getPreferredName());
|
||||
AlertUtils.writeSearchRequest(request, jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
jsonBuilder.endObject();
|
||||
|
||||
Input.Parser searchInputParser = new SearchInput.Parser(ImmutableSettings.settingsBuilder().build(),
|
||||
Input.Parser searchInputParser = new SearchInput.Parser(ImmutableSettings.EMPTY,
|
||||
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class)),
|
||||
ClientProxy.of(client()));
|
||||
|
||||
Input searchInput = searchInputParser.parse(XContentFactory.xContent(jsonBuilder.bytes()).createParser(jsonBuilder.bytes()));
|
||||
Input searchInput = searchInputParser.parse(parser);
|
||||
assertEquals(SearchInput.TYPE, searchInput.type());
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
|||
.field(DailySchedule.TYPE, daily)
|
||||
.endObject();
|
||||
BytesReference bytes = builder.bytes();
|
||||
System.out.println(bytes.toUtf8());
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||
parser.nextToken();
|
||||
Schedule schedule = registry.parse(parser);
|
||||
|
@ -114,7 +113,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
|||
.field(WeeklySchedule.TYPE, weekly)
|
||||
.endObject();
|
||||
BytesReference bytes = builder.bytes();
|
||||
System.out.println(bytes.toUtf8());
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||
parser.nextToken();
|
||||
Schedule schedule = registry.parse(parser);
|
||||
|
@ -131,7 +129,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
|||
.field(MonthlySchedule.TYPE, monthly)
|
||||
.endObject();
|
||||
BytesReference bytes = builder.bytes();
|
||||
System.out.println(bytes.toUtf8());
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||
parser.nextToken();
|
||||
Schedule schedule = registry.parse(parser);
|
||||
|
|
|
@ -116,7 +116,6 @@ public class ScriptTemplateTests extends ElasticsearchTestCase {
|
|||
|
||||
XContentBuilder builder = jsonBuilder().value(template);
|
||||
BytesReference bytes = builder.bytes();
|
||||
System.out.println(bytes.toUtf8());
|
||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||
parser.nextToken();
|
||||
ScriptTemplate parsed = templateParser.parse(parser);
|
||||
|
|
|
@ -3,33 +3,24 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.actions.email.EmailAction;
|
||||
import org.elasticsearch.alerts.AlertsPlugin;
|
||||
import org.elasticsearch.alerts.AlertsService;
|
||||
import org.elasticsearch.alerts.actions.email.service.Authentication;
|
||||
import org.elasticsearch.alerts.actions.email.service.Email;
|
||||
import org.elasticsearch.alerts.actions.email.service.EmailService;
|
||||
import org.elasticsearch.alerts.actions.email.service.Profile;
|
||||
import org.elasticsearch.alerts.actions.webhook.HttpClient;
|
||||
import org.elasticsearch.alerts.actions.webhook.WebhookAction;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.history.FiredAlert;
|
||||
import org.elasticsearch.alerts.history.HistoryStore;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.AlertUtils;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ScriptServiceProxy;
|
||||
import org.elasticsearch.alerts.support.template.ScriptTemplate;
|
||||
import org.elasticsearch.alerts.support.template.Template;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
|
@ -37,36 +28,34 @@ import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
|||
import org.elasticsearch.cluster.routing.IndexRoutingTable;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.hppc.cursors.ObjectObjectCursor;
|
||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
import org.elasticsearch.test.TestCluster;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
import javax.mail.internet.AddressException;
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.SUITE;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
|
||||
/**
|
||||
*/
|
||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||
public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest {
|
||||
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||
public abstract class AbstractAlertsIntegrationTests extends ElasticsearchIntegrationTest {
|
||||
|
||||
@Override
|
||||
protected Settings nodeSettings(int nodeOrdinal) {
|
||||
|
@ -129,10 +118,8 @@ public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest
|
|||
|
||||
builder.startObject("input");
|
||||
{
|
||||
builder.startObject("search");
|
||||
builder.field("request");
|
||||
builder.field("search");
|
||||
AlertUtils.writeSearchRequest(conditionRequest, builder, ToXContent.EMPTY_PARAMS);
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endObject();
|
||||
|
||||
|
@ -163,56 +150,6 @@ public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest
|
|||
return builder.bytes();
|
||||
}
|
||||
|
||||
public static SearchRequest createConditionSearchRequest(String... indices) {
|
||||
SearchRequest request = new SearchRequest(indices);
|
||||
request.indicesOptions(AlertUtils.DEFAULT_INDICES_OPTIONS);
|
||||
request.searchType(SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
return request;
|
||||
}
|
||||
|
||||
protected Alert createTestAlert(String alertName) throws AddressException {
|
||||
SearchRequest conditionRequest = createConditionSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest transformRequest = createConditionSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||
transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE);
|
||||
conditionRequest.searchType(SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
Template url = new ScriptTemplate(scriptService(), "http://localhost/foobarbaz/{{alert_name}}");
|
||||
Template body = new ScriptTemplate(scriptService(), "{{alert_name}} executed with {{response.hits.total}} hits");
|
||||
|
||||
actions.add(new WebhookAction(logger, httpClient(), HttpMethod.GET, url, body));
|
||||
|
||||
Email.Address from = new Email.Address("from@test.com");
|
||||
List<Email.Address> emailAddressList = new ArrayList<>();
|
||||
emailAddressList.add(new Email.Address("to@test.com"));
|
||||
Email.AddressList to = new Email.AddressList(emailAddressList);
|
||||
|
||||
|
||||
Email.Builder emailBuilder = Email.builder().id("prototype");
|
||||
emailBuilder.from(from);
|
||||
emailBuilder.to(to);
|
||||
|
||||
|
||||
EmailAction emailAction = new EmailAction(logger, noopEmailService(), emailBuilder.build(),
|
||||
new Authentication("testname", "testpassword"), Profile.STANDARD, "testaccount", body, body, null, true);
|
||||
|
||||
actions.add(emailAction);
|
||||
|
||||
Map<String, Object> metadata = new LinkedHashMap<>();
|
||||
metadata.put("foo", "bar");
|
||||
|
||||
return new Alert(
|
||||
alertName,
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()),
|
||||
conditionRequest),
|
||||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), transformRequest), new Actions(actions), metadata, new Alert.Status(), new TimeValue(0)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
protected AlertsClient alertClient() {
|
||||
return internalTestCluster().getInstance(AlertsClient.class);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.alerts.test;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.Alert;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.actions.email.EmailAction;
|
||||
import org.elasticsearch.alerts.actions.email.service.Authentication;
|
||||
import org.elasticsearch.alerts.actions.email.service.Email;
|
||||
import org.elasticsearch.alerts.actions.email.service.EmailService;
|
||||
import org.elasticsearch.alerts.actions.email.service.Profile;
|
||||
import org.elasticsearch.alerts.actions.webhook.HttpClient;
|
||||
import org.elasticsearch.alerts.actions.webhook.WebhookAction;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.AlertUtils;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ScriptServiceProxy;
|
||||
import org.elasticsearch.alerts.support.template.ScriptTemplate;
|
||||
import org.elasticsearch.alerts.support.template.Template;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.common.logging.ESLogger;
|
||||
import org.elasticsearch.common.netty.handler.codec.http.HttpMethod;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
|
||||
import javax.mail.internet.AddressException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public final class AlertsTestUtils {
|
||||
|
||||
private AlertsTestUtils() {
|
||||
}
|
||||
|
||||
public static SearchRequest newInputSearchRequest(String... indices) {
|
||||
SearchRequest request = new SearchRequest(indices);
|
||||
request.indicesOptions(AlertUtils.DEFAULT_INDICES_OPTIONS);
|
||||
request.searchType(SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
return request;
|
||||
}
|
||||
|
||||
public static SearchRequest matchAllRequest() {
|
||||
return new SearchRequest().source(SearchSourceBuilder.searchSource().query(matchAllQuery()));
|
||||
}
|
||||
|
||||
public static Alert createTestAlert(String alertName, ScriptServiceProxy scriptService, HttpClient httpClient, EmailService emailService, ESLogger logger) throws AddressException {
|
||||
SearchRequest conditionRequest = newInputSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest transformRequest = newInputSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||
transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE);
|
||||
conditionRequest.searchType(SearchInput.DEFAULT_SEARCH_TYPE);
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
Template url = new ScriptTemplate(scriptService, "http://localhost/foobarbaz/{{alert_name}}");
|
||||
Template body = new ScriptTemplate(scriptService, "{{alert_name}} executed with {{response.hits.total}} hits");
|
||||
|
||||
actions.add(new WebhookAction(logger, httpClient, HttpMethod.GET, url, body));
|
||||
|
||||
Email.Address from = new Email.Address("from@test.com");
|
||||
List<Email.Address> emailAddressList = new ArrayList<>();
|
||||
emailAddressList.add(new Email.Address("to@test.com"));
|
||||
Email.AddressList to = new Email.AddressList(emailAddressList);
|
||||
|
||||
|
||||
Email.Builder emailBuilder = Email.builder().id("prototype");
|
||||
emailBuilder.from(from);
|
||||
emailBuilder.to(to);
|
||||
|
||||
|
||||
EmailAction emailAction = new EmailAction(logger, emailService, emailBuilder.build(),
|
||||
new Authentication("testname", "testpassword"), Profile.STANDARD, "testaccount", body, body, null, true);
|
||||
|
||||
actions.add(emailAction);
|
||||
|
||||
Map<String, Object> metadata = new LinkedHashMap<>();
|
||||
metadata.put("foo", "bar");
|
||||
|
||||
return new Alert(
|
||||
alertName,
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
new SearchInput(logger, scriptService, ClientProxy.of(ElasticsearchIntegrationTest.client()),
|
||||
conditionRequest),
|
||||
new ScriptCondition(logger, scriptService, new Script("return true")),
|
||||
new SearchTransform(logger, scriptService, ClientProxy.of(ElasticsearchIntegrationTest.client()), transformRequest),
|
||||
new Actions(actions),
|
||||
metadata,
|
||||
new TimeValue(0),
|
||||
new Alert.Status());
|
||||
}
|
||||
}
|
|
@ -3,11 +3,12 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.alerts.history.HistoryStore;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -15,14 +16,19 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.alerts.client.AlertSourceBuilder.alertSourceBuilder;
|
||||
import static org.elasticsearch.alerts.condition.ConditionBuilders.scriptCondition;
|
||||
import static org.elasticsearch.alerts.input.InputBuilders.searchInput;
|
||||
import static org.elasticsearch.alerts.scheduler.schedule.Schedules.cron;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class AlertMetadataTest extends AbstractAlertingTests {
|
||||
public class AlertMetadataTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testAlertMetadata() throws Exception {
|
||||
|
@ -35,9 +41,12 @@ public class AlertMetadataTest extends AbstractAlertingTests {
|
|||
metaList.add("test");
|
||||
|
||||
metadata.put("baz", metaList);
|
||||
SearchRequest conditionRequest = createConditionSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
alertClient().preparePutAlert("1")
|
||||
.setAlertSource(createAlertSource("0/5 * * * * ? *", conditionRequest, "hits.total == 1", metadata))
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(cron("0/5 * * * * ? *"))
|
||||
.input(searchInput(AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery()))))
|
||||
.condition(scriptCondition("hits.total == 1"))
|
||||
.metadata(metadata))
|
||||
.get();
|
||||
// Wait for a no action entry to be added. (the condition search request will not match, because there are no docs in my-index)
|
||||
assertAlertWithNoActionNeeded("1", 1);
|
|
@ -3,42 +3,47 @@
|
|||
* 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.alerts.actions;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.*;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
|
||||
|
||||
/**
|
||||
*/
|
||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||
public class AlertStatsTests extends AbstractAlertingTests {
|
||||
@ClusterScope(scope = TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||
public class AlertStatsTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testStartedStats() throws Exception {
|
||||
AlertsStatsRequest alertsStatsRequest = alertClient().prepareAlertsStats().request();
|
||||
AlertsStatsResponse response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
||||
|
||||
assertTrue(response.isAlertActionManagerStarted());
|
||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
||||
assertThat(response.getAlertActionManagerQueueSize(), equalTo(0L));
|
||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(0L));
|
||||
assertThat(response.getAlertActionManagerLargestQueueSize(), equalTo(0L));
|
||||
assertThat(response.getVersion(), equalTo(AlertsVersion.CURRENT));
|
||||
assertThat(response.getBuild(), equalTo(AlertsBuild.CURRENT));
|
||||
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||
assertThat(response.getAlertManagerStarted(), is(AlertsService.State.STARTED));
|
||||
assertThat(response.getAlertActionManagerQueueSize(), is(0L));
|
||||
assertThat(response.getNumberOfRegisteredAlerts(), is(0L));
|
||||
assertThat(response.getAlertActionManagerLargestQueueSize(), is(0L));
|
||||
assertThat(response.getVersion(), is(AlertsVersion.CURRENT));
|
||||
assertThat(response.getBuild(), is(AlertsBuild.CURRENT));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -48,13 +53,13 @@ public class AlertStatsTests extends AbstractAlertingTests {
|
|||
AlertsStatsRequest alertsStatsRequest = alertsClient.prepareAlertsStats().request();
|
||||
AlertsStatsResponse response = alertsClient.alertsStats(alertsStatsRequest).actionGet();
|
||||
|
||||
assertTrue(response.isAlertActionManagerStarted());
|
||||
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
||||
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("* * * * * ? *", searchRequest, "hits.total == 1");
|
||||
alertClient().preparePutAlert("testAlert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSource)
|
||||
.get();
|
||||
|
||||
response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
||||
|
@ -63,9 +68,9 @@ public class AlertStatsTests extends AbstractAlertingTests {
|
|||
TimeValue waitTime = new TimeValue(30, TimeUnit.SECONDS);
|
||||
Thread.sleep(waitTime.getMillis());
|
||||
|
||||
assertTrue(response.isAlertActionManagerStarted());
|
||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(1L));
|
||||
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||
assertThat(response.getAlertManagerStarted(), is(AlertsService.State.STARTED));
|
||||
assertThat(response.getNumberOfRegisteredAlerts(), is(1L));
|
||||
//assertThat(response.getAlertActionManagerLargestQueueSize(), greaterThan(0L));
|
||||
}
|
||||
}
|
|
@ -3,41 +3,37 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.count.CountResponse;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
||||
import org.elasticsearch.alerts.Alert;
|
||||
import org.elasticsearch.alerts.actions.ActionBuilders;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.history.FiredAlert;
|
||||
import org.elasticsearch.alerts.history.HistoryStore;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.transport.actions.ack.AckAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.elasticsearch.alerts.client.AlertSourceBuilder.alertSourceBuilder;
|
||||
import static org.elasticsearch.alerts.condition.ConditionBuilders.scriptCondition;
|
||||
import static org.elasticsearch.alerts.input.InputBuilders.searchInput;
|
||||
import static org.elasticsearch.alerts.transform.TransformBuilders.searchTransform;
|
||||
import static org.elasticsearch.alerts.scheduler.schedule.Schedules.cron;
|
||||
import static org.elasticsearch.alerts.test.AlertsTestUtils.matchAllRequest;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
@ -45,7 +41,7 @@ import static org.hamcrest.core.IsEqual.equalTo;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class AlertThrottleTests extends AbstractAlertingTests {
|
||||
public class AlertThrottleTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testAckThrottle() throws Exception{
|
||||
|
@ -57,32 +53,22 @@ public class AlertThrottleTests extends AbstractAlertingTests {
|
|||
assertTrue(dummyEventIndexResponse.isCreated());
|
||||
refresh();
|
||||
|
||||
PutAlertResponse putAlertResponse = alertsClient.preparePutAlert()
|
||||
.alertName("throttled-alert")
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(cron("0/5 * * * * ? *"))
|
||||
.input(searchInput(matchAllRequest().indices("test-index")))
|
||||
.condition(scriptCondition("hits.total > 0"))
|
||||
.transform(searchTransform(matchAllRequest().indices("test-index")))
|
||||
.addAction(ActionBuilders.indexAction("action-index", "action-type"))
|
||||
.throttlePeriod(TimeValue.timeValueMillis(0)))
|
||||
.get();
|
||||
|
||||
SearchRequest request = createConditionSearchRequest("test-index").source(searchSource().query(matchAllQuery()));
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
actions.add(new IndexAction(logger, ClientProxy.of(client()), "action-index", "action-type"));
|
||||
|
||||
Alert alert = new Alert(
|
||||
"test-ack-throttle",
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()),
|
||||
request),
|
||||
new ScriptCondition(logger, scriptService(), new Script("hits.total > 0")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), request), new Actions(actions), null, new Alert.Status(), new TimeValue(0)
|
||||
);
|
||||
|
||||
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
PutAlertResponse putAlertResponse = alertsClient.preparePutAlert().setAlertName("throttled-alert").setAlertSource(jsonBuilder.bytes()).get();
|
||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||
|
||||
Thread.sleep(20000);
|
||||
AckAlertResponse ackResponse = alertsClient.prepareAckAlert("throttled-alert").get();
|
||||
assertEquals(Alert.Status.AckStatus.State.ACKED, ackResponse.getStatus().ackStatus().state());
|
||||
Assert.assertEquals(Alert.Status.AckStatus.State.ACKED, ackResponse.getStatus().ackStatus().state());
|
||||
|
||||
refresh();
|
||||
SearchResponse searchResponse = client()
|
||||
|
@ -138,24 +124,16 @@ public class AlertThrottleTests extends AbstractAlertingTests {
|
|||
assertTrue(dummyEventIndexResponse.isCreated());
|
||||
refresh();
|
||||
|
||||
SearchRequest request = createConditionSearchRequest("test-index").source(searchSource().query(matchAllQuery()));
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
actions.add(new IndexAction(logger, ClientProxy.of(client()), "action-index", "action-type"));
|
||||
|
||||
Alert alert = new Alert(
|
||||
"test-time-throttle",
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()), request),
|
||||
new ScriptCondition(logger, scriptService(), new Script("hits.total > 0")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), request),
|
||||
new Actions(actions), null, new Alert.Status(), new TimeValue(10, TimeUnit.SECONDS));
|
||||
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
PutAlertResponse putAlertResponse = alertsClient.preparePutAlert().setAlertName("throttled-alert").setAlertSource(jsonBuilder.bytes()).get();
|
||||
PutAlertResponse putAlertResponse = alertsClient.preparePutAlert()
|
||||
.alertName("throttled-alert")
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(cron("0/5 * * * * ? *"))
|
||||
.input(searchInput(matchAllRequest().indices("test-index")))
|
||||
.condition(scriptCondition("hits.total > 0"))
|
||||
.transform(searchTransform(matchAllRequest().indices("test-index")))
|
||||
.addAction(ActionBuilders.indexAction("action-index", "action-type"))
|
||||
.throttlePeriod(TimeValue.timeValueSeconds(10)))
|
||||
.get();
|
||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||
|
||||
forceFullSleepTime(new TimeValue(5, TimeUnit.SECONDS));
|
|
@ -3,18 +3,23 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.alerts.AlertsException;
|
||||
import org.elasticsearch.alerts.AlertsStore;
|
||||
import org.elasticsearch.alerts.client.AlertSourceBuilder;
|
||||
import org.elasticsearch.alerts.client.AlertsClient;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.IntervalSchedule;
|
||||
import org.elasticsearch.alerts.support.AlertUtils;
|
||||
import org.elasticsearch.alerts.support.Variables;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertRequest;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||
import org.elasticsearch.common.bytes.BytesReference;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.index.query.FilterBuilders;
|
||||
|
@ -28,6 +33,12 @@ import org.junit.Test;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.elasticsearch.alerts.actions.ActionBuilders.indexAction;
|
||||
import static org.elasticsearch.alerts.client.AlertSourceBuilder.alertSourceBuilder;
|
||||
import static org.elasticsearch.alerts.condition.ConditionBuilders.scriptCondition;
|
||||
import static org.elasticsearch.alerts.input.InputBuilders.searchInput;
|
||||
import static org.elasticsearch.alerts.scheduler.schedule.Schedules.cron;
|
||||
import static org.elasticsearch.alerts.scheduler.schedule.Schedules.interval;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.elasticsearch.index.query.FilterBuilders.rangeFilter;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
|
@ -39,7 +50,7 @@ import static org.hamcrest.Matchers.is;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class BasicAlertingTest extends AbstractAlertingTests {
|
||||
public class BasicAlertsTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testIndexAlert() throws Exception {
|
||||
|
@ -47,10 +58,12 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
alertsClient.preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))
|
||||
.input(searchInput(searchRequest))
|
||||
.condition(scriptCondition("hits.total == 1")))
|
||||
.get();
|
||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
||||
|
||||
|
@ -62,10 +75,12 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
@Test
|
||||
public void testIndexAlert_registerAlertBeforeTargetIndex() throws Exception {
|
||||
AlertsClient alertsClient = alertClient();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
alertsClient.preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))
|
||||
.input(searchInput(searchRequest))
|
||||
.condition(scriptCondition("hits.total == 1")))
|
||||
.get();
|
||||
|
||||
// The alert's condition won't meet because there is no data that matches with the query
|
||||
|
@ -82,10 +97,12 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
PutAlertResponse indexResponse = alertsClient.preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))
|
||||
.input(searchInput(searchRequest))
|
||||
.condition(scriptCondition("hits.total == 1")))
|
||||
.get();
|
||||
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
||||
|
||||
|
@ -117,13 +134,13 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
alertSource.startObject("schedule").field("cron", "0/5 * * * * ? *").endObject();
|
||||
|
||||
alertSource.startObject("condition").startObject("script").field("script", "return true").field("request");
|
||||
AlertUtils.writeSearchRequest(createConditionSearchRequest(), alertSource, ToXContent.EMPTY_PARAMS);
|
||||
AlertUtils.writeSearchRequest(AlertsTestUtils.newInputSearchRequest(), alertSource, ToXContent.EMPTY_PARAMS);
|
||||
alertSource.endObject();
|
||||
|
||||
alertSource.endObject();
|
||||
try {
|
||||
alertsClient.preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource.bytes())
|
||||
.source(alertSource.bytes())
|
||||
.get();
|
||||
fail();
|
||||
} catch (AlertsException e) {
|
||||
|
@ -145,12 +162,14 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
createIndex("my-index");
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
searchRequest.searchType(SearchType.QUERY_THEN_FETCH);
|
||||
// By accessing the actual hit we know that the fetch phase has been performed
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits?.hits[0]._score == 1.0");
|
||||
PutAlertResponse indexResponse = alertsClient.preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(interval(5, IntervalSchedule.Interval.Unit.SECONDS))
|
||||
.input(searchInput(searchRequest))
|
||||
.condition(scriptCondition("hits?.hits[0]._score == 1.0")))
|
||||
.get();
|
||||
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
||||
|
@ -158,19 +177,27 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
|
||||
@Test
|
||||
public void testModifyAlerts() throws Exception {
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index")
|
||||
.source(searchSource().query(matchAllQuery()));
|
||||
|
||||
AlertSourceBuilder source = alertSourceBuilder()
|
||||
.schedule(cron("0/5 * * * * ? *"))
|
||||
.input(searchInput(searchRequest))
|
||||
.addAction(indexAction("my-index", "trail"));
|
||||
|
||||
|
||||
alertClient().preparePutAlert("1")
|
||||
.setAlertSource(createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1"))
|
||||
.source(source.condition(scriptCondition("hits.total == 1")))
|
||||
.get();
|
||||
assertAlertWithMinimumPerformedActionsCount("1", 0, false);
|
||||
|
||||
alertClient().preparePutAlert("1")
|
||||
.setAlertSource(createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 0"))
|
||||
.source(source.condition(scriptCondition("hits.total == 0")))
|
||||
.get();
|
||||
assertAlertWithMinimumPerformedActionsCount("1", 1, false);
|
||||
|
||||
alertClient().preparePutAlert("1")
|
||||
.setAlertSource(createAlertSource("0/5 * * * * ? 2020", searchRequest, "hits.total == 0"))
|
||||
.source(source.schedule(cron("0/5 * * * * ? 2020")).condition(scriptCondition("hits.total == 0")))
|
||||
.get();
|
||||
|
||||
Thread.sleep(5000);
|
||||
|
@ -181,12 +208,13 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
|
||||
@Test
|
||||
public void testAggregations() throws Exception {
|
||||
class R implements Runnable {
|
||||
|
||||
class Indexer extends Thread {
|
||||
|
||||
private final long sleepTime;
|
||||
private final long totalTime;
|
||||
|
||||
R(long sleepTime, long totalTime) {
|
||||
Indexer(long sleepTime, long totalTime) {
|
||||
this.sleepTime = sleepTime;
|
||||
this.totalTime = totalTime;
|
||||
}
|
||||
|
@ -207,24 +235,30 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
}
|
||||
|
||||
assertAcked(prepareCreate("my-index").addMapping("my-type", "_timestamp", "enabled=true"));
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(
|
||||
searchSource()
|
||||
.query(QueryBuilders.constantScoreQuery(FilterBuilders.rangeFilter("_timestamp").from("{{scheduled_fire_time}}||-1m").to("{{scheduled_fire_time}}")))
|
||||
.aggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp").interval(DateHistogram.Interval.SECOND).order(Histogram.Order.COUNT_DESC))
|
||||
);
|
||||
BytesReference reference = createAlertSource("* 0/1 * * * ? *", searchRequest, "aggregations.rate.buckets[0]?.doc_count > 5");
|
||||
alertClient().preparePutAlert("rate-alert").setAlertSource(reference).get();
|
||||
.aggregation(AggregationBuilders.dateHistogram("rate").field("_timestamp").interval(DateHistogram.Interval.SECOND).order(Histogram.Order.COUNT_DESC)));
|
||||
// BytesReference reference = createAlertSource("* 0/1 * * * ? *", searchRequest, "aggregations.rate.buckets[0]?.doc_count > 5");
|
||||
alertClient().preparePutAlert("rate-alert")
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(cron("* 0/1 * * * ? *"))
|
||||
.input(searchInput(searchRequest))
|
||||
.condition(scriptCondition("aggregations.rate.buckets[0]?.doc_count > 5"))
|
||||
.addAction(indexAction("my-index", "trail")))
|
||||
.get();
|
||||
|
||||
Thread indexThread = new Thread(new R(500, 60000));
|
||||
indexThread.start();
|
||||
indexThread.join();
|
||||
Indexer indexer = new Indexer(500, 60000);
|
||||
indexer.start();
|
||||
indexer.join();
|
||||
|
||||
assertAlertWithExactPerformedActionsCount("rate-alert", 0);
|
||||
assertAlertWithNoActionNeeded("rate-alert", 1);
|
||||
|
||||
indexThread = new Thread(new R(100, 60000));
|
||||
indexThread.start();
|
||||
indexThread.join();
|
||||
indexer = new Indexer(100, 60000);
|
||||
indexer.start();
|
||||
indexer.join();
|
||||
|
||||
assertAlertWithMinimumPerformedActionsCount("rate-alert", 1);
|
||||
}
|
||||
|
||||
|
@ -235,7 +269,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
@Test
|
||||
public void testConditionSearchWithSource() throws Exception {
|
||||
testConditionSearch(
|
||||
createConditionSearchRequest("my-index").source(searchSourceBuilder)
|
||||
AlertsTestUtils.newInputSearchRequest("my-index").source(searchSourceBuilder)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -246,7 +280,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
.setId("my-template")
|
||||
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject())
|
||||
.get();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index");
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index");
|
||||
searchRequest.templateName("my-template");
|
||||
searchRequest.templateType(ScriptService.ScriptType.INDEXED);
|
||||
testConditionSearch(searchRequest);
|
||||
|
@ -259,7 +293,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
|||
|
||||
alertClient().prepareDeleteAlert(alertName).get();
|
||||
alertClient().preparePutAlert(alertName)
|
||||
.setAlertSource(createAlertSource(String.format(Locale.ROOT, "0/%s * * * * ? *", (scheduleTimeInMs / 1000)), request, "return hits.total >= 3"))
|
||||
.source(createAlertSource(String.format(Locale.ROOT, "0/%s * * * * ? *", (scheduleTimeInMs / 1000)), request, "return hits.total >= 3"))
|
||||
.get();
|
||||
|
||||
long time1 = System.currentTimeMillis();
|
|
@ -3,12 +3,15 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.WriteConsistencyLevel;
|
||||
import org.elasticsearch.action.count.CountResponse;
|
||||
import org.elasticsearch.action.index.IndexResponse;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.Alert;
|
||||
import org.elasticsearch.alerts.AlertsService;
|
||||
import org.elasticsearch.alerts.AlertsStore;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
|
@ -18,6 +21,8 @@ import org.elasticsearch.alerts.input.search.SearchInput;
|
|||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||
|
@ -43,13 +48,13 @@ import static org.hamcrest.core.IsEqual.equalTo;
|
|||
|
||||
/**
|
||||
*/
|
||||
public class BootStrapTest extends AbstractAlertingTests {
|
||||
public class BootStrapTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testBootStrapAlerts() throws Exception {
|
||||
ensureAlertingStarted();
|
||||
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0 0/5 * * * ? *", searchRequest, "hits.total == 1");
|
||||
client().prepareIndex(AlertsStore.ALERT_INDEX, AlertsStore.ALERT_TYPE, "my-first-alert")
|
||||
.setSource(alertSource)
|
||||
|
@ -76,16 +81,17 @@ public class BootStrapTest extends AbstractAlertingTests {
|
|||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(0L));
|
||||
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
Alert alert = new Alert(
|
||||
"test-serialization",
|
||||
new CronSchedule("0/5 * * * * ? 2035"), //Set this into the future so we don't get any extra runs
|
||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||
new Actions(new ArrayList<Action>()), null, new Alert.Status(), new TimeValue(0)
|
||||
|
||||
);
|
||||
new Actions(new ArrayList<Action>()),
|
||||
null, // metadata
|
||||
new TimeValue(0),
|
||||
new Alert.Status());
|
||||
|
||||
XContentBuilder builder = jsonBuilder().value(alert);
|
||||
IndexResponse indexResponse = client().prepareIndex(AlertsStore.ALERT_INDEX, AlertsStore.ALERT_TYPE, alert.name())
|
||||
|
@ -124,7 +130,7 @@ public class BootStrapTest extends AbstractAlertingTests {
|
|||
DateTime now = new DateTime(DateTimeZone.UTC);
|
||||
long numberOfAlertHistoryIndices = randomIntBetween(2,8);
|
||||
long numberOfAlertHistoryEntriesPerIndex = randomIntBetween(5,10);
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
|
||||
for (int i = 0; i < numberOfAlertHistoryIndices; i++) {
|
||||
DateTime historyIndexDate = now.minus((new TimeValue(i, TimeUnit.DAYS)).getMillis());
|
||||
|
@ -143,14 +149,13 @@ public class BootStrapTest extends AbstractAlertingTests {
|
|||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||
new Actions(new ArrayList<Action>()),
|
||||
null,
|
||||
new Alert.Status(),
|
||||
new TimeValue(0)
|
||||
);
|
||||
null, // metatdata
|
||||
new TimeValue(0),
|
||||
new Alert.Status());
|
||||
XContentBuilder jsonBuilder = jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
PutAlertResponse putAlertResponse = alertClient().preparePutAlert(alert.name()).setAlertSource(jsonBuilder.bytes()).get();
|
||||
PutAlertResponse putAlertResponse = alertClient().preparePutAlert(alert.name()).source(jsonBuilder.bytes()).get();
|
||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||
|
||||
FiredAlert firedAlert = new FiredAlert(alert, historyIndexDate, historyIndexDate);
|
|
@ -3,10 +3,13 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.alerts.AlertsService;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
|
@ -20,6 +23,7 @@ import org.elasticsearch.discovery.DiscoverySettings;
|
|||
import org.elasticsearch.discovery.MasterNotDiscoveredException;
|
||||
import org.elasticsearch.discovery.zen.elect.ElectMasterService;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
|
||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||
import org.junit.Test;
|
||||
|
@ -28,14 +32,15 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.elasticsearch.test.ElasticsearchIntegrationTest.Scope.TEST;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
|
||||
/**
|
||||
*/
|
||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, numDataNodes = 0)
|
||||
public class NoMasterNodeTests extends AbstractAlertingTests {
|
||||
@ClusterScope(scope = TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, numDataNodes = 0)
|
||||
public class NoMasterNodeTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
private ClusterDiscoveryConfiguration.UnicastZen config;
|
||||
|
||||
|
@ -60,10 +65,10 @@ public class NoMasterNodeTests extends AbstractAlertingTests {
|
|||
|
||||
// Have a sample document in the index, the alert is going to evaluate
|
||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
alertClient().preparePutAlert("my-first-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSource)
|
||||
.get();
|
||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
||||
|
||||
|
@ -88,7 +93,7 @@ public class NoMasterNodeTests extends AbstractAlertingTests {
|
|||
|
||||
// Add a new alert and wait for its condition to be met
|
||||
alertClient().preparePutAlert("my-second-alert")
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSource)
|
||||
.get();
|
||||
assertAlertWithMinimumPerformedActionsCount("my-second-alert", 1);
|
||||
}
|
||||
|
@ -108,10 +113,10 @@ public class NoMasterNodeTests extends AbstractAlertingTests {
|
|||
ensureAlertingStarted();
|
||||
for (int i = 1; i <= numberOfAlerts; i++) {
|
||||
String alertName = "alert" + i;
|
||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(searchSource().query(termQuery("field", "value")));
|
||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||
alertClient().preparePutAlert(alertName)
|
||||
.setAlertSource(alertSource)
|
||||
.source(alertSource)
|
||||
.get();
|
||||
}
|
||||
ensureGreen();
|
|
@ -3,40 +3,34 @@
|
|||
* 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.alerts;
|
||||
package org.elasticsearch.alerts.test.integration;
|
||||
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.alerts.actions.Action;
|
||||
import org.elasticsearch.alerts.actions.Actions;
|
||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.CronSchedule;
|
||||
import org.elasticsearch.alerts.support.Script;
|
||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||
import org.elasticsearch.alerts.scheduler.schedule.IntervalSchedule.Interval;
|
||||
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||
import org.elasticsearch.common.unit.TimeValue;
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||
import org.elasticsearch.script.ScriptService;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.alerts.actions.ActionBuilders.indexAction;
|
||||
import static org.elasticsearch.alerts.client.AlertSourceBuilder.alertSourceBuilder;
|
||||
import static org.elasticsearch.alerts.input.InputBuilders.searchInput;
|
||||
import static org.elasticsearch.alerts.transform.TransformBuilders.searchTransform;
|
||||
import static org.elasticsearch.alerts.scheduler.schedule.Schedules.interval;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class TransformSearchTest extends AbstractAlertingTests {
|
||||
public class TransformSearchTests extends AbstractAlertsIntegrationTests {
|
||||
|
||||
@Test
|
||||
public void testTransformSearchRequest() throws Exception {
|
||||
|
@ -46,31 +40,23 @@ public class TransformSearchTest extends AbstractAlertingTests {
|
|||
index("my-payload-index","payload", "mytestresult");
|
||||
refresh();
|
||||
|
||||
SearchRequest conditionRequest = createConditionSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest transformRequest = createConditionSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest inputRequest = AlertsTestUtils.newInputSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||
SearchRequest transformRequest = AlertsTestUtils.newInputSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||
transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE);
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(new IndexAction(logger, ClientProxy.of(client()), "my-payload-output","result"));
|
||||
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("foo", "bar");
|
||||
metadata.put("list", "baz");
|
||||
|
||||
Alert alert = new Alert(
|
||||
"test-serialization",
|
||||
new CronSchedule("0/5 * * * * ? *"),
|
||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()),
|
||||
conditionRequest),
|
||||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), transformRequest),
|
||||
new Actions(actions), metadata, new Alert.Status(), new TimeValue(0)
|
||||
);
|
||||
|
||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||
|
||||
PutAlertResponse putAlertResponse = alertClient().preparePutAlert("test-payload").setAlertSource(jsonBuilder.bytes()).get();
|
||||
PutAlertResponse putAlertResponse = alertClient().preparePutAlert("test-payload")
|
||||
.source(alertSourceBuilder()
|
||||
.schedule(interval(5, Interval.Unit.SECONDS))
|
||||
.input(searchInput(inputRequest))
|
||||
.transform(searchTransform(transformRequest))
|
||||
.addAction(indexAction("my-payload-output", "result"))
|
||||
.metadata(metadata)
|
||||
.throttlePeriod(TimeValue.timeValueSeconds(0)))
|
||||
.get();
|
||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||
|
||||
assertAlertWithMinimumPerformedActionsCount("test-payload", 1, false);
|
|
@ -24,9 +24,7 @@ import java.util.Collections;
|
|||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
@ -41,7 +39,7 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
|
|||
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
|
||||
Map<String, Object> params = Collections.emptyMap();
|
||||
Script script = new Script("_script", type, "_lang", params);
|
||||
ScriptTransform transform = new ScriptTransform(script, service);
|
||||
ScriptTransform transform = new ScriptTransform(service, script);
|
||||
|
||||
DateTime now = new DateTime();
|
||||
ExecutionContext ctx = mock(ExecutionContext.class);
|
||||
|
|
Loading…
Reference in New Issue