[ML] Delete calendar events endpoint (elastic/x-pack-elasticsearch#3388)
* Delete calendar events endpoint Original commit: elastic/x-pack-elasticsearch@70aebfae2c
This commit is contained in:
parent
bd3d652901
commit
f73a7803ce
|
@ -45,7 +45,6 @@ public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, D
|
|||
private String calendarId;
|
||||
|
||||
Request() {
|
||||
|
||||
}
|
||||
|
||||
public Request(String calendarId) {
|
||||
|
@ -117,5 +116,4 @@ public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, D
|
|||
writeAcknowledged(out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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.xpack.ml.action;
|
||||
|
||||
import org.elasticsearch.action.Action;
|
||||
import org.elasticsearch.action.ActionRequestBuilder;
|
||||
import org.elasticsearch.action.ActionRequestValidationException;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||
import org.elasticsearch.client.ElasticsearchClient;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||
import org.elasticsearch.xpack.ml.calendars.ScheduledEvent;
|
||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DeleteCalendarEventAction extends Action<DeleteCalendarEventAction.Request, DeleteCalendarEventAction.Response,
|
||||
DeleteCalendarEventAction.RequestBuilder> {
|
||||
|
||||
public static final DeleteCalendarEventAction INSTANCE = new DeleteCalendarEventAction();
|
||||
public static final String NAME = "cluster:admin/xpack/ml/calendars/events/delete";
|
||||
|
||||
private DeleteCalendarEventAction() {
|
||||
super(NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||
return new RequestBuilder(client, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response newResponse() {
|
||||
return new Response();
|
||||
}
|
||||
|
||||
public static class Request extends AcknowledgedRequest<Request> {
|
||||
private String calendarId;
|
||||
private String eventId;
|
||||
|
||||
Request() {
|
||||
}
|
||||
|
||||
public Request(String calendarId, String eventId) {
|
||||
this.calendarId = ExceptionsHelper.requireNonNull(calendarId, Calendar.ID.getPreferredName());
|
||||
this.eventId = ExceptionsHelper.requireNonNull(eventId, ScheduledEvent.EVENT_ID.getPreferredName());
|
||||
}
|
||||
|
||||
public String getCalendarId() {
|
||||
return calendarId;
|
||||
}
|
||||
|
||||
public String getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionRequestValidationException validate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
calendarId = in.readString();
|
||||
eventId = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
out.writeString(calendarId);
|
||||
out.writeString(eventId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(eventId, calendarId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Request other = (Request) obj;
|
||||
return Objects.equals(eventId, other.eventId) && Objects.equals(calendarId, other.calendarId);
|
||||
}
|
||||
}
|
||||
|
||||
public static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||
|
||||
public RequestBuilder(ElasticsearchClient client, DeleteCalendarEventAction action) {
|
||||
super(client, action, new Request());
|
||||
}
|
||||
}
|
||||
|
||||
public static class Response extends AcknowledgedResponse {
|
||||
|
||||
public Response(boolean acknowledged) {
|
||||
super(acknowledged);
|
||||
}
|
||||
|
||||
private Response() {}
|
||||
|
||||
@Override
|
||||
public void readFrom(StreamInput in) throws IOException {
|
||||
super.readFrom(in);
|
||||
readAcknowledged(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(StreamOutput out) throws IOException {
|
||||
super.writeTo(out);
|
||||
writeAcknowledged(out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
package org.elasticsearch.xpack.ml.calendars;
|
||||
|
||||
import org.elasticsearch.common.ParseField;
|
||||
import org.elasticsearch.common.inject.internal.Nullable;
|
||||
import org.elasticsearch.common.io.stream.StreamInput;
|
||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||
import org.elasticsearch.common.io.stream.Writeable;
|
||||
|
@ -39,6 +40,7 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
public static final ParseField START_TIME = new ParseField("start_time");
|
||||
public static final ParseField END_TIME = new ParseField("end_time");
|
||||
public static final ParseField TYPE = new ParseField("type");
|
||||
public static final ParseField EVENT_ID = new ParseField("event_id");
|
||||
|
||||
public static final ParseField RESULTS_FIELD = new ParseField("events");
|
||||
|
||||
|
@ -81,12 +83,14 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
private final ZonedDateTime startTime;
|
||||
private final ZonedDateTime endTime;
|
||||
private final String calendarId;
|
||||
private final String eventId;
|
||||
|
||||
ScheduledEvent(String description, ZonedDateTime startTime, ZonedDateTime endTime, String calendarId) {
|
||||
ScheduledEvent(String description, ZonedDateTime startTime, ZonedDateTime endTime, String calendarId, @Nullable String eventId) {
|
||||
this.description = Objects.requireNonNull(description);
|
||||
this.startTime = Objects.requireNonNull(startTime);
|
||||
this.endTime = Objects.requireNonNull(endTime);
|
||||
this.calendarId = Objects.requireNonNull(calendarId);
|
||||
this.eventId = eventId;
|
||||
}
|
||||
|
||||
public ScheduledEvent(StreamInput in) throws IOException {
|
||||
|
@ -94,6 +98,7 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
startTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(in.readVLong()), ZoneOffset.UTC);
|
||||
endTime = ZonedDateTime.ofInstant(Instant.ofEpochMilli(in.readVLong()), ZoneOffset.UTC);
|
||||
calendarId = in.readString();
|
||||
eventId = in.readOptionalString();
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
|
@ -112,6 +117,10 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
return calendarId;
|
||||
}
|
||||
|
||||
public String getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the scheduled event to a detection rule.
|
||||
* The rule will have 2 time based conditions for the start and
|
||||
|
@ -146,6 +155,7 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
out.writeVLong(startTime.toInstant().toEpochMilli());
|
||||
out.writeVLong(endTime.toInstant().toEpochMilli());
|
||||
out.writeString(calendarId);
|
||||
out.writeOptionalString(eventId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -155,6 +165,9 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
builder.dateField(START_TIME.getPreferredName(), START_TIME.getPreferredName() + "_string", startTime.toInstant().toEpochMilli());
|
||||
builder.dateField(END_TIME.getPreferredName(), END_TIME.getPreferredName() + "_string", endTime.toInstant().toEpochMilli());
|
||||
builder.field(Calendar.ID.getPreferredName(), calendarId);
|
||||
if (eventId != null) {
|
||||
builder.field(EVENT_ID.getPreferredName(), eventId);
|
||||
}
|
||||
if (params.paramAsBoolean(MlMetaIndex.INCLUDE_TYPE_KEY, false)) {
|
||||
builder.field(TYPE.getPreferredName(), SCHEDULED_EVENT_TYPE);
|
||||
}
|
||||
|
@ -197,7 +210,7 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
private ZonedDateTime startTime;
|
||||
private ZonedDateTime endTime;
|
||||
private String calendarId;
|
||||
|
||||
private String eventId;
|
||||
|
||||
public Builder description(String description) {
|
||||
this.description = description;
|
||||
|
@ -223,6 +236,11 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
return calendarId;
|
||||
}
|
||||
|
||||
public Builder eventId(String eventId) {
|
||||
this.eventId = eventId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScheduledEvent build() {
|
||||
if (description == null) {
|
||||
throw ExceptionsHelper.badRequestException(
|
||||
|
@ -249,7 +267,9 @@ public class ScheduledEvent implements ToXContentObject, Writeable {
|
|||
"] must come before end time [" + endTime + "]");
|
||||
}
|
||||
|
||||
return new ScheduledEvent(description, startTime, endTime, calendarId);
|
||||
ScheduledEvent event = new ScheduledEvent(description, startTime, endTime, calendarId, eventId);
|
||||
|
||||
return event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1062,14 +1062,16 @@ public class JobProvider {
|
|||
List<ScheduledEvent> events = new ArrayList<>();
|
||||
SearchHit[] hits = response.getHits().getHits();
|
||||
for (SearchHit hit : hits) {
|
||||
events.add(parseSearchHit(hit, ScheduledEvent.PARSER, handler::onFailure).build());
|
||||
ScheduledEvent.Builder event = parseSearchHit(hit, ScheduledEvent.PARSER, handler::onFailure);
|
||||
event.eventId(hit.getId());
|
||||
events.add(event.build());
|
||||
}
|
||||
|
||||
handler.onResponse(new QueryPage<>(events, response.getHits().getTotalHits(),
|
||||
ScheduledEvent.RESULTS_FIELD));
|
||||
},
|
||||
handler::onFailure)
|
||||
, client::search);
|
||||
handler::onFailure),
|
||||
client::search);
|
||||
}
|
||||
|
||||
public void getForecastRequestStats(String jobId, String forecastId, Consumer<ForecastRequestStats> handler,
|
||||
|
|
|
@ -24,8 +24,8 @@ import java.util.List;
|
|||
public class ScheduledEventsQueryBuilder {
|
||||
public static final int DEFAULT_SIZE = 1000;
|
||||
|
||||
private int from = 0;
|
||||
private int size = DEFAULT_SIZE;
|
||||
private Integer from = 0;
|
||||
private Integer size = DEFAULT_SIZE;
|
||||
|
||||
private List<String> calendarIds;
|
||||
private String after;
|
||||
|
@ -46,12 +46,22 @@ public class ScheduledEventsQueryBuilder {
|
|||
return this;
|
||||
}
|
||||
|
||||
public ScheduledEventsQueryBuilder from(int from) {
|
||||
/**
|
||||
* Set the query from parameter.
|
||||
* @param from If null then no from will be set
|
||||
* @return this
|
||||
*/
|
||||
public ScheduledEventsQueryBuilder from(Integer from) {
|
||||
this.from = from;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScheduledEventsQueryBuilder size(int size) {
|
||||
/**
|
||||
* Set the query size parameter.
|
||||
* @param size If null then no size will be set
|
||||
* @return this
|
||||
*/
|
||||
public ScheduledEventsQueryBuilder size(Integer size) {
|
||||
this.size = size;
|
||||
return this;
|
||||
}
|
||||
|
@ -78,8 +88,12 @@ public class ScheduledEventsQueryBuilder {
|
|||
|
||||
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
|
||||
searchSourceBuilder.sort(ScheduledEvent.START_TIME.getPreferredName());
|
||||
if (from != null) {
|
||||
searchSourceBuilder.from(from);
|
||||
}
|
||||
if (size != null) {
|
||||
searchSourceBuilder.size(size);
|
||||
}
|
||||
|
||||
if (queries.isEmpty()) {
|
||||
searchSourceBuilder.query(typeQuery);
|
||||
|
|
|
@ -52,6 +52,11 @@ import org.elasticsearch.xpack.XPackPlugin;
|
|||
import org.elasticsearch.xpack.XPackSettings;
|
||||
import org.elasticsearch.xpack.ml.action.CloseJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteCalendarAction;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteCalendarEventAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetCalendarEventsAction;
|
||||
import org.elasticsearch.xpack.ml.action.PostCalendarEventsAction;
|
||||
import org.elasticsearch.xpack.ml.action.TransportDeleteCalendarEventAction;
|
||||
import org.elasticsearch.xpack.ml.action.UpdateCalendarJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteDatafeedAction;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteExpiredDataAction;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteFilterAction;
|
||||
|
@ -61,7 +66,6 @@ import org.elasticsearch.xpack.ml.action.FinalizeJobExecutionAction;
|
|||
import org.elasticsearch.xpack.ml.action.FlushJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.ForecastJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetBucketsAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetCalendarEventsAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetCalendarsAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetCategoriesAction;
|
||||
import org.elasticsearch.xpack.ml.action.GetDatafeedsAction;
|
||||
|
@ -76,7 +80,6 @@ import org.elasticsearch.xpack.ml.action.GetRecordsAction;
|
|||
import org.elasticsearch.xpack.ml.action.IsolateDatafeedAction;
|
||||
import org.elasticsearch.xpack.ml.action.KillProcessAction;
|
||||
import org.elasticsearch.xpack.ml.action.OpenJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.PostCalendarEventsAction;
|
||||
import org.elasticsearch.xpack.ml.action.PostDataAction;
|
||||
import org.elasticsearch.xpack.ml.action.PreviewDatafeedAction;
|
||||
import org.elasticsearch.xpack.ml.action.PutCalendarAction;
|
||||
|
@ -129,7 +132,6 @@ import org.elasticsearch.xpack.ml.action.TransportUpdateModelSnapshotAction;
|
|||
import org.elasticsearch.xpack.ml.action.TransportUpdateProcessAction;
|
||||
import org.elasticsearch.xpack.ml.action.TransportValidateDetectorAction;
|
||||
import org.elasticsearch.xpack.ml.action.TransportValidateJobConfigAction;
|
||||
import org.elasticsearch.xpack.ml.action.UpdateCalendarJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.UpdateDatafeedAction;
|
||||
import org.elasticsearch.xpack.ml.action.UpdateJobAction;
|
||||
import org.elasticsearch.xpack.ml.action.UpdateModelSnapshotAction;
|
||||
|
@ -163,6 +165,7 @@ import org.elasticsearch.xpack.ml.notifications.AuditMessage;
|
|||
import org.elasticsearch.xpack.ml.notifications.Auditor;
|
||||
import org.elasticsearch.xpack.ml.rest.RestDeleteExpiredDataAction;
|
||||
import org.elasticsearch.xpack.ml.rest.calendar.RestDeleteCalendarAction;
|
||||
import org.elasticsearch.xpack.ml.rest.calendar.RestDeleteCalendarEventAction;
|
||||
import org.elasticsearch.xpack.ml.rest.calendar.RestDeleteCalendarJobAction;
|
||||
import org.elasticsearch.xpack.ml.rest.calendar.RestGetCalendarEventsAction;
|
||||
import org.elasticsearch.xpack.ml.rest.calendar.RestGetCalendarsAction;
|
||||
|
@ -513,6 +516,7 @@ public class MachineLearning implements MachineLearningClientActionPlugin, Actio
|
|||
new RestGetCalendarsAction(settings, restController),
|
||||
new RestPutCalendarAction(settings, restController),
|
||||
new RestDeleteCalendarAction(settings, restController),
|
||||
new RestDeleteCalendarEventAction(settings, restController),
|
||||
new RestDeleteCalendarJobAction(settings, restController),
|
||||
new RestPutCalendarJobAction(settings, restController),
|
||||
new RestGetCalendarEventsAction(settings, restController),
|
||||
|
@ -566,6 +570,7 @@ public class MachineLearning implements MachineLearningClientActionPlugin, Actio
|
|||
new ActionHandler<>(GetCalendarsAction.INSTANCE, TransportGetCalendarsAction.class),
|
||||
new ActionHandler<>(PutCalendarAction.INSTANCE, TransportPutCalendarAction.class),
|
||||
new ActionHandler<>(DeleteCalendarAction.INSTANCE, TransportDeleteCalendarAction.class),
|
||||
new ActionHandler<>(DeleteCalendarEventAction.INSTANCE, TransportDeleteCalendarEventAction.class),
|
||||
new ActionHandler<>(UpdateCalendarJobAction.INSTANCE, TransportUpdateCalendarJobAction.class),
|
||||
new ActionHandler<>(GetCalendarEventsAction.INSTANCE, TransportGetCalendarEventsAction.class),
|
||||
new ActionHandler<>(PostCalendarEventsAction.INSTANCE, TransportPostCalendarEventsAction.class)
|
||||
|
|
|
@ -7,18 +7,21 @@ package org.elasticsearch.xpack.ml.action;
|
|||
|
||||
import org.elasticsearch.ResourceNotFoundException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.bulk.BulkAction;
|
||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
||||
import org.elasticsearch.action.bulk.BulkResponse;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.get.GetAction;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.search.SearchRequest;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.index.query.QueryBuilder;
|
||||
import org.elasticsearch.index.query.QueryBuilders;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryAction;
|
||||
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||
|
@ -47,27 +50,41 @@ public class TransportDeleteCalendarAction extends HandledTransportAction<Delete
|
|||
|
||||
final String calendarId = request.getCalendarId();
|
||||
|
||||
DeleteRequest deleteRequest = new DeleteRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, Calendar.documentId(calendarId));
|
||||
|
||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
||||
bulkRequestBuilder.add(deleteRequest);
|
||||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
executeAsyncWithOrigin(client, ML_ORIGIN, BulkAction.INSTANCE, bulkRequestBuilder.request(),
|
||||
new ActionListener<BulkResponse>() {
|
||||
GetRequest getRequest = new GetRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, Calendar.documentId(calendarId));
|
||||
executeAsyncWithOrigin(client, ML_ORIGIN, GetAction.INSTANCE, getRequest, new ActionListener<GetResponse>() {
|
||||
@Override
|
||||
public void onResponse(BulkResponse bulkResponse) {
|
||||
if (bulkResponse.getItems()[0].status() == RestStatus.NOT_FOUND) {
|
||||
listener.onFailure(new ResourceNotFoundException("Could not delete calendar with ID [" + calendarId
|
||||
public void onResponse(GetResponse getResponse) {
|
||||
if (getResponse.isExists() == false) {
|
||||
listener.onFailure(new ResourceNotFoundException("Could not delete calendar [" + calendarId
|
||||
+ "] because it does not exist"));
|
||||
} else {
|
||||
listener.onResponse(new DeleteCalendarAction.Response(true));
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete calendar and events
|
||||
DeleteByQueryRequest dbqRequest = buildDeleteByQuery(calendarId);
|
||||
executeAsyncWithOrigin(client, ML_ORIGIN, DeleteByQueryAction.INSTANCE, dbqRequest, ActionListener.wrap(
|
||||
response -> listener.onResponse(new DeleteCalendarAction.Response(true)),
|
||||
listener::onFailure));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
listener.onFailure(ExceptionsHelper.serverError("Could not delete calendar with ID [" + calendarId + "]", e));
|
||||
}
|
||||
});
|
||||
listener.onFailure(ExceptionsHelper.serverError("Could not delete calendar [" + calendarId + "]", e));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private DeleteByQueryRequest buildDeleteByQuery(String calendarId) {
|
||||
SearchRequest searchRequest = new SearchRequest(MlMetaIndex.INDEX_NAME);
|
||||
// The DBQ request constructor wipes the search request source
|
||||
// so it has to be set after
|
||||
DeleteByQueryRequest request = new DeleteByQueryRequest(searchRequest);
|
||||
request.setSlices(5);
|
||||
request.setRefresh(true);
|
||||
|
||||
QueryBuilder query = QueryBuilders.termsQuery(Calendar.ID.getPreferredName(), calendarId);
|
||||
searchRequest.source(new SearchSourceBuilder().query(query));
|
||||
return request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.xpack.ml.action;
|
||||
|
||||
import org.elasticsearch.ElasticsearchStatusException;
|
||||
import org.elasticsearch.ResourceNotFoundException;
|
||||
import org.elasticsearch.action.ActionListener;
|
||||
import org.elasticsearch.action.delete.DeleteAction;
|
||||
import org.elasticsearch.action.delete.DeleteRequest;
|
||||
import org.elasticsearch.action.delete.DeleteResponse;
|
||||
import org.elasticsearch.action.get.GetAction;
|
||||
import org.elasticsearch.action.get.GetRequest;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.support.ActionFilters;
|
||||
import org.elasticsearch.action.support.HandledTransportAction;
|
||||
import org.elasticsearch.action.support.WriteRequest;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||
import org.elasticsearch.common.inject.Inject;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
||||
|
||||
public class TransportDeleteCalendarEventAction extends HandledTransportAction<DeleteCalendarEventAction.Request,
|
||||
DeleteCalendarEventAction.Response> {
|
||||
|
||||
private final Client client;
|
||||
|
||||
@Inject
|
||||
public TransportDeleteCalendarEventAction(Settings settings, ThreadPool threadPool,
|
||||
TransportService transportService, ActionFilters actionFilters,
|
||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||
Client client) {
|
||||
super(settings, DeleteCalendarEventAction.NAME, threadPool, transportService, actionFilters,
|
||||
indexNameExpressionResolver, DeleteCalendarEventAction.Request::new);
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doExecute(DeleteCalendarEventAction.Request request, ActionListener<DeleteCalendarEventAction.Response> listener) {
|
||||
final String eventId = request.getEventId();
|
||||
|
||||
GetRequest getRequest = new GetRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, eventId);
|
||||
executeAsyncWithOrigin(client, ML_ORIGIN, GetAction.INSTANCE, getRequest, new ActionListener<GetResponse>() {
|
||||
@Override
|
||||
public void onResponse(GetResponse getResponse) {
|
||||
if (getResponse.isExists() == false) {
|
||||
listener.onFailure(new ResourceNotFoundException("Missing event [" + eventId + "]"));
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> source = getResponse.getSourceAsMap();
|
||||
String calendarId = (String) source.get(Calendar.ID.getPreferredName());
|
||||
if (calendarId == null) {
|
||||
listener.onFailure(new ElasticsearchStatusException("Event [" + eventId + "] does not have a valid "
|
||||
+ Calendar.ID.getPreferredName(), RestStatus.BAD_REQUEST));
|
||||
return;
|
||||
}
|
||||
|
||||
if (calendarId.equals(request.getCalendarId()) == false) {
|
||||
listener.onFailure(new ElasticsearchStatusException(
|
||||
"Event [" + eventId + "] has " + Calendar.ID.getPreferredName() +
|
||||
" [" + calendarId + "] which does not match the request " + Calendar.ID.getPreferredName() +
|
||||
" [" + request.getCalendarId() + "]", RestStatus.BAD_REQUEST));
|
||||
return;
|
||||
}
|
||||
|
||||
deleteEvent(eventId, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
listener.onFailure(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void deleteEvent(String eventId, ActionListener<DeleteCalendarEventAction.Response> listener) {
|
||||
DeleteRequest deleteRequest = new DeleteRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, eventId);
|
||||
deleteRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||
|
||||
executeAsyncWithOrigin(client, ML_ORIGIN, DeleteAction.INSTANCE, deleteRequest,
|
||||
new ActionListener<DeleteResponse>() {
|
||||
@Override
|
||||
public void onResponse(DeleteResponse response) {
|
||||
|
||||
if (response.status() == RestStatus.NOT_FOUND) {
|
||||
listener.onFailure(new ResourceNotFoundException("Could not delete event [" + eventId
|
||||
+ "] because it does not exist"));
|
||||
} else {
|
||||
listener.onResponse(new DeleteCalendarEventAction.Response(true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
listener.onFailure(ExceptionsHelper.serverError("Could not delete event [" + eventId + "]", e));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.xpack.ml.rest.calendar;
|
||||
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.rest.BaseRestHandler;
|
||||
import org.elasticsearch.rest.RestController;
|
||||
import org.elasticsearch.rest.RestRequest;
|
||||
import org.elasticsearch.rest.action.AcknowledgedRestListener;
|
||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteCalendarEventAction;
|
||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||
import org.elasticsearch.xpack.ml.calendars.ScheduledEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class RestDeleteCalendarEventAction extends BaseRestHandler {
|
||||
|
||||
public RestDeleteCalendarEventAction(Settings settings, RestController controller) {
|
||||
super(settings);
|
||||
controller.registerHandler(RestRequest.Method.DELETE,
|
||||
MachineLearning.BASE_PATH + "calendars/{" + Calendar.ID.getPreferredName() + "}/events/{" +
|
||||
ScheduledEvent.EVENT_ID.getPreferredName() + "}", this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "xpack_ml_delete_calendar_event_action";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseRestHandler.RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||
String eventId = restRequest.param(ScheduledEvent.EVENT_ID.getPreferredName());
|
||||
String calendarId = restRequest.param(Calendar.ID.getPreferredName());
|
||||
DeleteCalendarEventAction.Request request = new DeleteCalendarEventAction.Request(calendarId, eventId);
|
||||
return channel -> client.execute(DeleteCalendarEventAction.INSTANCE, request, new AcknowledgedRestListener<>(channel));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.xpack.ml.action;
|
||||
|
||||
import org.elasticsearch.test.AbstractStreamableTestCase;
|
||||
import org.elasticsearch.xpack.ml.action.DeleteCalendarEventAction.Request;
|
||||
|
||||
public class DeleteCalendarEventActionRequestTests extends AbstractStreamableTestCase<DeleteCalendarEventAction.Request> {
|
||||
|
||||
@Override
|
||||
protected Request createTestInstance() {
|
||||
return new Request(randomAlphaOfLengthBetween(1, 20), randomAlphaOfLengthBetween(1, 20));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Request createBlankInstance() {
|
||||
return new Request();
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ public class ScheduledEventTests extends AbstractSerializingTestCase<ScheduledEv
|
|||
public static ScheduledEvent createScheduledEvent(String calendarId) {
|
||||
ZonedDateTime start = ZonedDateTime.ofInstant(Instant.ofEpochMilli(new DateTime(randomDateTimeZone()).getMillis()), ZoneOffset.UTC);
|
||||
return new ScheduledEvent(randomAlphaOfLength(10), start, start.plusSeconds(randomIntBetween(1, 10000)),
|
||||
calendarId);
|
||||
calendarId, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"xpack.ml.delete_calendar_event": {
|
||||
"methods": [ "DELETE" ],
|
||||
"url": {
|
||||
"path": "/_xpack/ml/calendars/{calendar_id}/events/{event_id}",
|
||||
"paths": [ "/_xpack/ml/calendars/{calendar_id}/events/{event_id}" ],
|
||||
"parts": {
|
||||
"calendar_id": {
|
||||
"type" : "string",
|
||||
"required" : true,
|
||||
"description" : "The ID of the calendar to modify"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"required": true,
|
||||
"description": "The ID of the event to remove from the calendar"
|
||||
}
|
||||
}
|
||||
},
|
||||
"body": null
|
||||
}
|
||||
}
|
|
@ -241,7 +241,7 @@
|
|||
job_id: "missing job"
|
||||
|
||||
---
|
||||
"Test calendar events":
|
||||
"Test calendar get events":
|
||||
|
||||
- do:
|
||||
xpack.ml.put_calendar:
|
||||
|
@ -264,6 +264,8 @@
|
|||
- match: { events.1.description: "event 2" }
|
||||
- match: { events.2.description: "event 3" }
|
||||
- match: { events.3.description: "event 4" }
|
||||
- is_true: events.0.event_id
|
||||
- set: { events.0.event_id: event_1_id }
|
||||
|
||||
- do:
|
||||
xpack.ml.get_calendar_events:
|
||||
|
@ -299,6 +301,98 @@
|
|||
- length: { events: 1 }
|
||||
- match: { events.0.description: "event 2" }
|
||||
|
||||
- do:
|
||||
xpack.ml.put_calendar:
|
||||
calendar_id: "events-2"
|
||||
|
||||
- do:
|
||||
xpack.ml.post_calendar_events:
|
||||
calendar_id: "events-2"
|
||||
body: >
|
||||
{ "description": "event 21", "start_time": "2017-12-02T00:00:00Z", "end_time": "2017-12-02T05:00:00Z"}
|
||||
{ "description": "event 22", "start_time": "2017-12-25T00:00:00Z", "end_time": "2017-12-26T00:00:00Z"}
|
||||
|
||||
- do:
|
||||
catch: bad_request
|
||||
xpack.ml.post_calendar_events:
|
||||
calendar_id: "events-2"
|
||||
body: >
|
||||
{ "description": "event 21", "start_time": "2017-12-02T00:00:00Z", "end_time": "2017-12-03T00:00:00Z", "calendar_id": "events"}
|
||||
|
||||
# Event is not in calendar events-2
|
||||
- do:
|
||||
catch: bad_request
|
||||
xpack.ml.delete_calendar_event:
|
||||
calendar_id: "events-2"
|
||||
event_id: $event_1_id
|
||||
|
||||
- do:
|
||||
xpack.ml.delete_calendar_event:
|
||||
calendar_id: "events"
|
||||
event_id: $event_1_id
|
||||
|
||||
- do:
|
||||
catch: missing
|
||||
xpack.ml.delete_calendar_event:
|
||||
calendar_id: "events"
|
||||
event_id: "missing event"
|
||||
|
||||
|
||||
---
|
||||
"Test delete calendar deletes events":
|
||||
|
||||
- do:
|
||||
xpack.ml.put_calendar:
|
||||
calendar_id: "cal-foo"
|
||||
|
||||
- do:
|
||||
xpack.ml.post_calendar_events:
|
||||
calendar_id: "cal-foo"
|
||||
body: >
|
||||
{ "description": "event 1", "start_time": "2017-12-01T00:00:00Z", "end_time": "2017-12-02T00:00:00Z" }
|
||||
{ "description": "event 2", "start_time": "2017-12-05T00:00:00Z", "end_time": "2017-12-06T00:00:00Z" }
|
||||
{ "description": "event 2", "start_time": "2017-12-05T00:00:00Z", "end_time": "2017-12-06T00:00:00Z" }
|
||||
|
||||
- do:
|
||||
xpack.ml.put_calendar:
|
||||
calendar_id: "cal-bar"
|
||||
|
||||
- do:
|
||||
xpack.ml.post_calendar_events:
|
||||
calendar_id: "cal-bar"
|
||||
body: >
|
||||
{ "description": "event 21", "start_time": "2017-12-02T00:00:00Z", "end_time": "2017-12-02T05:00:00Z"}
|
||||
{ "description": "event 22", "start_time": "2017-12-25T00:00:00Z", "end_time": "2017-12-26T00:00:00Z"}
|
||||
|
||||
- do:
|
||||
xpack.ml.delete_calendar:
|
||||
calendar_id: "cal-foo"
|
||||
|
||||
# Check the event from calendar 1 is deleted
|
||||
- do:
|
||||
count:
|
||||
index: .ml-meta
|
||||
body:
|
||||
query:
|
||||
constant_score:
|
||||
filter:
|
||||
term:
|
||||
type: scheduled_event
|
||||
- match: { count: 2 }
|
||||
|
||||
- do:
|
||||
count:
|
||||
index: .ml-meta
|
||||
body:
|
||||
query:
|
||||
bool:
|
||||
must:
|
||||
- term:
|
||||
type: scheduled_event
|
||||
- term:
|
||||
calendar_id: cal-foo
|
||||
- match: { count: 0 }
|
||||
|
||||
---
|
||||
"Test get all calendar events":
|
||||
|
||||
|
@ -386,6 +480,7 @@
|
|||
{ "description": "random2", "start_time": "2018-02-20T00:00:00Z", "end_time": "2018-02-26T00:00:00Z" }
|
||||
|
||||
|
||||
# Calendar Id must be _all if a job id is used
|
||||
- do:
|
||||
catch: /action_request_validation_exception/
|
||||
xpack.ml.get_calendar_events:
|
||||
|
|
Loading…
Reference in New Issue