REST high-level client: add support for Rollover Index API (#28698)

Relates to #27205
This commit is contained in:
Luca Cavanna 2018-02-20 15:58:58 +01:00 committed by GitHub
parent 94594f19ab
commit 8bbb3c9ffa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 1026 additions and 370 deletions

View File

@ -35,6 +35,8 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
@ -272,7 +274,7 @@ public final class IndicesClient {
* Splits an index using the Split Index API * Splits an index using the Split Index API
* <p> * <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-split-index.html"> * See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-split-index.html">
* Shrink Index API on elastic.co</a> * Split Index API on elastic.co</a>
*/ */
public ResizeResponse split(ResizeRequest resizeRequest, Header... headers) throws IOException { public ResizeResponse split(ResizeRequest resizeRequest, Header... headers) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent, return restHighLevelClient.performRequestAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent,
@ -289,4 +291,26 @@ public final class IndicesClient {
restHighLevelClient.performRequestAsyncAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent, restHighLevelClient.performRequestAsyncAndParseEntity(resizeRequest, Request::split, ResizeResponse::fromXContent,
listener, emptySet(), headers); listener, emptySet(), headers);
} }
/**
* Rolls over an index using the Rollover Index API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-rollover-index.html">
* Rollover Index API on elastic.co</a>
*/
public RolloverResponse rollover(RolloverRequest rolloverRequest, Header... headers) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(rolloverRequest, Request::rollover, RolloverResponse::fromXContent,
emptySet(), headers);
}
/**
* Asynchronously rolls over an index using the Rollover Index API
* <p>
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-rollover-index.html">
* Rollover Index API on elastic.co</a>
*/
public void rolloverAsync(RolloverRequest rolloverRequest, ActionListener<RolloverResponse> listener, Header... headers) {
restHighLevelClient.performRequestAsyncAndParseEntity(rolloverRequest, Request::rollover, RolloverResponse::fromXContent,
listener, emptySet(), headers);
}
} }

View File

@ -38,6 +38,7 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequest;
@ -498,11 +499,10 @@ public final class Request {
} }
static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException { static Request rankEval(RankEvalRequest rankEvalRequest) throws IOException {
// TODO maybe indices should be propery of RankEvalRequest and not of the spec // TODO maybe indices should be property of RankEvalRequest and not of the spec
List<String> indices = rankEvalRequest.getRankEvalSpec().getIndices(); List<String> indices = rankEvalRequest.getRankEvalSpec().getIndices();
String endpoint = endpoint(indices.toArray(new String[indices.size()]), Strings.EMPTY_ARRAY, "_rank_eval"); String endpoint = endpoint(indices.toArray(new String[indices.size()]), Strings.EMPTY_ARRAY, "_rank_eval");
HttpEntity entity = null; HttpEntity entity = createEntity(rankEvalRequest.getRankEvalSpec(), REQUEST_BODY_CONTENT_TYPE);
entity = createEntity(rankEvalRequest.getRankEvalSpec(), REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpGet.METHOD_NAME, endpoint, Collections.emptyMap(), entity); return new Request(HttpGet.METHOD_NAME, endpoint, Collections.emptyMap(), entity);
} }
@ -542,6 +542,19 @@ public final class Request {
return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity); return new Request(HttpPut.METHOD_NAME, endpoint, parameters.getParams(), entity);
} }
static Request rollover(RolloverRequest rolloverRequest) throws IOException {
Params params = Params.builder();
params.withTimeout(rolloverRequest.timeout());
params.withMasterTimeout(rolloverRequest.masterNodeTimeout());
params.withWaitForActiveShards(rolloverRequest.getCreateIndexRequest().waitForActiveShards());
if (rolloverRequest.isDryRun()) {
params.putParam("dry_run", Boolean.TRUE.toString());
}
String endpoint = buildEndpoint(rolloverRequest.getAlias(), "_rollover", rolloverRequest.getNewIndexName());
HttpEntity entity = createEntity(rolloverRequest, REQUEST_BODY_CONTENT_TYPE);
return new Request(HttpPost.METHOD_NAME, endpoint, params.getParams(), entity);
}
private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException { private static HttpEntity createEntity(ToXContent toXContent, XContentType xContentType) throws IOException {
BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef(); BytesRef source = XContentHelper.toXContent(toXContent, xContentType, false).toBytesRef();
return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType)); return new ByteArrayEntity(source.bytes, source.offset, source.length, createContentType(xContentType));

View File

@ -39,11 +39,18 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.common.xcontent.support.XContentMapValues;
@ -435,4 +442,57 @@ public class IndicesClientIT extends ESRestHighLevelClientTestCase {
Map<String, Object> aliasData = (Map<String, Object>)XContentMapValues.extractValue("target.aliases.alias", getIndexResponse); Map<String, Object> aliasData = (Map<String, Object>)XContentMapValues.extractValue("target.aliases.alias", getIndexResponse);
assertNotNull(aliasData); assertNotNull(aliasData);
} }
public void testRollover() throws IOException {
highLevelClient().indices().create(new CreateIndexRequest("test").alias(new Alias("alias")));
RolloverRequest rolloverRequest = new RolloverRequest("alias", "test_new");
rolloverRequest.addMaxIndexDocsCondition(1);
{
RolloverResponse rolloverResponse = execute(rolloverRequest, highLevelClient().indices()::rollover,
highLevelClient().indices()::rolloverAsync);
assertFalse(rolloverResponse.isRolledOver());
assertFalse(rolloverResponse.isDryRun());
Map<String, Boolean> conditionStatus = rolloverResponse.getConditionStatus();
assertEquals(1, conditionStatus.size());
assertFalse(conditionStatus.get("[max_docs: 1]"));
assertEquals("test", rolloverResponse.getOldIndex());
assertEquals("test_new", rolloverResponse.getNewIndex());
}
highLevelClient().index(new IndexRequest("test", "type", "1").source("field", "value"));
highLevelClient().index(new IndexRequest("test", "type", "2").source("field", "value")
.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL));
//without the refresh the rollover may not happen as the number of docs seen may be off
{
rolloverRequest.addMaxIndexAgeCondition(new TimeValue(1));
rolloverRequest.dryRun(true);
RolloverResponse rolloverResponse = execute(rolloverRequest, highLevelClient().indices()::rollover,
highLevelClient().indices()::rolloverAsync);
assertFalse(rolloverResponse.isRolledOver());
assertTrue(rolloverResponse.isDryRun());
Map<String, Boolean> conditionStatus = rolloverResponse.getConditionStatus();
assertEquals(2, conditionStatus.size());
assertTrue(conditionStatus.get("[max_docs: 1]"));
assertTrue(conditionStatus.get("[max_age: 1ms]"));
assertEquals("test", rolloverResponse.getOldIndex());
assertEquals("test_new", rolloverResponse.getNewIndex());
}
{
rolloverRequest.dryRun(false);
rolloverRequest.addMaxIndexSizeCondition(new ByteSizeValue(1, ByteSizeUnit.MB));
RolloverResponse rolloverResponse = execute(rolloverRequest, highLevelClient().indices()::rollover,
highLevelClient().indices()::rolloverAsync);
assertTrue(rolloverResponse.isRolledOver());
assertFalse(rolloverResponse.isDryRun());
Map<String, Boolean> conditionStatus = rolloverResponse.getConditionStatus();
assertEquals(3, conditionStatus.size());
assertTrue(conditionStatus.get("[max_docs: 1]"));
assertTrue(conditionStatus.get("[max_age: 1ms]"));
assertFalse(conditionStatus.get("[max_size: 1mb]"));
assertEquals("test", rolloverResponse.getOldIndex());
assertEquals("test_new", rolloverResponse.getNewIndex());
}
}
} }

View File

@ -40,6 +40,7 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkRequest;
@ -74,6 +75,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.index.VersionType; import org.elasticsearch.index.VersionType;
import org.elasticsearch.index.query.TermQueryBuilder; import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.rankeval.PrecisionAtK; import org.elasticsearch.index.rankeval.PrecisionAtK;
@ -1116,11 +1118,9 @@ public class RequestTests extends ESTestCase {
if (randomBoolean()) { if (randomBoolean()) {
randomAliases(createIndexRequest); randomAliases(createIndexRequest);
} }
setRandomWaitForActiveShards(createIndexRequest::waitForActiveShards, expectedParams);
resizeRequest.setTargetIndex(createIndexRequest); resizeRequest.setTargetIndex(createIndexRequest);
} else {
setRandomWaitForActiveShards(resizeRequest::setWaitForActiveShards, expectedParams);
} }
setRandomWaitForActiveShards(resizeRequest::setWaitForActiveShards, expectedParams);
Request request = function.apply(resizeRequest); Request request = function.apply(resizeRequest);
assertEquals(HttpPut.METHOD_NAME, request.getMethod()); assertEquals(HttpPut.METHOD_NAME, request.getMethod());
@ -1144,6 +1144,44 @@ public class RequestTests extends ESTestCase {
assertEquals(expectedParams, expectedRequest.getParameters()); assertEquals(expectedParams, expectedRequest.getParameters());
} }
public void testRollover() throws IOException {
RolloverRequest rolloverRequest = new RolloverRequest(randomAlphaOfLengthBetween(3, 10),
randomBoolean() ? null : randomAlphaOfLengthBetween(3, 10));
Map<String, String> expectedParams = new HashMap<>();
setRandomTimeout(rolloverRequest::timeout, rolloverRequest.timeout(), expectedParams);
setRandomMasterTimeout(rolloverRequest, expectedParams);
if (randomBoolean()) {
rolloverRequest.dryRun(randomBoolean());
if (rolloverRequest.isDryRun()) {
expectedParams.put("dry_run", "true");
}
}
if (randomBoolean()) {
rolloverRequest.addMaxIndexAgeCondition(new TimeValue(randomNonNegativeLong()));
}
if (randomBoolean()) {
String type = randomAlphaOfLengthBetween(3, 10);
rolloverRequest.getCreateIndexRequest().mapping(type, RandomCreateIndexGenerator.randomMapping(type));
}
if (randomBoolean()) {
RandomCreateIndexGenerator.randomAliases(rolloverRequest.getCreateIndexRequest());
}
if (randomBoolean()) {
rolloverRequest.getCreateIndexRequest().settings(RandomCreateIndexGenerator.randomIndexSettings());
}
setRandomWaitForActiveShards(rolloverRequest.getCreateIndexRequest()::waitForActiveShards, expectedParams);
Request request = Request.rollover(rolloverRequest);
if (rolloverRequest.getNewIndexName() == null) {
assertEquals("/" + rolloverRequest.getAlias() + "/_rollover", request.getEndpoint());
} else {
assertEquals("/" + rolloverRequest.getAlias() + "/_rollover/" + rolloverRequest.getNewIndexName(), request.getEndpoint());
}
assertEquals(HttpPost.METHOD_NAME, request.getMethod());
assertToXContentBody(rolloverRequest, request.getEntity());
assertEquals(expectedParams, request.getParameters());
}
private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException { private static void assertToXContentBody(ToXContent expectedBody, HttpEntity actualEntity) throws IOException {
BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false); BytesReference expectedBytes = XContentHelper.toXContent(expectedBody, REQUEST_BODY_CONTENT_TYPE, false);
assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue()); assertEquals(XContentType.JSON.mediaTypeWithoutParameters(), actualEntity.getContentType().getValue());

View File

