[ML] Special events calendar CRUD endpoints (elastic/x-pack-elasticsearch#3267)
* Calendar CRUD endpoints * Get calendars requires monitor permission * Address review comments * Add page params to get calendars Original commit: elastic/x-pack-elasticsearch@badd1e6add
This commit is contained in:
parent
249d06b256
commit
6113b86bdb
|
@ -52,6 +52,7 @@ import org.elasticsearch.xpack.XPackFeatureSet;
|
||||||
import org.elasticsearch.xpack.XPackPlugin;
|
import org.elasticsearch.xpack.XPackPlugin;
|
||||||
import org.elasticsearch.xpack.XPackSettings;
|
import org.elasticsearch.xpack.XPackSettings;
|
||||||
import org.elasticsearch.xpack.ml.action.CloseJobAction;
|
import org.elasticsearch.xpack.ml.action.CloseJobAction;
|
||||||
|
import org.elasticsearch.xpack.ml.action.DeleteCalendarAction;
|
||||||
import org.elasticsearch.xpack.ml.action.DeleteDatafeedAction;
|
import org.elasticsearch.xpack.ml.action.DeleteDatafeedAction;
|
||||||
import org.elasticsearch.xpack.ml.action.DeleteExpiredDataAction;
|
import org.elasticsearch.xpack.ml.action.DeleteExpiredDataAction;
|
||||||
import org.elasticsearch.xpack.ml.action.DeleteFilterAction;
|
import org.elasticsearch.xpack.ml.action.DeleteFilterAction;
|
||||||
|
@ -61,6 +62,7 @@ import org.elasticsearch.xpack.ml.action.FinalizeJobExecutionAction;
|
||||||
import org.elasticsearch.xpack.ml.action.FlushJobAction;
|
import org.elasticsearch.xpack.ml.action.FlushJobAction;
|
||||||
import org.elasticsearch.xpack.ml.action.ForecastJobAction;
|
import org.elasticsearch.xpack.ml.action.ForecastJobAction;
|
||||||
import org.elasticsearch.xpack.ml.action.GetBucketsAction;
|
import org.elasticsearch.xpack.ml.action.GetBucketsAction;
|
||||||
|
import org.elasticsearch.xpack.ml.action.GetCalendarsAction;
|
||||||
import org.elasticsearch.xpack.ml.action.GetCategoriesAction;
|
import org.elasticsearch.xpack.ml.action.GetCategoriesAction;
|
||||||
import org.elasticsearch.xpack.ml.action.GetDatafeedsAction;
|
import org.elasticsearch.xpack.ml.action.GetDatafeedsAction;
|
||||||
import org.elasticsearch.xpack.ml.action.GetDatafeedsStatsAction;
|
import org.elasticsearch.xpack.ml.action.GetDatafeedsStatsAction;
|
||||||
|
@ -76,6 +78,7 @@ import org.elasticsearch.xpack.ml.action.KillProcessAction;
|
||||||
import org.elasticsearch.xpack.ml.action.OpenJobAction;
|
import org.elasticsearch.xpack.ml.action.OpenJobAction;
|
||||||
import org.elasticsearch.xpack.ml.action.PostDataAction;
|
import org.elasticsearch.xpack.ml.action.PostDataAction;
|
||||||
import org.elasticsearch.xpack.ml.action.PreviewDatafeedAction;
|
import org.elasticsearch.xpack.ml.action.PreviewDatafeedAction;
|
||||||
|
import org.elasticsearch.xpack.ml.action.PutCalendarAction;
|
||||||
import org.elasticsearch.xpack.ml.action.PutDatafeedAction;
|
import org.elasticsearch.xpack.ml.action.PutDatafeedAction;
|
||||||
import org.elasticsearch.xpack.ml.action.PutFilterAction;
|
import org.elasticsearch.xpack.ml.action.PutFilterAction;
|
||||||
import org.elasticsearch.xpack.ml.action.PutJobAction;
|
import org.elasticsearch.xpack.ml.action.PutJobAction;
|
||||||
|
@ -114,6 +117,9 @@ import org.elasticsearch.xpack.ml.job.process.normalizer.NormalizerProcessFactor
|
||||||
import org.elasticsearch.xpack.ml.notifications.AuditMessage;
|
import org.elasticsearch.xpack.ml.notifications.AuditMessage;
|
||||||
import org.elasticsearch.xpack.ml.notifications.Auditor;
|
import org.elasticsearch.xpack.ml.notifications.Auditor;
|
||||||
import org.elasticsearch.xpack.ml.rest.RestDeleteExpiredDataAction;
|
import org.elasticsearch.xpack.ml.rest.RestDeleteExpiredDataAction;
|
||||||
|
import org.elasticsearch.xpack.ml.rest.calendar.RestDeleteCalendarAction;
|
||||||
|
import org.elasticsearch.xpack.ml.rest.calendar.RestGetCalendarsAction;
|
||||||
|
import org.elasticsearch.xpack.ml.rest.calendar.RestPutCalendarAction;
|
||||||
import org.elasticsearch.xpack.ml.rest.datafeeds.RestDeleteDatafeedAction;
|
import org.elasticsearch.xpack.ml.rest.datafeeds.RestDeleteDatafeedAction;
|
||||||
import org.elasticsearch.xpack.ml.rest.datafeeds.RestGetDatafeedStatsAction;
|
import org.elasticsearch.xpack.ml.rest.datafeeds.RestGetDatafeedStatsAction;
|
||||||
import org.elasticsearch.xpack.ml.rest.datafeeds.RestGetDatafeedsAction;
|
import org.elasticsearch.xpack.ml.rest.datafeeds.RestGetDatafeedsAction;
|
||||||
|
@ -458,7 +464,10 @@ public class MachineLearning implements ActionPlugin {
|
||||||
new RestStopDatafeedAction(settings, restController),
|
new RestStopDatafeedAction(settings, restController),
|
||||||
new RestDeleteModelSnapshotAction(settings, restController),
|
new RestDeleteModelSnapshotAction(settings, restController),
|
||||||
new RestDeleteExpiredDataAction(settings, restController),
|
new RestDeleteExpiredDataAction(settings, restController),
|
||||||
new RestForecastJobAction(settings, restController)
|
new RestForecastJobAction(settings, restController),
|
||||||
|
new RestGetCalendarsAction(settings, restController),
|
||||||
|
new RestPutCalendarAction(settings, restController),
|
||||||
|
new RestDeleteCalendarAction(settings, restController)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,7 +513,10 @@ public class MachineLearning implements ActionPlugin {
|
||||||
new ActionHandler<>(DeleteModelSnapshotAction.INSTANCE, DeleteModelSnapshotAction.TransportAction.class),
|
new ActionHandler<>(DeleteModelSnapshotAction.INSTANCE, DeleteModelSnapshotAction.TransportAction.class),
|
||||||
new ActionHandler<>(UpdateProcessAction.INSTANCE, UpdateProcessAction.TransportAction.class),
|
new ActionHandler<>(UpdateProcessAction.INSTANCE, UpdateProcessAction.TransportAction.class),
|
||||||
new ActionHandler<>(DeleteExpiredDataAction.INSTANCE, DeleteExpiredDataAction.TransportAction.class),
|
new ActionHandler<>(DeleteExpiredDataAction.INSTANCE, DeleteExpiredDataAction.TransportAction.class),
|
||||||
new ActionHandler<>(ForecastJobAction.INSTANCE, ForecastJobAction.TransportAction.class)
|
new ActionHandler<>(ForecastJobAction.INSTANCE, ForecastJobAction.TransportAction.class),
|
||||||
|
new ActionHandler<>(GetCalendarsAction.INSTANCE, GetCalendarsAction.TransportAction.class),
|
||||||
|
new ActionHandler<>(PutCalendarAction.INSTANCE, PutCalendarAction.TransportAction.class),
|
||||||
|
new ActionHandler<>(DeleteCalendarAction.INSTANCE, DeleteCalendarAction.TransportAction.class)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@ public final class MlMetaIndex {
|
||||||
*/
|
*/
|
||||||
public static final String INDEX_NAME = ".ml-meta";
|
public static final String INDEX_NAME = ".ml-meta";
|
||||||
|
|
||||||
|
public static final String INCLUDE_TYPE_KEY = "include_type";
|
||||||
|
|
||||||
public static final String TYPE = "doc";
|
public static final String TYPE = "doc";
|
||||||
|
|
||||||
private MlMetaIndex() {}
|
private MlMetaIndex() {}
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* 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.ResourceNotFoundException;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionListener;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
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.support.ActionFilters;
|
||||||
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
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.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.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
||||||
|
|
||||||
|
public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, DeleteCalendarAction.Response,
|
||||||
|
DeleteCalendarAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final DeleteCalendarAction INSTANCE = new DeleteCalendarAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/calendars/delete";
|
||||||
|
|
||||||
|
private DeleteCalendarAction() {
|
||||||
|
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;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String calendarId) {
|
||||||
|
this.calendarId = ExceptionsHelper.requireNonNull(calendarId, Calendar.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalendarId() {
|
||||||
|
return calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
calendarId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(calendarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(calendarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(calendarId, other.calendarId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends ActionRequestBuilder<Request, Response,
|
||||||
|
RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, DeleteCalendarAction 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TransportAction extends HandledTransportAction<DeleteCalendarAction.Request, DeleteCalendarAction.Response> {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TransportAction(Settings settings, ThreadPool threadPool,
|
||||||
|
TransportService transportService, ActionFilters actionFilters,
|
||||||
|
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||||
|
Client client) {
|
||||||
|
super(settings, NAME, threadPool, transportService, actionFilters,
|
||||||
|
indexNameExpressionResolver, Request::new);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doExecute(DeleteCalendarAction.Request request, ActionListener<DeleteCalendarAction.Response> listener) {
|
||||||
|
|
||||||
|
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>() {
|
||||||
|
@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
|
||||||
|
+ "] because it does not exist"));
|
||||||
|
} else {
|
||||||
|
listener.onResponse(new Response(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
listener.onFailure(ExceptionsHelper.serverError("Could not delete calendar with ID [" + calendarId + "]", e));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,314 @@
|
||||||
|
/*
|
||||||
|
* 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.ActionListener;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.ActionResponse;
|
||||||
|
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.search.SearchResponse;
|
||||||
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
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.NamedXContentRegistry;
|
||||||
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
|
import org.elasticsearch.search.SearchHit;
|
||||||
|
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||||
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
|
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
||||||
|
|
||||||
|
public class GetCalendarsAction extends Action<GetCalendarsAction.Request, GetCalendarsAction.Response, GetCalendarsAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final GetCalendarsAction INSTANCE = new GetCalendarsAction();
|
||||||
|
public static final String NAME = "cluster:monitor/xpack/ml/calendars/get";
|
||||||
|
|
||||||
|
private GetCalendarsAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest {
|
||||||
|
|
||||||
|
private String calendarId;
|
||||||
|
private PageParams pageParams;
|
||||||
|
|
||||||
|
public Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCalendarId(String calendarId) {
|
||||||
|
this.calendarId = calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCalendarId() {
|
||||||
|
return calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageParams getPageParams() {
|
||||||
|
return pageParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageParams(PageParams pageParams) {
|
||||||
|
this.pageParams = pageParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
ActionRequestValidationException validationException = null;
|
||||||
|
|
||||||
|
if (calendarId != null && pageParams != null) {
|
||||||
|
validationException = addValidationError("Params [" + PageParams.FROM.getPreferredName()
|
||||||
|
+ ", " + PageParams.SIZE.getPreferredName() + "] are incompatible with ["
|
||||||
|
+ Calendar.ID.getPreferredName() + "].",
|
||||||
|
validationException);
|
||||||
|
}
|
||||||
|
return validationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
calendarId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(calendarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(calendarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(calendarId, other.calendarId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client) {
|
||||||
|
super(client, INSTANCE, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends ActionResponse implements StatusToXContentObject {
|
||||||
|
|
||||||
|
private QueryPage<Calendar> calendars;
|
||||||
|
|
||||||
|
public Response(QueryPage<Calendar> calendars) {
|
||||||
|
this.calendars = calendars;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryPage<Calendar> getCalendars() {
|
||||||
|
return calendars;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
calendars = new QueryPage<>(in, Calendar::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
calendars.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RestStatus status() {
|
||||||
|
return RestStatus.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
calendars.doXContentBody(builder, params);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(calendars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Response other = (Response) obj;
|
||||||
|
return Objects.equals(calendars, other.calendars);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TransportAction(Settings settings, ThreadPool threadPool,
|
||||||
|
TransportService transportService, ActionFilters actionFilters,
|
||||||
|
IndexNameExpressionResolver indexNameExpressionResolver,
|
||||||
|
Client client) {
|
||||||
|
super(settings, NAME, threadPool, transportService, actionFilters,
|
||||||
|
indexNameExpressionResolver, Request::new);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doExecute(Request request, ActionListener<Response> listener) {
|
||||||
|
final String calendarId = request.getCalendarId();
|
||||||
|
if (request.getCalendarId() != null) {
|
||||||
|
getCalendar(calendarId, listener);
|
||||||
|
} else {
|
||||||
|
PageParams pageParams = request.getPageParams();
|
||||||
|
if (pageParams == null) {
|
||||||
|
pageParams = PageParams.defaultParams();
|
||||||
|
}
|
||||||
|
getCalendars(pageParams, listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getCalendar(String calendarId, ActionListener<Response> listener) {
|
||||||
|
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(GetResponse getDocResponse) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
QueryPage<Calendar> calendars;
|
||||||
|
if (getDocResponse.isExists()) {
|
||||||
|
BytesReference docSource = getDocResponse.getSourceAsBytesRef();
|
||||||
|
|
||||||
|
try (XContentParser parser =
|
||||||
|
XContentFactory.xContent(docSource).createParser(NamedXContentRegistry.EMPTY, docSource)) {
|
||||||
|
Calendar calendar = Calendar.PARSER.apply(parser, null).build();
|
||||||
|
calendars = new QueryPage<>(Collections.singletonList(calendar), 1, Calendar.RESULTS_FIELD);
|
||||||
|
|
||||||
|
Response response = new Response(calendars);
|
||||||
|
listener.onResponse(response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.onFailure(QueryPage.emptyQueryPage(Calendar.RESULTS_FIELD));
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
this.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
listener.onFailure(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getCalendars(PageParams pageParams, ActionListener<Response> listener) {
|
||||||
|
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder()
|
||||||
|
.from(pageParams.getFrom())
|
||||||
|
.size(pageParams.getSize())
|
||||||
|
.sort(Calendar.ID.getPreferredName())
|
||||||
|
.query(QueryBuilders.termQuery(Calendar.TYPE.getPreferredName(), Calendar.CALENDAR_TYPE));
|
||||||
|
|
||||||
|
SearchRequest searchRequest = new SearchRequest(MlMetaIndex.INDEX_NAME)
|
||||||
|
.indicesOptions(JobProvider.addIgnoreUnavailable(SearchRequest.DEFAULT_INDICES_OPTIONS))
|
||||||
|
.source(sourceBuilder);
|
||||||
|
|
||||||
|
executeAsyncWithOrigin(client.threadPool().getThreadContext(), ML_ORIGIN, searchRequest, new ActionListener<SearchResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(SearchResponse response) {
|
||||||
|
List<Calendar> docs = new ArrayList<>();
|
||||||
|
for (SearchHit hit : response.getHits().getHits()) {
|
||||||
|
BytesReference docSource = hit.getSourceRef();
|
||||||
|
try (XContentParser parser = XContentFactory.xContent(docSource).createParser(
|
||||||
|
NamedXContentRegistry.EMPTY, docSource)) {
|
||||||
|
docs.add(Calendar.PARSER.apply(parser, null).build());
|
||||||
|
} catch (IOException e) {
|
||||||
|
this.onFailure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Response getResponse = new Response(
|
||||||
|
new QueryPage<>(docs, docs.size(), Calendar.RESULTS_FIELD));
|
||||||
|
listener.onResponse(getResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
listener.onFailure(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
client::search);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* 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.ActionListener;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.DocWriteRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexAction;
|
||||||
|
import org.elasticsearch.action.index.IndexRequest;
|
||||||
|
import org.elasticsearch.action.index.IndexResponse;
|
||||||
|
import org.elasticsearch.action.support.ActionFilters;
|
||||||
|
import org.elasticsearch.action.support.HandledTransportAction;
|
||||||
|
import org.elasticsearch.action.support.WriteRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.client.Client;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
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.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
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.job.messages.Messages;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
||||||
|
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
||||||
|
|
||||||
|
public class PutCalendarAction extends Action<PutCalendarAction.Request, PutCalendarAction.Response, PutCalendarAction.RequestBuilder> {
|
||||||
|
public static final PutCalendarAction INSTANCE = new PutCalendarAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/calendars/put";
|
||||||
|
|
||||||
|
private PutCalendarAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest implements ToXContentObject {
|
||||||
|
|
||||||
|
public static Request parseRequest(String calendarId, XContentParser parser) {
|
||||||
|
Calendar.Builder builder = Calendar.PARSER.apply(parser, null);
|
||||||
|
if (builder.getId() == null) {
|
||||||
|
builder.setId(calendarId);
|
||||||
|
} else if (!Strings.isNullOrEmpty(calendarId) && !calendarId.equals(builder.getId())) {
|
||||||
|
// If we have both URI and body filter ID, they must be identical
|
||||||
|
throw new IllegalArgumentException(Messages.getMessage(Messages.INCONSISTENT_ID, Calendar.ID.getPreferredName(),
|
||||||
|
builder.getId(), calendarId));
|
||||||
|
}
|
||||||
|
return new Request(builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Calendar calendar;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(Calendar calendar) {
|
||||||
|
this.calendar = ExceptionsHelper.requireNonNull(calendar, "calendar");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Calendar getCalendar() {
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
ActionRequestValidationException validationException = null;
|
||||||
|
if ("_all".equals(calendar.getId())) {
|
||||||
|
validationException =
|
||||||
|
addValidationError("Cannot create a Calendar with the reserved name [_all]",
|
||||||
|
validationException);
|
||||||
|
}
|
||||||
|
return validationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
calendar = new Calendar(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
calendar.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
calendar.toXContent(builder, params);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(calendar, other.calendar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client) {
|
||||||
|
super(client, INSTANCE, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse implements ToXContentObject {
|
||||||
|
|
||||||
|
private Calendar calendar;
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response(Calendar calendar) {
|
||||||
|
super(true);
|
||||||
|
this.calendar = calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
return calendar.toXContent(builder, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
||||||
|
|
||||||
|
private final Client client;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public TransportAction(Settings settings, ThreadPool threadPool,
|
||||||
|
TransportService transportService, ActionFilters actionFilters,
|
||||||
|
IndexNameExpressionResolver indexNameExpressionResolver, Client client) {
|
||||||
|
super(settings, NAME, threadPool, transportService, actionFilters,
|
||||||
|
indexNameExpressionResolver, Request::new);
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doExecute(Request request, ActionListener<Response> listener) {
|
||||||
|
final Calendar calendar = request.getCalendar();
|
||||||
|
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, calendar.documentId());
|
||||||
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
|
indexRequest.source(calendar.toXContent(builder,
|
||||||
|
new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"))));
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("Failed to serialise calendar with id [" + calendar.getId() + "]", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make it an error to overwrite an existing calendar
|
||||||
|
indexRequest.opType(DocWriteRequest.OpType.CREATE);
|
||||||
|
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
||||||
|
|
||||||
|
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest,
|
||||||
|
new ActionListener<IndexResponse>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(IndexResponse indexResponse) {
|
||||||
|
listener.onResponse(new Response(calendar));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Exception e) {
|
||||||
|
listener.onFailure(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -181,7 +181,7 @@ public class PutFilterAction extends Action<PutFilterAction.Request, PutFilterAc
|
||||||
MlFilter filter = request.getFilter();
|
MlFilter filter = request.getFilter();
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, filter.documentId());
|
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, filter.documentId());
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
ToXContent.MapParams params = new ToXContent.MapParams(Collections.singletonMap(MlFilter.INCLUDE_TYPE_KEY, "true"));
|
ToXContent.MapParams params = new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"));
|
||||||
indexRequest.source(filter.toXContent(builder, params));
|
indexRequest.source(filter.toXContent(builder, params));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException("Failed to serialise filter with id [" + filter.getId() + "]", e);
|
throw new IllegalStateException("Failed to serialise filter with id [" + filter.getId() + "]", e);
|
||||||
|
|
|
@ -25,7 +25,6 @@ public class PageParams implements ToXContentObject, Writeable {
|
||||||
public static final int DEFAULT_FROM = 0;
|
public static final int DEFAULT_FROM = 0;
|
||||||
public static final int DEFAULT_SIZE = 100;
|
public static final int DEFAULT_SIZE = 100;
|
||||||
|
|
||||||
|
|
||||||
public static final ConstructingObjectParser<PageParams, Void> PARSER = new ConstructingObjectParser<>(PAGE.getPreferredName(),
|
public static final ConstructingObjectParser<PageParams, Void> PARSER = new ConstructingObjectParser<>(PAGE.getPreferredName(),
|
||||||
a -> new PageParams(a[0] == null ? DEFAULT_FROM : (int) a[0], a[1] == null ? DEFAULT_SIZE : (int) a[1]));
|
a -> new PageParams(a[0] == null ? DEFAULT_FROM : (int) a[0], a[1] == null ? DEFAULT_SIZE : (int) a[1]));
|
||||||
|
|
||||||
|
@ -39,6 +38,10 @@ public class PageParams implements ToXContentObject, Writeable {
|
||||||
private final int from;
|
private final int from;
|
||||||
private final int size;
|
private final int size;
|
||||||
|
|
||||||
|
public static PageParams defaultParams() {
|
||||||
|
return new PageParams(DEFAULT_FROM, DEFAULT_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
public PageParams(StreamInput in) throws IOException {
|
public PageParams(StreamInput in) throws IOException {
|
||||||
this(in.readVInt(), in.readVInt());
|
this(in.readVInt(), in.readVInt());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* 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.calendars;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.MlFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class Calendar implements ToXContentObject, Writeable {
|
||||||
|
|
||||||
|
public static final String CALENDAR_TYPE = "calendar";
|
||||||
|
|
||||||
|
public static final ParseField TYPE = new ParseField("type");
|
||||||
|
public static final ParseField ID = new ParseField("calendar_id");
|
||||||
|
public static final ParseField JOB_IDS = new ParseField("job_ids");
|
||||||
|
|
||||||
|
private static final String DOCUMENT_ID_PREFIX = "calendar_";
|
||||||
|
|
||||||
|
// For QueryPage
|
||||||
|
public static final ParseField RESULTS_FIELD = new ParseField("calendars");
|
||||||
|
|
||||||
|
public static final ObjectParser<Builder, Void> PARSER =
|
||||||
|
new ObjectParser<>(ID.getPreferredName(), Calendar.Builder::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString(Calendar.Builder::setId, ID);
|
||||||
|
PARSER.declareStringArray(Calendar.Builder::setJobIds, JOB_IDS);
|
||||||
|
PARSER.declareString((builder, s) -> {}, TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String documentId(String calendarId) {
|
||||||
|
return DOCUMENT_ID_PREFIX + calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
private final List<String> jobIds;
|
||||||
|
|
||||||
|
public Calendar(String id, List<String> jobIds) {
|
||||||
|
this.id = Objects.requireNonNull(id, ID.getPreferredName() + " must not be null");
|
||||||
|
this.jobIds = Objects.requireNonNull(jobIds, JOB_IDS.getPreferredName() + " must not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Calendar(StreamInput in) throws IOException {
|
||||||
|
id = in.readString();
|
||||||
|
jobIds = Arrays.asList(in.readStringArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String documentId() {
|
||||||
|
return documentId(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getJobIds() {
|
||||||
|
return new ArrayList<>(jobIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeString(id);
|
||||||
|
out.writeStringArray(jobIds.toArray(new String[jobIds.size()]));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(ID.getPreferredName(), id);
|
||||||
|
builder.field(JOB_IDS.getPreferredName(), jobIds);
|
||||||
|
if (params.paramAsBoolean(MlMetaIndex.INCLUDE_TYPE_KEY, false)) {
|
||||||
|
builder.field(TYPE.getPreferredName(), CALENDAR_TYPE);
|
||||||
|
}
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(obj instanceof Calendar)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar other = (Calendar) obj;
|
||||||
|
return id.equals(other.id) && jobIds.equals(other.jobIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(id, jobIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder builder() {
|
||||||
|
return new Builder();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
|
||||||
|
private String calendarId;
|
||||||
|
private List<String> jobIds = Collections.emptyList();
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return this.calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String calendarId) {
|
||||||
|
this.calendarId = calendarId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setJobIds(List<String> jobIds) {
|
||||||
|
this.jobIds = jobIds;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Calendar build() {
|
||||||
|
return new Calendar(calendarId, jobIds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||||
import org.elasticsearch.xpack.ml.job.config.Connective;
|
import org.elasticsearch.xpack.ml.job.config.Connective;
|
||||||
import org.elasticsearch.xpack.ml.job.config.DetectionRule;
|
import org.elasticsearch.xpack.ml.job.config.DetectionRule;
|
||||||
import org.elasticsearch.xpack.ml.job.config.Operator;
|
import org.elasticsearch.xpack.ml.job.config.Operator;
|
||||||
|
@ -171,7 +172,9 @@ public class SpecialEvent implements ToXContentObject, Writeable {
|
||||||
builder.dateField(START_TIME.getPreferredName(), START_TIME.getPreferredName() + "_string", startTime.toInstant().toEpochMilli());
|
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.dateField(END_TIME.getPreferredName(), END_TIME.getPreferredName() + "_string", endTime.toInstant().toEpochMilli());
|
||||||
builder.field(JOB_IDS.getPreferredName(), jobIds);
|
builder.field(JOB_IDS.getPreferredName(), jobIds);
|
||||||
builder.field(TYPE.getPreferredName(), SPECIAL_EVENT_TYPE);
|
if (params.paramAsBoolean(MlMetaIndex.INCLUDE_TYPE_KEY, false)) {
|
||||||
|
builder.field(TYPE.getPreferredName(), SPECIAL_EVENT_TYPE);
|
||||||
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -25,7 +26,6 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||||
|
|
||||||
public static final String DOCUMENT_ID_PREFIX = "filter_";
|
public static final String DOCUMENT_ID_PREFIX = "filter_";
|
||||||
|
|
||||||
public static final String INCLUDE_TYPE_KEY = "include_type";
|
|
||||||
public static final String FILTER_TYPE = "filter";
|
public static final String FILTER_TYPE = "filter";
|
||||||
|
|
||||||
public static final ParseField TYPE = new ParseField("type");
|
public static final ParseField TYPE = new ParseField("type");
|
||||||
|
@ -67,7 +67,7 @@ public class MlFilter implements ToXContentObject, Writeable {
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
builder.field(ID.getPreferredName(), id);
|
builder.field(ID.getPreferredName(), id);
|
||||||
builder.field(ITEMS.getPreferredName(), items);
|
builder.field(ITEMS.getPreferredName(), items);
|
||||||
if (params.paramAsBoolean(INCLUDE_TYPE_KEY, false)) {
|
if (params.paramAsBoolean(MlMetaIndex.INCLUDE_TYPE_KEY, false)) {
|
||||||
builder.field(TYPE.getPreferredName(), FILTER_TYPE);
|
builder.field(TYPE.getPreferredName(), FILTER_TYPE);
|
||||||
}
|
}
|
||||||
builder.endObject();
|
builder.endObject();
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||||
|
* or more contributor license agreements. Licensed under the Elastic License;
|
||||||
|
* you may not use this file except in compliance with the Elastic License.
|
||||||
|
*/
|
||||||
|
package org.elasticsearch.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.DeleteCalendarAction;
|
||||||
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class RestDeleteCalendarAction extends BaseRestHandler {
|
||||||
|
|
||||||
|
public RestDeleteCalendarAction(Settings settings, RestController controller) {
|
||||||
|
super(settings);
|
||||||
|
controller.registerHandler(RestRequest.Method.DELETE,
|
||||||
|
MachineLearning.BASE_PATH + "calendars/{" + Calendar.ID.getPreferredName() + "}", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "xpack_ml_delete_calendar_action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||||
|
DeleteCalendarAction.Request request = new DeleteCalendarAction.Request(restRequest.param(Calendar.ID.getPreferredName()));
|
||||||
|
return channel -> client.execute(DeleteCalendarAction.INSTANCE, request, new AcknowledgedRestListener<>(channel));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.Strings;
|
||||||
|
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.RestStatusToXContentListener;
|
||||||
|
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||||
|
import org.elasticsearch.xpack.ml.action.GetCalendarsAction;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class RestGetCalendarsAction extends BaseRestHandler {
|
||||||
|
|
||||||
|
public RestGetCalendarsAction(Settings settings, RestController controller) {
|
||||||
|
super(settings);
|
||||||
|
controller.registerHandler(RestRequest.Method.GET, MachineLearning.BASE_PATH + "calendars/{" + Calendar.ID.getPreferredName() + "}",
|
||||||
|
this);
|
||||||
|
controller.registerHandler(RestRequest.Method.GET, MachineLearning.BASE_PATH + "calendars/", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "xpack_ml_get_calendars_action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||||
|
GetCalendarsAction.Request getRequest = new GetCalendarsAction.Request();
|
||||||
|
String calendarId = restRequest.param(Calendar.ID.getPreferredName());
|
||||||
|
if (!Strings.isNullOrEmpty(calendarId)) {
|
||||||
|
getRequest.setCalendarId(calendarId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (restRequest.hasParam(PageParams.FROM.getPreferredName()) || restRequest.hasParam(PageParams.SIZE.getPreferredName())) {
|
||||||
|
getRequest.setPageParams(new PageParams(restRequest.paramAsInt(PageParams.FROM.getPreferredName(), PageParams.DEFAULT_FROM),
|
||||||
|
restRequest.paramAsInt(PageParams.SIZE.getPreferredName(), PageParams.DEFAULT_SIZE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel -> client.execute(GetCalendarsAction.INSTANCE, getRequest, new RestStatusToXContentListener<>(channel));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
/*
|
||||||
|
* 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.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.rest.BaseRestHandler;
|
||||||
|
import org.elasticsearch.rest.RestController;
|
||||||
|
import org.elasticsearch.rest.RestRequest;
|
||||||
|
import org.elasticsearch.rest.action.RestToXContentListener;
|
||||||
|
import org.elasticsearch.xpack.ml.MachineLearning;
|
||||||
|
import org.elasticsearch.xpack.ml.action.PutCalendarAction;
|
||||||
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public class RestPutCalendarAction extends BaseRestHandler {
|
||||||
|
|
||||||
|
public RestPutCalendarAction(Settings settings, RestController controller) {
|
||||||
|
super(settings);
|
||||||
|
controller.registerHandler(RestRequest.Method.PUT,
|
||||||
|
MachineLearning.BASE_PATH + "calendars/{" + Calendar.ID.getPreferredName() + "}", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "xpack_ml_put_calendar_action";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
|
||||||
|
String calendarId = restRequest.param(Calendar.ID.getPreferredName());
|
||||||
|
|
||||||
|
PutCalendarAction.Request putCalendarRequest;
|
||||||
|
// A calendar can be created with just a name or with an optional body
|
||||||
|
if (restRequest.hasContentOrSourceParam()) {
|
||||||
|
XContentParser parser = restRequest.contentOrSourceParamParser();
|
||||||
|
putCalendarRequest = PutCalendarAction.Request.parseRequest(calendarId, parser);
|
||||||
|
} else {
|
||||||
|
putCalendarRequest = new PutCalendarAction.Request(new Calendar(calendarId, Collections.emptyList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return channel -> client.execute(PutCalendarAction.INSTANCE, putCalendarRequest, new RestToXContentListener<>(channel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public class GetCalendarsActionRequestTests extends AbstractStreamableTestCase<GetCalendarsAction.Request> {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GetCalendarsAction.Request createTestInstance() {
|
||||||
|
GetCalendarsAction.Request request = new GetCalendarsAction.Request();
|
||||||
|
request.setCalendarId(randomAlphaOfLengthBetween(1, 20));
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected GetCalendarsAction.Request createBlankInstance() {
|
||||||
|
return new GetCalendarsAction.Request();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
|
||||||
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PutCalendarActionRequestTests extends AbstractStreamableXContentTestCase<PutCalendarAction.Request> {
|
||||||
|
|
||||||
|
private final String calendarId = randomAlphaOfLengthBetween(1, 20);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PutCalendarAction.Request createTestInstance() {
|
||||||
|
int size = randomInt(10);
|
||||||
|
List<String> jobIds = new ArrayList<>(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
jobIds.add(randomAlphaOfLengthBetween(1, 20));
|
||||||
|
}
|
||||||
|
Calendar calendar = new Calendar(calendarId, jobIds);
|
||||||
|
return new PutCalendarAction.Request(calendar);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean supportsUnknownFields() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PutCalendarAction.Request createBlankInstance() {
|
||||||
|
return new PutCalendarAction.Request();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PutCalendarAction.Request doParseInstance(XContentParser parser) {
|
||||||
|
return PutCalendarAction.Request.parseRequest(calendarId, parser);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.xpack.ml.calendars;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.test.AbstractSerializingTestCase;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
public class CalendarTests extends AbstractSerializingTestCase<Calendar> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Calendar createTestInstance() {
|
||||||
|
int size = randomInt(10);
|
||||||
|
List<String> items = new ArrayList<>(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
items.add(randomAlphaOfLengthBetween(1, 20));
|
||||||
|
}
|
||||||
|
return new Calendar(randomAlphaOfLengthBetween(1, 20), items);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Writeable.Reader<Calendar> instanceReader() {
|
||||||
|
return Calendar::new;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Calendar doParseInstance(XContentParser parser) throws IOException {
|
||||||
|
return Calendar.PARSER.apply(parser, null).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testNullId() {
|
||||||
|
NullPointerException ex = expectThrows(NullPointerException.class, () -> new Calendar(null, Collections.emptyList()));
|
||||||
|
assertEquals(Calendar.ID.getPreferredName() + " must not be null", ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testDocumentId() {
|
||||||
|
assertThat(Calendar.documentId("foo"), equalTo("calendar_foo"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -278,7 +278,8 @@ public class JobProviderIT extends XPackSingleNodeTestCase {
|
||||||
for (SpecialEvent event : events) {
|
for (SpecialEvent event : events) {
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, event.documentId());
|
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, event.documentId());
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||||
indexRequest.source(event.toXContent(builder, ToXContent.EMPTY_PARAMS));
|
ToXContent.MapParams params = new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"));
|
||||||
|
indexRequest.source(event.toXContent(builder, params));
|
||||||
bulkRequest.add(indexRequest);
|
bulkRequest.add(indexRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"xpack.ml.delete_calendar": {
|
||||||
|
"methods": [ "DELETE" ],
|
||||||
|
"url": {
|
||||||
|
"path": "/_xpack/ml/calendars/{calendar_id}",
|
||||||
|
"paths": [ "/_xpack/ml/calendars/{calendar_id}" ],
|
||||||
|
"parts": {
|
||||||
|
"calendar_id": {
|
||||||
|
"type" : "string",
|
||||||
|
"required" : true,
|
||||||
|
"description" : "The ID of the calendar to delete"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
{
|
||||||
|
"xpack.ml.get_calendars": {
|
||||||
|
"methods": [ "GET" ],
|
||||||
|
"url": {
|
||||||
|
"path": "/_xpack/ml/calendars/{calendar_id}",
|
||||||
|
"paths": [
|
||||||
|
"/_xpack/ml/calendars",
|
||||||
|
"/_xpack/ml/calendars/{calendar_id}"
|
||||||
|
],
|
||||||
|
"parts": {
|
||||||
|
"calendar_id": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The ID of the calendar to fetch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"params": {
|
||||||
|
"from": {
|
||||||
|
"type": "int",
|
||||||
|
"description": "skips a number of calendars"
|
||||||
|
},
|
||||||
|
"size": {
|
||||||
|
"type": "int",
|
||||||
|
"description": "specifies a max number of calendars to get"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"xpack.ml.put_calendar": {
|
||||||
|
"methods": [ "PUT" ],
|
||||||
|
"url": {
|
||||||
|
"path": "/_xpack/ml/calendars/{calendar_id}",
|
||||||
|
"paths": [ "/_xpack/ml/calendars/{calendar_id}" ],
|
||||||
|
"parts": {
|
||||||
|
"calendar_id": {
|
||||||
|
"type": "string",
|
||||||
|
"required": true,
|
||||||
|
"description": "The ID of the calendar to create"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"body": {
|
||||||
|
"description" : "The calendar details",
|
||||||
|
"required" : false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,108 @@
|
||||||
|
---
|
||||||
|
"Test calendar CRUD":
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "advent"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"job_ids": ["abc", "xyz"]
|
||||||
|
}
|
||||||
|
- match: { calendar_id: advent }
|
||||||
|
- match: { job_ids.0: abc }
|
||||||
|
- match: { job_ids.1: xyz }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.get_calendars:
|
||||||
|
calendar_id: "advent"
|
||||||
|
- match: { count: 1 }
|
||||||
|
- match:
|
||||||
|
calendars.0:
|
||||||
|
calendar_id: "advent"
|
||||||
|
job_ids: ["abc", "xyz"]
|
||||||
|
- is_false: type
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Dogs of the Year"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"job_ids": ["abc2"]
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Cats of the Year"
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.get_calendars: {}
|
||||||
|
- match: { count: 3 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.delete_calendar:
|
||||||
|
calendar_id: "Dogs of the Year"
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.get_calendars: {}
|
||||||
|
- match: { count: 2 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: missing
|
||||||
|
xpack.ml.get_calendars:
|
||||||
|
calendar_id: "Dogs of the Year"
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test PageParams":
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Calendar1"
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Calendar2"
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Calendar3"
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.get_calendars:
|
||||||
|
from: 2
|
||||||
|
- match: { count: 1 }
|
||||||
|
- match: { calendars.0.calendar_id: Calendar3 }
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.get_calendars:
|
||||||
|
from: 1
|
||||||
|
size: 1
|
||||||
|
- match: { count: 1 }
|
||||||
|
- match: { calendars.0.calendar_id: Calendar2 }
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test PageParams with ID is invalid":
|
||||||
|
- do:
|
||||||
|
catch: bad_request
|
||||||
|
xpack.ml.get_calendars:
|
||||||
|
calendar_id: Tides
|
||||||
|
size: 10
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test cannot overwrite an exisiting calendar":
|
||||||
|
|
||||||
|
- do:
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Mayan"
|
||||||
|
body: >
|
||||||
|
{
|
||||||
|
"job_ids": ["apocalypse"]
|
||||||
|
}
|
||||||
|
|
||||||
|
- do:
|
||||||
|
catch: /version_conflict_engine_exception/
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "Mayan"
|
||||||
|
|
||||||
|
---
|
||||||
|
"Test cannot create calendar with name _all":
|
||||||
|
- do:
|
||||||
|
catch: bad_request
|
||||||
|
xpack.ml.put_calendar:
|
||||||
|
calendar_id: "_all"
|
|
@ -17,6 +17,8 @@ integTestRunner {
|
||||||
systemProperty 'tests.rest.blacklist', [
|
systemProperty 'tests.rest.blacklist', [
|
||||||
// Remove tests that are expected to throw an exception, because we cannot then
|
// Remove tests that are expected to throw an exception, because we cannot then
|
||||||
// know whether to expect an authorization exception or a validation exception
|
// know whether to expect an authorization exception or a validation exception
|
||||||
|
'ml/calendar_crud/Test cannot create calendar with name _all',
|
||||||
|
'ml/calendar_crud/Test PageParams with ID is invalid',
|
||||||
'ml/custom_all_field/Test querying custom all field',
|
'ml/custom_all_field/Test querying custom all field',
|
||||||
'ml/datafeeds_crud/Test delete datafeed with missing id',
|
'ml/datafeeds_crud/Test delete datafeed with missing id',
|
||||||
'ml/datafeeds_crud/Test put datafeed referring to missing job_id',
|
'ml/datafeeds_crud/Test put datafeed referring to missing job_id',
|
||||||
|
|
Loading…
Reference in New Issue