[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.ActionRegistry;
|
||||||
import org.elasticsearch.alerts.actions.Actions;
|
import org.elasticsearch.alerts.actions.Actions;
|
||||||
import org.elasticsearch.alerts.scheduler.Scheduler;
|
|
||||||
import org.elasticsearch.alerts.condition.Condition;
|
import org.elasticsearch.alerts.condition.Condition;
|
||||||
import org.elasticsearch.alerts.condition.ConditionRegistry;
|
import org.elasticsearch.alerts.condition.ConditionRegistry;
|
||||||
|
import org.elasticsearch.alerts.condition.simple.AlwaysTrueCondition;
|
||||||
import org.elasticsearch.alerts.input.Input;
|
import org.elasticsearch.alerts.input.Input;
|
||||||
import org.elasticsearch.alerts.input.InputRegistry;
|
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.Schedule;
|
||||||
import org.elasticsearch.alerts.scheduler.schedule.ScheduleRegistry;
|
import org.elasticsearch.alerts.scheduler.schedule.ScheduleRegistry;
|
||||||
import org.elasticsearch.alerts.throttle.AlertThrottler;
|
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.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Streamable;
|
import org.elasticsearch.common.io.stream.Streamable;
|
||||||
import org.elasticsearch.common.joda.time.DateTime;
|
import org.elasticsearch.common.joda.time.DateTime;
|
||||||
|
import org.elasticsearch.common.joda.time.DateTimeZone;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
@ -57,7 +60,7 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Transform transform;
|
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.name = name;
|
||||||
this.schedule = schedule;
|
this.schedule = schedule;
|
||||||
this.input = input;
|
this.input = input;
|
||||||
|
@ -67,7 +70,6 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
this.throttlePeriod = throttlePeriod;
|
this.throttlePeriod = throttlePeriod;
|
||||||
this.metadata = metadata;
|
this.metadata = metadata;
|
||||||
this.transform = transform != null ? transform : Transform.NOOP;
|
this.transform = transform != null ? transform : Transform.NOOP;
|
||||||
|
|
||||||
throttler = new AlertThrottler(throttlePeriod);
|
throttler = new AlertThrottler(throttlePeriod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,6 +176,9 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
private final ActionRegistry actionRegistry;
|
private final ActionRegistry actionRegistry;
|
||||||
private final InputRegistry inputRegistry;
|
private final InputRegistry inputRegistry;
|
||||||
|
|
||||||
|
private final Input defaultInput;
|
||||||
|
private final Condition defaultCondition;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public Parser(Settings settings, ConditionRegistry conditionRegistry, ScheduleRegistry scheduleRegistry,
|
public Parser(Settings settings, ConditionRegistry conditionRegistry, ScheduleRegistry scheduleRegistry,
|
||||||
TransformRegistry transformRegistry, ActionRegistry actionRegistry,
|
TransformRegistry transformRegistry, ActionRegistry actionRegistry,
|
||||||
|
@ -185,6 +190,9 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
this.transformRegistry = transformRegistry;
|
this.transformRegistry = transformRegistry;
|
||||||
this.actionRegistry = actionRegistry;
|
this.actionRegistry = actionRegistry;
|
||||||
this.inputRegistry = inputRegistry;
|
this.inputRegistry = inputRegistry;
|
||||||
|
|
||||||
|
this.defaultInput = new NoneInput(logger);
|
||||||
|
this.defaultCondition = new AlwaysTrueCondition(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Alert parse(String name, boolean includeStatus, BytesReference source) {
|
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 {
|
public Alert parse(String name, boolean includeStatus, XContentParser parser) throws IOException {
|
||||||
Schedule schedule = null;
|
Schedule schedule = null;
|
||||||
Input input = null;
|
Input input = defaultInput;
|
||||||
Condition condition = null;
|
Condition condition = defaultCondition;
|
||||||
Actions actions = null;
|
Actions actions = null;
|
||||||
Transform transform = null;
|
Transform transform = null;
|
||||||
Map<String, Object> metatdata = null;
|
Map<String, Object> metatdata = null;
|
||||||
|
@ -244,30 +252,24 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
if (schedule == null) {
|
if (schedule == null) {
|
||||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert schedule");
|
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) {
|
if (actions == null) {
|
||||||
throw new AlertsSettingsException("could not parse alert [" + name + "]. missing alert actions");
|
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 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_CHECKED_FIELD = new ParseField("last_checked");
|
||||||
public static final ParseField LAST_MET_CONDITION_FIELD = new ParseField("last_met_condition");
|
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_THROTTLED_FIELD = new ParseField("last_throttled");
|
||||||
public static final ParseField LAST_EXECUTED_FIELD = new ParseField("last_executed");
|
public static final ParseField LAST_EXECUTED_FIELD = new ParseField("last_executed");
|
||||||
public static final ParseField ACK_FIELD = new ParseField("ack");
|
public static final ParseField ACK_FIELD = new ParseField("ack");
|
||||||
public static final ParseField STATE_FIELD = new ParseField("state");
|
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");
|
public static final ParseField REASON_FIELD = new ParseField("reason");
|
||||||
|
|
||||||
private transient long version;
|
private transient long version;
|
||||||
|
@ -335,6 +337,38 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
return ackStatus;
|
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
|
* Called whenever an alert is checked, ie. the condition of the alert is evaluated to see if
|
||||||
* the alert should be executed.
|
* the alert should be executed.
|
||||||
|
@ -534,7 +568,7 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
private final DateTime timestamp;
|
private final DateTime timestamp;
|
||||||
|
|
||||||
public AckStatus() {
|
public AckStatus() {
|
||||||
this(State.AWAITS_EXECUTION, new DateTime());
|
this(State.AWAITS_EXECUTION, new DateTime(DateTimeZone.UTC));
|
||||||
}
|
}
|
||||||
|
|
||||||
public AckStatus(State state, DateTime timestamp) {
|
public AckStatus(State state, DateTime timestamp) {
|
||||||
|
@ -550,6 +584,25 @@ public class Alert implements Scheduler.Job, ToXContent {
|
||||||
return timestamp;
|
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 {
|
public static class Throttle {
|
||||||
|
|
|
@ -43,6 +43,23 @@ public interface Payload extends ToXContent {
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
return builder.value(data);
|
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 {
|
static class ActionResponse extends Simple {
|
||||||
|
@ -50,7 +67,6 @@ public interface Payload extends ToXContent {
|
||||||
public ActionResponse(org.elasticsearch.action.ActionResponse response) {
|
public ActionResponse(org.elasticsearch.action.ActionResponse response) {
|
||||||
super(responseToData(response));
|
super(responseToData(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class XContent extends Simple {
|
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.
|
* 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
|
* @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;
|
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;
|
this.actions = actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return actions.size();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Action> iterator() {
|
public Iterator<Action> iterator() {
|
||||||
return actions.iterator();
|
return actions.iterator();
|
||||||
|
@ -38,4 +42,20 @@ public class Actions implements Iterable<Action>, ToXContent {
|
||||||
return builder;
|
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;
|
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.Action;
|
||||||
import org.elasticsearch.alerts.actions.ActionException;
|
import org.elasticsearch.alerts.actions.ActionException;
|
||||||
import org.elasticsearch.alerts.actions.ActionSettingsException;
|
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.Template;
|
||||||
import org.elasticsearch.alerts.support.template.XContentTemplate;
|
import org.elasticsearch.alerts.support.template.XContentTemplate;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
|
@ -25,6 +26,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
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());
|
logger.error("failed to connect to [{}] for alert [{}]", ioe, urlText, ctx.alert().name());
|
||||||
return new Result.Failure("failed to send http request. " + ioe.getMessage());
|
return new Result.Failure("failed to send http request. " + ioe.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject();
|
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);
|
builder.field(Parser.URL_FIELD.getPreferredName(), url);
|
||||||
if (body != null) {
|
if (body != null) {
|
||||||
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
builder.field(Parser.BODY_FIELD.getPreferredName(), body);
|
||||||
|
@ -96,7 +97,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
||||||
|
|
||||||
WebhookAction that = (WebhookAction) o;
|
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 (!method.equals(that.method)) return false;
|
||||||
if (!url.equals(that.url)) return false;
|
if (!url.equals(that.url)) return false;
|
||||||
|
|
||||||
|
@ -107,7 +108,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = method.hashCode();
|
int result = method.hashCode();
|
||||||
result = 31 * result + url.hashCode();
|
result = 31 * result + url.hashCode();
|
||||||
result = 31 * result + body.hashCode();
|
result = 31 * result + (body != null ? body.hashCode() : 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +206,7 @@ public class WebhookAction extends Action<WebhookAction.Result> {
|
||||||
currentFieldName = parser.currentName();
|
currentFieldName = parser.currentName();
|
||||||
} else if ((token.isValue() || token == XContentParser.Token.START_OBJECT) && currentFieldName != null ) {
|
} else if ((token.isValue() || token == XContentParser.Token.START_OBJECT) && currentFieldName != null ) {
|
||||||
if (METHOD_FIELD.match(currentFieldName)) {
|
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) {
|
if (method != HttpMethod.POST && method != HttpMethod.GET && method != HttpMethod.PUT) {
|
||||||
throw new ActionSettingsException("could not parse webhook action. unsupported http method [" + method.getName() + "]");
|
throw new ActionSettingsException("could not parse webhook action. unsupported http method [" + method.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 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.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -24,6 +25,10 @@ public class ConditionRegistry {
|
||||||
this.parsers = ImmutableMap.copyOf(parsers);
|
this.parsers = ImmutableMap.copyOf(parsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> types() {
|
||||||
|
return parsers.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the contents of parser to create the correct Condition
|
* 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.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.script.ExecutableScript;
|
import org.elasticsearch.script.ExecutableScript;
|
||||||
|
import org.elasticsearch.script.ScriptService;
|
||||||
|
|
||||||
import java.io.IOException;
|
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
|
* 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);
|
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> {
|
public static class Parser extends AbstractComponent implements Condition.Parser<Result, ScriptCondition> {
|
||||||
|
|
||||||
private final ScriptServiceProxy scriptService;
|
private final ScriptServiceProxy scriptService;
|
||||||
|
@ -131,6 +151,43 @@ public class ScriptCondition extends Condition<ScriptCondition.Result> {
|
||||||
.field(MET_FIELD.getPreferredName(), met())
|
.field(MET_FIELD.getPreferredName(), met())
|
||||||
.endObject();
|
.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.inject.Inject;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
|
@ -22,6 +23,7 @@ import java.io.IOException;
|
||||||
public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
||||||
|
|
||||||
public static final String TYPE = "always_false";
|
public static final String TYPE = "always_false";
|
||||||
|
|
||||||
public static final Result RESULT = new Result(TYPE, false) {
|
public static final Result RESULT = new Result(TYPE, false) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,6 +52,11 @@ public class AlwaysFalseCondition extends Condition<Condition.Result> {
|
||||||
return builder.startObject().endObject();
|
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> {
|
public static class Parser extends AbstractComponent implements Condition.Parser<Result, AlwaysFalseCondition> {
|
||||||
|
|
||||||
@Inject
|
@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 class AlwaysTrueCondition extends Condition<Condition.Result> {
|
||||||
|
|
||||||
public static final String TYPE = "always_true";
|
public static final String TYPE = "always_true";
|
||||||
|
|
||||||
public static final Result RESULT = new Result(TYPE, true) {
|
public static final Result RESULT = new Result(TYPE, true) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -49,6 +50,10 @@ public class AlwaysTrueCondition extends Condition<Condition.Result> {
|
||||||
return builder.startObject().endObject();
|
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> {
|
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.alerts.support.init.proxy.ClientProxy;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.component.AbstractComponent;
|
import org.elasticsearch.common.component.AbstractComponent;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.joda.time.DateTime;
|
import org.elasticsearch.common.joda.time.DateTime;
|
||||||
|
@ -74,8 +75,9 @@ public class HistoryStore extends AbstractComponent {
|
||||||
public void update(FiredAlert firedAlert) throws HistoryException {
|
public void update(FiredAlert firedAlert) throws HistoryException {
|
||||||
logger.debug("updating fired alert [{}]", firedAlert);
|
logger.debug("updating fired alert [{}]", firedAlert);
|
||||||
try {
|
try {
|
||||||
|
BytesReference bytes = XContentFactory.jsonBuilder().value(firedAlert).bytes();
|
||||||
IndexResponse response = client.prepareIndex(getAlertHistoryIndexNameForTime(firedAlert.scheduledTime()), ALERT_HISTORY_TYPE, firedAlert.id())
|
IndexResponse response = client.prepareIndex(getAlertHistoryIndexNameForTime(firedAlert.scheduledTime()), ALERT_HISTORY_TYPE, firedAlert.id())
|
||||||
.setSource(XContentFactory.jsonBuilder().value(firedAlert))
|
.setSource(bytes)
|
||||||
.setVersion(firedAlert.version())
|
.setVersion(firedAlert.version())
|
||||||
.get();
|
.get();
|
||||||
firedAlert.version(response.getVersion());
|
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;
|
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.Input;
|
||||||
import org.elasticsearch.alerts.input.InputException;
|
import org.elasticsearch.alerts.input.InputException;
|
||||||
import org.elasticsearch.alerts.support.AlertUtils;
|
import org.elasticsearch.alerts.support.AlertUtils;
|
||||||
|
import org.elasticsearch.alerts.support.SearchRequestEquivalence;
|
||||||
import org.elasticsearch.alerts.support.Variables;
|
import org.elasticsearch.alerts.support.Variables;
|
||||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
||||||
import org.elasticsearch.alerts.support.init.proxy.ScriptServiceProxy;
|
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 class SearchInput extends Input<SearchInput.Result> {
|
||||||
|
|
||||||
public static final String TYPE = "search";
|
public static final String TYPE = "search";
|
||||||
|
|
||||||
public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.COUNT;
|
public static final SearchType DEFAULT_SEARCH_TYPE = SearchType.COUNT;
|
||||||
|
|
||||||
private final SearchRequest searchRequest;
|
private final SearchRequest searchRequest;
|
||||||
|
@ -86,12 +88,25 @@ public class SearchInput extends Input<SearchInput.Result> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject();
|
return AlertUtils.writeSearchRequest(searchRequest, builder, params);
|
||||||
builder.field(Parser.REQUEST_FIELD.getPreferredName());
|
|
||||||
AlertUtils.writeSearchRequest(searchRequest, builder, params);
|
|
||||||
return builder.endObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
* 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
|
@Override
|
||||||
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
|
protected XContentBuilder toXContentBody(XContentBuilder builder, Params params) throws IOException {
|
||||||
if (request != null) {
|
builder.field(Parser.REQUEST_FIELD.getPreferredName());
|
||||||
builder.field(Parser.REQUEST_FIELD.getPreferredName());
|
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||||
AlertUtils.writeSearchRequest(request, builder, params);
|
|
||||||
}
|
|
||||||
return builder;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,27 +176,10 @@ public class SearchInput extends Input<SearchInput.Result> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SearchInput parse(XContentParser parser) throws IOException {
|
public SearchInput parse(XContentParser parser) throws IOException {
|
||||||
SearchRequest request = null;
|
SearchRequest request = AlertUtils.readSearchRequest(parser, DEFAULT_SEARCH_TYPE);
|
||||||
|
|
||||||
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 + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request == null) {
|
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);
|
return new SearchInput(logger, scriptService, client, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,4 +217,23 @@ public class SearchInput extends Input<SearchInput.Result> {
|
||||||
return new Result(TYPE, payload, request);
|
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.inject.Inject;
|
||||||
import org.elasticsearch.common.logging.ESLogger;
|
import org.elasticsearch.common.logging.ESLogger;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
|
||||||
import java.io.IOException;
|
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
|
* 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 class SimpleInput extends Input<SimpleInput.Result> {
|
||||||
|
|
||||||
public static final String TYPE = "simple";
|
public static final String TYPE = "simple";
|
||||||
|
|
||||||
private final Payload payload;
|
private final Payload payload;
|
||||||
|
|
||||||
public SimpleInput(ESLogger logger, Payload payload) {
|
public SimpleInput(ESLogger logger, Payload payload) {
|
||||||
|
@ -48,6 +53,23 @@ public class SimpleInput extends Input<SimpleInput.Result> {
|
||||||
return builder.endObject();
|
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 static class Result extends Input.Result {
|
||||||
|
|
||||||
public Result(String type, Payload payload) {
|
public Result(String type, Payload payload) {
|
||||||
|
@ -122,4 +144,29 @@ public class SimpleInput extends Input<SimpleInput.Result> {
|
||||||
return new Result(TYPE, payload);
|
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 {
|
protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception {
|
||||||
PutAlertRequest putAlertRequest = new PutAlertRequest();
|
PutAlertRequest putAlertRequest = new PutAlertRequest();
|
||||||
putAlertRequest.setAlertName(request.param("name"));
|
putAlertRequest.setAlertName(request.param("name"));
|
||||||
putAlertRequest.setAlertSource(request.content(), request.contentUnsafe());
|
putAlertRequest.source(request.content(), request.contentUnsafe());
|
||||||
alertsClient.putAlert(putAlertRequest, new RestBuilderListener<PutAlertResponse>(channel) {
|
alertsClient.putAlert(putAlertRequest, new RestBuilderListener<PutAlertResponse>(channel) {
|
||||||
@Override
|
@Override
|
||||||
public RestResponse buildResponse(PutAlertResponse response, XContentBuilder builder) throws Exception {
|
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.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -25,6 +26,10 @@ public class ScheduleRegistry {
|
||||||
this.parsers = ImmutableMap.copyOf(parsers);
|
this.parsers = ImmutableMap.copyOf(parsers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> types() {
|
||||||
|
return parsers.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
public Schedule parse(XContentParser parser) throws IOException {
|
public Schedule parse(XContentParser parser) throws IOException {
|
||||||
String type = null;
|
String type = null;
|
||||||
XContentParser.Token token;
|
XContentParser.Token token;
|
||||||
|
|
|
@ -155,13 +155,19 @@ public final class AlertUtils {
|
||||||
/**
|
/**
|
||||||
* Writes the searchRequest to the specified builder.
|
* 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) {
|
if (searchRequest == null) {
|
||||||
builder.nullValue();
|
builder.nullValue();
|
||||||
return;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.startObject();
|
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())) {
|
if (Strings.hasLength(searchRequest.source())) {
|
||||||
XContentHelper.writeRawField("body", searchRequest.source(), builder, params);
|
XContentHelper.writeRawField("body", searchRequest.source(), builder, params);
|
||||||
}
|
}
|
||||||
|
@ -171,11 +177,6 @@ public final class AlertUtils {
|
||||||
if (searchRequest.templateType() != null) {
|
if (searchRequest.templateType() != null) {
|
||||||
builder.field("template_type", searchRequest.templateType().name().toLowerCase(Locale.ROOT));
|
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) {
|
if (searchRequest.indicesOptions() != DEFAULT_INDICES_OPTIONS) {
|
||||||
IndicesOptions options = searchRequest.indicesOptions();
|
IndicesOptions options = searchRequest.indicesOptions();
|
||||||
builder.startObject("indices_options");
|
builder.startObject("indices_options");
|
||||||
|
@ -194,10 +195,7 @@ public final class AlertUtils {
|
||||||
builder.field("allow_no_indices", options.allowNoIndices());
|
builder.field("allow_no_indices", options.allowNoIndices());
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
}
|
}
|
||||||
if (searchRequest.searchType() != null) {
|
return builder.endObject();
|
||||||
builder.field("search_type", searchRequest.searchType().toString().toLowerCase(Locale.ENGLISH));
|
|
||||||
}
|
|
||||||
builder.endObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ public class Script implements ToXContent {
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
return builder.startObject()
|
return builder.startObject()
|
||||||
.field(SCRIPT_FIELD.getPreferredName(), script)
|
.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(LANG_FIELD.getPreferredName(), lang)
|
||||||
.field(PARAMS_FIELD.getPreferredName(), this.params)
|
.field(PARAMS_FIELD.getPreferredName(), this.params)
|
||||||
.endObject();
|
.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.XContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -18,6 +19,7 @@ import java.util.Map;
|
||||||
public class XContentTemplate implements Template {
|
public class XContentTemplate implements Template {
|
||||||
|
|
||||||
public static XContentTemplate YAML = new XContentTemplate(YamlXContent.yamlXContent);
|
public static XContentTemplate YAML = new XContentTemplate(YamlXContent.yamlXContent);
|
||||||
|
public static XContentTemplate JSON = new XContentTemplate(JsonXContent.jsonXContent);
|
||||||
|
|
||||||
private final XContent xContent;
|
private final XContent xContent;
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,11 @@ public class ChainTransform extends Transform {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(Injector injector) {
|
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
|
@Override
|
||||||
|
@ -106,8 +110,36 @@ public class ChainTransform extends Transform {
|
||||||
}
|
}
|
||||||
return new ChainTransform(builder.build());
|
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";
|
public static final String TYPE = "script";
|
||||||
|
|
||||||
private final Script script;
|
|
||||||
private final ScriptServiceProxy scriptService;
|
private final ScriptServiceProxy scriptService;
|
||||||
|
private final Script script;
|
||||||
|
|
||||||
public ScriptTransform(Script script, ScriptServiceProxy scriptService) {
|
public ScriptTransform(ScriptServiceProxy scriptService, Script script) {
|
||||||
this.script = script;
|
|
||||||
this.scriptService = scriptService;
|
this.scriptService = scriptService;
|
||||||
|
this.script = script;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -83,7 +83,30 @@ public class ScriptTransform extends Transform {
|
||||||
} catch (Script.ParseException pe) {
|
} catch (Script.ParseException pe) {
|
||||||
throw new AlertsSettingsException("could not parse [script] transform", 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 ESLogger logger;
|
||||||
protected final ScriptServiceProxy scriptService;
|
protected final ScriptServiceProxy scriptService;
|
||||||
protected final ClientProxy client;
|
protected final ClientProxy client;
|
||||||
|
|
||||||
protected final SearchRequest request;
|
protected final SearchRequest request;
|
||||||
|
|
||||||
public SearchTransform(ESLogger logger, ScriptServiceProxy scriptService, ClientProxy client, SearchRequest request) {
|
public SearchTransform(ESLogger logger, ScriptServiceProxy scriptService, ClientProxy client, SearchRequest request) {
|
||||||
|
@ -71,8 +72,7 @@ public class SearchTransform extends Transform {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
AlertUtils.writeSearchRequest(request, builder, params);
|
return AlertUtils.writeSearchRequest(request, builder, params);
|
||||||
return builder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public SearchRequest createRequest(SearchRequest requestPrototype, ExecutionContext ctx, Payload payload) throws IOException {
|
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();
|
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) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token == XContentParser.Token.FIELD_NAME) {
|
||||||
type = parser.currentName();
|
type = parser.currentName();
|
||||||
} else if (token == XContentParser.Token.START_OBJECT && type != null) {
|
} else if (type != null) {
|
||||||
Transform.Parser transformParser = parsers.get(type);
|
Transform.Parser transformParser = parsers.get(type);
|
||||||
if (transformParser == null) {
|
if (transformParser == null) {
|
||||||
throw new AlertsSettingsException("unknown transform type [" + type + "]");
|
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.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ValidateActions;
|
import org.elasticsearch.action.ValidateActions;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequest;
|
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.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -59,7 +62,14 @@ public class PutAlertRequest extends MasterNodeOperationRequest<PutAlertRequest>
|
||||||
/**
|
/**
|
||||||
* Set the source of the alert
|
* 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.alertSource = alertSource;
|
||||||
this.alertSourceUnsafe = false;
|
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
|
* 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.alertSource = alertSource;
|
||||||
this.alertSourceUnsafe = alertSourceUnsafe;
|
this.alertSourceUnsafe = alertSourceUnsafe;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ package org.elasticsearch.alerts.transport.actions.put;
|
||||||
|
|
||||||
import org.elasticsearch.action.ActionListener;
|
import org.elasticsearch.action.ActionListener;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.alerts.client.AlertSourceBuilder;
|
||||||
import org.elasticsearch.alerts.client.AlertsClient;
|
import org.elasticsearch.alerts.client.AlertsClient;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
@ -28,19 +29,26 @@ public class PutAlertRequestBuilder extends MasterNodeOperationRequestBuilder<Pu
|
||||||
/**
|
/**
|
||||||
* @param alertName The alert name to be created
|
* @param alertName The alert name to be created
|
||||||
*/
|
*/
|
||||||
public PutAlertRequestBuilder setAlertName(String alertName){
|
public PutAlertRequestBuilder alertName(String alertName){
|
||||||
request.setAlertName(alertName);
|
request.setAlertName(alertName);
|
||||||
return this;
|
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) {
|
public PutAlertRequestBuilder source(BytesReference source) {
|
||||||
request.setAlertSource(alertSource);
|
request.source(source);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param source the source of the alert to be created
|
||||||
|
*/
|
||||||
|
public PutAlertRequestBuilder source(AlertSourceBuilder source) {
|
||||||
|
request.source(source);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doExecute(ActionListener<PutAlertResponse> listener) {
|
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
|
@Test
|
||||||
public void testExecute() throws Exception {
|
public void testExecute() throws Exception {
|
||||||
|
@ -34,6 +35,7 @@ public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||||
xp.nextToken();
|
xp.nextToken();
|
||||||
|
|
||||||
Condition alwaysTrue = p.parse(xp);
|
Condition alwaysTrue = p.parse(xp);
|
||||||
assertTrue(alwaysTrue.execute(null).met());
|
assertTrue(alwaysTrue.execute(null).met());
|
||||||
}
|
}
|
||||||
|
@ -47,6 +49,7 @@ public class TestAlwaysTrueCondition extends ElasticsearchTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||||
xp.nextToken();
|
xp.nextToken();
|
||||||
|
|
||||||
p.parse(xp);
|
p.parse(xp);
|
||||||
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
||||||
+ AlwaysTrueCondition.TYPE + "] condition should not parse with a body");
|
+ 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, ["
|
fail("expected a condition exception trying to parse an invalid condition result XContent, ["
|
||||||
+ AlwaysTrueCondition.TYPE + "] condition result should not parse with a [met] field");
|
+ 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
|
@Test
|
||||||
public void testExecute() throws Exception {
|
public void testExecute() throws Exception {
|
||||||
|
@ -35,7 +34,6 @@ public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||||
xp.nextToken();
|
xp.nextToken();
|
||||||
|
|
||||||
Condition alwaysTrue = p.parse(xp);
|
Condition alwaysTrue = p.parse(xp);
|
||||||
assertTrue(alwaysTrue.execute(null).met());
|
assertTrue(alwaysTrue.execute(null).met());
|
||||||
}
|
}
|
||||||
|
@ -49,7 +47,6 @@ public class TestAlwaysFalseCondition extends ElasticsearchTestCase {
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
XContentParser xp = XContentFactory.xContent(builder.bytes()).createParser(builder.bytes());
|
||||||
xp.nextToken();
|
xp.nextToken();
|
||||||
|
|
||||||
p.parse(xp);
|
p.parse(xp);
|
||||||
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
fail("expected a condition exception trying to parse an invalid condition XContent, ["
|
||||||
+ AlwaysTrueCondition.TYPE + "] condition should not parse with a body");
|
+ 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, ["
|
fail("expected a condition exception trying to parse an invalid condition result XContent, ["
|
||||||
+ AlwaysTrueCondition.TYPE + "] condition result should not parse with a [met] field");
|
+ 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.condition.simple.AlwaysTrueCondition;
|
||||||
import org.elasticsearch.alerts.input.Input;
|
import org.elasticsearch.alerts.input.Input;
|
||||||
import org.elasticsearch.alerts.input.simple.SimpleInput;
|
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.alerts.throttle.Throttler;
|
||||||
import org.elasticsearch.common.joda.time.DateTime;
|
import org.elasticsearch.common.joda.time.DateTime;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
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
|
@Test
|
||||||
public void testParser() throws Exception {
|
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());
|
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
||||||
firedAlert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
firedAlert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
||||||
|
@ -43,7 +45,7 @@ public class FiredAlertTest extends AbstractAlertingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParser_WithSealedFiredAlert() throws Exception {
|
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());
|
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||||
ExecutionContext ctx = new ExecutionContext(firedAlert.id(), 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"));
|
ctx.onActionResult(new EmailAction.Result.Failure("failed to send because blah"));
|
||||||
|
@ -65,7 +67,7 @@ public class FiredAlertTest extends AbstractAlertingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParser_WithSealedFiredAlert_WithScriptSearchCondition() throws Exception {
|
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());
|
FiredAlert firedAlert = new FiredAlert(alert, new DateTime(), new DateTime());
|
||||||
ExecutionContext ctx = new ExecutionContext(firedAlert.id(), 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"));
|
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
|
@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(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(100000000000L, DateTimeZone.UTC)), equalTo(".alert_history_1973-03-03"));
|
||||||
assertThat(HistoryStore.getAlertHistoryIndexNameForTime(new DateTime(1416582852000L, DateTimeZone.UTC)), equalTo(".alert_history_2014-11-21"));
|
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.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.common.xcontent.json.JsonXContent;
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
import org.elasticsearch.script.ScriptService;
|
import org.elasticsearch.script.ScriptService;
|
||||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
@ -70,27 +72,21 @@ public class SearchInputTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParser_Valid() throws Exception {
|
public void testParser_Valid() throws Exception {
|
||||||
SearchSourceBuilder searchSourceBuilder = searchSource().query(
|
SearchRequest request = client().prepareSearch()
|
||||||
filteredQuery(matchQuery("event_type", "a"), rangeFilter("_timestamp").from("{{" + Variables.SCHEDULED_FIRE_TIME + "}}||-30s").to("{{" + Variables.SCHEDULED_FIRE_TIME + "}}"))
|
|
||||||
);
|
|
||||||
SearchRequest request = client()
|
|
||||||
.prepareSearch()
|
|
||||||
.setSearchType(SearchInput.DEFAULT_SEARCH_TYPE)
|
.setSearchType(SearchInput.DEFAULT_SEARCH_TYPE)
|
||||||
.request()
|
.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();
|
Input.Parser searchInputParser = new SearchInput.Parser(ImmutableSettings.EMPTY,
|
||||||
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(),
|
|
||||||
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class)),
|
ScriptServiceProxy.of(internalCluster().getInstance(ScriptService.class)),
|
||||||
ClientProxy.of(client()));
|
ClientProxy.of(client()));
|
||||||
|
|
||||||
Input searchInput = searchInputParser.parse(XContentFactory.xContent(jsonBuilder.bytes()).createParser(jsonBuilder.bytes()));
|
Input searchInput = searchInputParser.parse(parser);
|
||||||
assertEquals(SearchInput.TYPE, searchInput.type());
|
assertEquals(SearchInput.TYPE, searchInput.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
||||||
.field(DailySchedule.TYPE, daily)
|
.field(DailySchedule.TYPE, daily)
|
||||||
.endObject();
|
.endObject();
|
||||||
BytesReference bytes = builder.bytes();
|
BytesReference bytes = builder.bytes();
|
||||||
System.out.println(bytes.toUtf8());
|
|
||||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
Schedule schedule = registry.parse(parser);
|
Schedule schedule = registry.parse(parser);
|
||||||
|
@ -114,7 +113,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
||||||
.field(WeeklySchedule.TYPE, weekly)
|
.field(WeeklySchedule.TYPE, weekly)
|
||||||
.endObject();
|
.endObject();
|
||||||
BytesReference bytes = builder.bytes();
|
BytesReference bytes = builder.bytes();
|
||||||
System.out.println(bytes.toUtf8());
|
|
||||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
Schedule schedule = registry.parse(parser);
|
Schedule schedule = registry.parse(parser);
|
||||||
|
@ -131,7 +129,6 @@ public class ScheduleRegistryTests extends ScheduleTestCase {
|
||||||
.field(MonthlySchedule.TYPE, monthly)
|
.field(MonthlySchedule.TYPE, monthly)
|
||||||
.endObject();
|
.endObject();
|
||||||
BytesReference bytes = builder.bytes();
|
BytesReference bytes = builder.bytes();
|
||||||
System.out.println(bytes.toUtf8());
|
|
||||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
Schedule schedule = registry.parse(parser);
|
Schedule schedule = registry.parse(parser);
|
||||||
|
|
|
@ -116,7 +116,6 @@ public class ScriptTemplateTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
XContentBuilder builder = jsonBuilder().value(template);
|
XContentBuilder builder = jsonBuilder().value(template);
|
||||||
BytesReference bytes = builder.bytes();
|
BytesReference bytes = builder.bytes();
|
||||||
System.out.println(bytes.toUtf8());
|
|
||||||
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
XContentParser parser = JsonXContent.jsonXContent.createParser(bytes);
|
||||||
parser.nextToken();
|
parser.nextToken();
|
||||||
ScriptTemplate parsed = templateParser.parse(parser);
|
ScriptTemplate parsed = templateParser.parse(parser);
|
||||||
|
|
|
@ -3,33 +3,24 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.alerts.actions.Action;
|
import org.elasticsearch.alerts.AlertsPlugin;
|
||||||
import org.elasticsearch.alerts.actions.Actions;
|
import org.elasticsearch.alerts.AlertsService;
|
||||||
import org.elasticsearch.alerts.actions.email.EmailAction;
|
|
||||||
import org.elasticsearch.alerts.actions.email.service.Authentication;
|
import org.elasticsearch.alerts.actions.email.service.Authentication;
|
||||||
import org.elasticsearch.alerts.actions.email.service.Email;
|
import org.elasticsearch.alerts.actions.email.service.Email;
|
||||||
import org.elasticsearch.alerts.actions.email.service.EmailService;
|
import org.elasticsearch.alerts.actions.email.service.EmailService;
|
||||||
import org.elasticsearch.alerts.actions.email.service.Profile;
|
import org.elasticsearch.alerts.actions.email.service.Profile;
|
||||||
import org.elasticsearch.alerts.actions.webhook.HttpClient;
|
import org.elasticsearch.alerts.actions.webhook.HttpClient;
|
||||||
import org.elasticsearch.alerts.actions.webhook.WebhookAction;
|
|
||||||
import org.elasticsearch.alerts.client.AlertsClient;
|
import org.elasticsearch.alerts.client.AlertsClient;
|
||||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
|
||||||
import org.elasticsearch.alerts.history.FiredAlert;
|
import org.elasticsearch.alerts.history.FiredAlert;
|
||||||
import org.elasticsearch.alerts.history.HistoryStore;
|
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.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.init.proxy.ScriptServiceProxy;
|
||||||
import org.elasticsearch.alerts.support.template.ScriptTemplate;
|
|
||||||
import org.elasticsearch.alerts.support.template.Template;
|
import org.elasticsearch.alerts.support.template.Template;
|
||||||
import org.elasticsearch.alerts.transform.SearchTransform;
|
|
||||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
|
@ -37,36 +28,34 @@ import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
|
||||||
import org.elasticsearch.cluster.routing.IndexRoutingTable;
|
import org.elasticsearch.cluster.routing.IndexRoutingTable;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.hppc.cursors.ObjectObjectCursor;
|
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.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
import org.elasticsearch.common.xcontent.support.XContentMapValues;
|
||||||
import org.elasticsearch.script.ScriptService;
|
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
import org.elasticsearch.test.InternalTestCluster;
|
import org.elasticsearch.test.InternalTestCluster;
|
||||||
import org.elasticsearch.test.TestCluster;
|
import org.elasticsearch.test.TestCluster;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
import javax.mail.internet.AddressException;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
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.Matchers.*;
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
import static org.hamcrest.core.IsNot.not;
|
import static org.hamcrest.core.IsNot.not;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
@ClusterScope(scope = SUITE, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||||
public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest {
|
public abstract class AbstractAlertsIntegrationTests extends ElasticsearchIntegrationTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Settings nodeSettings(int nodeOrdinal) {
|
protected Settings nodeSettings(int nodeOrdinal) {
|
||||||
|
@ -129,10 +118,8 @@ public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest
|
||||||
|
|
||||||
builder.startObject("input");
|
builder.startObject("input");
|
||||||
{
|
{
|
||||||
builder.startObject("search");
|
builder.field("search");
|
||||||
builder.field("request");
|
|
||||||
AlertUtils.writeSearchRequest(conditionRequest, builder, ToXContent.EMPTY_PARAMS);
|
AlertUtils.writeSearchRequest(conditionRequest, builder, ToXContent.EMPTY_PARAMS);
|
||||||
builder.endObject();
|
|
||||||
}
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
||||||
|
@ -163,56 +150,6 @@ public abstract class AbstractAlertingTests extends ElasticsearchIntegrationTest
|
||||||
return builder.bytes();
|
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() {
|
protected AlertsClient alertClient() {
|
||||||
return internalTestCluster().getInstance(AlertsClient.class);
|
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;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.action.search.SearchResponse;
|
||||||
import org.elasticsearch.alerts.history.HistoryStore;
|
import org.elasticsearch.alerts.history.HistoryStore;
|
||||||
|
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||||
|
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -15,14 +16,19 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.matchAllQuery;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class AlertMetadataTest extends AbstractAlertingTests {
|
public class AlertMetadataTests extends AbstractAlertsIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAlertMetadata() throws Exception {
|
public void testAlertMetadata() throws Exception {
|
||||||
|
@ -35,9 +41,12 @@ public class AlertMetadataTest extends AbstractAlertingTests {
|
||||||
metaList.add("test");
|
metaList.add("test");
|
||||||
|
|
||||||
metadata.put("baz", metaList);
|
metadata.put("baz", metaList);
|
||||||
SearchRequest conditionRequest = createConditionSearchRequest("my-index").source(searchSource().query(matchAllQuery()));
|
|
||||||
alertClient().preparePutAlert("1")
|
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();
|
.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)
|
// 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);
|
assertAlertWithNoActionNeeded("1", 1);
|
|
@ -3,42 +3,47 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.action.search.SearchRequest;
|
||||||
import org.elasticsearch.alerts.*;
|
import org.elasticsearch.alerts.*;
|
||||||
import org.elasticsearch.alerts.client.AlertsClient;
|
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.AlertsStatsRequest;
|
||||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
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;
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
@ClusterScope(scope = TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false)
|
||||||
public class AlertStatsTests extends AbstractAlertingTests {
|
public class AlertStatsTests extends AbstractAlertsIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartedStats() throws Exception {
|
public void testStartedStats() throws Exception {
|
||||||
AlertsStatsRequest alertsStatsRequest = alertClient().prepareAlertsStats().request();
|
AlertsStatsRequest alertsStatsRequest = alertClient().prepareAlertsStats().request();
|
||||||
AlertsStatsResponse response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
AlertsStatsResponse response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
||||||
|
|
||||||
assertTrue(response.isAlertActionManagerStarted());
|
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
assertThat(response.getAlertManagerStarted(), is(AlertsService.State.STARTED));
|
||||||
assertThat(response.getAlertActionManagerQueueSize(), equalTo(0L));
|
assertThat(response.getAlertActionManagerQueueSize(), is(0L));
|
||||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(0L));
|
assertThat(response.getNumberOfRegisteredAlerts(), is(0L));
|
||||||
assertThat(response.getAlertActionManagerLargestQueueSize(), equalTo(0L));
|
assertThat(response.getAlertActionManagerLargestQueueSize(), is(0L));
|
||||||
assertThat(response.getVersion(), equalTo(AlertsVersion.CURRENT));
|
assertThat(response.getVersion(), is(AlertsVersion.CURRENT));
|
||||||
assertThat(response.getBuild(), equalTo(AlertsBuild.CURRENT));
|
assertThat(response.getBuild(), is(AlertsBuild.CURRENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -48,13 +53,13 @@ public class AlertStatsTests extends AbstractAlertingTests {
|
||||||
AlertsStatsRequest alertsStatsRequest = alertsClient.prepareAlertsStats().request();
|
AlertsStatsRequest alertsStatsRequest = alertsClient.prepareAlertsStats().request();
|
||||||
AlertsStatsResponse response = alertsClient.alertsStats(alertsStatsRequest).actionGet();
|
AlertsStatsResponse response = alertsClient.alertsStats(alertsStatsRequest).actionGet();
|
||||||
|
|
||||||
assertTrue(response.isAlertActionManagerStarted());
|
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
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");
|
BytesReference alertSource = createAlertSource("* * * * * ? *", searchRequest, "hits.total == 1");
|
||||||
alertClient().preparePutAlert("testAlert")
|
alertClient().preparePutAlert("testAlert")
|
||||||
.setAlertSource(alertSource)
|
.source(alertSource)
|
||||||
.get();
|
.get();
|
||||||
|
|
||||||
response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
response = alertClient().alertsStats(alertsStatsRequest).actionGet();
|
||||||
|
@ -63,9 +68,9 @@ public class AlertStatsTests extends AbstractAlertingTests {
|
||||||
TimeValue waitTime = new TimeValue(30, TimeUnit.SECONDS);
|
TimeValue waitTime = new TimeValue(30, TimeUnit.SECONDS);
|
||||||
Thread.sleep(waitTime.getMillis());
|
Thread.sleep(waitTime.getMillis());
|
||||||
|
|
||||||
assertTrue(response.isAlertActionManagerStarted());
|
assertThat(response.isAlertActionManagerStarted(), is(true));
|
||||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
assertThat(response.getAlertManagerStarted(), is(AlertsService.State.STARTED));
|
||||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(1L));
|
assertThat(response.getNumberOfRegisteredAlerts(), is(1L));
|
||||||
//assertThat(response.getAlertActionManagerLargestQueueSize(), greaterThan(0L));
|
//assertThat(response.getAlertActionManagerLargestQueueSize(), greaterThan(0L));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,41 +3,37 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.count.CountResponse;
|
||||||
import org.elasticsearch.action.delete.DeleteResponse;
|
import org.elasticsearch.action.delete.DeleteResponse;
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.action.search.SearchType;
|
import org.elasticsearch.action.search.SearchType;
|
||||||
import org.elasticsearch.alerts.actions.Action;
|
import org.elasticsearch.alerts.Alert;
|
||||||
import org.elasticsearch.alerts.actions.Actions;
|
import org.elasticsearch.alerts.actions.ActionBuilders;
|
||||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
|
||||||
import org.elasticsearch.alerts.client.AlertsClient;
|
import org.elasticsearch.alerts.client.AlertsClient;
|
||||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
|
||||||
import org.elasticsearch.alerts.history.FiredAlert;
|
import org.elasticsearch.alerts.history.FiredAlert;
|
||||||
import org.elasticsearch.alerts.history.HistoryStore;
|
import org.elasticsearch.alerts.history.HistoryStore;
|
||||||
import org.elasticsearch.alerts.input.search.SearchInput;
|
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||||
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.ack.AckAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.ack.AckAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
import org.elasticsearch.index.query.QueryBuilders;
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
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.index.query.QueryBuilders.matchAllQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
|
@ -45,7 +41,7 @@ import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class AlertThrottleTests extends AbstractAlertingTests {
|
public class AlertThrottleTests extends AbstractAlertsIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAckThrottle() throws Exception{
|
public void testAckThrottle() throws Exception{
|
||||||
|
@ -57,32 +53,22 @@ public class AlertThrottleTests extends AbstractAlertingTests {
|
||||||
assertTrue(dummyEventIndexResponse.isCreated());
|
assertTrue(dummyEventIndexResponse.isCreated());
|
||||||
refresh();
|
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());
|
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||||
|
|
||||||
Thread.sleep(20000);
|
Thread.sleep(20000);
|
||||||
AckAlertResponse ackResponse = alertsClient.prepareAckAlert("throttled-alert").get();
|
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();
|
refresh();
|
||||||
SearchResponse searchResponse = client()
|
SearchResponse searchResponse = client()
|
||||||
|
@ -138,24 +124,16 @@ public class AlertThrottleTests extends AbstractAlertingTests {
|
||||||
assertTrue(dummyEventIndexResponse.isCreated());
|
assertTrue(dummyEventIndexResponse.isCreated());
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
SearchRequest request = createConditionSearchRequest("test-index").source(searchSource().query(matchAllQuery()));
|
PutAlertResponse putAlertResponse = alertsClient.preparePutAlert()
|
||||||
|
.alertName("throttled-alert")
|
||||||
List<Action> actions = new ArrayList<>();
|
.source(alertSourceBuilder()
|
||||||
|
.schedule(cron("0/5 * * * * ? *"))
|
||||||
actions.add(new IndexAction(logger, ClientProxy.of(client()), "action-index", "action-type"));
|
.input(searchInput(matchAllRequest().indices("test-index")))
|
||||||
|
.condition(scriptCondition("hits.total > 0"))
|
||||||
Alert alert = new Alert(
|
.transform(searchTransform(matchAllRequest().indices("test-index")))
|
||||||
"test-time-throttle",
|
.addAction(ActionBuilders.indexAction("action-index", "action-type"))
|
||||||
new CronSchedule("0/5 * * * * ? *"),
|
.throttlePeriod(TimeValue.timeValueSeconds(10)))
|
||||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()), request),
|
.get();
|
||||||
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();
|
|
||||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||||
|
|
||||||
forceFullSleepTime(new TimeValue(5, TimeUnit.SECONDS));
|
forceFullSleepTime(new TimeValue(5, TimeUnit.SECONDS));
|
|
@ -3,18 +3,23 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchType;
|
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.client.AlertsClient;
|
||||||
|
import org.elasticsearch.alerts.scheduler.schedule.IntervalSchedule;
|
||||||
import org.elasticsearch.alerts.support.AlertUtils;
|
import org.elasticsearch.alerts.support.AlertUtils;
|
||||||
import org.elasticsearch.alerts.support.Variables;
|
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.DeleteAlertRequest;
|
||||||
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.get.GetAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
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.ToXContent;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.index.query.FilterBuilders;
|
import org.elasticsearch.index.query.FilterBuilders;
|
||||||
|
@ -28,6 +33,12 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Locale;
|
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.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.elasticsearch.index.query.FilterBuilders.rangeFilter;
|
import static org.elasticsearch.index.query.FilterBuilders.rangeFilter;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
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
|
@Test
|
||||||
public void testIndexAlert() throws Exception {
|
public void testIndexAlert() throws Exception {
|
||||||
|
@ -47,10 +58,12 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
createIndex("my-index");
|
createIndex("my-index");
|
||||||
// Have a sample document in the index, the alert is going to evaluate
|
// Have a sample document in the index, the alert is going to evaluate
|
||||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
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");
|
|
||||||
alertsClient.preparePutAlert("my-first-alert")
|
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();
|
.get();
|
||||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
||||||
|
|
||||||
|
@ -62,10 +75,12 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
@Test
|
@Test
|
||||||
public void testIndexAlert_registerAlertBeforeTargetIndex() throws Exception {
|
public void testIndexAlert_registerAlertBeforeTargetIndex() throws Exception {
|
||||||
AlertsClient alertsClient = alertClient();
|
AlertsClient alertsClient = alertClient();
|
||||||
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");
|
|
||||||
alertsClient.preparePutAlert("my-first-alert")
|
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();
|
.get();
|
||||||
|
|
||||||
// The alert's condition won't meet because there is no data that matches with the query
|
// 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");
|
createIndex("my-index");
|
||||||
// Have a sample document in the index, the alert is going to evaluate
|
// Have a sample document in the index, the alert is going to evaluate
|
||||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
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()));
|
||||||
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
|
||||||
PutAlertResponse indexResponse = alertsClient.preparePutAlert("my-first-alert")
|
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();
|
.get();
|
||||||
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
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("schedule").field("cron", "0/5 * * * * ? *").endObject();
|
||||||
|
|
||||||
alertSource.startObject("condition").startObject("script").field("script", "return true").field("request");
|
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();
|
||||||
|
|
||||||
alertSource.endObject();
|
alertSource.endObject();
|
||||||
try {
|
try {
|
||||||
alertsClient.preparePutAlert("my-first-alert")
|
alertsClient.preparePutAlert("my-first-alert")
|
||||||
.setAlertSource(alertSource.bytes())
|
.source(alertSource.bytes())
|
||||||
.get();
|
.get();
|
||||||
fail();
|
fail();
|
||||||
} catch (AlertsException e) {
|
} catch (AlertsException e) {
|
||||||
|
@ -145,12 +162,14 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
createIndex("my-index");
|
createIndex("my-index");
|
||||||
// Have a sample document in the index, the alert is going to evaluate
|
// Have a sample document in the index, the alert is going to evaluate
|
||||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
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);
|
searchRequest.searchType(SearchType.QUERY_THEN_FETCH);
|
||||||
// By accessing the actual hit we know that the fetch phase has been performed
|
// 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")
|
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();
|
.get();
|
||||||
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
assertThat(indexResponse.indexResponse().isCreated(), is(true));
|
||||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
||||||
|
@ -158,19 +177,27 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testModifyAlerts() throws Exception {
|
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")
|
alertClient().preparePutAlert("1")
|
||||||
.setAlertSource(createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1"))
|
.source(source.condition(scriptCondition("hits.total == 1")))
|
||||||
.get();
|
.get();
|
||||||
assertAlertWithMinimumPerformedActionsCount("1", 0, false);
|
assertAlertWithMinimumPerformedActionsCount("1", 0, false);
|
||||||
|
|
||||||
alertClient().preparePutAlert("1")
|
alertClient().preparePutAlert("1")
|
||||||
.setAlertSource(createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 0"))
|
.source(source.condition(scriptCondition("hits.total == 0")))
|
||||||
.get();
|
.get();
|
||||||
assertAlertWithMinimumPerformedActionsCount("1", 1, false);
|
assertAlertWithMinimumPerformedActionsCount("1", 1, false);
|
||||||
|
|
||||||
alertClient().preparePutAlert("1")
|
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();
|
.get();
|
||||||
|
|
||||||
Thread.sleep(5000);
|
Thread.sleep(5000);
|
||||||
|
@ -181,12 +208,13 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAggregations() throws Exception {
|
public void testAggregations() throws Exception {
|
||||||
class R implements Runnable {
|
|
||||||
|
class Indexer extends Thread {
|
||||||
|
|
||||||
private final long sleepTime;
|
private final long sleepTime;
|
||||||
private final long totalTime;
|
private final long totalTime;
|
||||||
|
|
||||||
R(long sleepTime, long totalTime) {
|
Indexer(long sleepTime, long totalTime) {
|
||||||
this.sleepTime = sleepTime;
|
this.sleepTime = sleepTime;
|
||||||
this.totalTime = totalTime;
|
this.totalTime = totalTime;
|
||||||
}
|
}
|
||||||
|
@ -207,24 +235,30 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
assertAcked(prepareCreate("my-index").addMapping("my-type", "_timestamp", "enabled=true"));
|
assertAcked(prepareCreate("my-index").addMapping("my-type", "_timestamp", "enabled=true"));
|
||||||
SearchRequest searchRequest = createConditionSearchRequest("my-index").source(
|
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index").source(
|
||||||
searchSource()
|
searchSource()
|
||||||
.query(QueryBuilders.constantScoreQuery(FilterBuilders.rangeFilter("_timestamp").from("{{scheduled_fire_time}}||-1m").to("{{scheduled_fire_time}}")))
|
.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))
|
.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");
|
||||||
BytesReference reference = createAlertSource("* 0/1 * * * ? *", searchRequest, "aggregations.rate.buckets[0]?.doc_count > 5");
|
alertClient().preparePutAlert("rate-alert")
|
||||||
alertClient().preparePutAlert("rate-alert").setAlertSource(reference).get();
|
.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));
|
Indexer indexer = new Indexer(500, 60000);
|
||||||
indexThread.start();
|
indexer.start();
|
||||||
indexThread.join();
|
indexer.join();
|
||||||
|
|
||||||
assertAlertWithExactPerformedActionsCount("rate-alert", 0);
|
assertAlertWithExactPerformedActionsCount("rate-alert", 0);
|
||||||
assertAlertWithNoActionNeeded("rate-alert", 1);
|
assertAlertWithNoActionNeeded("rate-alert", 1);
|
||||||
|
|
||||||
indexThread = new Thread(new R(100, 60000));
|
indexer = new Indexer(100, 60000);
|
||||||
indexThread.start();
|
indexer.start();
|
||||||
indexThread.join();
|
indexer.join();
|
||||||
|
|
||||||
assertAlertWithMinimumPerformedActionsCount("rate-alert", 1);
|
assertAlertWithMinimumPerformedActionsCount("rate-alert", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +269,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
@Test
|
@Test
|
||||||
public void testConditionSearchWithSource() throws Exception {
|
public void testConditionSearchWithSource() throws Exception {
|
||||||
testConditionSearch(
|
testConditionSearch(
|
||||||
createConditionSearchRequest("my-index").source(searchSourceBuilder)
|
AlertsTestUtils.newInputSearchRequest("my-index").source(searchSourceBuilder)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +280,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
.setId("my-template")
|
.setId("my-template")
|
||||||
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject())
|
.setSource(jsonBuilder().startObject().field("template").value(searchSourceBuilder).endObject())
|
||||||
.get();
|
.get();
|
||||||
SearchRequest searchRequest = createConditionSearchRequest("my-index");
|
SearchRequest searchRequest = AlertsTestUtils.newInputSearchRequest("my-index");
|
||||||
searchRequest.templateName("my-template");
|
searchRequest.templateName("my-template");
|
||||||
searchRequest.templateType(ScriptService.ScriptType.INDEXED);
|
searchRequest.templateType(ScriptService.ScriptType.INDEXED);
|
||||||
testConditionSearch(searchRequest);
|
testConditionSearch(searchRequest);
|
||||||
|
@ -259,7 +293,7 @@ public class BasicAlertingTest extends AbstractAlertingTests {
|
||||||
|
|
||||||
alertClient().prepareDeleteAlert(alertName).get();
|
alertClient().prepareDeleteAlert(alertName).get();
|
||||||
alertClient().preparePutAlert(alertName)
|
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();
|
.get();
|
||||||
|
|
||||||
long time1 = System.currentTimeMillis();
|
long time1 = System.currentTimeMillis();
|
|
@ -3,12 +3,15 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.WriteConsistencyLevel;
|
||||||
import org.elasticsearch.action.count.CountResponse;
|
import org.elasticsearch.action.count.CountResponse;
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
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.Action;
|
||||||
import org.elasticsearch.alerts.actions.Actions;
|
import org.elasticsearch.alerts.actions.Actions;
|
||||||
import org.elasticsearch.alerts.condition.script.ScriptCondition;
|
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.scheduler.schedule.CronSchedule;
|
||||||
import org.elasticsearch.alerts.support.Script;
|
import org.elasticsearch.alerts.support.Script;
|
||||||
import org.elasticsearch.alerts.support.init.proxy.ClientProxy;
|
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.transform.SearchTransform;
|
||||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
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
|
@Test
|
||||||
public void testBootStrapAlerts() throws Exception {
|
public void testBootStrapAlerts() throws Exception {
|
||||||
ensureAlertingStarted();
|
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");
|
BytesReference alertSource = createAlertSource("0 0/5 * * * ? *", searchRequest, "hits.total == 1");
|
||||||
client().prepareIndex(AlertsStore.ALERT_INDEX, AlertsStore.ALERT_TYPE, "my-first-alert")
|
client().prepareIndex(AlertsStore.ALERT_INDEX, AlertsStore.ALERT_TYPE, "my-first-alert")
|
||||||
.setSource(alertSource)
|
.setSource(alertSource)
|
||||||
|
@ -76,16 +81,17 @@ public class BootStrapTest extends AbstractAlertingTests {
|
||||||
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
assertThat(response.getAlertManagerStarted(), equalTo(AlertsService.State.STARTED));
|
||||||
assertThat(response.getNumberOfRegisteredAlerts(), equalTo(0L));
|
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(
|
Alert alert = new Alert(
|
||||||
"test-serialization",
|
"test-serialization",
|
||||||
new CronSchedule("0/5 * * * * ? 2035"), //Set this into the future so we don't get any extra runs
|
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 SearchInput(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||||
new Actions(new ArrayList<Action>()), 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);
|
XContentBuilder builder = jsonBuilder().value(alert);
|
||||||
IndexResponse indexResponse = client().prepareIndex(AlertsStore.ALERT_INDEX, AlertsStore.ALERT_TYPE, alert.name())
|
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);
|
DateTime now = new DateTime(DateTimeZone.UTC);
|
||||||
long numberOfAlertHistoryIndices = randomIntBetween(2,8);
|
long numberOfAlertHistoryIndices = randomIntBetween(2,8);
|
||||||
long numberOfAlertHistoryEntriesPerIndex = randomIntBetween(5,10);
|
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++) {
|
for (int i = 0; i < numberOfAlertHistoryIndices; i++) {
|
||||||
DateTime historyIndexDate = now.minus((new TimeValue(i, TimeUnit.DAYS)).getMillis());
|
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 ScriptCondition(logger, scriptService(), new Script("return true")),
|
||||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), searchRequest),
|
||||||
new Actions(new ArrayList<Action>()),
|
new Actions(new ArrayList<Action>()),
|
||||||
null,
|
null, // metatdata
|
||||||
new Alert.Status(),
|
new TimeValue(0),
|
||||||
new TimeValue(0)
|
new Alert.Status());
|
||||||
);
|
|
||||||
XContentBuilder jsonBuilder = jsonBuilder();
|
XContentBuilder jsonBuilder = jsonBuilder();
|
||||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
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());
|
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||||
|
|
||||||
FiredAlert firedAlert = new FiredAlert(alert, historyIndexDate, historyIndexDate);
|
FiredAlert firedAlert = new FiredAlert(alert, historyIndexDate, historyIndexDate);
|
|
@ -3,10 +3,13 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.ExceptionsHelper;
|
||||||
import org.elasticsearch.action.search.SearchRequest;
|
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.delete.DeleteAlertResponse;
|
||||||
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
import org.elasticsearch.alerts.transport.actions.stats.AlertsStatsResponse;
|
||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
|
@ -20,6 +23,7 @@ import org.elasticsearch.discovery.DiscoverySettings;
|
||||||
import org.elasticsearch.discovery.MasterNotDiscoveredException;
|
import org.elasticsearch.discovery.MasterNotDiscoveredException;
|
||||||
import org.elasticsearch.discovery.zen.elect.ElectMasterService;
|
import org.elasticsearch.discovery.zen.elect.ElectMasterService;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
|
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||||
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
|
import org.elasticsearch.test.discovery.ClusterDiscoveryConfiguration;
|
||||||
import org.elasticsearch.test.junit.annotations.TestLogging;
|
import org.elasticsearch.test.junit.annotations.TestLogging;
|
||||||
import org.junit.Test;
|
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.index.query.QueryBuilders.termQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
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.equalTo;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.core.Is.is;
|
import static org.hamcrest.core.Is.is;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
@ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, numDataNodes = 0)
|
@ClusterScope(scope = TEST, numClientNodes = 0, transportClientRatio = 0, randomDynamicTemplates = false, numDataNodes = 0)
|
||||||
public class NoMasterNodeTests extends AbstractAlertingTests {
|
public class NoMasterNodeTests extends AbstractAlertsIntegrationTests {
|
||||||
|
|
||||||
private ClusterDiscoveryConfiguration.UnicastZen config;
|
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
|
// Have a sample document in the index, the alert is going to evaluate
|
||||||
client().prepareIndex("my-index", "my-type").setSource("field", "value").get();
|
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");
|
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||||
alertClient().preparePutAlert("my-first-alert")
|
alertClient().preparePutAlert("my-first-alert")
|
||||||
.setAlertSource(alertSource)
|
.source(alertSource)
|
||||||
.get();
|
.get();
|
||||||
assertAlertWithMinimumPerformedActionsCount("my-first-alert", 1);
|
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
|
// Add a new alert and wait for its condition to be met
|
||||||
alertClient().preparePutAlert("my-second-alert")
|
alertClient().preparePutAlert("my-second-alert")
|
||||||
.setAlertSource(alertSource)
|
.source(alertSource)
|
||||||
.get();
|
.get();
|
||||||
assertAlertWithMinimumPerformedActionsCount("my-second-alert", 1);
|
assertAlertWithMinimumPerformedActionsCount("my-second-alert", 1);
|
||||||
}
|
}
|
||||||
|
@ -108,10 +113,10 @@ public class NoMasterNodeTests extends AbstractAlertingTests {
|
||||||
ensureAlertingStarted();
|
ensureAlertingStarted();
|
||||||
for (int i = 1; i <= numberOfAlerts; i++) {
|
for (int i = 1; i <= numberOfAlerts; i++) {
|
||||||
String alertName = "alert" + 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");
|
BytesReference alertSource = createAlertSource("0/5 * * * * ? *", searchRequest, "hits.total == 1");
|
||||||
alertClient().preparePutAlert(alertName)
|
alertClient().preparePutAlert(alertName)
|
||||||
.setAlertSource(alertSource)
|
.source(alertSource)
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
ensureGreen();
|
ensureGreen();
|
|
@ -3,40 +3,34 @@
|
||||||
* or more contributor license agreements. Licensed under the Elastic License;
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
* you may not use this file except in compliance with 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.SearchRequest;
|
||||||
import org.elasticsearch.action.search.SearchResponse;
|
import org.elasticsearch.action.search.SearchResponse;
|
||||||
import org.elasticsearch.alerts.actions.Action;
|
import org.elasticsearch.alerts.scheduler.schedule.IntervalSchedule.Interval;
|
||||||
import org.elasticsearch.alerts.actions.Actions;
|
import org.elasticsearch.alerts.test.AbstractAlertsIntegrationTests;
|
||||||
import org.elasticsearch.alerts.actions.index.IndexAction;
|
import org.elasticsearch.alerts.test.AlertsTestUtils;
|
||||||
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.transform.SearchTransform;
|
import org.elasticsearch.alerts.transform.SearchTransform;
|
||||||
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
import org.elasticsearch.alerts.transport.actions.put.PutAlertResponse;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.script.ScriptService;
|
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
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.index.query.QueryBuilders.matchAllQuery;
|
||||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
import static org.elasticsearch.search.builder.SearchSourceBuilder.searchSource;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public class TransformSearchTest extends AbstractAlertingTests {
|
public class TransformSearchTests extends AbstractAlertsIntegrationTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransformSearchRequest() throws Exception {
|
public void testTransformSearchRequest() throws Exception {
|
||||||
|
@ -46,31 +40,23 @@ public class TransformSearchTest extends AbstractAlertingTests {
|
||||||
index("my-payload-index","payload", "mytestresult");
|
index("my-payload-index","payload", "mytestresult");
|
||||||
refresh();
|
refresh();
|
||||||
|
|
||||||
SearchRequest conditionRequest = createConditionSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
SearchRequest inputRequest = AlertsTestUtils.newInputSearchRequest("my-condition-index").source(searchSource().query(matchAllQuery()));
|
||||||
SearchRequest transformRequest = createConditionSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
SearchRequest transformRequest = AlertsTestUtils.newInputSearchRequest("my-payload-index").source(searchSource().query(matchAllQuery()));
|
||||||
transformRequest.searchType(SearchTransform.DEFAULT_SEARCH_TYPE);
|
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<>();
|
Map<String, Object> metadata = new HashMap<>();
|
||||||
metadata.put("foo", "bar");
|
metadata.put("foo", "bar");
|
||||||
metadata.put("list", "baz");
|
metadata.put("list", "baz");
|
||||||
|
|
||||||
Alert alert = new Alert(
|
PutAlertResponse putAlertResponse = alertClient().preparePutAlert("test-payload")
|
||||||
"test-serialization",
|
.source(alertSourceBuilder()
|
||||||
new CronSchedule("0/5 * * * * ? *"),
|
.schedule(interval(5, Interval.Unit.SECONDS))
|
||||||
new SearchInput(logger, scriptService(), ClientProxy.of(client()),
|
.input(searchInput(inputRequest))
|
||||||
conditionRequest),
|
.transform(searchTransform(transformRequest))
|
||||||
new ScriptCondition(logger, scriptService(), new Script("return true")),
|
.addAction(indexAction("my-payload-output", "result"))
|
||||||
new SearchTransform(logger, scriptService(), ClientProxy.of(client()), transformRequest),
|
.metadata(metadata)
|
||||||
new Actions(actions), metadata, new Alert.Status(), new TimeValue(0)
|
.throttlePeriod(TimeValue.timeValueSeconds(0)))
|
||||||
);
|
.get();
|
||||||
|
|
||||||
XContentBuilder jsonBuilder = XContentFactory.jsonBuilder();
|
|
||||||
alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS);
|
|
||||||
|
|
||||||
PutAlertResponse putAlertResponse = alertClient().preparePutAlert("test-payload").setAlertSource(jsonBuilder.bytes()).get();
|
|
||||||
assertTrue(putAlertResponse.indexResponse().isCreated());
|
assertTrue(putAlertResponse.indexResponse().isCreated());
|
||||||
|
|
||||||
assertAlertWithMinimumPerformedActionsCount("test-payload", 1, false);
|
assertAlertWithMinimumPerformedActionsCount("test-payload", 1, false);
|
|
@ -24,9 +24,7 @@ import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ -41,7 +39,7 @@ public class ScriptTransformTests extends ElasticsearchTestCase {
|
||||||
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
|
ScriptService.ScriptType type = randomFrom(ScriptService.ScriptType.values());
|
||||||
Map<String, Object> params = Collections.emptyMap();
|
Map<String, Object> params = Collections.emptyMap();
|
||||||
Script script = new Script("_script", type, "_lang", params);
|
Script script = new Script("_script", type, "_lang", params);
|
||||||
ScriptTransform transform = new ScriptTransform(script, service);
|
ScriptTransform transform = new ScriptTransform(service, script);
|
||||||
|
|
||||||
DateTime now = new DateTime();
|
DateTime now = new DateTime();
|
||||||
ExecutionContext ctx = mock(ExecutionContext.class);
|
ExecutionContext ctx = mock(ExecutionContext.class);
|
||||||
|
|
Loading…
Reference in New Issue