@ -38,6 +38,8 @@ import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse; import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.rollover.RolloverResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse; import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType; import org.elasticsearch.action.admin.indices.shrink.ResizeType;
@ -46,6 +48,8 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.ESRestHighLevelClientTestCase;
import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
@ -731,7 +735,6 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
} }
} }
@SuppressWarnings({"unchecked", "rawtypes"})
public void testUpdateAliases() throws Exception { public void testUpdateAliases() throws Exception {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();
@ -811,12 +814,12 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
} }
} }
@SuppressWarnings({"unchecked", "rawtypes"})
public void testShrinkIndex() throws Exception { public void testShrinkIndex() throws Exception {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();
{ {
Map<String, Object> nodes = getAsMap("_nodes"); Map<String, Object> nodes = getAsMap("_nodes");
@SuppressWarnings("unchecked")
String firstNode = ((Map<String, Object>) nodes.get("nodes")).keySet().iterator().next(); String firstNode = ((Map<String, Object>) nodes.get("nodes")).keySet().iterator().next();
createIndex("source_index", Settings.builder().put("index.number_of_shards", 4).put("index.number_of_replicas", 0).build()); 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) updateIndexSettings("source_index", Settings.builder().put("index.routing.allocation.require._name", firstNode)
@ -836,8 +839,8 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
request.masterNodeTimeout("1m"); // <2> request.masterNodeTimeout("1m"); // <2>
// end::shrink-index-request-masterTimeout // end::shrink-index-request-masterTimeout
// tag::shrink-index-request-waitForActiveShards // tag::shrink-index-request-waitForActiveShards
request.getTargetIndexRequest().waitForActiveShards(2); // <1> request.setWaitForActiveShards(2); // <1>
request.getTargetIndexRequest().waitForActiveShards(ActiveShardCount.DEFAULT); // <2> request.setWaitForActiveShards(ActiveShardCount.DEFAULT); // <2>
// end::shrink-index-request-waitForActiveShards // end::shrink-index-request-waitForActiveShards
// tag::shrink-index-request-settings // tag::shrink-index-request-settings
request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 2)); // <1> request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 2)); // <1>
@ -882,7 +885,6 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
assertTrue(latch.await(30L, TimeUnit.SECONDS)); assertTrue(latch.await(30L, TimeUnit.SECONDS));
} }
@SuppressWarnings({"unchecked", "rawtypes"})
public void testSplitIndex() throws Exception { public void testSplitIndex() throws Exception {
RestHighLevelClient client = highLevelClient(); RestHighLevelClient client = highLevelClient();
@ -906,8 +908,8 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
request.masterNodeTimeout("1m"); // <2> request.masterNodeTimeout("1m"); // <2>
// end::split-index-request-masterTimeout // end::split-index-request-masterTimeout
// tag::split-index-request-waitForActiveShards // tag::split-index-request-waitForActiveShards
request.getTargetIndexRequest().waitForActiveShards(2); // <1> request.setWaitForActiveShards(2); // <1>
request.getTargetIndexRequest().waitForActiveShards(ActiveShardCount.DEFAULT); // <2> request.setWaitForActiveShards(ActiveShardCount.DEFAULT); // <2>
// end::split-index-request-waitForActiveShards // end::split-index-request-waitForActiveShards
// tag::split-index-request-settings // tag::split-index-request-settings
request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 4)); // <1> request.getTargetIndexRequest().settings(Settings.builder().put("index.number_of_shards", 4)); // <1>
@ -951,4 +953,89 @@ public class IndicesClientDocumentationIT extends ESRestHighLevelClientTestCase
assertTrue(latch.await(30L, TimeUnit.SECONDS)); assertTrue(latch.await(30L, TimeUnit.SECONDS));
} }
public void testRolloverIndex() throws Exception {
RestHighLevelClient client = highLevelClient();
{
client.indices().create(new CreateIndexRequest("index-1").alias(new Alias("alias")));
}
// tag::rollover-request
RolloverRequest request = new RolloverRequest("alias", "index-2"); // <1>
request.addMaxIndexAgeCondition(new TimeValue(7, TimeUnit.DAYS)); // <2>
request.addMaxIndexDocsCondition(1000); // <3>
request.addMaxIndexSizeCondition(new ByteSizeValue(5, ByteSizeUnit.GB)); // <4>
// end::rollover-request
// tag::rollover-request-timeout
request.timeout(TimeValue.timeValueMinutes(2)); // <1>
request.timeout("2m"); // <2>
// end::rollover-request-timeout
// tag::rollover-request-masterTimeout
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
request.masterNodeTimeout("1m"); // <2>
// end::rollover-request-masterTimeout
// tag::rollover-request-dryRun
request.dryRun(true); // <1>
// end::rollover-request-dryRun
// tag::rollover-request-waitForActiveShards
request.getCreateIndexRequest().waitForActiveShards(2); // <1>
request.getCreateIndexRequest().waitForActiveShards(ActiveShardCount.DEFAULT); // <2>
// end::rollover-request-waitForActiveShards
// tag::rollover-request-settings
request.getCreateIndexRequest().settings(Settings.builder().put("index.number_of_shards", 4)); // <1>
// end::rollover-request-settings
// tag::rollover-request-mapping
request.getCreateIndexRequest().mapping("type", "field", "type=keyword"); // <1>
// end::rollover-request-mapping
// tag::rollover-request-alias
request.getCreateIndexRequest().alias(new Alias("another_alias")); // <1>
// end::rollover-request-alias
// tag::rollover-execute
RolloverResponse rolloverResponse = client.indices().rollover(request);
// end::rollover-execute
// tag::rollover-response
boolean acknowledged = rolloverResponse.isAcknowledged(); // <1>
boolean shardsAcked = rolloverResponse.isShardsAcknowledged(); // <2>
String oldIndex = rolloverResponse.getOldIndex(); // <3>
String newIndex = rolloverResponse.getNewIndex(); // <4>
boolean isRolledOver = rolloverResponse.isRolledOver(); // <5>
boolean isDryRun = rolloverResponse.isDryRun(); // <6>
Map<String, Boolean> conditionStatus = rolloverResponse.getConditionStatus();// <7>
// end::rollover-response
assertFalse(acknowledged);
assertFalse(shardsAcked);
assertEquals("index-1", oldIndex);
assertEquals("index-2", newIndex);
assertFalse(isRolledOver);
assertTrue(isDryRun);
assertEquals(3, conditionStatus.size());
// tag::rollover-execute-listener
ActionListener<RolloverResponse> listener = new ActionListener<RolloverResponse>() {
@Override
public void onResponse(RolloverResponse rolloverResponse) {
// <1>
}
@Override
public void onFailure(Exception e) {
// <2>
}
};
// end::rollover-execute-listener
// Replace the empty listener by a blocking listener in test
final CountDownLatch latch = new CountDownLatch(1);
listener = new LatchedActionListener<>(listener, latch);
// tag::rollover-execute-async
client.indices().rolloverAsync(request,listener); // <1>
// end::rollover-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
}
} }

View File

@ -21,6 +21,7 @@ include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[create-index-reque
-------------------------------------------------- --------------------------------------------------
<1> Settings for this index <1> Settings for this index
[[java-rest-high-create-index-request-mappings]]
==== Index mappings ==== Index mappings
An index may be created with mappings for its document types An index may be created with mappings for its document types
@ -98,9 +99,9 @@ include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[create-index-reque
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[create-index-request-waitForActiveShards] include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[create-index-request-waitForActiveShards]
-------------------------------------------------- --------------------------------------------------
<1> The number of active shard copies to wait for before the create index API returns a <1> The number of active shard copies to wait for before the create index API returns a
response, as an `int`. response, as an `int`
<2> The number of active shard copies to wait for before the create index API returns a <2> The number of active shard copies to wait for before the create index API returns a
response, as an `ActiveShardCount`. response, as an `ActiveShardCount`
[[java-rest-high-create-index-sync]] [[java-rest-high-create-index-sync]]
==== Synchronous Execution ==== Synchronous Execution

View File

@ -41,7 +41,7 @@ include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[exists-alias-reque
-------------------------------------------------- --------------------------------------------------
<1> The `local` flag (defaults to `false`) controls whether the aliases need <1> The `local` flag (defaults to `false`) controls whether the aliases need
to be looked up in the local cluster state or in the cluster state held by to be looked up in the local cluster state or in the cluster state held by
the elected master node. the elected master node
[[java-rest-high-exists-alias-sync]] [[java-rest-high-exists-alias-sync]]
==== Synchronous Execution ==== Synchronous Execution

View File

@ -36,9 +36,9 @@ include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[open-index-request
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[open-index-request-waitForActiveShards] include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[open-index-request-waitForActiveShards]
-------------------------------------------------- --------------------------------------------------
<1> The number of active shard copies to wait for before the open index API <1> The number of active shard copies to wait for before the open index API
returns a response, as an `int`. returns a response, as an `int`
<2> The number of active shard copies to wait for before the open index API <2> The number of active shard copies to wait for before the open index API
returns a response, as an `ActiveShardCount`. returns a response, as an `ActiveShardCount`
["source","java",subs="attributes,callouts,macros"] ["source","java",subs="attributes,callouts,macros"]
-------------------------------------------------- --------------------------------------------------

View File

@ -0,0 +1,131 @@
[[java-rest-high-rollover-index]]
=== Rollover Index API
[[java-rest-high-rollover-request]]
==== Rollover Request
The Rollover Index API requires a `RolloverRequest` instance.
A `RolloverRequest` requires two string arguments at construction time, and
one or more conditions that determine when the index has to be rolled over:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-request]
--------------------------------------------------
<1> The alias (first argument) that points to the index to rollover, and
optionally the name of the new index in case the rollover operation is performed
<2> Condition on the age of the index
<3> Condition on the number of documents in the index
<4> Condition on the size of the index
==== Optional arguments
The following arguments can optionally be provided:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-request-dryRun]
--------------------------------------------------
<1> Whether the rollover should be performed (default) or only simulated
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-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[rollover-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[rollover-request-waitForActiveShards]
--------------------------------------------------
<1> The number of active shard copies to wait for before the rollover index API
returns a response, as an `int`
<2> The number of active shard copies to wait for before the rollover index API
returns a response, as an `ActiveShardCount`
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-request-settings]
--------------------------------------------------
<1> Add the settings to apply to the new index, which include the number of
shards to create for it
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-request-mapping]
--------------------------------------------------
<1> Add the mappings to associate the new index with. See <<java-rest-high-create-index-request-mappings>>
for examples on the different ways to provide mappings
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-request-alias]
--------------------------------------------------
<1> Add the aliases to associate the new index with
[[java-rest-high-rollover-sync]]
==== Synchronous Execution
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-execute]
--------------------------------------------------
[[java-rest-high-rollover-async]]
==== Asynchronous Execution
The asynchronous execution of a rollover request requires both the `RolloverRequest`
instance and an `ActionListener` instance to be passed to the asynchronous
method:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-execute-async]
--------------------------------------------------
<1> The `RolloverRequest` to execute and the `ActionListener` to use when
the execution completes
The asynchronous method does not block and returns immediately. Once it is
completed the `ActionListener` is called back using the `onResponse` method
if the execution successfully completed or using the `onFailure` method if
it failed.
A typical listener for `RolloverResponse` looks like:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-execute-listener]
--------------------------------------------------
<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-rollover-response]]
==== Rollover Response
The returned `RolloverResponse` allows to retrieve information about the
executed operation as follows:
["source","java",subs="attributes,callouts,macros"]
--------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[rollover-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
<3> The name of the old index, eventually rolled over
<4> The name of the new index
<5> Whether the index has been rolled over
<6> Whether the operation was performed or it was a dry run
<7> The different conditions and whether they were matched or not

View File

@ -38,22 +38,22 @@ include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-reques
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-waitForActiveShards] 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 <1> The number of active shard copies to wait for before the split index API
returns a response, as an `int`. returns a response, as an `int`
<2> The number of active shard copies to wait for before the split index API <2> The number of active shard copies to wait for before the split index API
returns a response, as an `ActiveShardCount`. returns a response, as an `ActiveShardCount`
["source","java",subs="attributes,callouts,macros"] ["source","java",subs="attributes,callouts,macros"]
-------------------------------------------------- --------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-settings] include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-settings]
-------------------------------------------------- --------------------------------------------------
<1> The settings to apply to the target index, which include the number of <1> The settings to apply to the target index, which include the number of
shards to create for it. shards to create for it
["source","java",subs="attributes,callouts,macros"] ["source","java",subs="attributes,callouts,macros"]
-------------------------------------------------- --------------------------------------------------
include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-aliases] include-tagged::{doc-tests}/IndicesClientDocumentationIT.java[split-index-request-aliases]
-------------------------------------------------- --------------------------------------------------
<1> The aliases to associate the target index with. <1> The aliases to associate the target index with
[[java-rest-high-split-index-sync]] [[java-rest-high-split-index-sync]]
==== Synchronous Execution ==== Synchronous Execution

View File

@ -52,6 +52,7 @@ Index Management::
* <<java-rest-high-close-index>> * <<java-rest-high-close-index>>
* <<java-rest-high-shrink-index>> * <<java-rest-high-shrink-index>>
* <<java-rest-high-split-index>> * <<java-rest-high-split-index>>
* <<java-rest-high-rollover-index>>
Mapping Management:: Mapping Management::
* <<java-rest-high-put-mapping>> * <<java-rest-high-put-mapping>>
@ -67,6 +68,7 @@ include::indices/open_index.asciidoc[]
include::indices/close_index.asciidoc[] include::indices/close_index.asciidoc[]
include::indices/shrink_index.asciidoc[] include::indices/shrink_index.asciidoc[]
include::indices/split_index.asciidoc[] include::indices/split_index.asciidoc[]
include::indices/rollover.asciidoc[]
include::indices/put_mapping.asciidoc[] include::indices/put_mapping.asciidoc[]
include::indices/update_aliases.asciidoc[] include::indices/update_aliases.asciidoc[]
include::indices/exists_alias.asciidoc[] include::indices/exists_alias.asciidoc[]

View File

@ -36,7 +36,6 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
@ -57,9 +56,9 @@ import java.util.Objects;
import java.util.Set; import java.util.Set;
import static org.elasticsearch.action.ValidateActions.addValidationError; import static org.elasticsearch.action.ValidateActions.addValidationError;
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
import static org.elasticsearch.common.settings.Settings.readSettingsFromStream; import static org.elasticsearch.common.settings.Settings.readSettingsFromStream;
import static org.elasticsearch.common.settings.Settings.writeSettingsToStream; import static org.elasticsearch.common.settings.Settings.writeSettingsToStream;
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
/** /**
* A request to create an index. Best created with {@link org.elasticsearch.client.Requests#createIndexRequest(String)}. * A request to create an index. Best created with {@link org.elasticsearch.client.Requests#createIndexRequest(String)}.
@ -72,7 +71,7 @@ import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
*/ */
public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest> implements IndicesRequest, ToXContentObject { public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest> implements IndicesRequest, ToXContentObject {
private static final ParseField MAPPINGS = new ParseField("mappings"); public static final ParseField MAPPINGS = new ParseField("mappings");
public static final ParseField SETTINGS = new ParseField("settings"); public static final ParseField SETTINGS = new ParseField("settings");
public static final ParseField ALIASES = new ParseField("aliases"); public static final ParseField ALIASES = new ParseField("aliases");
@ -525,7 +524,12 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
innerToXContent(builder, params);
builder.endObject();
return builder;
}
public XContentBuilder innerToXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(SETTINGS.getPreferredName()); builder.startObject(SETTINGS.getPreferredName());
settings.toXContent(builder, params); settings.toXContent(builder, params);
builder.endObject(); builder.endObject();
@ -545,8 +549,6 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
for (Map.Entry<String, IndexMetaData.Custom> entry : customs.entrySet()) { for (Map.Entry<String, IndexMetaData.Custom> entry : customs.entrySet()) {
builder.field(entry.getKey(), entry.getValue(), params); builder.field(entry.getKey(), entry.getValue(), params);
} }
builder.endObject();
return builder; return builder;
} }
} }

