From 80be19ab787b8e43639ec9d8095ef81ae5040322 Mon Sep 17 00:00:00 2001 From: olcbean <26058559+olcbean@users.noreply.github.com> Date: Thu, 7 Dec 2017 18:16:03 +0100 Subject: [PATCH] Add Open Index API to the high level REST client (#27574) Add _open to the high level REST client Relates to #27205 --- .../elasticsearch/client/IndicesClient.java | 27 ++++++- .../org/elasticsearch/client/Request.java | 14 ++++ .../client/RestHighLevelClient.java | 4 +- .../elasticsearch/client/IndicesClientIT.java | 74 +++++++++++++++++-- .../elasticsearch/client/RequestTests.java | 36 +++++++-- .../admin/indices/open/OpenIndexResponse.java | 34 ++++++++- .../indices/open/OpenIndexResponseTests.java | 63 ++++++++++++++++ 7 files changed, 238 insertions(+), 14 deletions(-) create mode 100644 core/src/test/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java index c876731839984..57dafbba50994 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java @@ -25,6 +25,8 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import java.io.IOException; import java.util.Collections; @@ -72,7 +74,7 @@ public void deleteIndexAsync(DeleteIndexRequest deleteIndexRequest, ActionListen */ public CreateIndexResponse createIndex(CreateIndexRequest createIndexRequest, Header... headers) throws IOException { return restHighLevelClient.performRequestAndParseEntity(createIndexRequest, Request::createIndex, CreateIndexResponse::fromXContent, - Collections.emptySet(), headers); + Collections.emptySet(), headers); } /** @@ -86,4 +88,27 @@ public void createIndexAsync(CreateIndexRequest createIndexRequest, ActionListen restHighLevelClient.performRequestAsyncAndParseEntity(createIndexRequest, Request::createIndex, CreateIndexResponse::fromXContent, listener, Collections.emptySet(), headers); } + + /** + * Opens an index using the Open Index API + *

+ * See + * Open Index API on elastic.co + */ + public OpenIndexResponse openIndex(OpenIndexRequest openIndexRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(openIndexRequest, Request::openIndex, OpenIndexResponse::fromXContent, + Collections.emptySet(), headers); + } + + /** + * Asynchronously opens an index using the Open Index API + *

+ * See + * Open Index API on elastic.co + */ + public void openIndexAsync(OpenIndexRequest openIndexRequest, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(openIndexRequest, Request::openIndex, OpenIndexResponse::fromXContent, + listener, Collections.emptySet(), headers); + } + } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java index a3544ddb89b77..dd08179cf6297 100755 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/Request.java @@ -31,6 +31,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.get.GetRequest; @@ -138,6 +139,19 @@ static Request deleteIndex(DeleteIndexRequest deleteIndexRequest) { return new Request(HttpDelete.METHOD_NAME, endpoint, parameters.getParams(), null); } + static Request openIndex(OpenIndexRequest openIndexRequest) { + String endpoint = endpoint(openIndexRequest.indices(), Strings.EMPTY_ARRAY, "_open"); + + Params parameters = Params.builder(); + + parameters.withTimeout(openIndexRequest.timeout()); + parameters.withMasterTimeout(openIndexRequest.masterNodeTimeout()); + parameters.withWaitForActiveShards(openIndexRequest.waitForActiveShards()); + parameters.withIndicesOptions(openIndexRequest.indicesOptions()); + + return new Request(HttpPost.METHOD_NAME, endpoint, parameters.getParams(), null); + } + static Request createIndex(CreateIndexRequest createIndexRequest) throws IOException { String endpoint = endpoint(createIndexRequest.indices(), Strings.EMPTY_ARRAY, ""); diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java index 29ab7f90ff5c8..ca244eee88c62 100755 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -26,6 +26,8 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionRequestValidationException; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; @@ -283,7 +285,7 @@ public final GetResponse get(GetRequest getRequest, Header... headers) throws IO * * See Get API on elastic.co */ - public void getAsync(GetRequest getRequest, ActionListener listener, Header... headers) { + public final void getAsync(GetRequest getRequest, ActionListener listener, Header... headers) { performRequestAsyncAndParseEntity(getRequest, Request::get, GetResponse::fromXContent, listener, singleton(404), headers); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java index 0d6430b591294..5f356c4c29f5e 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java @@ -25,14 +25,21 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.rest.RestStatus; + +import java.io.IOException; +import java.util.Locale; + +import static org.hamcrest.Matchers.equalTo; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; -import org.elasticsearch.rest.RestStatus; -import java.io.IOException; import java.util.Map; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; @@ -128,16 +135,73 @@ public void testDeleteIndex() throws IOException { } } + public void testOpenExistingIndex() throws IOException { + String[] indices = randomIndices(1, 5); + for (String index : indices) { + createIndex(index); + closeIndex(index); + ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest("GET", index + "/_search")); + assertThat(exception.getResponse().getStatusLine().getStatusCode(), equalTo(RestStatus.BAD_REQUEST.getStatus())); + assertThat(exception.getMessage().contains(index), equalTo(true)); + } + + OpenIndexRequest openIndexRequest = new OpenIndexRequest(indices); + OpenIndexResponse openIndexResponse = execute(openIndexRequest, highLevelClient().indices()::openIndex, + highLevelClient().indices()::openIndexAsync); + assertTrue(openIndexResponse.isAcknowledged()); + + for (String index : indices) { + Response response = client().performRequest("GET", index + "/_search"); + assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); + } + } + + public void testOpenNonExistentIndex() throws IOException { + String[] nonExistentIndices = randomIndices(1, 5); + for (String nonExistentIndex : nonExistentIndices) { + assertFalse(indexExists(nonExistentIndex)); + } + + OpenIndexRequest openIndexRequest = new OpenIndexRequest(nonExistentIndices); + ElasticsearchException exception = expectThrows(ElasticsearchException.class, + () -> execute(openIndexRequest, highLevelClient().indices()::openIndex, highLevelClient().indices()::openIndexAsync)); + assertEquals(RestStatus.NOT_FOUND, exception.status()); + + OpenIndexRequest lenientOpenIndexRequest = new OpenIndexRequest(nonExistentIndices); + lenientOpenIndexRequest.indicesOptions(IndicesOptions.lenientExpandOpen()); + OpenIndexResponse lenientOpenIndexResponse = execute(lenientOpenIndexRequest, highLevelClient().indices()::openIndex, + highLevelClient().indices()::openIndexAsync); + assertThat(lenientOpenIndexResponse.isAcknowledged(), equalTo(true)); + + OpenIndexRequest strictOpenIndexRequest = new OpenIndexRequest(nonExistentIndices); + strictOpenIndexRequest.indicesOptions(IndicesOptions.strictExpandOpen()); + ElasticsearchException strictException = expectThrows(ElasticsearchException.class, + () -> execute(openIndexRequest, highLevelClient().indices()::openIndex, highLevelClient().indices()::openIndexAsync)); + assertEquals(RestStatus.NOT_FOUND, strictException.status()); + } + + private static String[] randomIndices(int minIndicesNum, int maxIndicesNum) { + int numIndices = randomIntBetween(minIndicesNum, maxIndicesNum); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5).toLowerCase(Locale.ROOT); + } + return indices; + } + private static void createIndex(String index) throws IOException { Response response = client().performRequest("PUT", index); - - assertEquals(200, response.getStatusLine().getStatusCode()); + assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); } private static boolean indexExists(String index) throws IOException { Response response = client().performRequest("HEAD", index); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } - return response.getStatusLine().getStatusCode() == 200; + private static void closeIndex(String index) throws IOException { + Response response = client().performRequest("POST", index + "/_close"); + assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); } @SuppressWarnings("unchecked") diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java index 182de30fd1585..f39a7c77b80a4 100755 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestTests.java @@ -27,6 +27,7 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; +import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -37,7 +38,6 @@ import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.SearchType; -import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.action.support.master.AcknowledgedRequest; @@ -83,7 +83,6 @@ import java.util.Locale; import java.util.Map; import java.util.StringJoiner; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -93,10 +92,12 @@ import static org.elasticsearch.client.Request.enforceSameContentType; import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.Matchers.nullValue; public class RequestTests extends ESTestCase { - public void testConstructor() throws Exception { + public void testConstructor() { final String method = randomFrom("GET", "PUT", "POST", "HEAD", "DELETE"); final String endpoint = randomAlphaOfLengthBetween(1, 10); final Map parameters = singletonMap(randomAlphaOfLength(5), randomAlphaOfLength(5)); @@ -122,7 +123,7 @@ public void testConstructor() throws Exception { assertTrue("Request constructor is not public", Modifier.isPublic(constructors[0].getModifiers())); } - public void testClassVisibility() throws Exception { + public void testClassVisibility() { assertTrue("Request class is not public", Modifier.isPublic(Request.class.getModifiers())); } @@ -146,7 +147,7 @@ public void testGet() { getAndExistsTest(Request::get, "GET"); } - public void testDelete() throws IOException { + public void testDelete() { String index = randomAlphaOfLengthBetween(3, 10); String type = randomAlphaOfLengthBetween(3, 10); String id = randomAlphaOfLengthBetween(3, 10); @@ -283,7 +284,7 @@ public void testCreateIndex() throws IOException { assertToXContentBody(createIndexRequest, request.getEntity()); } - public void testDeleteIndex() throws IOException { + public void testDeleteIndex() { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(); int numIndices = randomIntBetween(0, 5); @@ -307,6 +308,29 @@ public void testDeleteIndex() throws IOException { assertNull(request.getEntity()); } + public void testOpenIndex() { + OpenIndexRequest openIndexRequest = new OpenIndexRequest(); + int numIndices = randomIntBetween(1, 5); + String[] indices = new String[numIndices]; + for (int i = 0; i < numIndices; i++) { + indices[i] = "index-" + randomAlphaOfLengthBetween(2, 5); + } + openIndexRequest.indices(indices); + + Map expectedParams = new HashMap<>(); + setRandomTimeout(openIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); + setRandomMasterTimeout(openIndexRequest, expectedParams); + setRandomIndicesOptions(openIndexRequest::indicesOptions, openIndexRequest::indicesOptions, expectedParams); + setRandomWaitForActiveShards(openIndexRequest::waitForActiveShards, expectedParams); + + Request request = Request.openIndex(openIndexRequest); + StringJoiner endpoint = new StringJoiner("/", "/", "").add(String.join(",", indices)).add("_open"); + assertThat(endpoint.toString(), equalTo(request.getEndpoint())); + assertThat(expectedParams, equalTo(request.getParameters())); + assertThat(request.getMethod(), equalTo("POST")); + assertThat(request.getEntity(), nullValue()); + } + public void testIndex() throws IOException { String index = randomAlphaOfLengthBetween(3, 10); String type = randomAlphaOfLengthBetween(3, 10); diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java b/core/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java index fe9343f363ff3..95fef9fc65344 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponse.java @@ -21,15 +21,34 @@ import org.elasticsearch.Version; import org.elasticsearch.action.support.master.AcknowledgedResponse; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; +import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; import java.io.IOException; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * A response for a open index action. */ -public class OpenIndexResponse extends AcknowledgedResponse { +public class OpenIndexResponse extends AcknowledgedResponse implements ToXContentObject { + private static final String SHARDS_ACKNOWLEDGED = "shards_acknowledged"; + private static final ParseField SHARDS_ACKNOWLEDGED_PARSER = new ParseField(SHARDS_ACKNOWLEDGED); + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("open_index", true, + args -> new OpenIndexResponse((boolean) args[0], (boolean) args[1])); + + static { + declareAcknowledgedField(PARSER); + PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED_PARSER, + ObjectParser.ValueType.BOOLEAN); + } private boolean shardsAcknowledged; @@ -68,4 +87,17 @@ public void writeTo(StreamOutput out) throws IOException { out.writeBoolean(shardsAcknowledged); } } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + addAcknowledgedField(builder); + builder.field(SHARDS_ACKNOWLEDGED, isShardsAcknowledged()); + builder.endObject(); + return builder; + } + + public static OpenIndexResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); + } } diff --git a/core/src/test/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponseTests.java b/core/src/test/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponseTests.java new file mode 100644 index 0000000000000..09ceb7960347b --- /dev/null +++ b/core/src/test/java/org/elasticsearch/action/admin/indices/open/OpenIndexResponseTests.java @@ -0,0 +1,63 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.action.admin.indices.open; + +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; +import static org.hamcrest.CoreMatchers.equalTo; + +public class OpenIndexResponseTests extends ESTestCase { + + public void testFromToXContent() throws IOException { + final OpenIndexResponse openIndexResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(openIndexResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + BytesReference mutated; + if (randomBoolean()) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + + OpenIndexResponse parsedOpenIndexResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedOpenIndexResponse = OpenIndexResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertThat(parsedOpenIndexResponse.isShardsAcknowledged(), equalTo(openIndexResponse.isShardsAcknowledged())); + assertThat(parsedOpenIndexResponse.isAcknowledged(), equalTo(openIndexResponse.isAcknowledged())); + } + + private static OpenIndexResponse createTestItem() { + boolean acknowledged = randomBoolean(); + boolean shardsAcked = acknowledged && randomBoolean(); + return new OpenIndexResponse(acknowledged, shardsAcked); + } +}