From 75ce20ecffde3ae00b39c24833146af9cfbeeb11 Mon Sep 17 00:00:00 2001 From: Brian Murphy Date: Tue, 4 Nov 2014 15:01:25 +0000 Subject: [PATCH] Alerting transport layer. This commit adds the transport layer to the alerting plugin. Original commit: elastic/x-pack-elasticsearch@a99dce94117d0c80ab2efe31f8b9788a9d0a9b33 --- .../java/org/elasticsearch/alerts/Alert.java | 48 ++++++++ .../elasticsearch/alerts/AlertManager.java | 18 +++ .../elasticsearch/alerts/AlertingModule.java | 6 + .../org/elasticsearch/alerts/AlertsStore.java | 22 ++++ .../alerts/actions/AlertAction.java | 7 ++ .../alerts/actions/AlertActionFactory.java | 5 + .../alerts/actions/AlertActionRegistry.java | 23 +++- .../alerts/actions/EmailAlertAction.java | 26 ++++ .../actions/EmailAlertActionFactory.java | 17 +++ .../alerts/actions/IndexAlertAction.java | 18 ++- .../actions/IndexAlertActionFactory.java | 8 +- .../alerts/plugin/AlertsPlugin.java | 1 + .../actions/create/CreateAlertAction.java | 35 ++++++ .../actions/create/CreateAlertRequest.java | 70 +++++++++++ .../create/CreateAlertRequestBuilder.java | 37 ++++++ .../actions/create/CreateAlertResponse.java | 49 ++++++++ .../create/TransportCreateAlertAction.java | 79 ++++++++++++ .../actions/delete/DeleteAlertAction.java | 34 ++++++ .../actions/delete/DeleteAlertRequest.java | 100 ++++++++++++++++ .../delete/DeleteAlertRequestBuilder.java | 40 +++++++ .../actions/delete/DeleteAlertResponse.java | 47 ++++++++ .../delete/TransportDeleteAlertAction.java | 79 ++++++++++++ .../actions/delete/package-info.java | 10 ++ .../transport/actions/get/GetAlertAction.java | 34 ++++++ .../actions/get/GetAlertRequest.java | 113 ++++++++++++++++++ .../actions/get/GetAlertRequestBuilder.java | 49 ++++++++ .../actions/get/GetAlertResponse.java | 59 +++++++++ .../actions/get/TransportGetAlertAction.java | 79 ++++++++++++ .../transport/actions/get/package-info.java | 10 ++ .../update/TransportUpdateAlertAction.java | 64 ++++++++++ .../actions/update/UpdateAlertAction.java | 35 ++++++ .../actions/update/UpdateAlertRequest.java | 64 ++++++++++ .../update/UpdateAlertRequestBuilder.java | 34 ++++++ .../actions/update/UpdateAlertResponse.java | 13 ++ .../alerts/triggers/AlertTrigger.java | 35 +++++- .../alerts/BasicAlertingTest.java | 17 +++ .../alerts/actions/AlertActionsTest.java | 70 ++++++++++- 37 files changed, 1444 insertions(+), 11 deletions(-) create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequest.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequestBuilder.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertResponse.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/create/TransportCreateAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequest.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequestBuilder.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertResponse.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/TransportDeleteAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/delete/package-info.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequest.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequestBuilder.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertResponse.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/TransportGetAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/get/package-info.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/update/TransportUpdateAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertAction.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequest.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequestBuilder.java create mode 100644 src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertResponse.java diff --git a/src/main/java/org/elasticsearch/alerts/Alert.java b/src/main/java/org/elasticsearch/alerts/Alert.java index 6f13f1970c0..b6e25247926 100644 --- a/src/main/java/org/elasticsearch/alerts/Alert.java +++ b/src/main/java/org/elasticsearch/alerts/Alert.java @@ -7,15 +7,22 @@ package org.elasticsearch.alerts; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.alerts.actions.AlertAction; +import org.elasticsearch.alerts.actions.AlertActionFactory; +import org.elasticsearch.alerts.actions.AlertActionRegistry; import org.elasticsearch.alerts.triggers.AlertTrigger; import org.elasticsearch.common.io.stream.DataOutputStreamOutput; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.joda.time.DateTimeZone; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.omg.CORBA.portable.Streamable; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.util.ArrayList; import java.util.List; public class Alert implements ToXContent { @@ -72,6 +79,47 @@ public class Alert implements ToXContent { return builder; } + public void readFrom(StreamInput in) throws IOException { + alertName = in.readString(); + searchRequest = new SearchRequest(); + searchRequest.readFrom(in); + trigger = AlertTrigger.readFrom(in); + int numActions = in.readInt(); + actions = new ArrayList<>(numActions); + for (int i=0; i getAllAlerts() { ensureStarted(); return ImmutableList.copyOf(alertsStore.getAlerts().values()); @@ -136,6 +150,10 @@ public class AlertManager extends AbstractComponent { } } + public Alert getAlert(String alertName) { + return alertsStore.getAlert(alertName); + } + private final class AlertsClusterStateListener implements ClusterStateListener { @Override diff --git a/src/main/java/org/elasticsearch/alerts/AlertingModule.java b/src/main/java/org/elasticsearch/alerts/AlertingModule.java index 5602832b0fb..7038e35878f 100644 --- a/src/main/java/org/elasticsearch/alerts/AlertingModule.java +++ b/src/main/java/org/elasticsearch/alerts/AlertingModule.java @@ -5,13 +5,17 @@ */ package org.elasticsearch.alerts; + import org.elasticsearch.alerts.actions.AlertActionManager; + import org.elasticsearch.alerts.actions.AlertActionRegistry; +import org.elasticsearch.alerts.client.AlertsClient; import org.elasticsearch.alerts.rest.AlertRestHandler; import org.elasticsearch.alerts.scheduler.AlertScheduler; import org.elasticsearch.alerts.triggers.TriggerManager; import org.elasticsearch.common.inject.AbstractModule; + public class AlertingModule extends AbstractModule { @Override @@ -23,6 +27,8 @@ public class AlertingModule extends AbstractModule { bind(AlertScheduler.class).asEagerSingleton(); bind(AlertActionRegistry.class).asEagerSingleton(); bind(AlertRestHandler.class).asEagerSingleton(); + //bind(AlertsClientInterface.class).to(AlertsClient.class).asEagerSingleton(); + bind(AlertsClient.class).asEagerSingleton(); } } diff --git a/src/main/java/org/elasticsearch/alerts/AlertsStore.java b/src/main/java/org/elasticsearch/alerts/AlertsStore.java index 9c58a2df8a8..fab87a1b598 100644 --- a/src/main/java/org/elasticsearch/alerts/AlertsStore.java +++ b/src/main/java/org/elasticsearch/alerts/AlertsStore.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.io.stream.BytesStreamInput; +import org.elasticsearch.common.io.stream.DataOutputStreamOutput; import org.elasticsearch.common.joda.time.DateTime; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; @@ -33,6 +34,8 @@ import org.elasticsearch.common.xcontent.*; import org.elasticsearch.search.SearchHit; import org.elasticsearch.threadpool.ThreadPool; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.util.List; import java.util.concurrent.ConcurrentMap; @@ -99,6 +102,25 @@ public class AlertsStore extends AbstractComponent { return alert; } + /** + * Creates an alert with the specified and fails if an alert with the name already exists. + */ + public Alert createAlert(Alert alert) throws IOException { + if (!client.admin().indices().prepareExists(ALERT_INDEX).execute().actionGet().isExists()) { + createAlertsIndex(); + } + + if (alertMap.putIfAbsent(alert.alertName(), alert) == null) { + XContentBuilder jsonBuilder = XContentFactory.jsonBuilder(); + alert.toXContent(jsonBuilder, ToXContent.EMPTY_PARAMS); + persistAlert(alert.alertName(), jsonBuilder.bytes(), IndexRequest.OpType.CREATE); + } else { + throw new ElasticsearchIllegalArgumentException("There is already an alert named [" + alert.alertName() + "]"); + } + return alert; + } + + /** * Updates the specified alert by making sure that the made changes are persisted. */ diff --git a/src/main/java/org/elasticsearch/alerts/actions/AlertAction.java b/src/main/java/org/elasticsearch/alerts/actions/AlertAction.java index 6ec15307b6b..f81ef93fc79 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/AlertAction.java +++ b/src/main/java/org/elasticsearch/alerts/actions/AlertAction.java @@ -6,6 +6,8 @@ package org.elasticsearch.alerts.actions; import org.elasticsearch.alerts.Alert; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -17,5 +19,10 @@ public interface AlertAction extends ToXContent { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException; + public void writeTo(StreamOutput out) throws IOException; + public void readFrom(StreamInput in) throws IOException; + public boolean doAction(Alert alert, AlertActionEntry actionEntry); + + } diff --git a/src/main/java/org/elasticsearch/alerts/actions/AlertActionFactory.java b/src/main/java/org/elasticsearch/alerts/actions/AlertActionFactory.java index 7452bd7eb7f..ecaa346ac73 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/AlertActionFactory.java +++ b/src/main/java/org/elasticsearch/alerts/actions/AlertActionFactory.java @@ -5,7 +5,9 @@ */ package org.elasticsearch.alerts.actions; + import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.io.stream.StreamInput; import java.io.IOException; @@ -13,4 +15,7 @@ public interface AlertActionFactory { AlertAction createAction(XContentParser parser) throws IOException; + + AlertAction readFrom(StreamInput in) throws IOException; + } diff --git a/src/main/java/org/elasticsearch/alerts/actions/AlertActionRegistry.java b/src/main/java/org/elasticsearch/alerts/actions/AlertActionRegistry.java index 9a1055e2f4d..531048ae8c8 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/AlertActionRegistry.java +++ b/src/main/java/org/elasticsearch/alerts/actions/AlertActionRegistry.java @@ -11,6 +11,8 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentParser; @@ -20,12 +22,12 @@ import java.util.List; public class AlertActionRegistry extends AbstractComponent { - private volatile ImmutableOpenMap actionImplemented; + private static volatile ImmutableOpenMap actionImplemented; @Inject public AlertActionRegistry(Settings settings, Client client) { super(settings); - this.actionImplemented = ImmutableOpenMap.builder() + actionImplemented = ImmutableOpenMap.builder() .fPut("email", new EmailAlertActionFactory()) .fPut("index", new IndexAlertActionFactory(client)) .build(); @@ -37,6 +39,7 @@ public class AlertActionRegistry extends AbstractComponent { .build(); } + public List instantiateAlertActions(XContentParser parser) throws IOException { List actions = new ArrayList<>(); ImmutableOpenMap actionImplemented = this.actionImplemented; @@ -53,7 +56,6 @@ public class AlertActionRegistry extends AbstractComponent { throw new ElasticsearchIllegalArgumentException("No action exists with the name [" + actionFactoryName + "]"); } } - } return actions; } @@ -64,4 +66,19 @@ public class AlertActionRegistry extends AbstractComponent { } } + public static void writeTo(AlertAction action, StreamOutput out) throws IOException { + out.writeString(action.getActionName()); + action.writeTo(out); + } + + public static AlertAction readFrom(StreamInput in) throws IOException { + String actionName = in.readString(); + AlertActionFactory factory = actionImplemented.get(actionName); + if (factory != null) { + return factory.readFrom(in); + } else { + throw new ElasticsearchIllegalArgumentException("No action exists with the name [" + actionName + "]"); + } + } + } diff --git a/src/main/java/org/elasticsearch/alerts/actions/EmailAlertAction.java b/src/main/java/org/elasticsearch/alerts/actions/EmailAlertAction.java index 472be8e3cf6..d55b0672008 100644 --- a/src/main/java/org/elasticsearch/alerts/actions/EmailAlertAction.java +++ b/src/main/java/org/elasticsearch/alerts/actions/EmailAlertAction.java @@ -7,6 +7,8 @@ package org.elasticsearch.alerts.actions; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.alerts.Alert; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; import javax.mail.*; @@ -68,6 +70,30 @@ public class EmailAlertAction implements AlertAction { return builder; } + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeOptionalString(displayField); + out.writeInt(emailAddresses.size()); + for (Address emailAddress : emailAddresses) { + out.writeString(emailAddress.toString()); + } + } + + @Override + public void readFrom(StreamInput in) throws IOException { + displayField = in.readOptionalString(); + int numberOfEmails = in.readInt(); + emailAddresses = new ArrayList<>(numberOfEmails); + for (int i=0; i { + + public static final CreateAlertAction INSTANCE = new CreateAlertAction(); + public static final String NAME = "indices:data/write/alert/create"; + + private CreateAlertAction() { + super(NAME); + } + + + @Override + public CreateAlertRequestBuilder newRequestBuilder(AlertsClientInterface client) { + return new CreateAlertRequestBuilder(client); + } + + @Override + public CreateAlertResponse newResponse() { + return new CreateAlertResponse(); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequest.java b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequest.java new file mode 100644 index 00000000000..410339049da --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequest.java @@ -0,0 +1,70 @@ +/* + * 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.transport.actions.create; + + +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ValidateActions; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.alerts.triggers.AlertTrigger; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.joda.time.DateTime; +import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.common.unit.TimeValue; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + */ +public class CreateAlertRequest extends MasterNodeOperationRequest { + + private Alert alert; + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (alert == null) { + validationException = ValidateActions.addValidationError("alert is missing", validationException); + } + return validationException; + } + + + CreateAlertRequest() { + } + + + public CreateAlertRequest(Alert alert) { + this.alert = alert; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + alert = new Alert(); + alert.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + alert.writeTo(out); + } + + + public Alert alert() { + return alert; + } + + public void Alert(Alert alert) { + this.alert = alert; + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequestBuilder.java b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequestBuilder.java new file mode 100644 index 00000000000..91f3e02d6f7 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertRequestBuilder.java @@ -0,0 +1,37 @@ +/* + * 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.transport.actions.create; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; + +/** + */ +public class CreateAlertRequestBuilder + extends MasterNodeOperationRequestBuilder { + + + public CreateAlertRequestBuilder(AlertsClientInterface client) { + super(client, new CreateAlertRequest(null)); + } + + + public CreateAlertRequestBuilder(AlertsClientInterface client, Alert alert) { + super(client, new CreateAlertRequest(alert)); + } + + @Override + protected void doExecute(ActionListener listener) { + client.createAlert(request, listener); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertResponse.java b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertResponse.java new file mode 100644 index 00000000000..f45727b3798 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/create/CreateAlertResponse.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.alerts.transport.actions.create; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + */ +public class CreateAlertResponse extends ActionResponse { + private boolean success; + + public CreateAlertResponse(boolean success) { + this.success = success; + } + + public CreateAlertResponse() { + this.success = success; + } + + + public boolean success() { + return success; + } + + public void success(boolean success) { + this.success = success; + } + + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeBoolean(success); + } + + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + success = in.readBoolean(); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/create/TransportCreateAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/create/TransportCreateAlertAction.java new file mode 100644 index 00000000000..f57279b7516 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/create/TransportCreateAlertAction.java @@ -0,0 +1,79 @@ +/* + * 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.transport.actions.create; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.alerts.actions.AlertAction; +import org.elasticsearch.alerts.actions.AlertActionManager; +import org.elasticsearch.alerts.triggers.TriggerManager; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; +import org.quartz.Trigger; + +import java.util.ArrayList; + +/** + */ +public class TransportCreateAlertAction extends TransportMasterNodeOperationAction { + + private final AlertManager alertManager; + + @Inject + public TransportCreateAlertAction(Settings settings, String actionName, TransportService transportService, + ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, + AlertManager alertManager) { + super(settings, actionName, transportService, clusterService, threadPool, actionFilters); + this.alertManager = alertManager; + } + + @Override + protected String executor() { + return ThreadPool.Names.MANAGEMENT; + } + + @Override + protected CreateAlertRequest newRequest() { + return new CreateAlertRequest(); + } + + @Override + protected CreateAlertResponse newResponse() { + return new CreateAlertResponse(); + } + + @Override + protected void masterOperation(CreateAlertRequest request, ClusterState state, ActionListener listener) throws ElasticsearchException { + try { + alertManager.addAlert(request.alert()); + listener.onResponse(new CreateAlertResponse(true)); + } catch (Exception e) { + listener.onFailure(e); + } + } + + @Override + protected ClusterBlockException checkBlock(CreateAlertRequest request, ClusterState state) { + if (!alertManager.isStarted()) { + return new ClusterBlockException(null); + } + return state.blocks().indicesBlockedException(ClusterBlockLevel.WRITE, new String[]{AlertsStore.ALERT_INDEX, AlertActionManager.ALERT_HISTORY_INDEX}); + + } + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertAction.java new file mode 100644 index 00000000000..b3689d0b145 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertAction.java @@ -0,0 +1,34 @@ +/* + * 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.transport.actions.delete; + +import org.elasticsearch.action.ClientAction; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientAction; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; + +/** + */ +public class DeleteAlertAction extends AlertsClientAction { + + public static final DeleteAlertAction INSTANCE = new DeleteAlertAction(); + public static final String NAME = "indices:data/write/alert/delete"; + + private DeleteAlertAction() { + super(NAME); + } + + @Override + public DeleteAlertResponse newResponse() { + return new DeleteAlertResponse(); + } + + @Override + public DeleteAlertRequestBuilder newRequestBuilder(AlertsClientInterface client) { + return new DeleteAlertRequestBuilder(client); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequest.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequest.java new file mode 100644 index 00000000000..98767018d22 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequest.java @@ -0,0 +1,100 @@ +/* + * 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.transport.actions.delete; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.ValidateActions; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.index.VersionType; +import org.elasticsearch.script.ScriptService; + +import java.io.IOException; + +import static org.elasticsearch.action.ValidateActions.addValidationError; + +/** + */ +public class DeleteAlertRequest extends MasterNodeOperationRequest implements IndicesRequest { + + private long version = Versions.MATCH_ANY; + + private String alertName; + + + public DeleteAlertRequest() { + } + + public DeleteAlertRequest(String alertName) { + this.alertName = alertName; + } + + public void alertName(String alertName) { + this.alertName = alertName; + } + + public String alertName() { + return alertName; + } + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (alertName == null){ + validationException = ValidateActions.addValidationError("alertName is missing", validationException); + } + return validationException; + } + + @Override + public String[] indices() { + return new String[]{AlertsStore.ALERT_INDEX}; + } + + @Override + public IndicesOptions indicesOptions() { + return IndicesOptions.strictSingleIndexNoExpandForbidClosed(); + } + + + /** + * Sets the version, which will cause the delete operation to only be performed if a matching + * version exists and no changes happened on the doc since then. + */ + public DeleteAlertRequest version(long version) { + this.version = version; + return this; + } + + public long version() { + return this.version; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + version = Versions.readVersion(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + Versions.writeVersion(version, out); + + } + + @Override + public String toString() { + return "delete {[" + AlertsStore.ALERT_INDEX + "][" + alertName + "]}"; + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequestBuilder.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequestBuilder.java new file mode 100644 index 00000000000..ed0e89fcbda --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertRequestBuilder.java @@ -0,0 +1,40 @@ +/* + * 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.transport.actions.delete; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; +import org.elasticsearch.index.VersionType; + +/** + * A delete document action request builder. + */ +public class DeleteAlertRequestBuilder + extends MasterNodeOperationRequestBuilder { + + public DeleteAlertRequestBuilder(AlertsClientInterface client) { + super(client, new DeleteAlertRequest()); + } + + public DeleteAlertRequestBuilder(AlertsClientInterface client, String alertName) { + super(client, new DeleteAlertRequest(alertName)); + } + + public DeleteAlertRequestBuilder setAlertName(String alertName) { + this.request().alertName(alertName); + return this; + } + + @Override + protected void doExecute(final ActionListener listener) { + client.deleteAlert(request, listener); + } + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertResponse.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertResponse.java new file mode 100644 index 00000000000..f76aee73947 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/DeleteAlertResponse.java @@ -0,0 +1,47 @@ +/* + * 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.transport.actions.delete; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + */ +public class DeleteAlertResponse extends ActionResponse { + + boolean success; + + public DeleteAlertResponse() { + success = false; + } + + public DeleteAlertResponse(boolean success) { + this.success = true; + } + + public boolean success() { + return success; + } + + public void success(boolean success) { + this.success = success; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + success = in.readBoolean(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeBoolean(success); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/TransportDeleteAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/TransportDeleteAlertAction.java new file mode 100644 index 00000000000..08bf486e063 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/TransportDeleteAlertAction.java @@ -0,0 +1,79 @@ +/* + * 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.transport.actions.delete; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.delete.DeleteResponse; +import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptAction; +import org.elasticsearch.action.indexedscripts.delete.DeleteIndexedScriptRequest; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.DelegatingActionListener; +import org.elasticsearch.action.support.HandledTransportAction; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.alerts.actions.AlertActionManager; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.script.ScriptService; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +/** + * Performs the delete operation. + */ +public class TransportDeleteAlertAction extends TransportMasterNodeOperationAction { + + private final AlertManager alertManager; + + @Inject + public TransportDeleteAlertAction(Settings settings, String actionName, TransportService transportService, + ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, + AlertManager alertManager) { + super(settings, actionName, transportService, clusterService, threadPool, actionFilters); + this.alertManager = alertManager; + } + + @Override + protected String executor() { + return ThreadPool.Names.MANAGEMENT; + } + + @Override + protected DeleteAlertRequest newRequest() { + return new DeleteAlertRequest(); + } + + @Override + protected DeleteAlertResponse newResponse() { + return new DeleteAlertResponse(); + } + + @Override + protected void masterOperation(DeleteAlertRequest request, ClusterState state, ActionListener listener) throws ElasticsearchException { + try { + boolean success = alertManager.deleteAlert(request.alertName()); + listener.onResponse(new DeleteAlertResponse(success)); + } catch (Exception e) { + listener.onFailure(e); + } + } + + @Override + protected ClusterBlockException checkBlock(DeleteAlertRequest request, ClusterState state) { + if (!alertManager.isStarted()) { + return new ClusterBlockException(null); + } + return state.blocks().indicesBlockedException(ClusterBlockLevel.WRITE, new String[]{AlertsStore.ALERT_INDEX, AlertActionManager.ALERT_HISTORY_INDEX}); + } + + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/delete/package-info.java b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/package-info.java new file mode 100644 index 00000000000..7eda4d1bddd --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/delete/package-info.java @@ -0,0 +1,10 @@ +/* + * 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. + */ + +/** + * Delete action. + */ +package org.elasticsearch.alerts.transport.actions.delete; \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertAction.java new file mode 100644 index 00000000000..82900cb7427 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertAction.java @@ -0,0 +1,34 @@ +/* + * 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.transport.actions.get; + +import org.elasticsearch.action.ClientAction; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientAction; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; + +/** + */ +public class GetAlertAction extends AlertsClientAction { + + public static final GetAlertAction INSTANCE = new GetAlertAction(); + public static final String NAME = "indices:data/read/alert/get"; + + private GetAlertAction() { + super(NAME); + } + + @Override + public GetAlertResponse newResponse() { + return new GetAlertResponse(); + } + + @Override + public GetAlertRequestBuilder newRequestBuilder(AlertsClientInterface client) { + return new GetAlertRequestBuilder(client); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequest.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequest.java new file mode 100644 index 00000000000..997453c19a6 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequest.java @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.alerts.transport.actions.get; + +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.ValidateActions; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.index.VersionType; + +import java.io.IOException; + +/** + */ +public class GetAlertRequest extends MasterNodeOperationRequest implements IndicesRequest { + + private String alertName; + private long version = Versions.MATCH_ANY; + private VersionType versionType = VersionType.INTERNAL; + + + public GetAlertRequest() { + } + + + public GetAlertRequest(String alertName) { + this.alertName = alertName; + } + + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (alertName == null) { + validationException = ValidateActions.addValidationError("alertName is missing", validationException); + } + return validationException; + } + + @Override + public String[] indices() { + return new String[]{AlertsStore.ALERT_INDEX}; + } + + @Override + public IndicesOptions indicesOptions() { + return IndicesOptions.strictSingleIndexNoExpandForbidClosed(); + } + + + + public String alertName() { + return alertName; + } + + public GetAlertRequest alertName(String alertName){ + this.alertName = alertName; + return this; + } + + /** + * Sets the version, which will cause the delete operation to only be performed if a matching + * version exists and no changes happened on the doc since then. + */ + public GetAlertRequest version(long version) { + this.version = version; + return this; + } + + public long version() { + return this.version; + } + + public GetAlertRequest versionType(VersionType versionType) { + this.versionType = versionType; + return this; + } + + public VersionType versionType() { + return this.versionType; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + version = Versions.readVersion(in); + versionType = VersionType.fromValue(in.readByte()); + alertName = in.readString(); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + Versions.writeVersion(version, out); + out.writeByte(versionType.getValue()); + out.writeString(alertName); + } + + @Override + public String toString() { + return "delete {[" + AlertsStore.ALERT_INDEX + "][" + alertName +"]}"; + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequestBuilder.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequestBuilder.java new file mode 100644 index 00000000000..342f3913f9e --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertRequestBuilder.java @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.alerts.transport.actions.get; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; +import org.elasticsearch.index.VersionType; + +/** + * A delete document action request builder. + */ +public class GetAlertRequestBuilder + extends MasterNodeOperationRequestBuilder { + + + public GetAlertRequestBuilder(AlertsClientInterface client, String alertName) { + super(client, new GetAlertRequest(alertName)); + } + + + public GetAlertRequestBuilder(AlertsClientInterface client) { + super(client, new GetAlertRequest()); + } + + public GetAlertRequestBuilder setAlertName(String alertName) { + request.alertName(alertName); + return this; + } + + /** + * Sets the type of versioning to use. Defaults to {@link org.elasticsearch.index.VersionType#INTERNAL}. + */ + public GetAlertRequestBuilder setVersionType(VersionType versionType) { + request.versionType(versionType); + return this; + } + + @Override + protected void doExecute(final ActionListener listener) { + client.getAlert(request, listener); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertResponse.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertResponse.java new file mode 100644 index 00000000000..29d7347b099 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/GetAlertResponse.java @@ -0,0 +1,59 @@ +/* + * 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.transport.actions.get; + +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + */ +public class GetAlertResponse extends ActionResponse { + boolean found = false; + Alert alert = null; + + public GetAlertResponse() { + + } + + public boolean found() { + return this.found; + } + + public void found(boolean found) { + this.found = found; + } + + public Alert alert() { + return alert; + } + + public void alert(Alert alert){ + this.alert = alert; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + found = in.readBoolean(); + if (found) { + alert = new Alert(); + alert.readFrom(in); + } + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeBoolean(found); + if (found && alert != null){ + alert.writeTo(out); + } + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/TransportGetAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/TransportGetAlertAction.java new file mode 100644 index 00000000000..32b26affc92 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/TransportGetAlertAction.java @@ -0,0 +1,79 @@ +/* + * 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.transport.actions.get; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.alerts.actions.AlertActionManager; +import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertRequest; +import org.elasticsearch.alerts.transport.actions.delete.DeleteAlertResponse; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +/** + * Performs the delete operation. + */ +public class TransportGetAlertAction extends TransportMasterNodeOperationAction { + + private final AlertManager alertManager; + + @Inject + public TransportGetAlertAction(Settings settings, String actionName, TransportService transportService, + ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, + AlertManager alertManager) { + super(settings, actionName, transportService, clusterService, threadPool, actionFilters); + this.alertManager = alertManager; + } + + @Override + protected String executor() { + return ThreadPool.Names.MANAGEMENT; + } + + @Override + protected GetAlertRequest newRequest() { + return new GetAlertRequest(); + } + + @Override + protected GetAlertResponse newResponse() { + return new GetAlertResponse(); + } + + @Override + protected void masterOperation(GetAlertRequest request, ClusterState state, ActionListener listener) throws ElasticsearchException { + try { + Alert alert = alertManager.getAlert(request.alertName()); + GetAlertResponse response = new GetAlertResponse(); + response.found(alert != null); + response.alert(alert); + listener.onResponse(response); + } catch (Exception e) { + listener.onFailure(e); + } + } + + @Override + protected ClusterBlockException checkBlock(GetAlertRequest request, ClusterState state) { + if (!alertManager.isStarted()) { + return new ClusterBlockException(null); + } + return state.blocks().indicesBlockedException(ClusterBlockLevel.WRITE, new String[]{AlertsStore.ALERT_INDEX, AlertActionManager.ALERT_HISTORY_INDEX}); + } + + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/get/package-info.java b/src/main/java/org/elasticsearch/alerts/transport/actions/get/package-info.java new file mode 100644 index 00000000000..414c52afb23 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/get/package-info.java @@ -0,0 +1,10 @@ +/* + * 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. + */ + +/** + * Delete action. + */ +package org.elasticsearch.alerts.transport.actions.get; \ No newline at end of file diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/update/TransportUpdateAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/update/TransportUpdateAlertAction.java new file mode 100644 index 00000000000..f5f0badf2c3 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/update/TransportUpdateAlertAction.java @@ -0,0 +1,64 @@ +/* + * 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.transport.actions.update; + +import org.elasticsearch.ElasticsearchException; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.support.ActionFilters; +import org.elasticsearch.action.support.master.TransportMasterNodeOperationAction; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.alerts.actions.AlertActionManager; +import org.elasticsearch.cluster.ClusterService; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.block.ClusterBlockException; +import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportService; + +/** + */ +public class TransportUpdateAlertAction extends TransportMasterNodeOperationAction { + + private final AlertManager alertManager; + + public TransportUpdateAlertAction(Settings settings, String actionName, TransportService transportService, + ClusterService clusterService, ThreadPool threadPool, ActionFilters actionFilters, + AlertManager alertManager) { + super(settings, actionName, transportService, clusterService, threadPool, actionFilters); + this.alertManager = alertManager; + } + + @Override + protected String executor() { + return ThreadPool.Names.MANAGEMENT; + } + + @Override + protected UpdateAlertRequest newRequest() { + return new UpdateAlertRequest(); + } + + @Override + protected UpdateAlertResponse newResponse() { + return new UpdateAlertResponse(); + } + + @Override + protected void masterOperation(UpdateAlertRequest request, ClusterState state, ActionListener listener) throws ElasticsearchException { + + } + + @Override + protected ClusterBlockException checkBlock(UpdateAlertRequest request, ClusterState state) { + if (!alertManager.isStarted()) { + return new ClusterBlockException(null); + } + return state.blocks().indicesBlockedException(ClusterBlockLevel.WRITE, new String[]{AlertsStore.ALERT_INDEX, AlertActionManager.ALERT_HISTORY_INDEX}); + } + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertAction.java b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertAction.java new file mode 100644 index 00000000000..468da5f6391 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertAction.java @@ -0,0 +1,35 @@ +/* + * 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.transport.actions.update; + +import org.elasticsearch.action.ClientAction; +import org.elasticsearch.alerts.client.AlertsClientAction; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; + +/** + */ +public class UpdateAlertAction extends AlertsClientAction { + + public static final UpdateAlertAction INSTANCE = new UpdateAlertAction(); + public static final String NAME = "indices:data/write/alert/update"; + + private UpdateAlertAction() { + super(NAME); + } + + + @Override + public UpdateAlertRequestBuilder newRequestBuilder(AlertsClientInterface client) { + return new UpdateAlertRequestBuilder(client); + } + + @Override + public UpdateAlertResponse newResponse() { + return new UpdateAlertResponse(); + } + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequest.java b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequest.java new file mode 100644 index 00000000000..309675ee510 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequest.java @@ -0,0 +1,64 @@ +/* + * 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.transport.actions.update; + +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ValidateActions; +import org.elasticsearch.action.support.master.MasterNodeOperationRequest; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; + +import java.io.IOException; + +/** + */ +public class UpdateAlertRequest extends MasterNodeOperationRequest { + + private Alert alert; + + + @Override + public ActionRequestValidationException validate() { + ActionRequestValidationException validationException = null; + if (alert == null) { + validationException = ValidateActions.addValidationError("alert is missing", validationException); + } + return validationException; + } + + UpdateAlertRequest() { + } + + public UpdateAlertRequest(Alert alert) { + this.alert = alert; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + alert = new Alert(); + alert.readFrom(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + alert.writeTo(out); + } + + + public Alert alert() { + return alert; + } + + public void Alert(Alert alert) { + this.alert = alert; + } + + + +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequestBuilder.java b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequestBuilder.java new file mode 100644 index 00000000000..137ee20007f --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertRequestBuilder.java @@ -0,0 +1,34 @@ +/* + * 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.transport.actions.update; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder; +import org.elasticsearch.alerts.Alert; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.client.Client; + +/** + */ +public class UpdateAlertRequestBuilder extends MasterNodeOperationRequestBuilder + { + + + public UpdateAlertRequestBuilder(AlertsClientInterface client) { + super(client, new UpdateAlertRequest()); + } + + public UpdateAlertRequestBuilder(AlertsClientInterface client, Alert alert) { + super(client, new UpdateAlertRequest(alert)); + } + + @Override + protected void doExecute(ActionListener listener) { + client.updateAlert(request, listener); + } +} diff --git a/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertResponse.java b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertResponse.java new file mode 100644 index 00000000000..cfb45267267 --- /dev/null +++ b/src/main/java/org/elasticsearch/alerts/transport/actions/update/UpdateAlertResponse.java @@ -0,0 +1,13 @@ +/* + * 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.transport.actions.update; + +import org.elasticsearch.action.ActionResponse; + +/** + */ +public class UpdateAlertResponse extends ActionResponse { +} diff --git a/src/main/java/org/elasticsearch/alerts/triggers/AlertTrigger.java b/src/main/java/org/elasticsearch/alerts/triggers/AlertTrigger.java index a74f93008ff..268a8c33d45 100644 --- a/src/main/java/org/elasticsearch/alerts/triggers/AlertTrigger.java +++ b/src/main/java/org/elasticsearch/alerts/triggers/AlertTrigger.java @@ -6,8 +6,11 @@ package org.elasticsearch.alerts.triggers; import org.elasticsearch.ElasticsearchIllegalArgumentException; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.script.ScriptService; import java.io.IOException; @@ -16,6 +19,7 @@ public class AlertTrigger implements ToXContent { private SimpleTrigger trigger; private TriggerType triggerType; private int value; + private ScriptedAlertTrigger scriptedTrigger; public ScriptedAlertTrigger scriptedTrigger() { return scriptedTrigger; @@ -25,8 +29,6 @@ public class AlertTrigger implements ToXContent { this.scriptedTrigger = scriptedTrigger; } - private ScriptedAlertTrigger scriptedTrigger; - public SimpleTrigger trigger() { return trigger; } @@ -193,4 +195,33 @@ public class AlertTrigger implements ToXContent { return result; } + + public static void writeTo(AlertTrigger trigger, StreamOutput out) throws IOException { + out.writeString(trigger.triggerType.toString()); + if (trigger.triggerType.equals(TriggerType.NUMBER_OF_EVENTS)) { + out.writeString(trigger.toString()); + out.writeInt(trigger.value); + } else { + out.writeString(trigger.scriptedTrigger.scriptLang); + ScriptService.ScriptType.writeTo(trigger.scriptedTrigger.scriptType, out); + out.writeString(trigger.scriptedTrigger.script); + } + } + + public static AlertTrigger readFrom(StreamInput in) throws IOException { + TriggerType triggerType = TriggerType.fromString(in.readString()); + if (triggerType.equals(TriggerType.NUMBER_OF_EVENTS)) { + SimpleTrigger trigger = SimpleTrigger.fromString(in.readString()); + int value = in.readInt(); + return new AlertTrigger(trigger, triggerType, value); + } else { + String scriptLang = in.readString(); + ScriptService.ScriptType scriptType = ScriptService.ScriptType.readFrom(in); + String script = in.readString(); + ScriptedAlertTrigger scriptedTrigger = new ScriptedAlertTrigger(script, scriptType, scriptLang); + return new AlertTrigger(scriptedTrigger); + } + } + + } diff --git a/src/test/java/org/elasticsearch/alerts/BasicAlertingTest.java b/src/test/java/org/elasticsearch/alerts/BasicAlertingTest.java index baa2656a56f..c69de41f731 100644 --- a/src/test/java/org/elasticsearch/alerts/BasicAlertingTest.java +++ b/src/test/java/org/elasticsearch/alerts/BasicAlertingTest.java @@ -10,6 +10,8 @@ import org.elasticsearch.alerts.actions.*; import org.elasticsearch.alerts.plugin.AlertsPlugin; import org.elasticsearch.alerts.triggers.AlertTrigger; import org.elasticsearch.alerts.triggers.ScriptedAlertTrigger; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.ImmutableSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -74,6 +76,16 @@ public class BasicAlertingTest extends ElasticsearchIntegrationTest { return builder; } + @Override + public void writeTo(StreamOutput out) throws IOException { + + } + + @Override + public void readFrom(StreamInput in) throws IOException { + + } + @Override public boolean doAction(Alert alert, AlertActionEntry actionEntry) { logger.info("Alert {} invoked: {}", alert.alertName(), actionEntry); @@ -88,6 +100,11 @@ public class BasicAlertingTest extends ElasticsearchIntegrationTest { parser.nextToken(); return alertAction; } + + @Override + public AlertAction readFrom(StreamInput in) throws IOException { + return alertAction; + } }); AlertTrigger alertTrigger = new AlertTrigger(new ScriptedAlertTrigger("return true", ScriptService.ScriptType.INLINE, "groovy")); Alert alert = new Alert( diff --git a/src/test/java/org/elasticsearch/alerts/actions/AlertActionsTest.java b/src/test/java/org/elasticsearch/alerts/actions/AlertActionsTest.java index 9cffe597666..fdb68f0437d 100644 --- a/src/test/java/org/elasticsearch/alerts/actions/AlertActionsTest.java +++ b/src/test/java/org/elasticsearch/alerts/actions/AlertActionsTest.java @@ -5,9 +5,18 @@ */ package org.elasticsearch.alerts.actions; + import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.ShardSearchFailure; +import org.elasticsearch.alerts.AlertManager; +import org.elasticsearch.alerts.AlertsStore; +import org.elasticsearch.alerts.BasicAlertingTest; +import org.elasticsearch.alerts.client.AlertsClient; +import org.elasticsearch.alerts.client.AlertsClientInterface; +import org.elasticsearch.alerts.plugin.AlertsPlugin; +import org.elasticsearch.alerts.transport.actions.create.CreateAlertRequest; +import org.elasticsearch.alerts.transport.actions.create.CreateAlertResponse; import org.elasticsearch.alerts.triggers.AlertTrigger; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.joda.FormatDateTimeFormatter; @@ -18,6 +27,9 @@ import org.elasticsearch.index.mapper.core.DateFieldMapper; import org.elasticsearch.search.internal.InternalSearchHit; import org.elasticsearch.search.internal.InternalSearchHits; import org.elasticsearch.search.internal.InternalSearchResponse; +import org.elasticsearch.common.settings.ImmutableSettings; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.test.ElasticsearchIntegrationTest; import org.junit.Test; @@ -25,6 +37,10 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.TimeUnit; + + +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; @@ -33,12 +49,29 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; @ElasticsearchIntegrationTest.ClusterScope(scope = ElasticsearchIntegrationTest.Scope.SUITE, numClientNodes = 0, transportClientRatio = 0, numDataNodes = 1) public class AlertActionsTest extends ElasticsearchIntegrationTest { + private static final FormatDateTimeFormatter formatter = DateFieldMapper.Defaults.DATE_TIME_FORMATTER; + + @Override + protected Settings nodeSettings(int nodeOrdinal) { + return ImmutableSettings.builder() + .put(super.nodeSettings(nodeOrdinal)) + .put("plugin.mandatory", "alerts") + .put("plugin.types", AlertsPlugin.class.getName()) + .put("node.mode", "network") + .put("plugins.load_classpath_plugins", false) + .build(); + } + + + @Test public void testAlertActionParser() throws Exception { - DateTime fireTime = new DateTime(DateTimeZone.UTC); - DateTime scheduledFireTime = new DateTime(DateTimeZone.UTC); + DateTime fireTime = new DateTime(DateTimeZone.UTC); + DateTime scheduledFireTime = new DateTime(DateTimeZone.UTC); + + Map triggerMap = new HashMap<>(); triggerMap.put("numberOfEvents", ">1"); Map actionMap = new HashMap<>(); @@ -83,4 +116,37 @@ public class AlertActionsTest extends ElasticsearchIntegrationTest { new AlertTrigger(AlertTrigger.SimpleTrigger.GREATER_THAN, AlertTrigger.TriggerType.NUMBER_OF_EVENTS, 1)); } + + @Test + public void testCreateAlert() throws Exception { + createIndex("my-index"); + createIndex(AlertsStore.ALERT_INDEX); + createIndex(AlertActionManager.ALERT_HISTORY_INDEX); + ensureGreen("my-index", AlertsStore.ALERT_INDEX, AlertActionManager.ALERT_HISTORY_INDEX); + + client().preparePutIndexedScript() + .setScriptLang("mustache") + .setId("query") + .setSource(jsonBuilder().startObject().startObject("template").startObject("match_all").endObject().endObject().endObject()) + .get(); + + CreateAlertRequest alertRequest = new CreateAlertRequest("myAlert"); + alertRequest.queryName("test-query"); + alertRequest.enabled(true); + alertRequest.schedule("0/5 * * * * ? *"); + alertRequest.trigger(new AlertTrigger(AlertTrigger.SimpleTrigger.GREATER_THAN, AlertTrigger.TriggerType.NUMBER_OF_EVENTS, 1)); + alertRequest.timePeriod(new TimeValue(300, TimeUnit.SECONDS)); + alertRequest.actions(new ArrayList()); + alertRequest.lastRan(new DateTime()); + alertRequest.lastActionFire(new DateTime()); + alertRequest.running(new DateTime()); + + + + AlertsClientInterface alertsClient = internalCluster().getInstance(AlertsClient.class, internalCluster().getMasterName()); + CreateAlertResponse alertsResponse = alertsClient.createAlert(alertRequest).actionGet(); + assertTrue(alertsResponse.success()); + + } + }