View File

@ -20,7 +20,7 @@
package org.elasticsearch.action.admin.indices.create; package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
@ -37,9 +37,8 @@ import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constru
/** /**
* A response for a create index action. * A response for a create index action.
*/ */
public class CreateIndexResponse extends AcknowledgedResponse implements ToXContentObject { public class CreateIndexResponse extends ShardsAcknowledgedResponse implements ToXContentObject {
private static final ParseField SHARDS_ACKNOWLEDGED = new ParseField("shards_acknowledged");
private static final ParseField INDEX = new ParseField("index"); private static final ParseField INDEX = new ParseField("index");
private static final ConstructingObjectParser<CreateIndexResponse, Void> PARSER = new ConstructingObjectParser<>("create_index", private static final ConstructingObjectParser<CreateIndexResponse, Void> PARSER = new ConstructingObjectParser<>("create_index",
@ -50,22 +49,17 @@ public class CreateIndexResponse extends AcknowledgedResponse implements ToXCont
} }
protected static <T extends CreateIndexResponse> void declareFields(ConstructingObjectParser<T, Void> objectParser) { protected static <T extends CreateIndexResponse> void declareFields(ConstructingObjectParser<T, Void> objectParser) {
declareAcknowledgedField(objectParser); declareAcknowledgedAndShardsAcknowledgedFields(objectParser);
objectParser.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED, objectParser.declareField(constructorArg(), (parser, context) -> parser.textOrNull(), INDEX, ObjectParser.ValueType.STRING_OR_NULL);
ObjectParser.ValueType.BOOLEAN);
objectParser.declareField(constructorArg(), (parser, context) -> parser.text(), INDEX, ObjectParser.ValueType.STRING);
} }
private boolean shardsAcknowledged;
private String index; private String index;
protected CreateIndexResponse() { protected CreateIndexResponse() {
} }
protected CreateIndexResponse(boolean acknowledged, boolean shardsAcknowledged, String index) { protected CreateIndexResponse(boolean acknowledged, boolean shardsAcknowledged, String index) {
super(acknowledged); super(acknowledged, shardsAcknowledged);
assert acknowledged || shardsAcknowledged == false; // if its not acknowledged, then shardsAcknowledged should be false too
this.shardsAcknowledged = shardsAcknowledged;
this.index = index; this.index = index;
} }
@ -73,7 +67,7 @@ public class CreateIndexResponse extends AcknowledgedResponse implements ToXCont
public void readFrom(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException {
super.readFrom(in); super.readFrom(in);
readAcknowledged(in); readAcknowledged(in);
shardsAcknowledged = in.readBoolean(); readShardsAcknowledged(in);
if (in.getVersion().onOrAfter(Version.V_5_6_0)) { if (in.getVersion().onOrAfter(Version.V_5_6_0)) {
index = in.readString(); index = in.readString();
} }
@ -83,35 +77,22 @@ public class CreateIndexResponse extends AcknowledgedResponse implements ToXCont
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out); super.writeTo(out);
writeAcknowledged(out); writeAcknowledged(out);
out.writeBoolean(shardsAcknowledged); writeShardsAcknowledged(out);
if (out.getVersion().onOrAfter(Version.V_5_6_0)) { if (out.getVersion().onOrAfter(Version.V_5_6_0)) {
out.writeString(index); out.writeString(index);
} }
} }
/**
* Returns true if the requisite number of shards were started before
* returning from the index creation operation. If {@link #isAcknowledged()}
* is false, then this also returns false.
*/
public boolean isShardsAcknowledged() {
return shardsAcknowledged;
}
public String index() { public String index() {
return index; return index;
} }
public void addCustomFields(XContentBuilder builder) throws IOException {
builder.field(SHARDS_ACKNOWLEDGED.getPreferredName(), isShardsAcknowledged());
builder.field(INDEX.getPreferredName(), index());
}
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
addAcknowledgedField(builder); addAcknowledgedField(builder);
addCustomFields(builder); addShardsAcknowledgedField(builder);
builder.field(INDEX.getPreferredName(), index());
builder.endObject(); builder.endObject();
return builder; return builder;
} }

View File

@ -68,7 +68,7 @@ public class DeleteIndexResponse extends AcknowledgedResponse implements ToXCont
return builder; return builder;
} }
public static DeleteIndexResponse fromXContent(XContentParser parser) throws IOException { public static DeleteIndexResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null); return PARSER.apply(parser, null);
} }
} }

View File

@ -20,54 +20,33 @@
package org.elasticsearch.action.admin.indices.open; package org.elasticsearch.action.admin.indices.open;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ConstructingObjectParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException; import java.io.IOException;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
/** /**
* A response for a open index action. * A response for a open index action.
*/ */
public class OpenIndexResponse extends AcknowledgedResponse implements ToXContentObject { public class OpenIndexResponse extends ShardsAcknowledgedResponse 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<OpenIndexResponse, Void> PARSER = new ConstructingObjectParser<>("open_index", true, private static final ConstructingObjectParser<OpenIndexResponse, Void> PARSER = new ConstructingObjectParser<>("open_index", true,
args -> new OpenIndexResponse((boolean) args[0], (boolean) args[1])); args -> new OpenIndexResponse((boolean) args[0], (boolean) args[1]));
static { static {
declareAcknowledgedField(PARSER); declareAcknowledgedAndShardsAcknowledgedFields(PARSER);
PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED_PARSER,
ObjectParser.ValueType.BOOLEAN);
} }
private boolean shardsAcknowledged;
OpenIndexResponse() { OpenIndexResponse() {
} }
OpenIndexResponse(boolean acknowledged, boolean shardsAcknowledged) { OpenIndexResponse(boolean acknowledged, boolean shardsAcknowledged) {
super(acknowledged); super(acknowledged, shardsAcknowledged);
assert acknowledged || shardsAcknowledged == false; // if its not acknowledged, then shards acked should be false too
this.shardsAcknowledged = shardsAcknowledged;
}
/**
* Returns true if the requisite number of shards were started before
* returning from the indices opening operation. If {@link #isAcknowledged()}
* is false, then this also returns false.
*/
public boolean isShardsAcknowledged() {
return shardsAcknowledged;
} }
@Override @Override
@ -75,7 +54,7 @@ public class OpenIndexResponse extends AcknowledgedResponse implements ToXConten
super.readFrom(in); super.readFrom(in);
readAcknowledged(in); readAcknowledged(in);
if (in.getVersion().onOrAfter(Version.V_6_1_0)) { if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
shardsAcknowledged = in.readBoolean(); readShardsAcknowledged(in);
} }
} }
@ -84,7 +63,7 @@ public class OpenIndexResponse extends AcknowledgedResponse implements ToXConten
super.writeTo(out); super.writeTo(out);
writeAcknowledged(out); writeAcknowledged(out);
if (out.getVersion().onOrAfter(Version.V_6_1_0)) { if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
out.writeBoolean(shardsAcknowledged); writeShardsAcknowledged(out);
} }
} }
@ -92,12 +71,12 @@ public class OpenIndexResponse extends AcknowledgedResponse implements ToXConten
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
addAcknowledgedField(builder); addAcknowledgedField(builder);
builder.field(SHARDS_ACKNOWLEDGED, isShardsAcknowledged()); addShardsAcknowledgedField(builder);
builder.endObject(); builder.endObject();
return builder; return builder;
} }
public static OpenIndexResponse fromXContent(XContentParser parser) throws IOException { public static OpenIndexResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null); return PARSER.apply(parser, null);
} }
} }

View File

@ -20,30 +20,16 @@
package org.elasticsearch.action.admin.indices.rollover; package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.NamedWriteable; import org.elasticsearch.common.io.stream.NamedWriteable;
import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.ToXContentFragment;
import org.elasticsearch.common.xcontent.ObjectParser;
import java.util.Set; import java.util.Objects;
/** /**
* Base class for rollover request conditions * Base class for rollover request conditions
*/ */
public abstract class Condition<T> implements NamedWriteable { public abstract class Condition<T> implements NamedWriteable, ToXContentFragment {
public static ObjectParser<Set<Condition>, Void> PARSER = new ObjectParser<>("conditions", null);
static {
PARSER.declareString((conditions, s) ->
conditions.add(new MaxAgeCondition(TimeValue.parseTimeValue(s, MaxAgeCondition.NAME))),
new ParseField(MaxAgeCondition.NAME));
PARSER.declareLong((conditions, value) ->
conditions.add(new MaxDocsCondition(value)), new ParseField(MaxDocsCondition.NAME));
PARSER.declareString((conditions, s) ->
conditions.add(new MaxSizeCondition(ByteSizeValue.parseBytesSizeValue(s, MaxSizeCondition.NAME))),
new ParseField(MaxSizeCondition.NAME));
}
protected T value; protected T value;
protected final String name; protected final String name;
@ -62,6 +48,24 @@ public abstract class Condition<T> implements NamedWriteable {
return true; return true;
} }
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Condition<?> condition = (Condition<?>) o;
return Objects.equals(value, condition.value) &&
Objects.equals(name, condition.name);
}
@Override
public int hashCode() {
return Objects.hash(value, name);
}
@Override @Override
public final String toString() { public final String toString() {
return "[" + name + ": " + value + "]"; return "[" + name + ": " + value + "]";

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
@ -55,6 +56,12 @@ public class MaxAgeCondition extends Condition<TimeValue> {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
//TODO here we should just use TimeValue#writeTo and same for de-serialization in the constructor, we lose information this way
out.writeLong(value.getMillis()); out.writeLong(value.getMillis());
} }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.field(NAME, value.getStringRep());
}
} }

View File

@ -21,6 +21,7 @@ package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
@ -55,4 +56,9 @@ public class MaxDocsCondition extends Condition<Long> {
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
out.writeLong(value); out.writeLong(value);
} }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.field(NAME, value);
}
} }

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.ByteSizeUnit; import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException; import java.io.IOException;
@ -61,6 +62,12 @@ public class MaxSizeCondition extends Condition<ByteSizeValue> {
@Override @Override
public void writeTo(StreamOutput out) throws IOException { public void writeTo(StreamOutput out) throws IOException {
//TODO here we should just use ByteSizeValue#writeTo and same for de-serialization in the constructor
out.writeVLong(value.getBytes()); out.writeVLong(value.getBytes());
} }
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
return builder.field(NAME, value.getStringRep());
}
} }

View File

