Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get data stream accepts single search parameter #54530

Merged
merged 10 commits into from
Apr 3, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
],
"parts":{
"name":{
"type":"list",
"description":"The comma separated names of data streams"
"type":"string",
"description":"The name or wildcard expression of the requested data streams"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
- is_true: acknowledged

- do:
indices.get_data_streams: {}
indices.get_data_streams:
name: "*"
- match: { 0.name: simple-data-stream1 }
- match: { 0.timestamp_field: '@timestamp' }
- length: { 0.indices: 1 }
Expand Down Expand Up @@ -54,3 +55,67 @@

- match: { status: 400 }
- match: { error.root_cause.0.type: "illegal_argument_exception" }

---
"Get data stream":
- skip:
version: " - 7.99.99"
reason: available only in 7.7+

- do:
indices.create_data_stream:
name: get-data-stream1
body:
timestamp_field: "@timestamp"
- is_true: acknowledged

- do:
indices.create_data_stream:
name: get-data-stream2
body:
timestamp_field: "@timestamp2"
- is_true: acknowledged

- do:
indices.get_data_streams: {}
- match: { 0.name: get-data-stream1 }
- match: { 0.timestamp_field: '@timestamp' }
- match: { 1.name: get-data-stream2 }
- match: { 1.timestamp_field: '@timestamp2' }

- do:
indices.get_data_streams:
name: get-data-stream1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to also test that GET _data_stream/get-data-stream* works and returns both streams?

- match: { 0.name: get-data-stream1 }
- match: { 0.timestamp_field: '@timestamp' }

- do:
indices.get_data_streams:
name: get-data-*
- match: { 0.name: get-data-stream1 }
- match: { 0.timestamp_field: '@timestamp' }
- match: { 1.name: get-data-stream2 }
- match: { 1.timestamp_field: '@timestamp2' }

- do:
indices.get_data_streams:
name: nonexistent-data-stream
catch: missing

- match: { status: 404 }
- match: { error.root_cause.0.type: "resource_not_found_exception" }

- do:
indices.get_data_streams:
name: nonexistent*
- match: { $body: [] }

- do:
indices.delete_data_stream:
name: get-data-stream1
- is_true: acknowledged

- do:
indices.delete_data_stream:
name: get-data-stream2
- is_true: acknowledged
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.elasticsearch.action.admin.indices.datastream;

import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.ActionResponse;
Expand All @@ -43,7 +44,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand All @@ -59,10 +60,10 @@ private GetDataStreamsAction() {

public static class Request extends MasterNodeReadRequest<Request> {

private final String[] names;
private final String name;

public Request(String[] names) {
this.names = Objects.requireNonNull(names);
public Request(String name) {
this.name = name;
}

@Override
Expand All @@ -72,26 +73,26 @@ public ActionRequestValidationException validate() {

public Request(StreamInput in) throws IOException {
super(in);
this.names = in.readStringArray();
this.name = in.readOptionalString();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeStringArray(names);
out.writeOptionalString(name);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Request request = (Request) o;
return Arrays.equals(names, request.names);
return Objects.equals(name, request.name);
}

@Override
public int hashCode() {
return Arrays.hashCode(names);
return Objects.hash(name);
}
}

Expand Down Expand Up @@ -164,22 +165,21 @@ static List<DataStream> getDataStreams(ClusterState clusterState, Request reques
Map<String, DataStream> dataStreams = clusterState.metadata().dataStreams();

// return all data streams if no name was specified
if (request.names.length == 0) {
return new ArrayList<>(dataStreams.values());
}
final String requestedName = request.name == null ? "*" : request.name;

final List<DataStream> results = new ArrayList<>();
for (String name : request.names) {
if (Regex.isSimpleMatchPattern(name)) {
if (Regex.isSimpleMatchPattern(requestedName)) {
for (Map.Entry<String, DataStream> entry : dataStreams.entrySet()) {
if (Regex.simpleMatch(name, entry.getKey())) {
if (Regex.simpleMatch(requestedName, entry.getKey())) {
results.add(entry.getValue());
}
}
} else if (dataStreams.containsKey(name)) {
results.add(dataStreams.get(name));
} else if (dataStreams.containsKey(request.name)) {
results.add(dataStreams.get(request.name));
} else {
throw new ResourceNotFoundException("data_stream matching [" + request.name + "] not found");
}
}
results.sort(Comparator.comparing(DataStream::getName));
return results;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import org.elasticsearch.action.admin.indices.datastream.GetDataStreamsAction;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
Expand All @@ -45,8 +44,7 @@ public List<Route> routes() {

@Override
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
String[] names = Strings.splitStringByCommaToArray(request.param("name"));
GetDataStreamsAction.Request getDataStreamsRequest = new GetDataStreamsAction.Request(names);
GetDataStreamsAction.Request getDataStreamsRequest = new GetDataStreamsAction.Request(request.param("name"));
return channel -> client.admin().indices().getDataStreams(getDataStreamsRequest, new RestToXContentListener<>(channel));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
package org.elasticsearch.action.admin.indices.datastream;

import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.ResourceNotFoundException;
import org.elasticsearch.action.admin.indices.datastream.GetDataStreamsAction.Request;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
Expand All @@ -31,6 +31,7 @@
import java.util.List;
import java.util.Map;

import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;

public class GetDataStreamsRequestTests extends AbstractWireSerializingTestCase<Request> {
Expand All @@ -42,31 +43,72 @@ protected Writeable.Reader<Request> instanceReader() {

@Override
protected Request createTestInstance() {
return new Request(generateRandomStringArray(8, 8, false));
final String searchParameter;
switch (randomIntBetween(1, 4)) {
case 1:
searchParameter = randomAlphaOfLength(8);
break;
case 2:
searchParameter = randomAlphaOfLength(8) + "*";
break;
case 3:
searchParameter = "*";
break;
default:
searchParameter = null;
break;
}
return new Request(searchParameter);
}

public void testValidateRequest() {
GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(new String[]{});
ActionRequestValidationException e = req.validate();
assertNull(e);
}

public void testGetDataStreams() {
public void testGetDataStream() {
final String dataStreamName = "my-data-stream";
DataStream existingDataStream = new DataStream(dataStreamName, "timestamp", Collections.emptyList());
ClusterState cs = ClusterState.builder(new ClusterName("_name"))
.metadata(Metadata.builder().dataStreams(Map.of(dataStreamName, existingDataStream)).build()).build();
GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(new String[]{dataStreamName});
GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(dataStreamName);
List<DataStream> dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(1));
assertThat(dataStreams.get(0).getName(), equalTo(dataStreamName));
}

public void testGetDataStreamsWithWildcards() {
final String[] dataStreamNames = {"my-data-stream", "another-data-stream"};
DataStream ds1 = new DataStream(dataStreamNames[0], "timestamp", Collections.emptyList());
DataStream ds2 = new DataStream(dataStreamNames[1], "timestamp", Collections.emptyList());
ClusterState cs = ClusterState.builder(new ClusterName("_name"))
.metadata(Metadata.builder().dataStreams(
Map.of(dataStreamNames[0], ds1, dataStreamNames[1], ds2)).build())
.build();

GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(dataStreamNames[1].substring(0, 5) + "*");
List<DataStream> dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(1));
assertThat(dataStreams.get(0).getName(), equalTo(dataStreamNames[1]));

req = new GetDataStreamsAction.Request("*");
dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(2));
assertThat(dataStreams.get(0).getName(), equalTo(dataStreamNames[1]));
assertThat(dataStreams.get(1).getName(), equalTo(dataStreamNames[0]));

req = new GetDataStreamsAction.Request((String) null);
dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(2));
assertThat(dataStreams.get(0).getName(), equalTo(dataStreamNames[1]));
assertThat(dataStreams.get(1).getName(), equalTo(dataStreamNames[0]));

req = new GetDataStreamsAction.Request("matches-none*");
dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(0));
}

public void testGetNonexistentDataStream() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a bit more tests:

  1. Get non existent data stream based on wildcard (which should return empty array).
  2. Get data stream based on wildcard, returning multiple.

final String dataStreamName = "my-data-stream";
ClusterState cs = ClusterState.builder(new ClusterName("_name")).build();
GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(new String[]{dataStreamName});
List<DataStream> dataStreams = GetDataStreamsAction.TransportAction.getDataStreams(cs, req);
assertThat(dataStreams.size(), equalTo(0));
GetDataStreamsAction.Request req = new GetDataStreamsAction.Request(dataStreamName);
ResourceNotFoundException e = expectThrows(ResourceNotFoundException.class,
() -> GetDataStreamsAction.TransportAction.getDataStreams(cs, req));
assertThat(e.getMessage(), containsString("data_stream matching [" + dataStreamName + "] not found"));
}
}