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 a7c9e00931517..5e4559a8a4a9d 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 @@ -21,11 +21,11 @@ import org.apache.http.Header; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; +import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.close.CloseIndexResponse; -import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; -import org.elasticsearch.action.admin.indices.alias.IndicesAliasesResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -34,6 +34,8 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; import java.io.IOException; @@ -208,4 +210,48 @@ public void existsAliasAsync(GetAliasesRequest getAliasesRequest, ActionListener restHighLevelClient.performRequestAsync(getAliasesRequest, Request::existsAlias, RestHighLevelClient::convertExistsResponse, listener, emptySet(), headers); } + + /** + * Shrinks an index using the Shrink Index API + *

+ * See + * Shrink Index API on elastic.co + */ + public ResizeResponse shrink(ResizeRequest resizeRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(resizeRequest, Request::shrink, ResizeResponse::fromXContent, + emptySet(), headers); + } + + /** + * Asynchronously shrinks an index using the Shrink index API + *

+ * See + * Shrink Index API on elastic.co + */ + public void shrinkAsync(ResizeRequest resizeRequest, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(resizeRequest, Request::shrink, ResizeResponse::fromXContent, + listener, emptySet(), headers); + } + + /** + * Splits an index using the Split Index API + *

+ * See + * Shrink Index API on elastic.co + */ + public ResizeResponse split(ResizeRequest resizeRequest, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent, + emptySet(), headers); + } + + /** + * Asynchronously splits an index using the Split Index API + *

+ * See + * Split Index API on elastic.co + */ + public void splitAsync(ResizeRequest resizeRequest, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent, + listener, 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 5597fbfc16b4c..9c67a255e8048 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 @@ -36,6 +36,8 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.get.GetRequest; @@ -182,12 +184,12 @@ static Request createIndex(CreateIndexRequest createIndexRequest) throws IOExcep HttpEntity entity = createEntity(createIndexRequest, REQUEST_BODY_CONTENT_TYPE); return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); } - + static Request updateAliases(IndicesAliasesRequest indicesAliasesRequest) throws IOException { Params parameters = Params.builder(); parameters.withTimeout(indicesAliasesRequest.timeout()); parameters.withMasterTimeout(indicesAliasesRequest.masterNodeTimeout()); - + HttpEntity entity = createEntity(indicesAliasesRequest, REQUEST_BODY_CONTENT_TYPE); return new Request(HttpPost.METHOD_NAME, "/_aliases", parameters.getParams(), entity); } @@ -496,7 +498,31 @@ static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException { HttpEntity entity = null; entity = createEntity(rankEvalRequest.getRankEvalSpec(), REQUEST_BODY_CONTENT_TYPE); return new Request(HttpGet.METHOD_NAME, endpoint, Collections.emptyMap(), entity); + } + + static Request split(ResizeRequest resizeRequest) throws IOException { + if (resizeRequest.getResizeType() != ResizeType.SPLIT) { + throw new IllegalArgumentException("Wrong resize type [" + resizeRequest.getResizeType() + "] for indices split request"); + } + return resize(resizeRequest); + } + static Request shrink(ResizeRequest resizeRequest) throws IOException { + if (resizeRequest.getResizeType() != ResizeType.SHRINK) { + throw new IllegalArgumentException("Wrong resize type [" + resizeRequest.getResizeType() + "] for indices shrink request"); + } + return resize(resizeRequest); + } + + private static Request resize(ResizeRequest resizeRequest) throws IOException { + Params params = Params.builder(); + params.withTimeout(resizeRequest.timeout()); + params.withMasterTimeout(resizeRequest.masterNodeTimeout()); + params.withWaitForActiveShards(resizeRequest.getTargetIndexRequest().waitForActiveShards()); + String endpoint = buildEndpoint(resizeRequest.getSourceIndex(), "_" + resizeRequest.getResizeType().name().toLowerCase(Locale.ROOT), + resizeRequest.getTargetIndexRequest().index()); + HttpEntity entity = createEntity(resizeRequest, REQUEST_BODY_CONTENT_TYPE); + return new Request(HttpPut.METHOD_NAME, endpoint, params.getParams(), entity); } private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { 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 3a4912c91f55a..f9717f262b872 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 @@ -20,8 +20,6 @@ package org.elasticsearch.client; import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpHead; -import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchStatusException; @@ -40,13 +38,14 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; +import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.support.IndicesOptions; -import org.elasticsearch.common.Strings; 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.common.xcontent.support.XContentMapValues; import org.elasticsearch.rest.RestStatus; import java.io.IOException; @@ -59,7 +58,7 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase { - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public void testCreateIndex() throws IOException { { // Create index @@ -69,7 +68,7 @@ public void testCreateIndex() throws IOException { CreateIndexRequest createIndexRequest = new CreateIndexRequest(indexName); CreateIndexResponse createIndexResponse = - execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync); + execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync); assertTrue(createIndexResponse.isAcknowledged()); assertTrue(indexExists(indexName)); @@ -97,37 +96,30 @@ public void testCreateIndex() throws IOException { createIndexRequest.mapping("type_name", mappingBuilder); CreateIndexResponse createIndexResponse = - execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync); + execute(createIndexRequest, highLevelClient().indices()::create, highLevelClient().indices()::createAsync); assertTrue(createIndexResponse.isAcknowledged()); - Map indexMetaData = getIndexMetadata(indexName); + Map getIndexResponse = getAsMap(indexName); + assertEquals("2", XContentMapValues.extractValue(indexName + ".settings.index.number_of_replicas", getIndexResponse)); - Map settingsData = (Map) indexMetaData.get("settings"); - Map indexSettings = (Map) settingsData.get("index"); - assertEquals("2", indexSettings.get("number_of_replicas")); - - Map aliasesData = (Map) indexMetaData.get("aliases"); - Map aliasData = (Map) aliasesData.get("alias_name"); + Map aliasData = + (Map)XContentMapValues.extractValue(indexName + ".aliases.alias_name", getIndexResponse); + assertNotNull(aliasData); assertEquals("1", aliasData.get("index_routing")); Map filter = (Map) aliasData.get("filter"); Map term = (Map) filter.get("term"); assertEquals(2016, term.get("year")); - Map mappingsData = (Map) indexMetaData.get("mappings"); - Map typeData = (Map) mappingsData.get("type_name"); - Map properties = (Map) typeData.get("properties"); - Map field = (Map) properties.get("field"); - - assertEquals("text", field.get("type")); + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.type_name.properties.field.type", getIndexResponse)); } } - @SuppressWarnings({ "unchecked", "rawtypes" }) + @SuppressWarnings({"unchecked", "rawtypes"}) public void testPutMapping() throws IOException { { // Add mappings to index String indexName = "mapping_index"; - createIndex(indexName); + createIndex(indexName, Settings.EMPTY); PutMappingRequest putMappingRequest = new PutMappingRequest(indexName); putMappingRequest.type("type_name"); @@ -138,16 +130,11 @@ public void testPutMapping() throws IOException { putMappingRequest.source(mappingBuilder); PutMappingResponse putMappingResponse = - execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); + execute(putMappingRequest, highLevelClient().indices()::putMapping, highLevelClient().indices()::putMappingAsync); assertTrue(putMappingResponse.isAcknowledged()); - Map indexMetaData = getIndexMetadata(indexName); - Map mappingsData = (Map) indexMetaData.get("mappings"); - Map typeData = (Map) mappingsData.get("type_name"); - Map properties = (Map) typeData.get("properties"); - Map field = (Map) properties.get("field"); - - assertEquals("text", field.get("type")); + Map getIndexResponse = getAsMap(indexName); + assertEquals("text", XContentMapValues.extractValue(indexName + ".mappings.type_name.properties.field.type", getIndexResponse)); } } @@ -155,11 +142,11 @@ public void testDeleteIndex() throws IOException { { // Delete index if exists String indexName = "test_index"; - createIndex(indexName); + createIndex(indexName, Settings.EMPTY); DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(indexName); DeleteIndexResponse deleteIndexResponse = - execute(deleteIndexRequest, highLevelClient().indices()::delete, highLevelClient().indices()::deleteAsync); + execute(deleteIndexRequest, highLevelClient().indices()::delete, highLevelClient().indices()::deleteAsync); assertTrue(deleteIndexResponse.isAcknowledged()); assertFalse(indexExists(indexName)); @@ -172,7 +159,7 @@ public void testDeleteIndex() throws IOException { DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(nonExistentIndex); ElasticsearchException exception = expectThrows(ElasticsearchException.class, - () -> execute(deleteIndexRequest, highLevelClient().indices()::delete, highLevelClient().indices()::deleteAsync)); + () -> execute(deleteIndexRequest, highLevelClient().indices()::delete, highLevelClient().indices()::deleteAsync)); assertEquals(RestStatus.NOT_FOUND, exception.status()); } } @@ -182,7 +169,7 @@ public void testUpdateAliases() throws IOException { String index = "index"; String alias = "alias"; - createIndex(index); + createIndex(index, Settings.EMPTY); assertThat(aliasExists(index, alias), equalTo(false)); assertThat(aliasExists(alias), equalTo(false)); @@ -242,7 +229,7 @@ public void testAliasesNonExistentIndex() throws IOException { assertThat(exception.getMessage(), equalTo("Elasticsearch exception [type=index_not_found_exception, reason=no such index]")); assertThat(exception.getMetadata("es.index"), hasItem(nonExistentIndex)); - createIndex(index); + createIndex(index, Settings.EMPTY); IndicesAliasesRequest mixedRequest = new IndicesAliasesRequest(); mixedRequest.addAliasAction(new AliasActions(AliasActions.Type.ADD).indices(index).aliases(alias)); mixedRequest.addAliasAction(new AliasActions(AliasActions.Type.REMOVE).indices(nonExistentIndex).alias(alias)); @@ -270,7 +257,7 @@ public void testAliasesNonExistentIndex() throws IOException { public void testOpenExistingIndex() throws IOException { String index = "index"; - createIndex(index); + createIndex(index, Settings.EMPTY); closeIndex(index); ResponseException exception = expectThrows(ResponseException.class, () -> client().performRequest(HttpGet.METHOD_NAME, index + "/_search")); @@ -310,7 +297,7 @@ public void testOpenNonExistentIndex() throws IOException { public void testCloseExistingIndex() throws IOException { String index = "index"; - createIndex(index); + createIndex(index, Settings.EMPTY); Response response = client().performRequest(HttpGet.METHOD_NAME, index + "/_search"); assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); @@ -339,7 +326,7 @@ public void testExistsAlias() throws IOException { GetAliasesRequest getAliasesRequest = new GetAliasesRequest("alias"); assertFalse(execute(getAliasesRequest, highLevelClient().indices()::existsAlias, highLevelClient().indices()::existsAliasAsync)); - createIndex("index"); + createIndex("index", Settings.EMPTY); client().performRequest(HttpPut.METHOD_NAME, "/index/_alias/alias"); assertTrue(execute(getAliasesRequest, highLevelClient().indices()::existsAlias, highLevelClient().indices()::existsAliasAsync)); @@ -351,64 +338,49 @@ public void testExistsAlias() throws IOException { assertFalse(execute(getAliasesRequest2, highLevelClient().indices()::existsAlias, highLevelClient().indices()::existsAliasAsync)); } - private static void createIndex(String index) throws IOException { - Response response = client().performRequest(HttpPut.METHOD_NAME, index); - assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); - } - - private static boolean indexExists(String index) throws IOException { - Response response = client().performRequest(HttpHead.METHOD_NAME, index); - return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); - } - - private static void closeIndex(String index) throws IOException { - Response response = client().performRequest(HttpPost.METHOD_NAME, index + "/_close"); - assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); - } - - private static boolean aliasExists(String alias) throws IOException { - Response response = client().performRequest(HttpHead.METHOD_NAME, "/_alias/" + alias); - return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); - } - - private static boolean aliasExists(String index, String alias) throws IOException { - Response response = client().performRequest(HttpHead.METHOD_NAME, "/" + index + "/_alias/" + alias); - return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static Map getIndexMetadata(String index) throws IOException { - Response response = client().performRequest(HttpGet.METHOD_NAME, index); - - XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue()); - Map responseEntity = XContentHelper.convertToMap(entityContentType.xContent(), response.getEntity().getContent(), - false); - - Map indexMetaData = (Map) responseEntity.get(index); - assertNotNull(indexMetaData); - - return indexMetaData; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - private static Map getAlias(final String index, final String alias) throws IOException { - String endpoint = "/_alias"; - if (false == Strings.isEmpty(index)) { - endpoint = index + endpoint; - } - if (false == Strings.isEmpty(alias)) { - endpoint = endpoint + "/" + alias; - } - Map performGet = get(endpoint); - return (Map) ((Map) ((Map) performGet.get(index)).get("aliases")).get(alias); + @SuppressWarnings("unchecked") + public void testShrink() throws IOException { + Map nodes = getAsMap("_nodes"); + String firstNode = ((Map) nodes.get("nodes")).keySet().iterator().next(); + createIndex("source", Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build()); + updateIndexSettings("source", Settings.builder().put("index.routing.allocation.require._name", firstNode) + .put("index.blocks.write", true)); + + ResizeRequest resizeRequest = new ResizeRequest("target", "source"); + resizeRequest.setResizeType(ResizeType.SHRINK); + Settings targetSettings = Settings.builder().put("index.number_of_shards", 2).put("index.number_of_replicas", 0).build(); + resizeRequest.setTargetIndex(new CreateIndexRequest("target").settings(targetSettings).alias(new Alias("alias"))); + ResizeResponse resizeResponse = highLevelClient().indices().shrink(resizeRequest); + assertTrue(resizeResponse.isAcknowledged()); + assertTrue(resizeResponse.isShardsAcknowledged()); + Map getIndexResponse = getAsMap("target"); + Map indexSettings = (Map)XContentMapValues.extractValue("target.settings.index", getIndexResponse); + assertNotNull(indexSettings); + assertEquals("2", indexSettings.get("number_of_shards")); + assertEquals("0", indexSettings.get("number_of_replicas")); + Map aliasData = (Map)XContentMapValues.extractValue("target.aliases.alias", getIndexResponse); + assertNotNull(aliasData); } - private static Map get(final String endpoint) throws IOException { - Response response = client().performRequest(HttpGet.METHOD_NAME, endpoint); - XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue()); - Map responseEntity = XContentHelper.convertToMap(entityContentType.xContent(), response.getEntity().getContent(), - false); - assertNotNull(responseEntity); - return responseEntity; + @SuppressWarnings("unchecked") + public void testSplit() throws IOException { + createIndex("source", Settings.builder().put("index.number_of_shards", 2).put("index.number_of_replicas", 0) + .put("index.number_of_routing_shards", 4).build()); + updateIndexSettings("source", Settings.builder().put("index.blocks.write", true)); + + ResizeRequest resizeRequest = new ResizeRequest("target", "source"); + resizeRequest.setResizeType(ResizeType.SPLIT); + Settings targetSettings = Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build(); + resizeRequest.setTargetIndex(new CreateIndexRequest("target").settings(targetSettings).alias(new Alias("alias"))); + ResizeResponse resizeResponse = highLevelClient().indices().split(resizeRequest); + assertTrue(resizeResponse.isAcknowledged()); + assertTrue(resizeResponse.isShardsAcknowledged()); + Map getIndexResponse = getAsMap("target"); + Map indexSettings = (Map)XContentMapValues.extractValue("target.settings.index", getIndexResponse); + assertNotNull(indexSettings); + assertEquals("4", indexSettings.get("number_of_shards")); + assertEquals("0", indexSettings.get("number_of_replicas")); + Map aliasData = (Map)XContentMapValues.extractValue("target.aliases.alias", getIndexResponse); + assertNotNull(aliasData); } -} +} \ No newline at end of file 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 e9cab9f89533a..0e6ae3b21d5b6 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 @@ -38,6 +38,8 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkShardRequest; import org.elasticsearch.action.delete.DeleteRequest; @@ -57,6 +59,7 @@ import org.elasticsearch.action.support.replication.ReplicationRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.common.CheckedBiConsumer; +import org.elasticsearch.common.CheckedFunction; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; @@ -108,6 +111,9 @@ import static java.util.Collections.singletonMap; import static org.elasticsearch.client.Request.REQUEST_BODY_CONTENT_TYPE; import static org.elasticsearch.client.Request.enforceSameContentType; +import static org.elasticsearch.index.RandomCreateIndexGenerator.randomAliases; +import static org.elasticsearch.index.RandomCreateIndexGenerator.randomCreateIndexRequest; +import static org.elasticsearch.index.RandomCreateIndexGenerator.randomIndexSettings; import static org.elasticsearch.index.alias.RandomAliasActionsGenerator.randomAliasAction; import static org.elasticsearch.search.RandomSearchRequestGenerator.randomSearchRequest; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent; @@ -315,20 +321,15 @@ private static void getAndExistsTest(Function requestConver } public void testCreateIndex() throws IOException { - CreateIndexRequest createIndexRequest = new CreateIndexRequest(); - - String indexName = "index-" + randomAlphaOfLengthBetween(2, 5); - - createIndexRequest.index(indexName); + CreateIndexRequest createIndexRequest = randomCreateIndexRequest(); Map expectedParams = new HashMap<>(); - setRandomTimeout(createIndexRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams); setRandomMasterTimeout(createIndexRequest, expectedParams); setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams); Request request = Request.createIndex(createIndexRequest); - assertEquals("/" + indexName, request.getEndpoint()); + assertEquals("/" + createIndexRequest.index(), request.getEndpoint()); assertEquals(expectedParams, request.getParameters()); assertEquals(HttpPut.METHOD_NAME, request.getMethod()); assertToXContentBody(createIndexRequest, request.getEntity()); @@ -1026,6 +1027,7 @@ public void testExistsAlias() { if (Strings.hasLength(alias)) { expectedEndpoint.add(alias); } + assertEquals(HttpHead.METHOD_NAME, request.getMethod()); assertEquals(expectedEndpoint.toString(), request.getEndpoint()); assertEquals(expectedParams, request.getParameters()); assertNull(request.getEntity()); @@ -1057,6 +1059,64 @@ public void testRankEval() throws Exception { assertToXContentBody(spec, request.getEntity()); } + public void testSplit() throws IOException { + resizeTest(ResizeType.SPLIT, Request::split); + } + + public void testSplitWrongResizeType() { + ResizeRequest resizeRequest = new ResizeRequest("target", "source"); + resizeRequest.setResizeType(ResizeType.SHRINK); + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> Request.split(resizeRequest)); + assertEquals("Wrong resize type [SHRINK] for indices split request", iae.getMessage()); + } + + public void testShrinkWrongResizeType() { + ResizeRequest resizeRequest = new ResizeRequest("target", "source"); + resizeRequest.setResizeType(ResizeType.SPLIT); + IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> Request.shrink(resizeRequest)); + assertEquals("Wrong resize type [SPLIT] for indices shrink request", iae.getMessage()); + } + + public void testShrink() throws IOException { + resizeTest(ResizeType.SHRINK, Request::shrink); + } + + private static void resizeTest(ResizeType resizeType, CheckedFunction function) + throws IOException { + String[] indices = randomIndicesNames(2, 2); + ResizeRequest resizeRequest = new ResizeRequest(indices[0], indices[1]); + resizeRequest.setResizeType(resizeType); + Map expectedParams = new HashMap<>(); + setRandomMasterTimeout(resizeRequest, expectedParams); + setRandomTimeout(resizeRequest::timeout, resizeRequest.timeout(), expectedParams); + + if (randomBoolean()) { + CreateIndexRequest createIndexRequest = new CreateIndexRequest(randomAlphaOfLengthBetween(3, 10)); + if (randomBoolean()) { + createIndexRequest.settings(randomIndexSettings()); + } + if (randomBoolean()) { + randomAliases(createIndexRequest); + } + if (randomBoolean()) { + setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams); + } + resizeRequest.setTargetIndex(createIndexRequest); + } else { + if (randomBoolean()) { + setRandomWaitForActiveShards(resizeRequest::setWaitForActiveShards, expectedParams); + } + } + + Request request = function.apply(resizeRequest); + assertEquals(HttpPut.METHOD_NAME, request.getMethod()); + String expectedEndpoint = "/" + resizeRequest.getSourceIndex() + "/_" + resizeType.name().toLowerCase(Locale.ROOT) + "/" + + resizeRequest.getTargetIndexRequest().index(); + assertEquals(expectedEndpoint, request.getEndpoint()); + assertEquals(expectedParams, request.getParameters()); + assertToXContentBody(resizeRequest, request.getEntity()); + } + private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException { BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false); assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue()); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java index 1ea66ffe70bdc..c851c0a89fd16 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java @@ -36,6 +36,9 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; +import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; +import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; +import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.ESRestHighLevelClientTestCase; @@ -47,6 +50,7 @@ import org.elasticsearch.rest.RestStatus; import java.io.IOException; +import java.util.Map; /** * This class is used to generate the Java Indices API documentation. @@ -334,7 +338,6 @@ public void testOpenIndex() throws Exception { request.waitForActiveShards(ActiveShardCount.DEFAULT); // <2> // end::open-index-request-waitForActiveShards - // tag::open-index-request-indicesOptions request.indicesOptions(IndicesOptions.strictExpandOpen()); // <1> // end::open-index-request-indicesOptions @@ -559,4 +562,125 @@ public void onFailure(Exception e) { assertBusy(() -> assertTrue(client.indices().existsAlias(new GetAliasesRequest("async")))); } } + + @SuppressWarnings("unchecked") + public void testShrinkIndex() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + Map nodes = getAsMap("_nodes"); + String firstNode = ((Map) nodes.get("nodes")).keySet().iterator().next(); + createIndex("source_index", Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build()); + updateIndexSettings("source_index", Settings.builder().put("index.routing.allocation.require._name", firstNode) + .put("index.blocks.write", true)); + } + + // tag::shrink-index-request + ResizeRequest request = new ResizeRequest("target_index","source_index"); // <1> + // end::shrink-index-request + + // tag::shrink-index-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::shrink-index-request-timeout + // tag::shrink-index-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::shrink-index-request-masterTimeout + // tag::shrink-index-request-waitForActiveShards + request.getTargetIndexRequest().waitForActiveShards(2); // <1> + request.getTargetIndexRequest().waitForActiveShards(ActiveShardCount.DEFAULT); // <2> + // end::shrink-index-request-waitForActiveShards + // tag::shrink-index-request-settings + request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 2)); // <1> + // end::shrink-index-request-settings + // tag::shrink-index-request-aliases + request.getTargetIndexRequest().alias(new Alias("target_alias")); // <1> + // end::shrink-index-request-aliases + + // tag::shrink-index-execute + ResizeResponse resizeResponse = client.indices().shrink(request); + // end::shrink-index-execute + + // tag::shrink-index-response + boolean acknowledged = resizeResponse.isAcknowledged(); // <1> + boolean shardsAcked = resizeResponse.isShardsAcknowledged(); // <2> + // end::shrink-index-response + assertTrue(acknowledged); + assertTrue(shardsAcked); + + // tag::shrink-index-execute-async + client.indices().shrinkAsync(request, new ActionListener() { + @Override + public void onResponse(ResizeResponse resizeResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::shrink-index-execute-async + } + + @SuppressWarnings("unchecked") + public void testSplitIndex() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + createIndex("source_index", Settings.builder().put("index.number_of_shards", 2).put("index.number_of_replicas", 0) + .put("index.number_of_routing_shards", 4).build()); + updateIndexSettings("source_index", Settings.builder().put("index.blocks.write", true)); + } + + // tag::split-index-request + ResizeRequest request = new ResizeRequest("target_index","source_index"); // <1> + request.setResizeType(ResizeType.SPLIT); // <2> + // end::split-index-request + + // tag::split-index-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::split-index-request-timeout + // tag::split-index-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::split-index-request-masterTimeout + // tag::split-index-request-waitForActiveShards + request.getTargetIndexRequest().waitForActiveShards(2); // <1> + request.getTargetIndexRequest().waitForActiveShards(ActiveShardCount.DEFAULT); // <2> + // end::split-index-request-waitForActiveShards + // tag::split-index-request-settings + request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 4)); // <1> + // end::split-index-request-settings + // tag::split-index-request-aliases + request.getTargetIndexRequest().alias(new Alias("target_alias")); // <1> + // end::split-index-request-aliases + + // tag::split-index-execute + ResizeResponse resizeResponse = client.indices().split(request); + // end::split-index-execute + + // tag::split-index-response + boolean acknowledged = resizeResponse.isAcknowledged(); // <1> + boolean shardsAcked = resizeResponse.isShardsAcknowledged(); // <2> + // end::split-index-response + assertTrue(acknowledged); + assertTrue(shardsAcked); + + // tag::split-index-execute-async + client.indices().splitAsync(request, new ActionListener() { + @Override + public void onResponse(ResizeResponse resizeResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }); + // end::split-index-execute-async + } } diff --git a/docs/java-rest/high-level/apis/index.asciidoc b/docs/java-rest/high-level/apis/index.asciidoc index 5f1f15b644799..f81eecc3ebe9a 100644 --- a/docs/java-rest/high-level/apis/index.asciidoc +++ b/docs/java-rest/high-level/apis/index.asciidoc @@ -12,6 +12,10 @@ include::update_aliases.asciidoc[] include::exists_alias.asciidoc[] +include::shrink_index.asciidoc[] + +include::split_index.asciidoc[] + include::_index.asciidoc[] include::get.asciidoc[] diff --git a/docs/java-rest/high-level/apis/shrink_index.asciidoc b/docs/java-rest/high-level/apis/shrink_index.asciidoc new file mode 100644 index 0000000000000..22eb814b57ab5 --- /dev/null +++ b/docs/java-rest/high-level/apis/shrink_index.asciidoc @@ -0,0 +1,90 @@ +[[java-rest-high-shrink-index]] +=== Shrink Index API + +[[java-rest-high-shrink-index-request]] +==== Resize Request + +The Shrink API requires a `ResizeRequest` instance. +A `ResizeRequest` requires two string arguments: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request] +-------------------------------------------------- +<1> The target index (first argument) to shrink the source index (second argument) into + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the index is opened +as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the index is opened +as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request-waitForActiveShards] +-------------------------------------------------- +<1> The number of active shard copies to wait for before the shrink index API +returns a response, as an `int` +<2> The number of active shard copies to wait for before the shrink index API +returns a response, as an `ActiveShardCount` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request-settings] +-------------------------------------------------- +<1> The settings to apply to the target index, which include the number of +shards to create for it + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-request-aliases] +-------------------------------------------------- +<1> The aliases to associate the target index with + +[[java-rest-high-shrink-index-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-execute] +-------------------------------------------------- + +[[java-rest-high-shrink-index-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-execute-async] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument + +[[java-rest-high-shrink-index-response]] +==== Shrink Index Response + +The returned `ResizeResponse` allows to retrieve information about the +executed operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[shrink-index-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request +<2> Indicates whether the requisite number of shard copies were started for +each shard in the index before timing out + + diff --git a/docs/java-rest/high-level/apis/split_index.asciidoc b/docs/java-rest/high-level/apis/split_index.asciidoc new file mode 100644 index 0000000000000..5d7285991a275 --- /dev/null +++ b/docs/java-rest/high-level/apis/split_index.asciidoc @@ -0,0 +1,91 @@ +[[java-rest-high-split-index]] +=== Split Index API + +[[java-rest-high-split-index-request]] +==== Resize Request + +The Split API requires a `ResizeRequest` instance. +A `ResizeRequest` requires two string arguments: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request] +-------------------------------------------------- +<1> The target index (first argument) to split the source index (second argument) into +<2> The resize type needs to be set to `SPLIT` + +==== Optional arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-timeout] +-------------------------------------------------- +<1> Timeout to wait for the all the nodes to acknowledge the index is opened +as a `TimeValue` +<2> Timeout to wait for the all the nodes to acknowledge the index is opened +as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-waitForActiveShards] +-------------------------------------------------- +<1> The number of active shard copies to wait for before the split index API +returns a response, as an `int`. +<2> The number of active shard copies to wait for before the split index API +returns a response, as an `ActiveShardCount`. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-settings] +-------------------------------------------------- +<1> The settings to apply to the target index, which include the number of +shards to create for it. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-aliases] +-------------------------------------------------- +<1> The aliases to associate the target index with. + +[[java-rest-high-split-index-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-execute] +-------------------------------------------------- + +[[java-rest-high-split-index-async]] +==== Asynchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-execute-async] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of failure. The raised exception is provided as an argument + +[[java-rest-high-split-index-response]] +==== Split Index Response + +The returned `ResizeResponse` allows to retrieve information about the +executed operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-response] +-------------------------------------------------- +<1> Indicates whether all of the nodes have acknowledged the request +<2> Indicates whether the requisite number of shard copies were started for +each shard in the index before timing out + + diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 8eb2590e99d9d..a75d5f8c7ab50 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -11,6 +11,8 @@ Indices APIs:: * <> * <> * <> +* <> +* <> Single document APIs:: * <> diff --git a/qa/mixed-cluster/src/test/java/org/elasticsearch/backwards/IndexingIT.java b/qa/mixed-cluster/src/test/java/org/elasticsearch/backwards/IndexingIT.java index 958cd9fe3ef91..e0ee8bac8bfe0 100644 --- a/qa/mixed-cluster/src/test/java/org/elasticsearch/backwards/IndexingIT.java +++ b/qa/mixed-cluster/src/test/java/org/elasticsearch/backwards/IndexingIT.java @@ -103,7 +103,7 @@ public void testIndexVersionPropagation() throws Exception { logger.info("indexing docs with [{}] concurrent updates initially", nUpdates); final int finalVersionForDoc1 = indexDocWithConcurrentUpdates(index, 1, nUpdates); logger.info("allowing shards on all nodes"); - updateIndexSetting(index, Settings.builder().putNull("index.routing.allocation.include._name")); + updateIndexSettings(index, Settings.builder().putNull("index.routing.allocation.include._name")); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); List shards = buildShards(index, nodes, newNodeClient); @@ -128,7 +128,7 @@ public void testIndexVersionPropagation() throws Exception { primary = shards.stream().filter(Shard::isPrimary).findFirst().get(); logger.info("moving primary to new node by excluding {}", primary.getNode().getNodeName()); - updateIndexSetting(index, Settings.builder().put("index.routing.allocation.exclude._name", primary.getNode().getNodeName())); + updateIndexSettings(index, Settings.builder().put("index.routing.allocation.exclude._name", primary.getNode().getNodeName())); ensureGreen(index); nUpdates = randomIntBetween(minUpdates, maxUpdates); logger.info("indexing docs with [{}] concurrent updates after moving primary", nUpdates); @@ -141,7 +141,7 @@ public void testIndexVersionPropagation() throws Exception { } logger.info("setting number of replicas to 0"); - updateIndexSetting(index, Settings.builder().put("index.number_of_replicas", 0)); + updateIndexSettings(index, Settings.builder().put("index.number_of_replicas", 0)); ensureGreen(index); nUpdates = randomIntBetween(minUpdates, maxUpdates); logger.info("indexing doc with [{}] concurrent updates after setting number of replicas to 0", nUpdates); @@ -154,7 +154,7 @@ public void testIndexVersionPropagation() throws Exception { } logger.info("setting number of replicas to 1"); - updateIndexSetting(index, Settings.builder().put("index.number_of_replicas", 1)); + updateIndexSettings(index, Settings.builder().put("index.number_of_replicas", 1)); ensureGreen(index); nUpdates = randomIntBetween(minUpdates, maxUpdates); logger.info("indexing doc with [{}] concurrent updates after setting number of replicas to 1", nUpdates); @@ -189,7 +189,7 @@ public void testSeqNoCheckpoints() throws Exception { numDocs += indexDocs(index, 0, numberOfInitialDocs); assertSeqNoOnShards(index, nodes, nodes.getBWCVersion().major >= 6 ? numDocs : 0, newNodeClient); logger.info("allowing shards on all nodes"); - updateIndexSetting(index, Settings.builder().putNull("index.routing.allocation.include._name")); + updateIndexSettings(index, Settings.builder().putNull("index.routing.allocation.include._name")); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); for (final String bwcName : bwcNamesList) { @@ -201,7 +201,7 @@ public void testSeqNoCheckpoints() throws Exception { assertSeqNoOnShards(index, nodes, nodes.getBWCVersion().major >= 6 ? numDocs : 0, newNodeClient); Shard primary = buildShards(index, nodes, newNodeClient).stream().filter(Shard::isPrimary).findFirst().get(); logger.info("moving primary to new node by excluding {}", primary.getNode().getNodeName()); - updateIndexSetting(index, Settings.builder().put("index.routing.allocation.exclude._name", primary.getNode().getNodeName())); + updateIndexSettings(index, Settings.builder().put("index.routing.allocation.exclude._name", primary.getNode().getNodeName())); ensureGreen(index); int numDocsOnNewPrimary = 0; final int numberOfDocsAfterMovingPrimary = 1 + randomInt(5); @@ -214,13 +214,13 @@ public void testSeqNoCheckpoints() throws Exception { * the recovery code. */ logger.info("setting number of replicas to 0"); - updateIndexSetting(index, Settings.builder().put("index.number_of_replicas", 0)); + updateIndexSettings(index, Settings.builder().put("index.number_of_replicas", 0)); final int numberOfDocsAfterDroppingReplicas = 1 + randomInt(5); logger.info("indexing [{}] docs after setting number of replicas to 0", numberOfDocsAfterDroppingReplicas); numDocsOnNewPrimary += indexDocs(index, numDocs, numberOfDocsAfterDroppingReplicas); numDocs += numberOfDocsAfterDroppingReplicas; logger.info("setting number of replicas to 1"); - updateIndexSetting(index, Settings.builder().put("index.number_of_replicas", 1)); + updateIndexSettings(index, Settings.builder().put("index.number_of_replicas", 1)); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); @@ -272,7 +272,7 @@ public void testUpdateSnapshotStatus() throws Exception { ); // Allocating shards on all nodes, taking snapshots should happen on all nodes. - updateIndexSetting(index, Settings.builder().putNull("index.routing.allocation.include._name")); + updateIndexSettings(index, Settings.builder().putNull("index.routing.allocation.include._name")); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); diff --git a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java index d20ccc7e4746f..d208a7097a784 100644 --- a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java +++ b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/RecoveryIT.java @@ -172,20 +172,20 @@ public void testRecoveryWithConcurrentIndexing() throws Exception { indexDocs(index, 0, 10); ensureGreen(index); // make sure that we can index while the replicas are recovering - updateIndexSetting(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "primaries")); + updateIndexSettings(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "primaries")); break; case MIXED: - updateIndexSetting(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)); + updateIndexSettings(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)); asyncIndexDocs(index, 10, 50).get(); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); assertCount(index, "_only_nodes:" + nodes.get(0), 60); assertCount(index, "_only_nodes:" + nodes.get(1), 60); // make sure that we can index while the replicas are recovering - updateIndexSetting(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "primaries")); + updateIndexSettings(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "primaries")); break; case UPGRADED: - updateIndexSetting(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)); + updateIndexSettings(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null)); asyncIndexDocs(index, 60, 50).get(); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); @@ -237,27 +237,27 @@ public void testRelocationWithConcurrentIndexing() throws Exception { ensureGreen(index); // make sure that no shards are allocated, so we can make sure the primary stays on the old node (when one // node stops, we lose the master too, so a replica will not be promoted) - updateIndexSetting(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "none")); + updateIndexSettings(index, Settings.builder().put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), "none")); break; case MIXED: final String newNode = getNodeId(v -> v.equals(Version.CURRENT)); final String oldNode = getNodeId(v -> v.before(Version.CURRENT)); // remove the replica and guaranteed the primary is placed on the old node - updateIndexSetting(index, Settings.builder() + updateIndexSettings(index, Settings.builder() .put(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0) .put(INDEX_ROUTING_ALLOCATION_ENABLE_SETTING.getKey(), (String)null) .put("index.routing.allocation.include._id", oldNode) ); ensureGreen(index); // wait for the primary to be assigned ensureNoInitializingShards(); // wait for all other shard activity to finish - updateIndexSetting(index, Settings.builder().put("index.routing.allocation.include._id", newNode)); + updateIndexSettings(index, Settings.builder().put("index.routing.allocation.include._id", newNode)); asyncIndexDocs(index, 10, 50).get(); ensureGreen(index); assertOK(client().performRequest("POST", index + "/_refresh")); assertCount(index, "_only_nodes:" + newNode, 60); break; case UPGRADED: - updateIndexSetting(index, Settings.builder() + updateIndexSettings(index, Settings.builder() .put(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 1) .put("index.routing.allocation.include._id", (String)null) ); diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java index 12f9f75619412..93d3530e53680 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java @@ -70,8 +70,8 @@ public class CreateIndexRequest extends AcknowledgedRequest implements IndicesRequest, ToXContentObject { private static final ParseField MAPPINGS = new ParseField("mappings"); - private static final ParseField SETTINGS = new ParseField("settings"); - private static final ParseField ALIASES = new ParseField("aliases"); + public static final ParseField SETTINGS = new ParseField("settings"); + public static final ParseField ALIASES = new ParseField("aliases"); private String cause = ""; diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java index 6065fcd449b3f..be30a8c97b189 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponse.java @@ -46,10 +46,14 @@ public class CreateIndexResponse extends AcknowledgedResponse implements ToXCont true, args -> new CreateIndexResponse((boolean) args[0], (boolean) args[1], (String) args[2])); static { - declareAcknowledgedField(PARSER); - PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED, - ObjectParser.ValueType.BOOLEAN); - PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), INDEX, ObjectParser.ValueType.STRING); + declareFields(PARSER); + } + + protected static void declareFields(ConstructingObjectParser objectParser) { + declareAcknowledgedField(objectParser); + objectParser.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED, + ObjectParser.ValueType.BOOLEAN); + objectParser.declareField(constructorArg(), (parser, context) -> parser.text(), INDEX, ObjectParser.ValueType.STRING); } private boolean shardsAcknowledged; @@ -112,7 +116,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public static CreateIndexResponse fromXContent(XContentParser parser) throws IOException { + public static CreateIndexResponse fromXContent(XContentParser parser) { return PARSER.apply(parser, null); } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequest.java index 016ada92794f6..79600674f4ade 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequest.java @@ -18,9 +18,9 @@ */ package org.elasticsearch.action.admin.indices.shrink; -import org.elasticsearch.Version; import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.IndicesRequest; +import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.IndicesOptions; @@ -30,6 +30,9 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; 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 java.util.Objects; @@ -39,7 +42,7 @@ /** * Request class to shrink an index into a single shard */ -public class ResizeRequest extends AcknowledgedRequest implements IndicesRequest { +public class ResizeRequest extends AcknowledgedRequest implements IndicesRequest, ToXContentObject { public static final ObjectParser PARSER = new ObjectParser<>("resize_request", null); static { @@ -173,4 +176,29 @@ public void setResizeType(ResizeType type) { public ResizeType getResizeType() { return type; } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + { + builder.startObject(CreateIndexRequest.SETTINGS.getPreferredName()); + { + targetIndexRequest.settings().toXContent(builder, params); + } + builder.endObject(); + builder.startObject(CreateIndexRequest.ALIASES.getPreferredName()); + { + for (Alias alias : targetIndexRequest.aliases()) { + alias.toXContent(builder, params); + } + } + builder.endObject(); + } + builder.endObject(); + return builder; + } + + public void fromXContent(XContentParser parser) throws IOException { + PARSER.parse(parser, this, null); + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponse.java index efbb87e291b4d..c116bd896c81f 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponse.java @@ -20,12 +20,29 @@ package org.elasticsearch.action.admin.indices.shrink; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.XContentParser; +/** + * A response for a resize index action, either shrink or split index. + */ public final class ResizeResponse extends CreateIndexResponse { + + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>("resize_index", + true, args -> new ResizeResponse((boolean) args[0], (boolean) args[1], (String) args[2])); + + static { + declareFields(PARSER); + } + ResizeResponse() { } ResizeResponse(boolean acknowledged, boolean shardsAcknowledged, String index) { super(acknowledged, shardsAcknowledged, index); } + + public static ResizeResponse fromXContent(XContentParser parser) { + return PARSER.apply(parser, null); + } } diff --git a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java index aac8f6af42c9e..18cb416a763fe 100755 --- a/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java +++ b/server/src/main/java/org/elasticsearch/action/support/master/AcknowledgedResponse.java @@ -38,8 +38,8 @@ public abstract class AcknowledgedResponse extends ActionResponse { private static final ParseField ACKNOWLEDGED = new ParseField("acknowledged"); - protected static void declareAcknowledgedField(ConstructingObjectParser PARSER) { - PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), ACKNOWLEDGED, + protected static void declareAcknowledgedField(ConstructingObjectParser objectParser) { + objectParser.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), ACKNOWLEDGED, ObjectParser.ValueType.BOOLEAN); } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestShrinkIndexAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestShrinkIndexAction.java index a0071d70758af..c72dad2654e61 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestShrinkIndexAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestShrinkIndexAction.java @@ -55,7 +55,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC } ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index")); shrinkIndexRequest.setResizeType(ResizeType.SHRINK); - request.applyContentParser(parser -> ResizeRequest.PARSER.parse(parser, shrinkIndexRequest, null)); + request.applyContentParser(shrinkIndexRequest::fromXContent); shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout())); shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout())); shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSplitIndexAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSplitIndexAction.java index dcc811bd0177b..9bd1711d15a6e 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSplitIndexAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestSplitIndexAction.java @@ -55,7 +55,7 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC } ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index")); shrinkIndexRequest.setResizeType(ResizeType.SPLIT); - request.applyContentParser(parser -> ResizeRequest.PARSER.parse(parser, shrinkIndexRequest, null)); + request.applyContentParser(shrinkIndexRequest::fromXContent); shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout())); shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout())); shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java index d7553ebf07cda..acb7161fb5a1f 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -26,18 +26,16 @@ import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.common.xcontent.XContentBuilder; -import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.test.ESTestCase; import java.io.IOException; import java.util.Map; import java.util.Set; -import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS; @@ -60,7 +58,7 @@ public void testSerialization() throws IOException { } } - public void testTopLevelKeys() throws IOException { + public void testTopLevelKeys() { String createIndex = "{\n" + " \"FOO_SHOULD_BE_ILLEGAL_HERE\": {\n" @@ -109,7 +107,7 @@ public void testToXContent() throws IOException { public void testToAndFromXContent() throws IOException { - final CreateIndexRequest createIndexRequest = createTestItem(); + final CreateIndexRequest createIndexRequest = RandomCreateIndexGenerator.randomCreateIndexRequest(); boolean humanReadable = randomBoolean(); final XContentType xContentType = randomFrom(XContentType.values()); @@ -135,7 +133,7 @@ private void assertMappingsEqual(Map expected, Map expected, Set actual) throws IOException { + public static void assertAliasesEqual(Set expected, Set actual) throws IOException { assertEquals(expected, actual); for (Alias expectedAlias : expected) { @@ -149,97 +147,4 @@ private static void assertAliasesEqual(Set expected, Set actual) t } } } - - /** - * Returns a random {@link CreateIndexRequest}. - */ - private static CreateIndexRequest createTestItem() throws IOException { - String index = randomAlphaOfLength(5); - - CreateIndexRequest request = new CreateIndexRequest(index); - - int aliasesNo = randomIntBetween(0, 2); - for (int i = 0; i < aliasesNo; i++) { - request.alias(randomAlias()); - } - - if (randomBoolean()) { - String type = randomAlphaOfLength(5); - request.mapping(type, randomMapping(type)); - } - - if (randomBoolean()) { - request.settings(randomIndexSettings()); - } - - return request; - } - - private static Settings randomIndexSettings() { - Settings.Builder builder = Settings.builder(); - - if (randomBoolean()) { - int numberOfShards = randomIntBetween(1, 10); - builder.put(SETTING_NUMBER_OF_SHARDS, numberOfShards); - } - - if (randomBoolean()) { - int numberOfReplicas = randomIntBetween(1, 10); - builder.put(SETTING_NUMBER_OF_REPLICAS, numberOfReplicas); - } - - return builder.build(); - } - - private static XContentBuilder randomMapping(String type) throws IOException { - XContentBuilder builder = XContentFactory.jsonBuilder(); - builder.startObject().startObject(type); - - randomMappingFields(builder, true); - - builder.endObject().endObject(); - return builder; - } - - public static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { - builder.startObject("properties"); - - int fieldsNo = randomIntBetween(0, 5); - for (int i = 0; i < fieldsNo; i++) { - builder.startObject(randomAlphaOfLength(5)); - - if (allowObjectField && randomBoolean()) { - randomMappingFields(builder, false); - } else { - builder.field("type", "text"); - } - - builder.endObject(); - } - - builder.endObject(); - } - - private static Alias randomAlias() { - Alias alias = new Alias(randomAlphaOfLength(5)); - - if (randomBoolean()) { - if (randomBoolean()) { - alias.routing(randomAlphaOfLength(5)); - } else { - if (randomBoolean()) { - alias.indexRouting(randomAlphaOfLength(5)); - } - if (randomBoolean()) { - alias.searchRouting(randomAlphaOfLength(5)); - } - } - } - - if (randomBoolean()) { - alias.filter("{\"term\":{\"year\":2016}}"); - } - - return alias; - } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java index 6f6518462213f..69238599194d3 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/create/CreateIndexResponseTests.java @@ -117,7 +117,7 @@ private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws /** * Returns a random {@link CreateIndexResponse}. */ - private static CreateIndexResponse createTestItem() throws IOException { + private static CreateIndexResponse createTestItem() { boolean acknowledged = randomBoolean(); boolean shardsAcknowledged = acknowledged && randomBoolean(); String index = randomAlphaOfLength(5); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java index 902dc1870934c..0030dc3c7aee5 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestTests.java @@ -35,6 +35,7 @@ import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.yaml.YamlXContent; import org.elasticsearch.index.Index; +import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.test.ESTestCase; import java.io.IOException; @@ -172,7 +173,7 @@ private static XContentBuilder randomMapping() throws IOException { builder.startObject(); if (randomBoolean()) { - CreateIndexRequestTests.randomMappingFields(builder, true); + RandomCreateIndexGenerator.randomMappingFields(builder, true); } builder.endObject(); diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java new file mode 100644 index 0000000000000..6061be3353929 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeRequestTests.java @@ -0,0 +1,95 @@ +/* + * 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.shrink; + +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequestTests; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.RandomCreateIndexGenerator; +import org.elasticsearch.test.ESTestCase; + +import java.io.IOException; + +import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; +import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS; + +public class ResizeRequestTests extends ESTestCase { + + public void testToXContent() throws IOException { + { + ResizeRequest request = new ResizeRequest("target", "source"); + String actualRequestBody = Strings.toString(request); + assertEquals("{\"settings\":{},\"aliases\":{}}", actualRequestBody); + } + { + ResizeRequest request = new ResizeRequest(); + CreateIndexRequest target = new CreateIndexRequest("target"); + Alias alias = new Alias("test_alias"); + alias.routing("1"); + alias.filter("{\"term\":{\"year\":2016}}"); + target.alias(alias); + Settings.Builder settings = Settings.builder(); + settings.put(SETTING_NUMBER_OF_SHARDS, 10); + target.settings(settings); + request.setTargetIndex(target); + String actualRequestBody = Strings.toString(request); + String expectedRequestBody = "{\"settings\":{\"index\":{\"number_of_shards\":\"10\"}}," + + "\"aliases\":{\"test_alias\":{\"filter\":{\"term\":{\"year\":2016}},\"routing\":\"1\"}}}"; + assertEquals(expectedRequestBody, actualRequestBody); + } + } + + public void testToAndFromXContent() throws IOException { + final ResizeRequest resizeRequest = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(resizeRequest, xContentType, EMPTY_PARAMS, humanReadable); + + ResizeRequest parsedResizeRequest = new ResizeRequest(resizeRequest.getTargetIndexRequest().index(), + resizeRequest.getSourceIndex()); + parsedResizeRequest.fromXContent(createParser(xContentType.xContent(), originalBytes)); + + assertEquals(resizeRequest.getSourceIndex(), parsedResizeRequest.getSourceIndex()); + assertEquals(resizeRequest.getTargetIndexRequest().index(), parsedResizeRequest.getTargetIndexRequest().index()); + CreateIndexRequestTests.assertAliasesEqual(resizeRequest.getTargetIndexRequest().aliases(), + parsedResizeRequest.getTargetIndexRequest().aliases()); + assertEquals(resizeRequest.getTargetIndexRequest().settings(), parsedResizeRequest.getTargetIndexRequest().settings()); + } + + private static ResizeRequest createTestItem() { + ResizeRequest resizeRequest = new ResizeRequest(randomAlphaOfLengthBetween(3, 10), randomAlphaOfLengthBetween(3, 10)); + if (randomBoolean()) { + CreateIndexRequest createIndexRequest = new CreateIndexRequest(randomAlphaOfLengthBetween(3, 10)); + if (randomBoolean()) { + RandomCreateIndexGenerator.randomAliases(createIndexRequest); + } + if (randomBoolean()) { + createIndexRequest.settings(RandomCreateIndexGenerator.randomIndexSettings()); + } + resizeRequest.setTargetIndex(createIndexRequest); + } + return resizeRequest; + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponseTests.java new file mode 100644 index 0000000000000..6ed3d01e1b7dd --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/shrink/ResizeResponseTests.java @@ -0,0 +1,86 @@ +/* + * 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.shrink; + +import org.elasticsearch.common.Strings; +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; + +public class ResizeResponseTests extends ESTestCase { + + public void testToXContent() { + ResizeResponse response = new ResizeResponse(true, false, "index_name"); + String output = Strings.toString(response); + assertEquals("{\"acknowledged\":true,\"shards_acknowledged\":false,\"index\":\"index_name\"}", output); + } + + public void testToAndFromXContent() throws IOException { + doFromXContentTestWithRandomFields(false); + } + + /** + * This test adds random fields and objects to the xContent rendered out to + * ensure we can parse it back to be forward compatible with additions to + * the xContent + */ + public void testFromXContentWithRandomFields() throws IOException { + doFromXContentTestWithRandomFields(true); + } + + private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws IOException { + + final ResizeResponse resizeResponse = createTestItem(); + + boolean humanReadable = randomBoolean(); + final XContentType xContentType = randomFrom(XContentType.values()); + BytesReference originalBytes = toShuffledXContent(resizeResponse, xContentType, ToXContent.EMPTY_PARAMS, humanReadable); + + BytesReference mutated; + if (addRandomFields) { + mutated = insertRandomFields(xContentType, originalBytes, null, random()); + } else { + mutated = originalBytes; + } + ResizeResponse parsedResizeResponse; + try (XContentParser parser = createParser(xContentType.xContent(), mutated)) { + parsedResizeResponse = ResizeResponse.fromXContent(parser); + assertNull(parser.nextToken()); + } + + assertEquals(resizeResponse.index(), parsedResizeResponse.index()); + assertEquals(resizeResponse.isShardsAcknowledged(), parsedResizeResponse.isShardsAcknowledged()); + assertEquals(resizeResponse.isAcknowledged(), parsedResizeResponse.isAcknowledged()); + } + + private static ResizeResponse createTestItem() { + boolean acknowledged = randomBoolean(); + boolean shardsAcknowledged = acknowledged && randomBoolean(); + String index = randomAlphaOfLength(5); + + return new ResizeResponse(acknowledged, shardsAcknowledged, index); + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java new file mode 100644 index 0000000000000..ec3c9e4dbb430 --- /dev/null +++ b/test/framework/src/main/java/org/elasticsearch/index/RandomCreateIndexGenerator.java @@ -0,0 +1,143 @@ +/* + * 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.index; + +import org.elasticsearch.action.admin.indices.alias.Alias; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; + +import java.io.IOException; + +import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS; +import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS; +import static org.elasticsearch.test.ESTestCase.randomAlphaOfLength; +import static org.elasticsearch.test.ESTestCase.randomBoolean; +import static org.elasticsearch.test.ESTestCase.randomIntBetween; + +public final class RandomCreateIndexGenerator { + + private RandomCreateIndexGenerator() {} + + /** + * Returns a random {@link CreateIndexRequest}. Randomizes the index name, the aliases, + * mappings and settings associated with the index. + */ + public static CreateIndexRequest randomCreateIndexRequest() throws IOException { + String index = randomAlphaOfLength(5); + CreateIndexRequest request = new CreateIndexRequest(index); + randomAliases(request); + if (randomBoolean()) { + String type = randomAlphaOfLength(5); + request.mapping(type, randomMapping(type)); + } + if (randomBoolean()) { + request.settings(randomIndexSettings()); + } + return request; + } + + /** + * Returns a {@link Settings} instance which include random values for + * {@link org.elasticsearch.cluster.metadata.IndexMetaData#SETTING_NUMBER_OF_SHARDS} and + * {@link org.elasticsearch.cluster.metadata.IndexMetaData#SETTING_NUMBER_OF_REPLICAS} + */ + public static Settings randomIndexSettings() { + Settings.Builder builder = Settings.builder(); + + if (randomBoolean()) { + int numberOfShards = randomIntBetween(1, 10); + builder.put(SETTING_NUMBER_OF_SHARDS, numberOfShards); + } + + if (randomBoolean()) { + int numberOfReplicas = randomIntBetween(1, 10); + builder.put(SETTING_NUMBER_OF_REPLICAS, numberOfReplicas); + } + + return builder.build(); + } + + private static XContentBuilder randomMapping(String type) throws IOException { + XContentBuilder builder = XContentFactory.jsonBuilder(); + builder.startObject().startObject(type); + + randomMappingFields(builder, true); + + builder.endObject().endObject(); + return builder; + } + + /** + * Adds random mapping fields to the provided {@link XContentBuilder} + */ + public static void randomMappingFields(XContentBuilder builder, boolean allowObjectField) throws IOException { + builder.startObject("properties"); + + int fieldsNo = randomIntBetween(0, 5); + for (int i = 0; i < fieldsNo; i++) { + builder.startObject(randomAlphaOfLength(5)); + + if (allowObjectField && randomBoolean()) { + randomMappingFields(builder, false); + } else { + builder.field("type", "text"); + } + + builder.endObject(); + } + + builder.endObject(); + } + + /** + * Sets random aliases to the provided {@link CreateIndexRequest} + */ + public static void randomAliases(CreateIndexRequest request) { + int aliasesNo = randomIntBetween(0, 2); + for (int i = 0; i < aliasesNo; i++) { + request.alias(randomAlias()); + } + } + + private static Alias randomAlias() { + Alias alias = new Alias(randomAlphaOfLength(5)); + + if (randomBoolean()) { + if (randomBoolean()) { + alias.routing(randomAlphaOfLength(5)); + } else { + if (randomBoolean()) { + alias.indexRouting(randomAlphaOfLength(5)); + } + if (randomBoolean()) { + alias.searchRouting(randomAlphaOfLength(5)); + } + } + } + + if (randomBoolean()) { + alias.filter("{\"term\":{\"year\":2016}}"); + } + + return alias; + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java b/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java index 7a8355c05f91d..d4d2d78789b8e 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java +++ b/test/framework/src/main/java/org/elasticsearch/index/alias/RandomAliasActionsGenerator.java @@ -34,7 +34,10 @@ import static org.elasticsearch.test.ESTestCase.randomIntBetween; import static org.elasticsearch.test.ESTestCase.randomLong; -public class RandomAliasActionsGenerator { +public final class RandomAliasActionsGenerator { + + private RandomAliasActionsGenerator() {} + public static AliasActions randomAliasAction() { return randomAliasAction(false); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java index 8fa316802c111..0290a1009144d 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/ESRestTestCase.java @@ -21,6 +21,10 @@ import org.apache.http.Header; import org.apache.http.HttpHost; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicHeader; @@ -38,9 +42,12 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.common.xcontent.support.XContentMapValues; +import org.elasticsearch.rest.RestStatus; import org.elasticsearch.test.ESTestCase; import org.junit.After; import org.junit.AfterClass; @@ -70,7 +77,6 @@ import static java.util.Collections.sort; import static java.util.Collections.unmodifiableList; import static org.hamcrest.Matchers.anyOf; -import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; /** @@ -423,7 +429,7 @@ private Set runningTasks(Response response) throws IOException { return runningTasks; } - protected void assertOK(Response response) { + protected static void assertOK(Response response) { assertThat(response.getStatusLine().getStatusCode(), anyOf(equalTo(200), equalTo(201))); } @@ -432,7 +438,7 @@ protected void assertOK(Response response) { * in an non green state * @param index index to test for **/ - protected void ensureGreen(String index) throws IOException { + protected static void ensureGreen(String index) throws IOException { Map params = new HashMap<>(); params.put("wait_for_status", "green"); params.put("wait_for_no_relocating_shards", "true"); @@ -445,7 +451,7 @@ protected void ensureGreen(String index) throws IOException { * waits until all shard initialization is completed. This is a handy alternative to ensureGreen as it relates to all shards * in the cluster and doesn't require to know how many nodes/replica there are. */ - protected void ensureNoInitializingShards() throws IOException { + protected static void ensureNoInitializingShards() throws IOException { Map params = new HashMap<>(); params.put("wait_for_no_initializing_shards", "true"); params.put("timeout", "70s"); @@ -453,22 +459,64 @@ protected void ensureNoInitializingShards() throws IOException { assertOK(client().performRequest("GET", "_cluster/health/", params)); } - protected void createIndex(String name, Settings settings) throws IOException { + protected static void createIndex(String name, Settings settings) throws IOException { createIndex(name, settings, ""); } - protected void createIndex(String name, Settings settings, String mapping) throws IOException { - assertOK(client().performRequest("PUT", name, Collections.emptyMap(), + protected static void createIndex(String name, Settings settings, String mapping) throws IOException { + assertOK(client().performRequest(HttpPut.METHOD_NAME, name, Collections.emptyMap(), new StringEntity("{ \"settings\": " + Strings.toString(settings) + ", \"mappings\" : {" + mapping + "} }", ContentType.APPLICATION_JSON))); } - protected void updateIndexSetting(String index, Settings.Builder settings) throws IOException { - updateIndexSetting(index, settings.build()); + protected static void updateIndexSettings(String index, Settings.Builder settings) throws IOException { + updateIndexSettings(index, settings.build()); } - private void updateIndexSetting(String index, Settings settings) throws IOException { + private static void updateIndexSettings(String index, Settings settings) throws IOException { assertOK(client().performRequest("PUT", index + "/_settings", Collections.emptyMap(), new StringEntity(Strings.toString(settings), ContentType.APPLICATION_JSON))); } + + protected static boolean indexExists(String index) throws IOException { + Response response = client().performRequest(HttpHead.METHOD_NAME, index); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } + + protected static void closeIndex(String index) throws IOException { + Response response = client().performRequest(HttpPost.METHOD_NAME, index + "/_close"); + assertThat(response.getStatusLine().getStatusCode(), equalTo(RestStatus.OK.getStatus())); + } + + protected static boolean aliasExists(String alias) throws IOException { + Response response = client().performRequest(HttpHead.METHOD_NAME, "/_alias/" + alias); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } + + protected static boolean aliasExists(String index, String alias) throws IOException { + Response response = client().performRequest(HttpHead.METHOD_NAME, "/" + index + "/_alias/" + alias); + return RestStatus.OK.getStatus() == response.getStatusLine().getStatusCode(); + } + + @SuppressWarnings("unchecked") + protected static Map getAlias(final String index, final String alias) throws IOException { + String endpoint = "/_alias"; + if (false == Strings.isEmpty(index)) { + endpoint = index + endpoint; + } + if (false == Strings.isEmpty(alias)) { + endpoint = endpoint + "/" + alias; + } + Map getAliasResponse = getAsMap(endpoint); + return (Map)XContentMapValues.extractValue(index + ".aliases." + alias, getAliasResponse); + } + + protected static Map getAsMap(final String endpoint) throws IOException { + Response response = client().performRequest(HttpGet.METHOD_NAME, endpoint); + XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue()); + Map responseEntity = XContentHelper.convertToMap(entityContentType.xContent(), + response.getEntity().getContent(), false); + assertNotNull(responseEntity); + return responseEntity; + } }