@ -21,7 +21,6 @@ package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParseField;
@ -30,40 +29,57 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ObjectParser; 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.io.IOException;
import java.util.HashSet; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static org.elasticsearch.action.ValidateActions.addValidationError; import static org.elasticsearch.action.ValidateActions.addValidationError;
/** /**
* Request class to swap index under an alias upon satisfying conditions * Request class to swap index under an alias upon satisfying conditions
*/ */
public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implements IndicesRequest { public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implements IndicesRequest, ToXContentObject {
private static final ObjectParser<RolloverRequest, Void> PARSER = new ObjectParser<>("rollover");
private static final ObjectParser<Map<String, Condition>, Void> CONDITION_PARSER = new ObjectParser<>("conditions");
private static final ParseField CONDITIONS = new ParseField("conditions");
private static final ParseField MAX_AGE_CONDITION = new ParseField(MaxAgeCondition.NAME);
private static final ParseField MAX_DOCS_CONDITION = new ParseField(MaxDocsCondition.NAME);
private static final ParseField MAX_SIZE_CONDITION = new ParseField(MaxSizeCondition.NAME);
public static final ObjectParser<RolloverRequest, Void> PARSER = new ObjectParser<>("conditions", null);
static { static {
PARSER.declareField((parser, request, context) -> Condition.PARSER.parse(parser, request.conditions, null), CONDITION_PARSER.declareString((conditions, s) ->
new ParseField("conditions"), ObjectParser.ValueType.OBJECT); conditions.put(MaxAgeCondition.NAME, new MaxAgeCondition(TimeValue.parseTimeValue(s, MaxAgeCondition.NAME))),
MAX_AGE_CONDITION);
CONDITION_PARSER.declareLong((conditions, value) ->
conditions.put(MaxDocsCondition.NAME, new MaxDocsCondition(value)), MAX_DOCS_CONDITION);
CONDITION_PARSER.declareString((conditions, s) ->
conditions.put(MaxSizeCondition.NAME, new MaxSizeCondition(ByteSizeValue.parseBytesSizeValue(s, MaxSizeCondition.NAME))),
MAX_SIZE_CONDITION);
PARSER.declareField((parser, request, context) -> CONDITION_PARSER.parse(parser, request.conditions, null),
CONDITIONS, ObjectParser.ValueType.OBJECT);
PARSER.declareField((parser, request, context) -> request.createIndexRequest.settings(parser.map()), PARSER.declareField((parser, request, context) -> request.createIndexRequest.settings(parser.map()),
new ParseField("settings"), ObjectParser.ValueType.OBJECT); CreateIndexRequest.SETTINGS, ObjectParser.ValueType.OBJECT);
PARSER.declareField((parser, request, context) -> { PARSER.declareField((parser, request, context) -> {
for (Map.Entry<String, Object> mappingsEntry : parser.map().entrySet()) { for (Map.Entry<String, Object> mappingsEntry : parser.map().entrySet()) {
request.createIndexRequest.mapping(mappingsEntry.getKey(), request.createIndexRequest.mapping(mappingsEntry.getKey(), (Map<String, Object>) mappingsEntry.getValue());
(Map<String, Object>) mappingsEntry.getValue());
} }
}, new ParseField("mappings"), ObjectParser.ValueType.OBJECT); }, CreateIndexRequest.MAPPINGS, ObjectParser.ValueType.OBJECT);
PARSER.declareField((parser, request, context) -> request.createIndexRequest.aliases(parser.map()), PARSER.declareField((parser, request, context) -> request.createIndexRequest.aliases(parser.map()),
new ParseField("aliases"), ObjectParser.ValueType.OBJECT); CreateIndexRequest.ALIASES, ObjectParser.ValueType.OBJECT);
} }
private String alias; private String alias;
private String newIndexName; private String newIndexName;
private boolean dryRun; private boolean dryRun;
private Set<Condition> conditions = new HashSet<>(2); private Map<String, Condition> conditions = new HashMap<>(2);
//the index name "_na_" is never read back, what matters are settings, mappings and aliases
private CreateIndexRequest createIndexRequest = new CreateIndexRequest("_na_"); private CreateIndexRequest createIndexRequest = new CreateIndexRequest("_na_");
RolloverRequest() {} RolloverRequest() {}
@ -75,13 +91,10 @@ public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implem
@Override @Override
public ActionRequestValidationException validate() { public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = createIndexRequest == null ? null : createIndexRequest.validate(); ActionRequestValidationException validationException = createIndexRequest.validate();
if (alias == null) { if (alias == null) {
validationException = addValidationError("index alias is missing", validationException); validationException = addValidationError("index alias is missing", validationException);
} }
if (createIndexRequest == null) {
validationException = addValidationError("create index request is missing", validationException);
}
return validationException; return validationException;
} }
@ -93,7 +106,8 @@ public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implem
dryRun = in.readBoolean(); dryRun = in.readBoolean();
int size = in.readVInt(); int size = in.readVInt();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
this.conditions.add(in.readNamedWriteable(Condition.class)); Condition condition = in.readNamedWriteable(Condition.class);
this.conditions.put(condition.name, condition);
} }
createIndexRequest = new CreateIndexRequest(); createIndexRequest = new CreateIndexRequest();
createIndexRequest.readFrom(in); createIndexRequest.readFrom(in);
@ -106,7 +120,7 @@ public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implem
out.writeOptionalString(newIndexName); out.writeOptionalString(newIndexName);
out.writeBoolean(dryRun); out.writeBoolean(dryRun);
out.writeVInt(conditions.size()); out.writeVInt(conditions.size());
for (Condition condition : conditions) { for (Condition condition : conditions.values()) {
if (condition.includedInVersion(out.getVersion())) { if (condition.includedInVersion(out.getVersion())) {
out.writeNamedWriteable(condition); out.writeNamedWriteable(condition);
} }
@ -148,76 +162,75 @@ public class RolloverRequest extends AcknowledgedRequest<RolloverRequest> implem
* Adds condition to check if the index is at least <code>age</code> old * Adds condition to check if the index is at least <code>age</code> old
*/ */
public void addMaxIndexAgeCondition(TimeValue age) { public void addMaxIndexAgeCondition(TimeValue age) {
this.conditions.add(new MaxAgeCondition(age)); MaxAgeCondition maxAgeCondition = new MaxAgeCondition(age);
if (this.conditions.containsKey(maxAgeCondition.name)) {
throw new IllegalArgumentException(maxAgeCondition.name + " condition is already set");
}
this.conditions.put(maxAgeCondition.name, maxAgeCondition);
} }
/** /**
* Adds condition to check if the index has at least <code>numDocs</code> * Adds condition to check if the index has at least <code>numDocs</code>
*/ */
public void addMaxIndexDocsCondition(long numDocs) { public void addMaxIndexDocsCondition(long numDocs) {
this.conditions.add(new MaxDocsCondition(numDocs)); MaxDocsCondition maxDocsCondition = new MaxDocsCondition(numDocs);
if (this.conditions.containsKey(maxDocsCondition.name)) {
throw new IllegalArgumentException(maxDocsCondition.name + " condition is already set");
}
this.conditions.put(maxDocsCondition.name, maxDocsCondition);
} }
/** /**
* Adds a size-based condition to check if the index size is at least <code>size</code>. * Adds a size-based condition to check if the index size is at least <code>size</code>.
*/ */
public void addMaxIndexSizeCondition(ByteSizeValue size) { public void addMaxIndexSizeCondition(ByteSizeValue size) {
this.conditions.add(new MaxSizeCondition(size)); MaxSizeCondition maxSizeCondition = new MaxSizeCondition(size);
if (this.conditions.containsKey(maxSizeCondition.name)) {
throw new IllegalArgumentException(maxSizeCondition + " condition is already set");
}
this.conditions.put(maxSizeCondition.name, maxSizeCondition);
} }
/**
* Sets rollover index creation request to override index settings when
* the rolled over index has to be created
*/
public void setCreateIndexRequest(CreateIndexRequest createIndexRequest) {
this.createIndexRequest = Objects.requireNonNull(createIndexRequest, "create index request must not be null");;
}
boolean isDryRun() { public boolean isDryRun() {
return dryRun; return dryRun;
} }
Set<Condition> getConditions() { Map<String, Condition> getConditions() {
return conditions; return conditions;
} }
String getAlias() { public String getAlias() {
return alias; return alias;
} }
String getNewIndexName() { public String getNewIndexName() {
return newIndexName; return newIndexName;
} }
CreateIndexRequest getCreateIndexRequest() { /**
* Returns the inner {@link CreateIndexRequest}. Allows to configure mappings, settings and aliases for the new index.
*/
public CreateIndexRequest getCreateIndexRequest() {
return createIndexRequest; return createIndexRequest;
} }
/** @Override
* Sets the number of shard copies that should be active for creation of the public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
* new rollover index to return. Defaults to {@link ActiveShardCount#DEFAULT}, which will builder.startObject();
* wait for one shard copy (the primary) to become active. Set this value to createIndexRequest.innerToXContent(builder, params);
* {@link ActiveShardCount#ALL} to wait for all shards (primary and all replicas) to be active
* before returning. Otherwise, use {@link ActiveShardCount#from(int)} to set this value to any builder.startObject(CONDITIONS.getPreferredName());
* non-negative integer, up to the number of copies per shard (number of replicas + 1), for (Condition condition : conditions.values()) {
* to wait for the desired amount of shard copies to become active before returning. condition.toXContent(builder, params);
* Index creation will only wait up until the timeout value for the number of shard copies }
* to be active before returning. Check {@link RolloverResponse#isShardsAcknowledged()} to builder.endObject();
* determine if the requisite shard copies were all started before returning or timing out.
* builder.endObject();
* @param waitForActiveShards number of active shard copies to wait on return builder;
*/
public void setWaitForActiveShards(ActiveShardCount waitForActiveShards) {
this.createIndexRequest.waitForActiveShards(waitForActiveShards);
} }
/** public void fromXContent(XContentParser parser) throws IOException {
* A shortcut for {@link #setWaitForActiveShards(ActiveShardCount)} where the numerical PARSER.parse(parser, this, null);
* shard count is passed in, instead of having to first call {@link ActiveShardCount#from(int)}
* to get the ActiveShardCount.
*/
public void setWaitForActiveShards(final int waitForActiveShards) {
setWaitForActiveShards(ActiveShardCount.from(waitForActiveShards));
} }
} }

View File

@ -93,7 +93,7 @@ public class RolloverRequestBuilder extends MasterNodeOperationRequestBuilder<Ro
* @param waitForActiveShards number of active shard copies to wait on * @param waitForActiveShards number of active shard copies to wait on
*/ */
public RolloverRequestBuilder waitForActiveShards(ActiveShardCount waitForActiveShards) { public RolloverRequestBuilder waitForActiveShards(ActiveShardCount waitForActiveShards) {
this.request.setWaitForActiveShards(waitForActiveShards); this.request.getCreateIndexRequest().waitForActiveShards(waitForActiveShards);
return this; return this;
} }

View File

@ -19,51 +19,62 @@
package org.elasticsearch.action.admin.indices.rollover; package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.support.master.ShardsAcknowledgedResponse;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; 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.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException; import java.io.IOException;
import java.util.AbstractMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Objects;
import java.util.stream.Collectors;
public final class RolloverResponse extends ActionResponse implements ToXContentObject { import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
private static final String NEW_INDEX = "new_index"; public final class RolloverResponse extends ShardsAcknowledgedResponse implements ToXContentObject {
private static final String OLD_INDEX = "old_index";
private static final String DRY_RUN = "dry_run"; private static final ParseField NEW_INDEX = new ParseField("new_index");
private static final String ROLLED_OVER = "rolled_over"; private static final ParseField OLD_INDEX = new ParseField("old_index");
private static final String CONDITIONS = "conditions"; private static final ParseField DRY_RUN = new ParseField("dry_run");
private static final String ACKNOWLEDGED = "acknowledged"; private static final ParseField ROLLED_OVER = new ParseField("rolled_over");
private static final String SHARDS_ACKED = "shards_acknowledged"; private static final ParseField CONDITIONS = new ParseField("conditions");
@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<RolloverResponse, Void> PARSER = new ConstructingObjectParser<>("rollover",
true, args -> new RolloverResponse((String) args[0], (String) args[1], (Map<String,Boolean>) args[2],
(Boolean)args[3], (Boolean)args[4], (Boolean) args[5], (Boolean) args[6]));
static {
PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), OLD_INDEX, ObjectParser.ValueType.STRING);
PARSER.declareField(constructorArg(), (parser, context) -> parser.text(), NEW_INDEX, ObjectParser.ValueType.STRING);
PARSER.declareObject(constructorArg(), (parser, context) -> parser.map(), CONDITIONS);
PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), DRY_RUN, ObjectParser.ValueType.BOOLEAN);
PARSER.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), ROLLED_OVER, ObjectParser.ValueType.BOOLEAN);
declareAcknowledgedAndShardsAcknowledgedFields(PARSER);
}
private String oldIndex; private String oldIndex;
private String newIndex; private String newIndex;
private Set<Map.Entry<String, Boolean>> conditionStatus; private Map<String, Boolean> conditionStatus;
private boolean dryRun; private boolean dryRun;
private boolean rolledOver; private boolean rolledOver;
private boolean acknowledged;
private boolean shardsAcknowledged;
RolloverResponse() { RolloverResponse() {
} }
RolloverResponse(String oldIndex, String newIndex, Set<Condition.Result> conditionResults, RolloverResponse(String oldIndex, String newIndex, Map<String, Boolean> conditionResults,
boolean dryRun, boolean rolledOver, boolean acknowledged, boolean shardsAcknowledged) { boolean dryRun, boolean rolledOver, boolean acknowledged, boolean shardsAcknowledged) {
super(acknowledged, shardsAcknowledged);
this.oldIndex = oldIndex; this.oldIndex = oldIndex;
this.newIndex = newIndex; this.newIndex = newIndex;
this.dryRun = dryRun; this.dryRun = dryRun;
this.rolledOver = rolledOver; this.rolledOver = rolledOver;
this.acknowledged = acknowledged; this.conditionStatus = conditionResults;
this.shardsAcknowledged = shardsAcknowledged;
this.conditionStatus = conditionResults.stream()
.map(result -> new AbstractMap.SimpleEntry<>(result.condition.toString(), result.matched))
.collect(Collectors.toSet());
} }
/** /**
@ -83,7 +94,7 @@ public final class RolloverResponse extends ActionResponse implements ToXContent
/** /**
* Returns the statuses of all the request conditions * Returns the statuses of all the request conditions
*/ */
public Set<Map.Entry<String, Boolean>> getConditionStatus() { public Map<String, Boolean> getConditionStatus() {
return conditionStatus; return conditionStatus;
} }
@ -101,42 +112,20 @@ public final class RolloverResponse extends ActionResponse implements ToXContent
return rolledOver; return rolledOver;
} }
/**
* Returns true if the creation of the new rollover index and switching of the
* alias to the newly created index was successful, and returns false otherwise.
* If {@link #isDryRun()} is true, then this will also return false. If this
* returns false, then {@link #isShardsAcknowledged()} will also return false.
*/
public boolean isAcknowledged() {
return acknowledged;
}
/**
* Returns true if the requisite number of shards were started in the newly
* created rollover index before returning. If {@link #isAcknowledged()} is
* false, then this will also return false.
*/
public boolean isShardsAcknowledged() {
return shardsAcknowledged;
}
@Override @Override
public void readFrom(StreamInput in) throws IOException { public void readFrom(StreamInput in) throws IOException {
super.readFrom(in); super.readFrom(in);
oldIndex = in.readString(); oldIndex = in.readString();
newIndex = in.readString(); newIndex = in.readString();
int conditionSize = in.readVInt(); int conditionSize = in.readVInt();
Set<Map.Entry<String, Boolean>> conditions = new HashSet<>(conditionSize); conditionStatus = new HashMap<>(conditionSize);
for (int i = 0; i < conditionSize; i++) { for (int i = 0; i < conditionSize; i++) {
String condition = in.readString(); conditionStatus.put(in.readString(), in.readBoolean());
boolean satisfied = in.readBoolean();
conditions.add(new AbstractMap.SimpleEntry<>(condition, satisfied));
} }
conditionStatus = conditions;
dryRun = in.readBoolean(); dryRun = in.readBoolean();
rolledOver = in.readBoolean(); rolledOver = in.readBoolean();
acknowledged = in.readBoolean(); readAcknowledged(in);
shardsAcknowledged = in.readBoolean(); readShardsAcknowledged(in);
} }
@Override @Override
@ -145,31 +134,58 @@ public final class RolloverResponse extends ActionResponse implements ToXContent
out.writeString(oldIndex); out.writeString(oldIndex);
out.writeString(newIndex); out.writeString(newIndex);
out.writeVInt(conditionStatus.size()); out.writeVInt(conditionStatus.size());
for (Map.Entry<String, Boolean> entry : conditionStatus) { for (Map.Entry<String, Boolean> entry : conditionStatus.entrySet()) {
out.writeString(entry.getKey()); out.writeString(entry.getKey());
out.writeBoolean(entry.getValue()); out.writeBoolean(entry.getValue());
} }
out.writeBoolean(dryRun); out.writeBoolean(dryRun);
out.writeBoolean(rolledOver); out.writeBoolean(rolledOver);
out.writeBoolean(acknowledged); writeAcknowledged(out);
out.writeBoolean(shardsAcknowledged); writeShardsAcknowledged(out);
} }
@Override @Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(OLD_INDEX, oldIndex); builder.field(OLD_INDEX.getPreferredName(), oldIndex);
builder.field(NEW_INDEX, newIndex); builder.field(NEW_INDEX.getPreferredName(), newIndex);
builder.field(ROLLED_OVER, rolledOver); builder.field(ROLLED_OVER.getPreferredName(), rolledOver);
builder.field(DRY_RUN, dryRun); builder.field(DRY_RUN.getPreferredName(), dryRun);
builder.field(ACKNOWLEDGED, acknowledged); addAcknowledgedField(builder);
builder.field(SHARDS_ACKED, shardsAcknowledged); addShardsAcknowledgedField(builder);
builder.startObject(CONDITIONS); builder.startObject(CONDITIONS.getPreferredName());
for (Map.Entry<String, Boolean> entry : conditionStatus) { for (Map.Entry<String, Boolean> entry : conditionStatus.entrySet()) {
builder.field(entry.getKey(), entry.getValue()); builder.field(entry.getKey(), entry.getValue());
} }
builder.endObject(); builder.endObject();
builder.endObject(); builder.endObject();
return builder; return builder;
} }
public static RolloverResponse fromXContent(XContentParser parser) {
return PARSER.apply(parser, null);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RolloverResponse that = (RolloverResponse) o;
return isAcknowledged() == that.isAcknowledged() &&
isShardsAcknowledged() == that.isShardsAcknowledged() &&
dryRun == that.dryRun &&
rolledOver == that.rolledOver &&
Objects.equals(oldIndex, that.oldIndex) &&
Objects.equals(newIndex, that.newIndex) &&
Objects.equals(conditionStatus, that.conditionStatus);
}
@Override
public int hashCode() {
return Objects.hash(isAcknowledged(), isShardsAcknowledged(), oldIndex, newIndex, conditionStatus, dryRun, rolledOver);
}
} }

