diff --git a/x-pack/docs/en/rest-api/rollup/rollup-index-caps.asciidoc b/x-pack/docs/en/rest-api/rollup/rollup-index-caps.asciidoc new file mode 100644 index 00000000000..4636d9775e9 --- /dev/null +++ b/x-pack/docs/en/rest-api/rollup/rollup-index-caps.asciidoc @@ -0,0 +1,161 @@ +[role="xpack"] +[[rollup-get-rollup-index-caps]] +=== Get Rollup Index Capabilities +++++ +Get Rollup Index Caps +++++ + +experimental[] + +This API returns the rollup capabilities of all jobs inside of a rollup index (e.g. the index where rollup data is stored). +A single rollup index may store the data for multiple rollup jobs, and may have a variety of capabilities depending on those jobs. + +This API will allow you to determine: + +1. What jobs are stored in an index (or indices specified via a pattern)? +2. What target indices were rolled up, what fields were used in those rollups and what aggregations can be performed on each job? + +==== Request + +`GET {index}/_xpack/rollup/data` + +//===== Description + +==== Path Parameters + +`index`:: + (string) Index or index-pattern of concrete rollup indices to check for capabilities. + + + +==== Request Body + +There is no request body for the Get Jobs API. + +==== Authorization + +You must have `monitor`, `monitor_rollup`, `manage` or `manage_rollup` cluster privileges to use this API. +For more information, see +{xpack-ref}/security-privileges.html[Security Privileges]. + +==== Examples + +Imagine we have an index named `sensor-1` full of raw data. We know that the data will grow over time, so there +will be a `sensor-2`, `sensor-3`, etc. Let's create a Rollup job, which stores it's data in `sensor_rollup`: + +[source,js] +-------------------------------------------------- +PUT _xpack/rollup/job/sensor +{ + "index_pattern": "sensor-*", + "rollup_index": "sensor_rollup", + "cron": "*/30 * * * * ?", + "page_size" :1000, + "groups" : { + "date_histogram": { + "field": "timestamp", + "interval": "1h", + "delay": "7d" + }, + "terms": { + "fields": ["node"] + } + }, + "metrics": [ + { + "field": "temperature", + "metrics": ["min", "max", "sum"] + }, + { + "field": "voltage", + "metrics": ["avg"] + } + ] +} +-------------------------------------------------- +// CONSOLE +// TEST[setup:sensor_index] + +If at a later date, we'd like to determine what jobs and capabilities were stored in the `sensor_rollup` index, we can use the Get Rollup +Index API: + +[source,js] +-------------------------------------------------- +GET /sensor_rollup/_xpack/rollup/data +-------------------------------------------------- +// CONSOLE +// TEST[continued] + +Note how we are requesting the concrete rollup index name (`sensor_rollup`) as the first part of the URL. +This will yield the following response: + +[source,js] +---- +{ + "sensor_rollup" : { + "rollup_jobs" : [ + { + "job_id" : "sensor", + "rollup_index" : "sensor_rollup", + "index_pattern" : "sensor-*", + "fields" : { + "node" : [ + { + "agg" : "terms" + } + ], + "temperature" : [ + { + "agg" : "min" + }, + { + "agg" : "max" + }, + { + "agg" : "sum" + } + ], + "timestamp" : [ + { + "agg" : "date_histogram", + "time_zone" : "UTC", + "interval" : "1h", + "delay": "7d" + } + ], + "voltage" : [ + { + "agg" : "avg" + } + ] + } + } + ] + } +} +---- +// TESTRESPONSE + + +The response that is returned contains information that is similar to the original Rollup configuration, but formatted +differently. First, there are some house-keeping details: the Rollup job's ID, the index that holds the rolled data, +the index pattern that the job was targeting. + +Next it shows a list of fields that contain data eligible for rollup searches. Here we see four fields: `node`, `temperature`, +`timestamp` and `voltage`. Each of these fields list the aggregations that are possible. For example, you can use a min, max +or sum aggregation on the `temperature` field, but only a `date_histogram` on `timestamp`. + +Note that the `rollup_jobs` element is an array; there can be multiple, independent jobs configured for a single index +or index pattern. Each of these jobs may have different configurations, so the API returns a list of all the various +configurations available. + + +Like other APIs that interact with indices, you can specify index patterns instead of explicit indices: + +[source,js] +-------------------------------------------------- +GET /*_rollup/_xpack/rollup/data +-------------------------------------------------- +// CONSOLE +// TEST[continued] + diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupCapsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupCapsAction.java index ea98c2f4628..128874a6c8c 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupCapsAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupCapsAction.java @@ -139,7 +139,7 @@ public class GetRollupCapsAction extends Action { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(); for (Map.Entry entry : jobs.entrySet()) { - entry.getValue().toXContent(builder, params); + entry.getValue().toXContent(builder, params); } builder.endObject(); return builder; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupIndexCapsAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupIndexCapsAction.java new file mode 100644 index 00000000000..4f95919c498 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/GetRollupIndexCapsAction.java @@ -0,0 +1,195 @@ +/* + * 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.core.rollup.action; + + +import org.elasticsearch.action.Action; +import org.elasticsearch.action.ActionRequest; +import org.elasticsearch.action.ActionRequestBuilder; +import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.ActionResponse; +import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.ElasticsearchClient; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.Strings; +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.ToXContent; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.rollup.RollupField; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.Objects; + +public class GetRollupIndexCapsAction extends Action { + + public static final GetRollupIndexCapsAction INSTANCE = new GetRollupIndexCapsAction(); + public static final String NAME = "indices:data/read/xpack/rollup/get/index/caps"; + public static final ParseField CONFIG = new ParseField("config"); + public static final ParseField STATUS = new ParseField("status"); + private static final ParseField INDICES_OPTIONS = new ParseField("indices_options"); + + private GetRollupIndexCapsAction() { + super(NAME); + } + + @Override + public Response newResponse() { + return new Response(); + } + + public static class Request extends ActionRequest implements IndicesRequest.Replaceable, ToXContent { + private String[] indices; + private IndicesOptions options; + + public Request(String[] indices) { + this(indices, IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED); + } + + public Request(String[] indices, IndicesOptions options) { + this.indices = indices; + this.options = options; + } + + public Request() {} + + @Override + public IndicesOptions indicesOptions() { + return options; + } + + @Override + public String[] indices() { + return indices; + } + + @Override + public IndicesRequest indices(String... indices) { + Objects.requireNonNull(indices, "indices must not be null"); + for (String index : indices) { + Objects.requireNonNull(index, "index must not be null"); + } + this.indices = indices; + return this; + } + + @Override + public void readFrom(StreamInput in) throws IOException { + super.readFrom(in); + this.indices = in.readStringArray(); + this.options = IndicesOptions.readIndicesOptions(in); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeStringArray(indices); + options.writeIndicesOptions(out); + } + + @Override + public ActionRequestValidationException validate() { + return null; + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.array(RollupField.ID.getPreferredName(), indices); + builder.field(INDICES_OPTIONS.getPreferredName(), options); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(indices), options); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Request other = (Request) obj; + return Arrays.equals(indices, other.indices) + && Objects.equals(options, other.options); + } + } + + public static class RequestBuilder extends ActionRequestBuilder { + + protected RequestBuilder(ElasticsearchClient client, GetRollupIndexCapsAction action) { + super(client, action, new Request()); + } + } + + public static class Response extends ActionResponse implements Writeable, ToXContentObject { + + private Map jobs = Collections.emptyMap(); + + public Response() { + + } + + public Response(Map jobs) { + this.jobs = Objects.requireNonNull(jobs); + } + + Response(StreamInput in) throws IOException { + jobs = in.readMap(StreamInput::readString, RollableIndexCaps::new); + } + + public Map getJobs() { + return jobs; + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + super.writeTo(out); + out.writeMap(jobs, StreamOutput::writeString, (out1, value) -> value.writeTo(out1)); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + for (Map.Entry entry : jobs.entrySet()) { + entry.getValue().toXContent(builder, params); + } + builder.endObject(); + return builder; + } + + @Override + public int hashCode() { + return Objects.hash(jobs); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Response other = (Response) obj; + return Objects.equals(jobs, other.jobs); + } + + @Override + public final String toString() { + return Strings.toString(this); + } + } +} diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java index cc24a0b4ab9..546103df5dd 100644 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/Rollup.java @@ -38,6 +38,7 @@ import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.rollup.RollupField; import org.elasticsearch.xpack.core.rollup.action.DeleteRollupJobAction; import org.elasticsearch.xpack.core.rollup.action.GetRollupCapsAction; +import org.elasticsearch.xpack.core.rollup.action.GetRollupIndexCapsAction; import org.elasticsearch.xpack.core.rollup.action.GetRollupJobsAction; import org.elasticsearch.xpack.core.rollup.action.PutRollupJobAction; import org.elasticsearch.xpack.core.rollup.action.RollupSearchAction; @@ -47,6 +48,7 @@ import org.elasticsearch.xpack.core.scheduler.SchedulerEngine; import org.elasticsearch.xpack.core.template.TemplateUtils; import org.elasticsearch.xpack.rollup.action.TransportDeleteRollupJobAction; import org.elasticsearch.xpack.rollup.action.TransportGetRollupCapsAction; +import org.elasticsearch.xpack.rollup.action.TransportGetRollupIndexCapsAction; import org.elasticsearch.xpack.rollup.action.TransportGetRollupJobAction; import org.elasticsearch.xpack.rollup.action.TransportPutRollupJobAction; import org.elasticsearch.xpack.rollup.action.TransportRollupSearchAction; @@ -55,6 +57,7 @@ import org.elasticsearch.xpack.rollup.action.TransportStopRollupAction; import org.elasticsearch.xpack.rollup.job.RollupJobTask; import org.elasticsearch.xpack.rollup.rest.RestDeleteRollupJobAction; import org.elasticsearch.xpack.rollup.rest.RestGetRollupCapsAction; +import org.elasticsearch.xpack.rollup.rest.RestGetRollupIndexCapsAction; import org.elasticsearch.xpack.rollup.rest.RestGetRollupJobsAction; import org.elasticsearch.xpack.rollup.rest.RestPutRollupJobAction; import org.elasticsearch.xpack.rollup.rest.RestRollupSearchAction; @@ -136,13 +139,14 @@ public class Rollup extends Plugin implements ActionPlugin, PersistentTaskPlugin } return Arrays.asList( - new RestRollupSearchAction(settings, restController), - new RestPutRollupJobAction(settings, restController), - new RestStartRollupJobAction(settings, restController), - new RestStopRollupJobAction(settings, restController), - new RestDeleteRollupJobAction(settings, restController), - new RestGetRollupJobsAction(settings, restController), - new RestGetRollupCapsAction(settings, restController) + new RestRollupSearchAction(settings, restController), + new RestPutRollupJobAction(settings, restController), + new RestStartRollupJobAction(settings, restController), + new RestStopRollupJobAction(settings, restController), + new RestDeleteRollupJobAction(settings, restController), + new RestGetRollupJobsAction(settings, restController), + new RestGetRollupCapsAction(settings, restController), + new RestGetRollupIndexCapsAction(settings, restController) ); } @@ -153,13 +157,14 @@ public class Rollup extends Plugin implements ActionPlugin, PersistentTaskPlugin return emptyList(); } return Arrays.asList( - new ActionHandler<>(RollupSearchAction.INSTANCE, TransportRollupSearchAction.class), - new ActionHandler<>(PutRollupJobAction.INSTANCE, TransportPutRollupJobAction.class), - new ActionHandler<>(StartRollupJobAction.INSTANCE, TransportStartRollupAction.class), - new ActionHandler<>(StopRollupJobAction.INSTANCE, TransportStopRollupAction.class), - new ActionHandler<>(DeleteRollupJobAction.INSTANCE, TransportDeleteRollupJobAction.class), - new ActionHandler<>(GetRollupJobsAction.INSTANCE, TransportGetRollupJobAction.class), - new ActionHandler<>(GetRollupCapsAction.INSTANCE, TransportGetRollupCapsAction.class) + new ActionHandler<>(RollupSearchAction.INSTANCE, TransportRollupSearchAction.class), + new ActionHandler<>(PutRollupJobAction.INSTANCE, TransportPutRollupJobAction.class), + new ActionHandler<>(StartRollupJobAction.INSTANCE, TransportStartRollupAction.class), + new ActionHandler<>(StopRollupJobAction.INSTANCE, TransportStopRollupAction.class), + new ActionHandler<>(DeleteRollupJobAction.INSTANCE, TransportDeleteRollupJobAction.class), + new ActionHandler<>(GetRollupJobsAction.INSTANCE, TransportGetRollupJobAction.class), + new ActionHandler<>(GetRollupCapsAction.INSTANCE, TransportGetRollupCapsAction.class), + new ActionHandler<>(GetRollupIndexCapsAction.INSTANCE, TransportGetRollupIndexCapsAction.class) ); } diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportGetRollupCapsAction.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportGetRollupCapsAction.java index 5f013e8897b..6d565e43b86 100644 --- a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportGetRollupCapsAction.java +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/action/TransportGetRollupCapsAction.java @@ -44,7 +44,6 @@ public class TransportGetRollupCapsAction extends HandledTransportAction listener) { - Map allCaps = getCaps(request.getIndexPattern(), clusterService.state().getMetaData().indices()); listener.onResponse(new GetRollupCapsAction.Response(allCaps)); } @@ -67,7 +66,7 @@ public class TransportGetRollupCapsAction extends HandledTransportAction { String pattern = indexPattern.equals(MetaData.ALL) - ? jobCap.getIndexPattern() : indexPattern; + ? jobCap.getIndexPattern() : indexPattern; // Do we already have an entry for this index pattern? RollableIndexCaps indexCaps = allCaps.get(pattern); @@ -98,11 +97,11 @@ public class TransportGetRollupCapsAction extends HandledTransportAction { + + private final ClusterService clusterService; + + @Inject + public TransportGetRollupIndexCapsAction(Settings settings, TransportService transportService, + ClusterService clusterService, ActionFilters actionFilters) { + super(settings, GetRollupIndexCapsAction.NAME, transportService, actionFilters, + (Supplier) GetRollupIndexCapsAction.Request::new); + this.clusterService = clusterService; + } + + @Override + protected void doExecute(Task task, GetRollupIndexCapsAction.Request request, + ActionListener listener) { + + IndexNameExpressionResolver resolver = new IndexNameExpressionResolver(clusterService.getSettings()); + String[] indices = resolver.concreteIndexNames(clusterService.state(), + request.indicesOptions(), request.indices()); + Map allCaps = getCapsByRollupIndex(Arrays.asList(indices), + clusterService.state().getMetaData().indices()); + listener.onResponse(new GetRollupIndexCapsAction.Response(allCaps)); + } + + static Map getCapsByRollupIndex(List resolvedIndexNames, + ImmutableOpenMap indices) { + Map allCaps = new TreeMap<>(); + + StreamSupport.stream(indices.spliterator(), false) + .filter(entry -> resolvedIndexNames.contains(entry.key)) + .forEach(entry -> { + // Does this index have rollup metadata? + TransportGetRollupCapsAction.findRollupIndexCaps(entry.key, entry.value) + .ifPresent(cap -> { + cap.getJobCaps().forEach(jobCap -> { + // Do we already have an entry for this index? + RollableIndexCaps indexCaps = allCaps.get(jobCap.getRollupIndex()); + if (indexCaps == null) { + indexCaps = new RollableIndexCaps(jobCap.getRollupIndex()); + } + indexCaps.addJobCap(jobCap); + allCaps.put(jobCap.getRollupIndex(), indexCaps); + }); + }); + }); + + return allCaps; + } + +} diff --git a/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/rest/RestGetRollupIndexCapsAction.java b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/rest/RestGetRollupIndexCapsAction.java new file mode 100644 index 00000000000..4f4336f11ab --- /dev/null +++ b/x-pack/plugin/rollup/src/main/java/org/elasticsearch/xpack/rollup/rest/RestGetRollupIndexCapsAction.java @@ -0,0 +1,38 @@ +/* + * 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.rollup.rest; + +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.ParseField; +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.RestToXContentListener; +import org.elasticsearch.xpack.core.rollup.action.GetRollupIndexCapsAction; + +public class RestGetRollupIndexCapsAction extends BaseRestHandler { + public static final ParseField INDEX = new ParseField("index"); + + public RestGetRollupIndexCapsAction(Settings settings, RestController controller) { + super(settings); + controller.registerHandler(RestRequest.Method.GET, "/{index}/_xpack/rollup/data", this); + } + + @Override + protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) { + String index = restRequest.param(INDEX.getPreferredName()); + IndicesOptions options = IndicesOptions.fromRequest(restRequest, IndicesOptions.STRICT_EXPAND_OPEN_FORBID_CLOSED); + GetRollupIndexCapsAction.Request request = new GetRollupIndexCapsAction.Request(new String[]{index}, options); + return channel -> client.execute(GetRollupIndexCapsAction.INSTANCE, request, new RestToXContentListener<>(channel)); + } + + @Override + public String getName() { + return "rollup_get_caps_action"; + } +} diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupCapsActionRequestTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupCapsActionRequestTests.java index e63650397ab..e3a45dbd66b 100644 --- a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupCapsActionRequestTests.java +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupCapsActionRequestTests.java @@ -11,11 +11,11 @@ import org.elasticsearch.cluster.metadata.MappingMetaData; import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.test.AbstractStreamableTestCase; +import org.elasticsearch.xpack.core.rollup.ConfigTestHelpers; import org.elasticsearch.xpack.core.rollup.RollupField; import org.elasticsearch.xpack.core.rollup.action.GetRollupCapsAction; import org.elasticsearch.xpack.core.rollup.action.RollableIndexCaps; import org.elasticsearch.xpack.core.rollup.job.RollupJobConfig; -import org.elasticsearch.xpack.core.rollup.ConfigTestHelpers; import org.mockito.Mockito; import java.io.IOException; diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupIndexCapsActionRequestTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupIndexCapsActionRequestTests.java new file mode 100644 index 00000000000..2066d664996 --- /dev/null +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/action/GetRollupIndexCapsActionRequestTests.java @@ -0,0 +1,177 @@ +/* + * 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.rollup.action; + + +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.cluster.metadata.MappingMetaData; +import org.elasticsearch.cluster.metadata.MetaData; +import org.elasticsearch.common.collect.ImmutableOpenMap; +import org.elasticsearch.test.AbstractStreamableTestCase; +import org.elasticsearch.xpack.core.rollup.ConfigTestHelpers; +import org.elasticsearch.xpack.core.rollup.RollupField; +import org.elasticsearch.xpack.core.rollup.action.GetRollupIndexCapsAction; +import org.elasticsearch.xpack.core.rollup.action.RollableIndexCaps; +import org.mockito.Mockito; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.elasticsearch.xpack.rollup.action.TransportGetRollupIndexCapsAction.getCapsByRollupIndex; +import static org.hamcrest.Matchers.equalTo; + + +public class GetRollupIndexCapsActionRequestTests extends AbstractStreamableTestCase { + + @Override + protected GetRollupIndexCapsAction.Request createTestInstance() { + if (randomBoolean()) { + return new GetRollupIndexCapsAction.Request(new String[]{MetaData.ALL}); + } + return new GetRollupIndexCapsAction.Request(new String[]{randomAlphaOfLengthBetween(1, 20)}); + } + + @Override + protected GetRollupIndexCapsAction.Request createBlankInstance() { + return new GetRollupIndexCapsAction.Request(); + } + + + public void testNoIndicesByRollup() { + ImmutableOpenMap indices = new ImmutableOpenMap.Builder().build(); + Map caps = getCapsByRollupIndex(Collections.singletonList("foo"), indices); + assertThat(caps.size(), equalTo(0)); + } + + public void testAllIndicesByRollupSingleRollup() throws IOException { + int num = randomIntBetween(1,5); + ImmutableOpenMap.Builder indices = new ImmutableOpenMap.Builder<>(5); + int indexCounter = 0; + for (int j = 0; j < 5; j++) { + + Map jobs = new HashMap<>(num); + for (int i = 0; i < num; i++) { + String jobName = randomAlphaOfLength(10); + String indexName = Integer.toString(indexCounter); + indexCounter += 1; + jobs.put(jobName, ConfigTestHelpers.getRollupJob(jobName).setRollupIndex("foo").build()); + } + + MappingMetaData mappingMeta = new MappingMetaData(RollupField.TYPE_NAME, + Collections.singletonMap(RollupField.TYPE_NAME, + Collections.singletonMap("_meta", + Collections.singletonMap(RollupField.ROLLUP_META, jobs)))); + + ImmutableOpenMap.Builder mappings = ImmutableOpenMap.builder(1); + mappings.put(RollupField.TYPE_NAME, mappingMeta); + IndexMetaData meta = Mockito.mock(IndexMetaData.class); + Mockito.when(meta.getMappings()).thenReturn(mappings.build()); + indices.put("foo", meta); + } + + Map caps = getCapsByRollupIndex(Collections.singletonList("foo"), + indices.build()); + assertThat(caps.size(), equalTo(1)); + } + + public void testAllIndicesByRollupManyRollup() throws IOException { + ImmutableOpenMap.Builder indices = new ImmutableOpenMap.Builder<>(5); + int indexCounter = 0; + for (int j = 0; j < 5; j++) { + + Map jobs = new HashMap<>(1); + String jobName = randomAlphaOfLength(10); + String indexName = Integer.toString(indexCounter); + indexCounter += 1; + jobs.put(jobName, ConfigTestHelpers.getRollupJob(jobName) + .setIndexPattern(indexName) + .setRollupIndex("rollup_" + indexName).build()); + + + MappingMetaData mappingMeta = new MappingMetaData(RollupField.TYPE_NAME, + Collections.singletonMap(RollupField.TYPE_NAME, + Collections.singletonMap("_meta", + Collections.singletonMap(RollupField.ROLLUP_META, jobs)))); + + ImmutableOpenMap.Builder mappings = ImmutableOpenMap.builder(1); + mappings.put(RollupField.TYPE_NAME, mappingMeta); + IndexMetaData meta = Mockito.mock(IndexMetaData.class); + Mockito.when(meta.getMappings()).thenReturn(mappings.build()); + indices.put("rollup_" + indexName, meta); + } + + Map caps = getCapsByRollupIndex(Arrays.asList(indices.keys().toArray(String.class)), indices.build()); + assertThat(caps.size(), equalTo(5)); + } + + + public void testOneIndexByRollupManyRollup() throws IOException { + ImmutableOpenMap.Builder indices = new ImmutableOpenMap.Builder<>(5); + int indexCounter = 0; + for (int j = 0; j < 5; j++) { + + Map jobs = new HashMap<>(1); + String jobName = randomAlphaOfLength(10); + String indexName = Integer.toString(indexCounter); + indexCounter += 1; + jobs.put(jobName, ConfigTestHelpers.getRollupJob(jobName) + .setIndexPattern("foo_" + indexName) + .setRollupIndex("rollup_" + indexName).build()); + + MappingMetaData mappingMeta = new MappingMetaData(RollupField.TYPE_NAME, + Collections.singletonMap(RollupField.TYPE_NAME, + Collections.singletonMap("_meta", + Collections.singletonMap(RollupField.ROLLUP_META, jobs)))); + + ImmutableOpenMap.Builder mappings = ImmutableOpenMap.builder(1); + mappings.put(RollupField.TYPE_NAME, mappingMeta); + IndexMetaData meta = Mockito.mock(IndexMetaData.class); + Mockito.when(meta.getMappings()).thenReturn(mappings.build()); + indices.put("rollup_" + indexName, meta); + } + + Map caps = getCapsByRollupIndex(Collections.singletonList("rollup_1"), indices.build()); + assertThat(caps.size(), equalTo(1)); + assertThat(caps.get("rollup_1").getIndexName(), equalTo("rollup_1")); + assertThat(caps.get("rollup_1").getJobCaps().size(), equalTo(1)); + } + + public void testOneIndexByRollupOneRollup() throws IOException { + ImmutableOpenMap.Builder indices = new ImmutableOpenMap.Builder<>(5); + int indexCounter = 0; + for (int j = 0; j < 5; j++) { + + Map jobs = new HashMap<>(1); + String jobName = randomAlphaOfLength(10); + String indexName = Integer.toString(indexCounter); + indexCounter += 1; + jobs.put(jobName, ConfigTestHelpers.getRollupJob(jobName) + .setIndexPattern("foo_" + indexName) + .setRollupIndex("rollup_foo").build()); + + MappingMetaData mappingMeta = new MappingMetaData(RollupField.TYPE_NAME, + Collections.singletonMap(RollupField.TYPE_NAME, + Collections.singletonMap("_meta", + Collections.singletonMap(RollupField.ROLLUP_META, jobs)))); + + ImmutableOpenMap.Builder mappings = ImmutableOpenMap.builder(1); + mappings.put(RollupField.TYPE_NAME, mappingMeta); + IndexMetaData meta = Mockito.mock(IndexMetaData.class); + Mockito.when(meta.getMappings()).thenReturn(mappings.build()); + indices.put("rollup_foo", meta); + } + + Map caps = getCapsByRollupIndex(Collections.singletonList("rollup_foo"), indices.build()); + assertThat(caps.size(), equalTo(1)); + assertThat(caps.get("rollup_foo").getIndexName(), equalTo("rollup_foo")); + assertThat(caps.get("rollup_foo").getJobCaps().size(), equalTo(1)); + } +} + + diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.rollup.get_rollup_index_caps.json b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.rollup.get_rollup_index_caps.json new file mode 100644 index 00000000000..458311417d4 --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/api/xpack.rollup.get_rollup_index_caps.json @@ -0,0 +1,17 @@ +{ + "xpack.rollup.get_rollup_index_caps": { + "documentation": "", + "methods": [ "GET" ], + "url": { + "path": "/{index}/_xpack/rollup/data", + "paths": [ "/{index}/_xpack/rollup/data" ], + "parts": { + "index": { + "type": "string", + "required": true, + "description": "The rollup index or index pattern to obtain rollup capabilities from." + } + } + } + } +} diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_caps.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_caps.yml index 050e49bc4b4..f8bb401a772 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_caps.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_caps.yml @@ -22,6 +22,18 @@ setup: type: date value_field: type: integer + + - do: + indices.create: + index: foo3 + include_type_name: false + body: + mappings: + properties: + the_field: + type: date + value_field: + type: integer - do: headers: Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser @@ -228,4 +240,3 @@ setup: - agg: "min" - agg: "max" - agg: "sum" - diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_index_caps.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_index_caps.yml new file mode 100644 index 00000000000..7a539edcc67 --- /dev/null +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/get_rollup_index_caps.yml @@ -0,0 +1,363 @@ +setup: + - do: + indices.create: + index: foo + include_type_name: false + body: + mappings: + properties: + the_field: + type: date + value_field: + type: integer + + - do: + indices.create: + index: foo2 + include_type_name: false + body: + mappings: + properties: + the_field: + type: date + value_field: + type: integer + + - do: + indices.create: + index: foo3 + include_type_name: false + body: + mappings: + properties: + the_field: + type: date + value_field: + type: integer + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo + body: > + { + "index_pattern": "foo", + "rollup_index": "foo_rollup", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + +--- +"Verify one job caps by rollup index": + + - do: + xpack.rollup.get_rollup_index_caps: + index: "foo_rollup" + + - match: + foo_rollup: + rollup_jobs: + - job_id: "foo" + rollup_index: "foo_rollup" + index_pattern: "foo" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + +--- +"Verify two job caps by rollup index": + + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo2 + body: > + { + "index_pattern": "foo", + "rollup_index": "foo_rollup", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + - do: + xpack.rollup.get_rollup_index_caps: + index: "foo_rollup" + + - match: + foo_rollup: + rollup_jobs: + - job_id: "foo" + rollup_index: "foo_rollup" + index_pattern: "foo" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + - job_id: "foo2" + rollup_index: "foo_rollup" + index_pattern: "foo" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + + +--- +"Verify two different job caps by rollup index": + + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo2 + body: > + { + "index_pattern": "foo2", + "rollup_index": "foo_rollup2", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + - do: + xpack.rollup.get_rollup_index_caps: + index: "foo_rollup" + + - match: + foo_rollup: + rollup_jobs: + - job_id: "foo" + rollup_index: "foo_rollup" + index_pattern: "foo" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + +--- +"Verify all job caps by rollup index": + + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo2 + body: > + { + "index_pattern": "foo2", + "rollup_index": "foo_rollup", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo3 + body: > + { + "index_pattern": "foo3", + "rollup_index": "foo_rollup2", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + + - do: + xpack.rollup.get_rollup_index_caps: + index: "_all" + + - match: + $body: + foo_rollup: + rollup_jobs: + - job_id: "foo" + rollup_index: "foo_rollup" + index_pattern: "foo" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + - job_id: "foo2" + rollup_index: "foo_rollup" + index_pattern: "foo2" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + foo_rollup2: + rollup_jobs: + - job_id: "foo3" + rollup_index: "foo_rollup2" + index_pattern: "foo3" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" + +--- +"Verify index pattern": + + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo2 + body: > + { + "index_pattern": "foo2", + "rollup_index": "foo_rollup", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + - do: + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo3 + body: > + { + "index_pattern": "foo3", + "rollup_index": "foo_rollup2", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "value_field", + "metrics": ["min", "max", "sum"] + } + ] + } + + - do: + xpack.rollup.get_rollup_index_caps: + index: "*_rollup2" + + - match: + $body: + foo_rollup2: + rollup_jobs: + - job_id: "foo3" + rollup_index: "foo_rollup2" + index_pattern: "foo3" + fields: + the_field: + - agg: "date_histogram" + interval: "1h" + time_zone: "UTC" + value_field: + - agg: "min" + - agg: "max" + - agg: "sum" +