View File

@ -51,9 +51,10 @@ import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService; import org.elasticsearch.transport.TransportService;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Map;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -122,7 +123,7 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
new ActionListener<IndicesStatsResponse>() { new ActionListener<IndicesStatsResponse>() {
@Override @Override
public void onResponse(IndicesStatsResponse statsResponse) { public void onResponse(IndicesStatsResponse statsResponse) {
final Set<Condition.Result> conditionResults = evaluateConditions(rolloverRequest.getConditions(), final Map<String, Boolean> conditionResults = evaluateConditions(rolloverRequest.getConditions().values(),
metaData.index(sourceIndexName), statsResponse); metaData.index(sourceIndexName), statsResponse);
if (rolloverRequest.isDryRun()) { if (rolloverRequest.isDryRun()) {
@ -130,7 +131,7 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
new RolloverResponse(sourceIndexName, rolloverIndexName, conditionResults, true, false, false, false)); new RolloverResponse(sourceIndexName, rolloverIndexName, conditionResults, true, false, false, false));
return; return;
} }
if (conditionResults.size() == 0 || conditionResults.stream().anyMatch(result -> result.matched)) { if (conditionResults.size() == 0 || conditionResults.values().stream().anyMatch(result -> result)) {
CreateIndexClusterStateUpdateRequest updateRequest = prepareCreateIndexRequest(unresolvedName, rolloverIndexName, CreateIndexClusterStateUpdateRequest updateRequest = prepareCreateIndexRequest(unresolvedName, rolloverIndexName,
rolloverRequest); rolloverRequest);
createIndexService.createIndex(updateRequest, ActionListener.wrap(createIndexClusterStateUpdateResponse -> { createIndexService.createIndex(updateRequest, ActionListener.wrap(createIndexClusterStateUpdateResponse -> {
@ -197,17 +198,17 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
} }
} }
static Set<Condition.Result> evaluateConditions(final Set<Condition> conditions, static Map<String, Boolean> evaluateConditions(final Collection<Condition> conditions,
final DocsStats docsStats, final IndexMetaData metaData) { final DocsStats docsStats, final IndexMetaData metaData) {
final long numDocs = docsStats == null ? 0 : docsStats.getCount(); final long numDocs = docsStats == null ? 0 : docsStats.getCount();
final long indexSize = docsStats == null ? 0 : docsStats.getTotalSizeInBytes(); final long indexSize = docsStats == null ? 0 : docsStats.getTotalSizeInBytes();
final Condition.Stats stats = new Condition.Stats(numDocs, metaData.getCreationDate(), new ByteSizeValue(indexSize)); final Condition.Stats stats = new Condition.Stats(numDocs, metaData.getCreationDate(), new ByteSizeValue(indexSize));
return conditions.stream() return conditions.stream()
.map(condition -> condition.evaluate(stats)) .map(condition -> condition.evaluate(stats))
.collect(Collectors.toSet()); .collect(Collectors.toMap(result -> result.condition.toString(), result -> result.matched));
} }
static Set<Condition.Result> evaluateConditions(final Set<Condition> conditions, final IndexMetaData metaData, static Map<String, Boolean> evaluateConditions(final Collection<Condition> conditions, final IndexMetaData metaData,
final IndicesStatsResponse statsResponse) { final IndicesStatsResponse statsResponse) {
return evaluateConditions(conditions, statsResponse.getPrimaries().getDocs(), metaData); return evaluateConditions(conditions, statsResponse.getPrimaries().getDocs(), metaData);
} }

View File

@ -62,14 +62,14 @@ public abstract class AcknowledgedResponse extends ActionResponse {
} }
/** /**
* Reads the timeout value * Reads the acknowledged value
*/ */
protected void readAcknowledged(StreamInput in) throws IOException { protected void readAcknowledged(StreamInput in) throws IOException {
acknowledged = in.readBoolean(); acknowledged = in.readBoolean();
} }
/** /**
* Writes the timeout value * Writes the acknowledged value
*/ */
protected void writeAcknowledged(StreamOutput out) throws IOException { protected void writeAcknowledged(StreamOutput out) throws IOException {
out.writeBoolean(acknowledged); out.writeBoolean(acknowledged);

View File

@ -0,0 +1,76 @@
/*
* 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.support.master;
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.XContentBuilder;
import java.io.IOException;
import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg;
public abstract class ShardsAcknowledgedResponse extends AcknowledgedResponse {
private static final ParseField SHARDS_ACKNOWLEDGED = new ParseField("shards_acknowledged");
protected static <T extends ShardsAcknowledgedResponse> void declareAcknowledgedAndShardsAcknowledgedFields(
ConstructingObjectParser<T, Void> objectParser) {
declareAcknowledgedField(objectParser);
objectParser.declareField(constructorArg(), (parser, context) -> parser.booleanValue(), SHARDS_ACKNOWLEDGED,
ObjectParser.ValueType.BOOLEAN);
}
private boolean shardsAcknowledged;
protected ShardsAcknowledgedResponse() {
}
protected ShardsAcknowledgedResponse(boolean acknowledged, boolean shardsAcknowledged) {
super(acknowledged);
assert acknowledged || shardsAcknowledged == false; // if it's not acknowledged, then shards acked should be false too
this.shardsAcknowledged = shardsAcknowledged;
}
/**
* Returns true if the requisite number of shards were started before
* returning from the index creation operation. If {@link #isAcknowledged()}
* is false, then this also returns false.
*/
public boolean isShardsAcknowledged() {
return shardsAcknowledged;
}
protected void readShardsAcknowledged(StreamInput in) throws IOException {
shardsAcknowledged = in.readBoolean();
}
protected void writeShardsAcknowledged(StreamOutput out) throws IOException {
out.writeBoolean(shardsAcknowledged);
}
protected void addShardsAcknowledgedField(XContentBuilder builder) throws IOException {
builder.field(SHARDS_ACKNOWLEDGED.getPreferredName(), isShardsAcknowledged());
}
}

View File

@ -28,6 +28,7 @@ import java.io.IOException;
import static org.elasticsearch.rest.RestStatus.OK; import static org.elasticsearch.rest.RestStatus.OK;
//TODO once all the responses that use this class implement ToXContent we can move to RestToXContentListener and remove this class
public class AcknowledgedRestListener<T extends AcknowledgedResponse> extends RestBuilderListener<T> { public class AcknowledgedRestListener<T extends AcknowledgedResponse> extends RestBuilderListener<T> {
public AcknowledgedRestListener(RestChannel channel) { public AcknowledgedRestListener(RestChannel channel) {
@ -36,7 +37,6 @@ public class AcknowledgedRestListener<T extends AcknowledgedResponse> extends Re
@Override @Override
public RestResponse buildResponse(T response, XContentBuilder builder) throws Exception { public RestResponse buildResponse(T response, XContentBuilder builder) throws Exception {
// TODO - Once AcknowledgedResponse implements ToXContent, this method should be updated to call response.toXContent.
builder.startObject() builder.startObject()
.field(Fields.ACKNOWLEDGED, response.isAcknowledged()); .field(Fields.ACKNOWLEDGED, response.isAcknowledged());
addCustomFields(builder, response); addCustomFields(builder, response);

View File

@ -20,15 +20,13 @@
package org.elasticsearch.rest.action.admin.indices; package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException; import java.io.IOException;
@ -52,11 +50,6 @@ public class RestCreateIndexAction extends BaseRestHandler {
createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout())); createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout()));
createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout())); createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout()));
createIndexRequest.waitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); createIndexRequest.waitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards")));
return channel -> client.admin().indices().create(createIndexRequest, new AcknowledgedRestListener<CreateIndexResponse>(channel) { return channel -> client.admin().indices().create(createIndexRequest, new RestToXContentListener<>(channel));
@Override
public void addCustomFields(XContentBuilder builder, CreateIndexResponse response) throws IOException {
response.addCustomFields(builder);
}
});
} }
} }

View File

@ -27,7 +27,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException; import java.io.IOException;
@ -49,6 +49,6 @@ public class RestDeleteIndexAction extends BaseRestHandler {
deleteIndexRequest.timeout(request.paramAsTime("timeout", deleteIndexRequest.timeout())); deleteIndexRequest.timeout(request.paramAsTime("timeout", deleteIndexRequest.timeout()));
deleteIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", deleteIndexRequest.masterNodeTimeout())); deleteIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", deleteIndexRequest.masterNodeTimeout()));
deleteIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, deleteIndexRequest.indicesOptions())); deleteIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, deleteIndexRequest.indicesOptions()));
return channel -> client.admin().indices().delete(deleteIndexRequest, new AcknowledgedRestListener<>(channel)); return channel -> client.admin().indices().delete(deleteIndexRequest, new RestToXContentListener<>(channel));
} }
} }

View File

@ -20,17 +20,15 @@
package org.elasticsearch.rest.action.admin.indices; package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.open.OpenIndexRequest; import org.elasticsearch.action.admin.indices.open.OpenIndexRequest;
import org.elasticsearch.action.admin.indices.open.OpenIndexResponse;
import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException; import java.io.IOException;
@ -56,11 +54,6 @@ public class RestOpenIndexAction extends BaseRestHandler {
if (waitForActiveShards != null) { if (waitForActiveShards != null) {
openIndexRequest.waitForActiveShards(ActiveShardCount.parseString(waitForActiveShards)); openIndexRequest.waitForActiveShards(ActiveShardCount.parseString(waitForActiveShards));
} }
return channel -> client.admin().indices().open(openIndexRequest, new AcknowledgedRestListener<OpenIndexResponse>(channel) { return channel -> client.admin().indices().open(openIndexRequest, new RestToXContentListener<>(channel));
@Override
protected void addCustomFields(XContentBuilder builder, OpenIndexResponse response) throws IOException {
builder.field("shards_acknowledged", response.isShardsAcknowledged());
}
});
} }
} }

View File

@ -45,11 +45,12 @@ public class RestRolloverIndexAction extends BaseRestHandler {
@Override @Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
RolloverRequest rolloverIndexRequest = new RolloverRequest(request.param("index"), request.param("new_index")); RolloverRequest rolloverIndexRequest = new RolloverRequest(request.param("index"), request.param("new_index"));
request.applyContentParser(parser -> RolloverRequest.PARSER.parse(parser, rolloverIndexRequest, null)); request.applyContentParser(rolloverIndexRequest::fromXContent);
rolloverIndexRequest.dryRun(request.paramAsBoolean("dry_run", false)); rolloverIndexRequest.dryRun(request.paramAsBoolean("dry_run", false));
rolloverIndexRequest.timeout(request.paramAsTime("timeout", rolloverIndexRequest.timeout())); rolloverIndexRequest.timeout(request.paramAsTime("timeout", rolloverIndexRequest.timeout()));
rolloverIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", rolloverIndexRequest.masterNodeTimeout())); rolloverIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", rolloverIndexRequest.masterNodeTimeout()));
rolloverIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); rolloverIndexRequest.getCreateIndexRequest().waitForActiveShards(
ActiveShardCount.parseString(request.param("wait_for_active_shards")));
return channel -> client.admin().indices().rolloverIndex(rolloverIndexRequest, new RestToXContentListener<>(channel)); return channel -> client.admin().indices().rolloverIndex(rolloverIndexRequest, new RestToXContentListener<>(channel));
} }
} }

View File

@ -20,16 +20,14 @@
package org.elasticsearch.rest.action.admin.indices; package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; 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.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException; import java.io.IOException;
@ -47,23 +45,12 @@ public class RestShrinkIndexAction extends BaseRestHandler {
@Override @Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
if (request.param("target") == null) {
throw new IllegalArgumentException("no target index");
}
if (request.param("index") == null) {
throw new IllegalArgumentException("no source index");
}
ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index")); ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index"));
shrinkIndexRequest.setResizeType(ResizeType.SHRINK); shrinkIndexRequest.setResizeType(ResizeType.SHRINK);
request.applyContentParser(shrinkIndexRequest::fromXContent); request.applyContentParser(shrinkIndexRequest::fromXContent);
shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout())); shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout()));
shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout())); shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout()));
shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards")));
return channel -> client.admin().indices().resizeIndex(shrinkIndexRequest, new AcknowledgedRestListener<ResizeResponse>(channel) { return channel -> client.admin().indices().resizeIndex(shrinkIndexRequest, new RestToXContentListener<>(channel));
@Override
public void addCustomFields(XContentBuilder builder, ResizeResponse response) throws IOException {
response.addCustomFields(builder);
}
});
} }
} }

View File

@ -20,16 +20,14 @@
package org.elasticsearch.rest.action.admin.indices; package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest; 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.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController; import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.AcknowledgedRestListener; import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException; import java.io.IOException;
@ -47,23 +45,12 @@ public class RestSplitIndexAction extends BaseRestHandler {
@Override @Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
if (request.param("target") == null) {
throw new IllegalArgumentException("no target index");
}
if (request.param("index") == null) {
throw new IllegalArgumentException("no source index");
}
ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index")); ResizeRequest shrinkIndexRequest = new ResizeRequest(request.param("target"), request.param("index"));
shrinkIndexRequest.setResizeType(ResizeType.SPLIT); shrinkIndexRequest.setResizeType(ResizeType.SPLIT);
request.applyContentParser(shrinkIndexRequest::fromXContent); request.applyContentParser(shrinkIndexRequest::fromXContent);
shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout())); shrinkIndexRequest.timeout(request.paramAsTime("timeout", shrinkIndexRequest.timeout()));
shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout())); shrinkIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", shrinkIndexRequest.masterNodeTimeout()));
shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); shrinkIndexRequest.setWaitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards")));
return channel -> client.admin().indices().resizeIndex(shrinkIndexRequest, new AcknowledgedRestListener<ResizeResponse>(channel) { return channel -> client.admin().indices().resizeIndex(shrinkIndexRequest, new RestToXContentListener<>(channel));
@Override
public void addCustomFields(XContentBuilder builder, ResizeResponse response) throws IOException {
response.addCustomFields(builder);
}
});
} }
} }

View File

@ -26,11 +26,14 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.LoggingDeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import java.io.IOException; import java.io.IOException;
import java.util.Map; import java.util.Map;
@ -119,17 +122,22 @@ public class CreateIndexRequestTests extends ESTestCase {
assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings()); assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings());
assertAliasesEqual(createIndexRequest.aliases(), parsedCreateIndexRequest.aliases()); assertAliasesEqual(createIndexRequest.aliases(), parsedCreateIndexRequest.aliases());
assertEquals(createIndexRequest.settings(), parsedCreateIndexRequest.settings()); assertEquals(createIndexRequest.settings(), parsedCreateIndexRequest.settings());
BytesReference finalBytes = toShuffledXContent(parsedCreateIndexRequest, xContentType, EMPTY_PARAMS, humanReadable);
ElasticsearchAssertions.assertToXContentEquivalent(originalBytes, finalBytes, xContentType);
} }
private void assertMappingsEqual(Map<String, String> expected, Map<String, String> actual) throws IOException { public static void assertMappingsEqual(Map<String, String> expected, Map<String, String> actual) throws IOException {
assertEquals(expected.keySet(), actual.keySet()); assertEquals(expected.keySet(), actual.keySet());
for (Map.Entry<String, String> expectedEntry : expected.entrySet()) { for (Map.Entry<String, String> expectedEntry : expected.entrySet()) {
String expectedValue = expectedEntry.getValue(); String expectedValue = expectedEntry.getValue();
String actualValue = actual.get(expectedEntry.getKey()); String actualValue = actual.get(expectedEntry.getKey());
XContentParser expectedJson = createParser(XContentType.JSON.xContent(), expectedValue); XContentParser expectedJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
XContentParser actualJson = createParser(XContentType.JSON.xContent(), actualValue); LoggingDeprecationHandler.INSTANCE, expectedValue);
assertEquals(expectedJson.mapOrdered(), actualJson.mapOrdered()); XContentParser actualJson = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
LoggingDeprecationHandler.INSTANCE, actualValue);
assertEquals(expectedJson.map(), actualJson.map());
} }
} }

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.io.IOException; import java.io.IOException;
@ -76,6 +77,18 @@ public class CreateIndexResponseTests extends ESTestCase {
assertEquals("{\"acknowledged\":true,\"shards_acknowledged\":false,\"index\":\"index_name\"}", output); assertEquals("{\"acknowledged\":true,\"shards_acknowledged\":false,\"index\":\"index_name\"}", output);
} }
public void testToAndFromXContentIndexNull() throws IOException {
CreateIndexResponse response = new CreateIndexResponse(true, false, null);
String output = Strings.toString(response);
assertEquals("{\"acknowledged\":true,\"shards_acknowledged\":false,\"index\":null}", output);
try (XContentParser parser = createParser(JsonXContent.jsonXContent, output)) {
CreateIndexResponse parsedResponse = CreateIndexResponse.fromXContent(parser);
assertNull(parsedResponse.index());
assertTrue(parsedResponse.isAcknowledged());
assertFalse(parsedResponse.isShardsAcknowledged());
}
}
public void testToAndFromXContent() throws IOException { public void testToAndFromXContent() throws IOException {
doFromXContentTestWithRandomFields(false); doFromXContentTestWithRandomFields(false);
} }

View File

@ -23,12 +23,13 @@ import org.elasticsearch.common.unit.ByteSizeUnit;
import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class ConditionTests extends ESTestCase { public class ConditionTests extends ESTestCase {
public void testMaxAge() throws Exception { public void testMaxAge() {
final MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(1)); final MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(1));
long indexCreatedMatch = System.currentTimeMillis() - TimeValue.timeValueMinutes(61).getMillis(); long indexCreatedMatch = System.currentTimeMillis() - TimeValue.timeValueMinutes(61).getMillis();
@ -42,7 +43,7 @@ public class ConditionTests extends ESTestCase {
assertThat(evaluate.matched, equalTo(false)); assertThat(evaluate.matched, equalTo(false));
} }
public void testMaxDocs() throws Exception { public void testMaxDocs() {
final MaxDocsCondition maxDocsCondition = new MaxDocsCondition(100L); final MaxDocsCondition maxDocsCondition = new MaxDocsCondition(100L);
long maxDocsMatch = randomIntBetween(100, 1000); long maxDocsMatch = randomIntBetween(100, 1000);
@ -56,7 +57,7 @@ public class ConditionTests extends ESTestCase {
assertThat(evaluate.matched, equalTo(false)); assertThat(evaluate.matched, equalTo(false));
} }
public void testMaxSize() throws Exception { public void testMaxSize() {
MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomIntBetween(10, 20), ByteSizeUnit.MB)); MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomIntBetween(10, 20), ByteSizeUnit.MB));
Condition.Result result = maxSizeCondition.evaluate(new Condition.Stats(randomNonNegativeLong(), randomNonNegativeLong(), Condition.Result result = maxSizeCondition.evaluate(new Condition.Stats(randomNonNegativeLong(), randomNonNegativeLong(),
@ -72,7 +73,21 @@ public class ConditionTests extends ESTestCase {
assertThat(result.matched, equalTo(true)); assertThat(result.matched, equalTo(true));
} }
private ByteSizeValue randomByteSize() { public void testEqualsAndHashCode() {
MaxDocsCondition maxDocsCondition = new MaxDocsCondition(randomLong());
EqualsHashCodeTestUtils.checkEqualsAndHashCode(maxDocsCondition, condition -> new MaxDocsCondition(condition.value),
condition -> new MaxDocsCondition(randomLong()));
MaxSizeCondition maxSizeCondition = new MaxSizeCondition(randomByteSize());
EqualsHashCodeTestUtils.checkEqualsAndHashCode(maxSizeCondition, condition -> new MaxSizeCondition(condition.value),
condition -> new MaxSizeCondition(randomByteSize()));
MaxAgeCondition maxAgeCondition = new MaxAgeCondition(new TimeValue(randomNonNegativeLong()));
EqualsHashCodeTestUtils.checkEqualsAndHashCode(maxAgeCondition, condition -> new MaxAgeCondition(condition.value),
condition -> new MaxAgeCondition(new TimeValue(randomNonNegativeLong())));
}
private static ByteSizeValue randomByteSize() {
return new ByteSizeValue(randomNonNegativeLong(), ByteSizeUnit.BYTES); return new ByteSizeValue(randomNonNegativeLong(), ByteSizeUnit.BYTES);
} }
} }

View File

@ -37,15 +37,12 @@ import org.joda.time.format.DateTimeFormat;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.everyItem; import static org.hamcrest.Matchers.everyItem;
import static org.hamcrest.Matchers.hasProperty;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST) @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST)
@ -143,12 +140,8 @@ public class RolloverIT extends ESIntegTestCase {
assertThat(response.isDryRun(), equalTo(false)); assertThat(response.isDryRun(), equalTo(false));
assertThat(response.isRolledOver(), equalTo(false)); assertThat(response.isRolledOver(), equalTo(false));
assertThat(response.getConditionStatus().size(), equalTo(2)); assertThat(response.getConditionStatus().size(), equalTo(2));
assertThat(response.getConditionStatus().values(), everyItem(is(false)));
Set<String> conditions = response.getConditionStatus().keySet();
assertThat(response.getConditionStatus(), everyItem(hasProperty("value", is(false))));
Set<String> conditions = response.getConditionStatus().stream()
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
assertThat(conditions, containsInAnyOrder( assertThat(conditions, containsInAnyOrder(
new MaxSizeCondition(new ByteSizeValue(10, ByteSizeUnit.MB)).toString(), new MaxSizeCondition(new ByteSizeValue(10, ByteSizeUnit.MB)).toString(),
new MaxAgeCondition(TimeValue.timeValueHours(4)).toString())); new MaxAgeCondition(TimeValue.timeValueHours(4)).toString()));

View File

@ -19,6 +19,10 @@
package org.elasticsearch.action.admin.indices.rollover; package org.elasticsearch.action.admin.indices.rollover;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestTests;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput;
@ -29,15 +33,22 @@ import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.indices.IndicesModule;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.XContentTestUtils;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import org.junit.Before; import org.junit.Before;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Map;
import java.util.stream.Collectors; import java.util.function.Consumer;
import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
public class RolloverRequestTests extends ESTestCase { public class RolloverRequestTests extends ESTestCase {
@ -61,23 +72,15 @@ public class RolloverRequestTests extends ESTestCase {
.field("max_size", "45gb") .field("max_size", "45gb")
.endObject() .endObject()
.endObject(); .endObject();
RolloverRequest.PARSER.parse(createParser(builder), request, null); request.fromXContent(createParser(builder));
Set<Condition> conditions = request.getConditions(); Map<String, Condition> conditions = request.getConditions();
assertThat(conditions.size(), equalTo(3)); assertThat(conditions.size(), equalTo(3));
for (Condition condition : conditions) { MaxAgeCondition maxAgeCondition = (MaxAgeCondition)conditions.get(MaxAgeCondition.NAME);
if (condition instanceof MaxAgeCondition) { assertThat(maxAgeCondition.value.getMillis(), equalTo(TimeValue.timeValueHours(24 * 10).getMillis()));
MaxAgeCondition maxAgeCondition = (MaxAgeCondition) condition; MaxDocsCondition maxDocsCondition = (MaxDocsCondition)conditions.get(MaxDocsCondition.NAME);
assertThat(maxAgeCondition.value.getMillis(), equalTo(TimeValue.timeValueHours(24 * 10).getMillis())); assertThat(maxDocsCondition.value, equalTo(100L));
} else if (condition instanceof MaxDocsCondition) { MaxSizeCondition maxSizeCondition = (MaxSizeCondition)conditions.get(MaxSizeCondition.NAME);
MaxDocsCondition maxDocsCondition = (MaxDocsCondition) condition; assertThat(maxSizeCondition.value.getBytes(), equalTo(ByteSizeUnit.GB.toBytes(45)));
assertThat(maxDocsCondition.value, equalTo(100L));
} else if (condition instanceof MaxSizeCondition) {
MaxSizeCondition maxSizeCondition = (MaxSizeCondition) condition;
assertThat(maxSizeCondition.value.getBytes(), equalTo(ByteSizeUnit.GB.toBytes(45)));
} else {
fail("unexpected condition " + condition);
}
}
} }
public void testParsingWithIndexSettings() throws Exception { public void testParsingWithIndexSettings() throws Exception {
@ -105,8 +108,8 @@ public class RolloverRequestTests extends ESTestCase {
.startObject("alias1").endObject() .startObject("alias1").endObject()
.endObject() .endObject()
.endObject(); .endObject();
RolloverRequest.PARSER.parse(createParser(builder), request, null); request.fromXContent(createParser(builder));
Set<Condition> conditions = request.getConditions(); Map<String, Condition> conditions = request.getConditions();
assertThat(conditions.size(), equalTo(2)); assertThat(conditions.size(), equalTo(2));
assertThat(request.getCreateIndexRequest().mappings().size(), equalTo(1)); assertThat(request.getCreateIndexRequest().mappings().size(), equalTo(1));
assertThat(request.getCreateIndexRequest().aliases().size(), equalTo(1)); assertThat(request.getCreateIndexRequest().aliases().size(), equalTo(1));
@ -126,19 +129,92 @@ public class RolloverRequestTests extends ESTestCase {
cloneRequest.readFrom(in); cloneRequest.readFrom(in);
assertThat(cloneRequest.getNewIndexName(), equalTo(originalRequest.getNewIndexName())); assertThat(cloneRequest.getNewIndexName(), equalTo(originalRequest.getNewIndexName()));
assertThat(cloneRequest.getAlias(), equalTo(originalRequest.getAlias())); assertThat(cloneRequest.getAlias(), equalTo(originalRequest.getAlias()));
for (Map.Entry<String, Condition> entry : cloneRequest.getConditions().entrySet()) {
List<String> originalConditions = originalRequest.getConditions().stream() Condition condition = originalRequest.getConditions().get(entry.getKey());
.map(Condition::toString) //here we compare the string representation as there is some information loss when serializing
.sorted() //and de-serializing MaxAgeCondition
.collect(Collectors.toList()); assertEquals(condition.toString(), entry.getValue().toString());
}
List<String> cloneConditions = cloneRequest.getConditions().stream()
.map(Condition::toString)
.sorted()
.collect(Collectors.toList());
assertThat(originalConditions, equalTo(cloneConditions));
} }
} }
} }
public void testToAndFromXContent() throws IOException {
RolloverRequest rolloverRequest = createTestItem();
final XContentType xContentType = randomFrom(XContentType.values());
boolean humanReadable = randomBoolean();
BytesReference originalBytes = toShuffledXContent(rolloverRequest, xContentType, EMPTY_PARAMS, humanReadable);
RolloverRequest parsedRolloverRequest = new RolloverRequest();
parsedRolloverRequest.fromXContent(createParser(xContentType.xContent(), originalBytes));
CreateIndexRequest createIndexRequest = rolloverRequest.getCreateIndexRequest();
CreateIndexRequest parsedCreateIndexRequest = parsedRolloverRequest.getCreateIndexRequest();
CreateIndexRequestTests.assertMappingsEqual(createIndexRequest.mappings(), parsedCreateIndexRequest.mappings());
CreateIndexRequestTests.assertAliasesEqual(createIndexRequest.aliases(), parsedCreateIndexRequest.aliases());
assertEquals(createIndexRequest.settings(), parsedCreateIndexRequest.settings());
assertEquals(rolloverRequest.getConditions(), parsedRolloverRequest.getConditions());
BytesReference finalBytes = toShuffledXContent(parsedRolloverRequest, xContentType, EMPTY_PARAMS, humanReadable);
ElasticsearchAssertions.assertToXContentEquivalent(originalBytes, finalBytes, xContentType);
}
public void testUnknownFields() throws IOException {
final RolloverRequest request = new RolloverRequest();
XContentType xContentType = randomFrom(XContentType.values());
final XContentBuilder builder = XContentFactory.contentBuilder(xContentType);
builder.startObject();
{
builder.startObject("conditions");
builder.field("max_age", "10d");
builder.endObject();
}
builder.endObject();
BytesReference mutated = XContentTestUtils.insertRandomFields(xContentType, builder.bytes(), null, random());
expectThrows(ParsingException.class, () -> request.fromXContent(createParser(xContentType.xContent(), mutated)));
}
public void testSameConditionCanOnlyBeAddedOnce() {
RolloverRequest rolloverRequest = new RolloverRequest();
Consumer<RolloverRequest> rolloverRequestConsumer = randomFrom(conditionsGenerator);
rolloverRequestConsumer.accept(rolloverRequest);
expectThrows(IllegalArgumentException.class, () -> rolloverRequestConsumer.accept(rolloverRequest));
}
public void testValidation() {
RolloverRequest rolloverRequest = new RolloverRequest();
assertNotNull(rolloverRequest.getCreateIndexRequest());
ActionRequestValidationException validationException = rolloverRequest.validate();
assertNotNull(validationException);
assertEquals(1, validationException.validationErrors().size());
assertEquals("index alias is missing", validationException.validationErrors().get(0));
}
private static List<Consumer<RolloverRequest>> conditionsGenerator = new ArrayList<>();
static {
conditionsGenerator.add((request) -> request.addMaxIndexDocsCondition(randomNonNegativeLong()));
conditionsGenerator.add((request) -> request.addMaxIndexSizeCondition(new ByteSizeValue(randomNonNegativeLong())));
conditionsGenerator.add((request) -> request.addMaxIndexAgeCondition(new TimeValue(randomNonNegativeLong())));
}
private static RolloverRequest createTestItem() throws IOException {
RolloverRequest rolloverRequest = new RolloverRequest();
if (randomBoolean()) {
String type = randomAlphaOfLengthBetween(3, 10);
rolloverRequest.getCreateIndexRequest().mapping(type, RandomCreateIndexGenerator.randomMapping(type));
}
if (randomBoolean()) {
RandomCreateIndexGenerator.randomAliases(rolloverRequest.getCreateIndexRequest());
}
if (randomBoolean()) {
rolloverRequest.getCreateIndexRequest().settings(RandomCreateIndexGenerator.randomIndexSettings());
}
int numConditions = randomIntBetween(0, 3);
List<Consumer<RolloverRequest>> conditions = randomSubsetOf(numConditions, conditionsGenerator);
for (Consumer<RolloverRequest> consumer : conditions) {
consumer.accept(rolloverRequest);
}
return rolloverRequest;
}
} }

View File

@ -0,0 +1,132 @@
/*
* 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.rollover;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.test.AbstractStreamableXContentTestCase;
import org.elasticsearch.test.EqualsHashCodeTestUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.function.Supplier;
public class RolloverResponseTests extends AbstractStreamableXContentTestCase<RolloverResponse> {
@Override
protected RolloverResponse createTestInstance() {
boolean acknowledged = randomBoolean();
boolean shardsAcknowledged = acknowledged && randomBoolean();
return new RolloverResponse(randomAlphaOfLengthBetween(3, 10),
randomAlphaOfLengthBetween(3, 10), randomResults(true), randomBoolean(), randomBoolean(), acknowledged, shardsAcknowledged);
}
private static Map<String, Boolean> randomResults(boolean allowNoItems) {
Map<String, Boolean> results = new HashMap<>();
int numResults = randomIntBetween(allowNoItems ? 0 : 1, 3);
List<Supplier<Condition<?>>> conditions = randomSubsetOf(numResults, conditionSuppliers);
for (Supplier<Condition<?>> condition : conditions) {
Condition<?> cond = condition.get();
results.put(cond.name, randomBoolean());
}
return results;
}
private static final List<Supplier<Condition<?>>> conditionSuppliers = new ArrayList<>();
static {
conditionSuppliers.add(() -> new MaxAgeCondition(new TimeValue(randomNonNegativeLong())));
conditionSuppliers.add(() -> new MaxDocsCondition(randomNonNegativeLong()));
conditionSuppliers.add(() -> new MaxDocsCondition(randomNonNegativeLong()));
}
@Override
protected RolloverResponse createBlankInstance() {
return new RolloverResponse();
}
@Override
protected RolloverResponse doParseInstance(XContentParser parser) {
return RolloverResponse.fromXContent(parser);
}
@Override
protected Predicate<String> getRandomFieldsExcludeFilter() {
return field -> field.startsWith("conditions");
}
@Override
protected EqualsHashCodeTestUtils.MutateFunction<RolloverResponse> getMutateFunction() {
return response -> {
int i = randomIntBetween(0, 6);
switch(i) {
case 0:
return new RolloverResponse(response.getOldIndex() + randomAlphaOfLengthBetween(2, 5),
response.getNewIndex(), response.getConditionStatus(), response.isDryRun(), response.isRolledOver(),
response.isAcknowledged(), response.isShardsAcknowledged());
case 1:
return new RolloverResponse(response.getOldIndex(), response.getNewIndex() + randomAlphaOfLengthBetween(2, 5),
response.getConditionStatus(), response.isDryRun(), response.isRolledOver(),
response.isAcknowledged(), response.isShardsAcknowledged());
case 2:
Map<String, Boolean> results;
if (response.getConditionStatus().isEmpty()) {
results = randomResults(false);
} else {
results = new HashMap<>(response.getConditionStatus().size());
List<String> keys = randomSubsetOf(randomIntBetween(1, response.getConditionStatus().size()),
response.getConditionStatus().keySet());
for (Map.Entry<String, Boolean> entry : response.getConditionStatus().entrySet()) {
boolean value = keys.contains(entry.getKey()) ? entry.getValue() == false : entry.getValue();
results.put(entry.getKey(), value);
}
}
return new RolloverResponse(response.getOldIndex(), response.getNewIndex(), results, response.isDryRun(),
response.isRolledOver(), response.isAcknowledged(), response.isShardsAcknowledged());
case 3:
return new RolloverResponse(response.getOldIndex(), response.getNewIndex(),
response.getConditionStatus(), response.isDryRun() == false, response.isRolledOver(),
response.isAcknowledged(), response.isShardsAcknowledged());
case 4:
return new RolloverResponse(response.getOldIndex(), response.getNewIndex(),
response.getConditionStatus(), response.isDryRun(), response.isRolledOver() == false,
response.isAcknowledged(), response.isShardsAcknowledged());
case 5: {
boolean acknowledged = response.isAcknowledged() == false;
boolean shardsAcknowledged = acknowledged && response.isShardsAcknowledged();
return new RolloverResponse(response.getOldIndex(), response.getNewIndex(),
response.getConditionStatus(), response.isDryRun(), response.isRolledOver(),
acknowledged, shardsAcknowledged);
}
case 6: {
boolean shardsAcknowledged = response.isShardsAcknowledged() == false;
boolean acknowledged = shardsAcknowledged || response.isAcknowledged();
return new RolloverResponse(response.getOldIndex(), response.getNewIndex(),
response.getConditionStatus(), response.isDryRun(), response.isRolledOver(),
acknowledged, shardsAcknowledged);
}
default:
throw new UnsupportedOperationException();
}
};
}
}

View File

@ -44,6 +44,7 @@ import org.mockito.ArgumentCaptor;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.elasticsearch.action.admin.indices.rollover.TransportRolloverAction.evaluateConditions; import static org.elasticsearch.action.admin.indices.rollover.TransportRolloverAction.evaluateConditions;
@ -58,7 +59,7 @@ import static org.mockito.Mockito.when;
public class TransportRolloverActionTests extends ESTestCase { public class TransportRolloverActionTests extends ESTestCase {
public void testDocStatsSelectionFromPrimariesOnly() throws Exception { public void testDocStatsSelectionFromPrimariesOnly() {
long docsInPrimaryShards = 100; long docsInPrimaryShards = 100;
long docsInShards = 200; long docsInShards = 200;
@ -70,7 +71,7 @@ public class TransportRolloverActionTests extends ESTestCase {
assertEquals(docsInPrimaryShards, argument.getValue().numDocs); assertEquals(docsInPrimaryShards, argument.getValue().numDocs);
} }
public void testEvaluateConditions() throws Exception { public void testEvaluateConditions() {
MaxDocsCondition maxDocsCondition = new MaxDocsCondition(100L); MaxDocsCondition maxDocsCondition = new MaxDocsCondition(100L);
MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(2)); MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(2));
MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomIntBetween(10, 100), ByteSizeUnit.MB)); MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomIntBetween(10, 100), ByteSizeUnit.MB));
@ -89,29 +90,29 @@ public class TransportRolloverActionTests extends ESTestCase {
.settings(settings) .settings(settings)
.build(); .build();
final Set<Condition> conditions = Sets.newHashSet(maxDocsCondition, maxAgeCondition, maxSizeCondition); final Set<Condition> conditions = Sets.newHashSet(maxDocsCondition, maxAgeCondition, maxSizeCondition);
Set<Condition.Result> results = evaluateConditions(conditions, Map<String, Boolean> results = evaluateConditions(conditions,
new DocsStats(matchMaxDocs, 0L, ByteSizeUnit.MB.toBytes(120)), metaData); new DocsStats(matchMaxDocs, 0L, ByteSizeUnit.MB.toBytes(120)), metaData);
assertThat(results.size(), equalTo(3)); assertThat(results.size(), equalTo(3));
for (Condition.Result result : results) { for (Boolean matched : results.values()) {
assertThat(result.matched, equalTo(true)); assertThat(matched, equalTo(true));
} }
results = evaluateConditions(conditions, new DocsStats(notMatchMaxDocs, 0, notMatchMaxSize.getBytes()), metaData); results = evaluateConditions(conditions, new DocsStats(notMatchMaxDocs, 0, notMatchMaxSize.getBytes()), metaData);
assertThat(results.size(), equalTo(3)); assertThat(results.size(), equalTo(3));
for (Condition.Result result : results) { for (Map.Entry<String, Boolean> entry : results.entrySet()) {
if (result.condition instanceof MaxAgeCondition) { if (entry.getKey().equals(maxAgeCondition.toString())) {
assertThat(result.matched, equalTo(true)); assertThat(entry.getValue(), equalTo(true));
} else if (result.condition instanceof MaxDocsCondition) { } else if (entry.getKey().equals(maxDocsCondition.toString())) {
assertThat(result.matched, equalTo(false)); assertThat(entry.getValue(), equalTo(false));
} else if (result.condition instanceof MaxSizeCondition) { } else if (entry.getKey().equals(maxSizeCondition.toString())) {
assertThat(result.matched, equalTo(false)); assertThat(entry.getValue(), equalTo(false));
} else { } else {
fail("unknown condition result found " + result.condition); fail("unknown condition result found " + entry.getKey());
} }
} }
} }
public void testEvaluateWithoutDocStats() throws Exception { public void testEvaluateWithoutDocStats() {
MaxDocsCondition maxDocsCondition = new MaxDocsCondition(randomNonNegativeLong()); MaxDocsCondition maxDocsCondition = new MaxDocsCondition(randomNonNegativeLong());
MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(randomIntBetween(1, 3))); MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(randomIntBetween(1, 3)));
MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomNonNegativeLong())); MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomNonNegativeLong()));
@ -128,23 +129,23 @@ public class TransportRolloverActionTests extends ESTestCase {
.creationDate(System.currentTimeMillis() - TimeValue.timeValueHours(randomIntBetween(5, 10)).getMillis()) .creationDate(System.currentTimeMillis() - TimeValue.timeValueHours(randomIntBetween(5, 10)).getMillis())
.settings(settings) .settings(settings)
.build(); .build();
Set<Condition.Result> results = evaluateConditions(conditions, null, metaData); Map<String, Boolean> results = evaluateConditions(conditions, null, metaData);
assertThat(results.size(), equalTo(3)); assertThat(results.size(), equalTo(3));
for (Condition.Result result : results) { for (Map.Entry<String, Boolean> entry : results.entrySet()) {
if (result.condition instanceof MaxAgeCondition) { if (entry.getKey().equals(maxAgeCondition.toString())) {
assertThat(result.matched, equalTo(true)); assertThat(entry.getValue(), equalTo(true));
} else if (result.condition instanceof MaxDocsCondition) { } else if (entry.getKey().equals(maxDocsCondition.toString())) {
assertThat(result.matched, equalTo(false)); assertThat(entry.getValue(), equalTo(false));
} else if (result.condition instanceof MaxSizeCondition) { } else if (entry.getKey().equals(maxSizeCondition.toString())) {
assertThat(result.matched, equalTo(false)); assertThat(entry.getValue(), equalTo(false));
} else { } else {
fail("unknown condition result found " + result.condition); fail("unknown condition result found " + entry.getKey());
} }
} }
} }
public void testCreateUpdateAliasRequest() throws Exception { public void testCreateUpdateAliasRequest() {
String sourceAlias = randomAlphaOfLength(10); String sourceAlias = randomAlphaOfLength(10);
String sourceIndex = randomAlphaOfLength(10); String sourceIndex = randomAlphaOfLength(10);
String targetIndex = randomAlphaOfLength(10); String targetIndex = randomAlphaOfLength(10);
@ -171,7 +172,7 @@ public class TransportRolloverActionTests extends ESTestCase {
assertTrue(foundRemove); assertTrue(foundRemove);
} }
public void testValidation() throws Exception { public void testValidation() {
String index1 = randomAlphaOfLength(10); String index1 = randomAlphaOfLength(10);
String alias = randomAlphaOfLength(10); String alias = randomAlphaOfLength(10);
String index2 = randomAlphaOfLength(10); String index2 = randomAlphaOfLength(10);
@ -206,7 +207,7 @@ public class TransportRolloverActionTests extends ESTestCase {
TransportRolloverAction.validate(metaData, new RolloverRequest(alias, randomAlphaOfLength(10))); TransportRolloverAction.validate(metaData, new RolloverRequest(alias, randomAlphaOfLength(10)));
} }
public void testGenerateRolloverIndexName() throws Exception { public void testGenerateRolloverIndexName() {
String invalidIndexName = randomAlphaOfLength(10) + "A"; String invalidIndexName = randomAlphaOfLength(10) + "A";
IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(Settings.EMPTY); IndexNameExpressionResolver indexNameExpressionResolver = new IndexNameExpressionResolver(Settings.EMPTY);
expectThrows(IllegalArgumentException.class, () -> expectThrows(IllegalArgumentException.class, () ->
@ -224,12 +225,12 @@ public class TransportRolloverActionTests extends ESTestCase {
indexNameExpressionResolver)); indexNameExpressionResolver));
} }
public void testCreateIndexRequest() throws Exception { public void testCreateIndexRequest() {
String alias = randomAlphaOfLength(10); String alias = randomAlphaOfLength(10);
String rolloverIndex = randomAlphaOfLength(10); String rolloverIndex = randomAlphaOfLength(10);
final RolloverRequest rolloverRequest = new RolloverRequest(alias, randomAlphaOfLength(10)); final RolloverRequest rolloverRequest = new RolloverRequest(alias, randomAlphaOfLength(10));
final ActiveShardCount activeShardCount = randomBoolean() ? ActiveShardCount.ALL : ActiveShardCount.ONE; final ActiveShardCount activeShardCount = randomBoolean() ? ActiveShardCount.ALL : ActiveShardCount.ONE;
rolloverRequest.setWaitForActiveShards(activeShardCount); rolloverRequest.getCreateIndexRequest().waitForActiveShards(activeShardCount);
final Settings settings = Settings.builder() final Settings settings = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()) .put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
@ -244,7 +245,7 @@ public class TransportRolloverActionTests extends ESTestCase {
assertThat(createIndexRequest.cause(), equalTo("rollover_index")); assertThat(createIndexRequest.cause(), equalTo("rollover_index"));
} }
public void testRejectDuplicateAlias() throws Exception { public void testRejectDuplicateAlias() {
final IndexTemplateMetaData template = IndexTemplateMetaData.builder("test-template") final IndexTemplateMetaData template = IndexTemplateMetaData.builder("test-template")
.patterns(Arrays.asList("foo-*", "bar-*")) .patterns(Arrays.asList("foo-*", "bar-*"))
.putAlias(AliasMetaData.builder("foo-write")).putAlias(AliasMetaData.builder("bar-write")) .putAlias(AliasMetaData.builder("foo-write")).putAlias(AliasMetaData.builder("bar-write"))
@ -271,7 +272,7 @@ public class TransportRolloverActionTests extends ESTestCase {
return response; return response;
} }
private IndexMetaData createMetaData() { private static IndexMetaData createMetaData() {
final Settings settings = Settings.builder() final Settings settings = Settings.builder()
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()) .put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
@ -284,7 +285,7 @@ public class TransportRolloverActionTests extends ESTestCase {
.build(); .build();
} }
private Condition createTestCondition() { private static Condition createTestCondition() {
final Condition condition = mock(Condition.class); final Condition condition = mock(Condition.class);
when(condition.evaluate(any())).thenReturn(new Condition.Result(condition, true)); when(condition.evaluate(any())).thenReturn(new Condition.Result(condition, true));
return condition; return condition;

View File

@ -28,6 +28,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.RandomCreateIndexGenerator; import org.elasticsearch.index.RandomCreateIndexGenerator;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.hamcrest.ElasticsearchAssertions;
import java.io.IOException; import java.io.IOException;
@ -76,6 +77,9 @@ public class ResizeRequestTests extends ESTestCase {
CreateIndexRequestTests.assertAliasesEqual(resizeRequest.getTargetIndexRequest().aliases(), CreateIndexRequestTests.assertAliasesEqual(resizeRequest.getTargetIndexRequest().aliases(),
parsedResizeRequest.getTargetIndexRequest().aliases()); parsedResizeRequest.getTargetIndexRequest().aliases());
assertEquals(resizeRequest.getTargetIndexRequest().settings(), parsedResizeRequest.getTargetIndexRequest().settings()); assertEquals(resizeRequest.getTargetIndexRequest().settings(), parsedResizeRequest.getTargetIndexRequest().settings());
BytesReference finalBytes = toShuffledXContent(parsedResizeRequest, xContentType, EMPTY_PARAMS, humanReadable);
ElasticsearchAssertions.assertToXContentEquivalent(originalBytes, finalBytes, xContentType);
} }
private static ResizeRequest createTestItem() { private static ResizeRequest createTestItem() {

View File

@ -76,7 +76,7 @@ public final class RandomCreateIndexGenerator {
return builder.build(); return builder.build();
} }
private static XContentBuilder randomMapping(String type) throws IOException { public static XContentBuilder randomMapping(String type) throws IOException {
XContentBuilder builder = XContentFactory.jsonBuilder(); XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject().startObject(type); builder.startObject().startObject(type);

View File

@ -58,7 +58,7 @@ public abstract class AbstractStreamableTestCase<T extends Streamable> extends E
} }
/** /**
* Returns a {@link MutateFunction} that can be used to make create a copy * Returns a {@link MutateFunction} that can be used to create a copy
* of the given instance that is different to this instance. This defaults * of the given instance that is different to this instance. This defaults
* to null. * to null.
*/ */
@ -71,7 +71,7 @@ public abstract class AbstractStreamableTestCase<T extends Streamable> extends E
* Tests that the equals and hashcode methods are consistent and copied * Tests that the equals and hashcode methods are consistent and copied
* versions of the instance have are equal. * versions of the instance have are equal.
*/ */
public void testEqualsAndHashcode() throws IOException { public void testEqualsAndHashcode() {
for (int runs = 0; runs < NUMBER_OF_TEST_RUNS; runs++) { for (int runs = 0; runs < NUMBER_OF_TEST_RUNS; runs++) {
EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), getCopyFunction(), getMutateFunction()); EqualsHashCodeTestUtils.checkEqualsAndHashCode(createTestInstance(), getCopyFunction(), getMutateFunction());
} }

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException; import java.io.IOException;
import java.util.function.Predicate;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
@ -44,7 +45,7 @@ public abstract class AbstractStreamableXContentTestCase<T extends ToXContent &
BytesReference withRandomFields; BytesReference withRandomFields;
if (supportsUnknownFields()) { if (supportsUnknownFields()) {
// we add a few random fields to check that parser is lenient on new fields // we add a few random fields to check that parser is lenient on new fields
withRandomFields = XContentTestUtils.insertRandomFields(xContentType, shuffled, null, random()); withRandomFields = XContentTestUtils.insertRandomFields(xContentType, shuffled, getRandomFieldsExcludeFilter(), random());
} else { } else {
withRandomFields = shuffled; withRandomFields = shuffled;
} }
@ -74,6 +75,10 @@ public abstract class AbstractStreamableXContentTestCase<T extends ToXContent &
return true; return true;
} }
protected Predicate<String> getRandomFieldsExcludeFilter() {
return field -> false;
}
private T parseInstance(XContentParser parser) throws IOException { private T parseInstance(XContentParser parser) throws IOException {
T parsedInstance = doParseInstance(parser); T parsedInstance = doParseInstance(parser);
assertNull(parser.nextToken()); assertNull(parser.nextToken());