From 9681b8b0923316f0dee831aba7a6e5c613d0f0db Mon Sep 17 00:00:00 2001 From: James Baiera Date: Mon, 18 Jun 2018 17:28:24 -0400 Subject: [PATCH 01/14] Add SnapshotsStatus API to High Level Rest Client SnapshotStats fromXContent added. SnapshotSharsStats fromXContent added. SnapshotIndexShardStatus fromXContent added. SnapshotIndexStatus fromXContent added. SnapshotStatus fromXContent added. SnapshotStatusResponse fromXContent added. Add RequestConverter code. Add snapshots status apis to the snapshot client. Add testing and documentation for snapshots status api --- .../client/RequestConverters.java | 15 +++ .../elasticsearch/client/SnapshotClient.java | 33 +++++ .../client/RequestConvertersTests.java | 23 ++++ .../org/elasticsearch/client/SnapshotIT.java | 32 +++++ .../SnapshotClientDocumentationIT.java | 72 ++++++++++- .../snapshot/snapshots_status.asciidoc | 92 ++++++++++++++ .../high-level/supported-apis.asciidoc | 2 + .../status/SnapshotIndexShardStatus.java | 80 +++++++++++++ .../snapshots/status/SnapshotIndexStatus.java | 64 +++++++++- .../snapshots/status/SnapshotShardsStats.java | 89 ++++++++++++++ .../snapshots/status/SnapshotStats.java | 109 +++++++++++++++++ .../snapshots/status/SnapshotStatus.java | 113 ++++++++++++++++++ .../status/SnapshotsStatusResponse.java | 40 +++++++ .../status/SnapshotIndexShardStatusTests.java | 44 +++++++ .../status/SnapshotIndexStatusTests.java | 38 ++++++ .../status/SnapshotShardsStatsTests.java | 36 ++++++ .../snapshots/status/SnapshotStatsTests.java | 39 ++++++ .../snapshots/status/SnapshotStatusTests.java | 34 +++++- .../status/SnapshotsStatusResponseTests.java | 31 +++++ 19 files changed, 983 insertions(+), 3 deletions(-) create mode 100644 docs/java-rest/high-level/snapshot/snapshots_status.asciidoc create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java create mode 100644 server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index cd67bc8e48325..578d688e5c39e 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -40,6 +40,7 @@ import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest; import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest; import org.elasticsearch.action.admin.indices.cache.clear.ClearIndicesCacheRequest; @@ -845,6 +846,20 @@ static Request verifyRepository(VerifyRepositoryRequest verifyRepositoryRequest) return request; } + static Request snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest) { + String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot") + .addPathPart(snapshotsStatusRequest.repository()) + .addCommaSeparatedPathParts(snapshotsStatusRequest.snapshots()) + .addPathPartAsIs("_status") + .build(); + Request request = new Request(HttpGet.METHOD_NAME, endpoint); + + Params parameters = new Params(request); + parameters.withMasterTimeout(snapshotsStatusRequest.masterNodeTimeout()); + parameters.putParam("ignore_unavailable", Boolean.toString(snapshotsStatusRequest.ignoreUnavailable())); + return request; + } + static Request deleteSnapshot(DeleteSnapshotRequest deleteSnapshotRequest) { String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot") .addPathPart(deleteSnapshotRequest.repository()) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java index 36b4f473ce82f..aa9eb0c991d79 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java @@ -28,6 +28,8 @@ import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryResponse; import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest; import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse; @@ -164,6 +166,37 @@ public void verifyRepositoryAsync(VerifyRepositoryRequest verifyRepositoryReques VerifyRepositoryResponse::fromXContent, listener, emptySet()); } + /** + * Gets the status of any snapshots currently in progress. If snapshot names are provided, this will return detailed status information + * for them even if they are not currently running. + * See Snapshot and Restore + * API on elastic.co + * @param snapshotsStatusRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public SnapshotsStatusResponse snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options) + throws IOException { + return restHighLevelClient.performRequestAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options, + SnapshotsStatusResponse::fromXContent, emptySet()); + } + + /** + * Asynchronously gets the status of any snapshots currently in progress. If snapshot names are provided, this will return detailed + * status information for them even if they are not currently running. + * See Snapshot and Restore + * API on elastic.co + * @param snapshotsStatusRequest the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @param listener the listener to be notified upon request completion + */ + public void snapshotsStatusAsync(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options, + SnapshotsStatusResponse::fromXContent, listener, emptySet()); + } + /** * Deletes a snapshot. * See Snapshot and Restore diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index eee37cea561b0..4825996184fee 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -40,6 +40,7 @@ import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest; import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions; @@ -1858,6 +1859,28 @@ public void testVerifyRepository() { assertThat(expectedParams, equalTo(request.getParameters())); } + public void testSnapshotsStatus() { + Map expectedParams = new HashMap<>(); + String repository = randomIndicesNames(1, 1)[0]; + String[] snapshots = randomIndicesNames(1, 5); + StringBuilder snapshotNames = new StringBuilder(snapshots[0]); + for (int idx = 1; idx < snapshots.length; idx++) { + snapshotNames.append(",").append(snapshots[idx]); + } + boolean ignoreUnavailable = randomBoolean(); + String endpoint = "/_snapshot/" + repository + "/" + snapshotNames.toString() + "/_status"; + + SnapshotsStatusRequest snapshotsStatusRequest = new SnapshotsStatusRequest(repository, snapshots); + setRandomMasterTimeout(snapshotsStatusRequest, expectedParams); + snapshotsStatusRequest.ignoreUnavailable(ignoreUnavailable); + expectedParams.put("ignore_unavailable", Boolean.toString(ignoreUnavailable)); + + Request request = RequestConverters.snapshotsStatus(snapshotsStatusRequest); + assertThat(request.getEndpoint(), equalTo(endpoint)); + assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME)); + assertThat(request.getParameters(), equalTo(expectedParams)); + } + public void testDeleteSnapshot() { Map expectedParams = new HashMap<>(); String repository = randomIndicesNames(1, 1)[0]; diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java index f4d325e158bc5..ef82d7074bdd0 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java @@ -19,6 +19,8 @@ package org.elasticsearch.client; +import org.apache.http.entity.ContentType; +import org.apache.http.nio.entity.NStringEntity; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest; import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryResponse; @@ -28,6 +30,9 @@ import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryResponse; import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest; import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse; import org.elasticsearch.common.xcontent.XContentType; @@ -38,6 +43,7 @@ import java.util.Locale; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; public class SnapshotIT extends ESRestHighLevelClientTestCase { @@ -55,6 +61,12 @@ private Response createTestSnapshot(String repository, String snapshot) throws I return highLevelClient().getLowLevelClient().performRequest(createSnapshot); } + private Response createTestSnapshot(String repository, String snapshot, String index) throws IOException { + Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repository, snapshot)); + createSnapshot.addParameter("wait_for_completion", "true"); + createSnapshot.setEntity(new NStringEntity("{\"indices\":\""+index+"\"}", ContentType.APPLICATION_JSON)); + return highLevelClient().getLowLevelClient().performRequest(createSnapshot); + } public void testCreateRepository() throws IOException { PutRepositoryResponse response = createTestRepository("test", FsRepository.TYPE, "{\"location\": \".\"}"); @@ -119,6 +131,26 @@ public void testVerifyRepository() throws IOException { assertThat(response.getNodes().size(), equalTo(1)); } + public void testSnapshotsStatus() throws IOException { + PutRepositoryResponse putRepositoryResponse = createTestRepository("test", FsRepository.TYPE, "{\"location\": \".\"}"); + assertTrue(putRepositoryResponse.isAcknowledged()); + + createIndex("test_index", Settings.EMPTY); + + Response snapshotResponse = createTestSnapshot("test", "snapshot", "test_index"); + assertEquals(2, snapshotResponse.getHttpResponse().getStatusLine().getStatusCode() / 100); + + SnapshotsStatusRequest request = new SnapshotsStatusRequest(); + request.repository("test"); + request.snapshots(new String[]{"snapshot"}); + SnapshotsStatusResponse response = execute(request, highLevelClient().snapshot()::snapshotsStatus, + highLevelClient().snapshot()::snapshotsStatusAsync); + assertThat(response.getSnapshots().size(), equalTo(1)); + assertThat(response.getSnapshots().get(0).getSnapshot().getRepository(), equalTo("test")); + assertThat(response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo("snapshot")); + assertThat(response.getSnapshots().get(0).getIndices().containsKey("test_index"), is(true)); + } + public void testDeleteSnapshot() throws IOException { String repository = "test_repository"; String snapshot = "test_snapshot"; diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java index 965f9641e48ad..8cee53c34c6de 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java @@ -31,6 +31,9 @@ import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse; import org.elasticsearch.client.ESRestHighLevelClientTestCase; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; @@ -73,7 +76,6 @@ public class SnapshotClientDocumentationIT extends ESRestHighLevelClientTestCase { private static final String repositoryName = "test_repository"; - private static final String snapshotName = "test_snapshot"; public void testSnapshotCreateRepository() throws IOException { @@ -367,6 +369,74 @@ public void onFailure(Exception e) { } } + public void testSnapshotSnapshotsStatus() throws IOException { + RestHighLevelClient client = highLevelClient(); + createTestRepositories(); + createTestSnapshots(); + + // tag::snapshots-status-request + SnapshotsStatusRequest request = new SnapshotsStatusRequest(); + // end::snapshots-status-request + + // tag::snapshots-status-request-repository + request.repository(repositoryName); // <1> + // end::snapshots-status-request-repository + // tag::snapshots-status-request-snapshots + String [] snapshots = new String[] {snapshotName}; + request.snapshots(snapshots); // <1> + // end::snapshots-status-request-snapshots + // tag::snapshots-status-request-ignoreUnavailable + request.ignoreUnavailable(true); // <1> + // end::snapshots-status-request-ignoreUnavailable + // tag::snapshots-status-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::snapshots-status-request-masterTimeout + + // tag::snapshots-status-execute + SnapshotsStatusResponse response = client.snapshot().snapshotsStatus(request, RequestOptions.DEFAULT); + // end::snapshots-status-execute + + // tag::snapshots-status-response + List snapshotStatusesResponse = response.getSnapshots(); + // end::snapshots-status-response + assertThat(snapshotStatusesResponse.size(), equalTo(1)); + assertThat(snapshotStatusesResponse.get(0).getSnapshot().getRepository(), equalTo(repositoryName)); + assertThat(snapshotStatusesResponse.get(0).getSnapshot().getSnapshotId().getName(), equalTo(snapshotName)); + } + + public void testSnapshotSnapshotsStatusAsync() throws InterruptedException { + RestHighLevelClient client = highLevelClient(); + { + SnapshotsStatusRequest request = new SnapshotsStatusRequest(); + + // tag::snapshots-status-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(SnapshotsStatusResponse snapshotsStatusResponse) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::snapshots-status-execute-listener + + // Replace the empty listener with a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::snapshots-status-execute-async + client.snapshot().snapshotsStatusAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::snapshots-status-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + public void testSnapshotDeleteSnapshot() throws IOException { RestHighLevelClient client = highLevelClient(); diff --git a/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc b/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc new file mode 100644 index 0000000000000..bd13416891e31 --- /dev/null +++ b/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc @@ -0,0 +1,92 @@ +[[java-rest-high-snapshot-snapshots-status]] +=== Snapshots Status API + +The Snapshots Status API allows to retrieve detailed information about snapshots in progress. + +[[java-rest-high-snapshot-snapshots-status-request]] +==== Snapshots Status Request + +A `SnapshotsStatusRequest`: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request] +-------------------------------------------------- + +==== Optional Arguments +The following arguments can optionally be provided: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-repository] +-------------------------------------------------- +<1> Sets the repository to check for snapshot statuses currently in progress + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-snapshots] +-------------------------------------------------- +<1> The list of snapshot names to check the status of. If this is set, the status for the snapshots +is returned, even if they are not currently in progress + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-ignoreUnavailable] +-------------------------------------------------- +<1> The command will fail if some of the snapshots are unavailable. The `ignore_unavailable` flag +set to true will return all snapshots that are currently available. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-masterTimeout] +-------------------------------------------------- +<1> Timeout to connect to the master node as a `TimeValue` +<2> Timeout to connect to the master node as a `String` + +[[java-rest-high-snapshot-snapshots-status-sync]] +==== Synchronous Execution + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-execute] +-------------------------------------------------- + +[[java-rest-high-snapshot-snapshots-status-async]] +==== Asynchronous Execution + +The asynchronous execution of retrieving snapshot statuses requires both the +`SnapshotsStatusRequest` instance and an `ActionListener` instance to be +passed to the asynchronous method: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-execute-async] +-------------------------------------------------- +<1> The `SnapshotsStatusRequest` 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 `SnapshotsStatusResponse` looks like: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-execute-listener] +-------------------------------------------------- +<1> Called when the execution is successfully completed. The response is +provided as an argument +<2> Called in case of a failure. The raised exception is provided as an argument + +[[java-rest-high-snapshot-snapshots-status-response]] +==== Snapshots Status Response + +The returned `SnapshotsStatusResponse` allows to retrieve information about the +executed operation as follows: + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-response] +-------------------------------------------------- diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 727088aa5737f..3d329785302e8 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -136,12 +136,14 @@ The Java High Level REST Client supports the following Snapshot APIs: * <> * <> * <> +* <> * <> include::snapshot/get_repository.asciidoc[] include::snapshot/create_repository.asciidoc[] include::snapshot/delete_repository.asciidoc[] include::snapshot/verify_repository.asciidoc[] +include::snapshot/snapshots_status.asciidoc[] include::snapshot/delete_snapshot.asciidoc[] == Tasks APIs diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index 39abd8613caa4..a4957870b22b8 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -19,11 +19,16 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.support.broadcast.BroadcastShardResponse; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.index.Index; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.index.snapshots.IndexShardSnapshotStatus; @@ -80,6 +85,14 @@ private SnapshotIndexShardStatus() { this.nodeId = nodeId; } + SnapshotIndexShardStatus(ShardId shardId, SnapshotIndexShardStage stage, SnapshotStats stats, String nodeId, String failure) { + super(shardId); + this.stage = stage; + this.stats = stats; + this.nodeId = nodeId; + this.failure = failure; + } + /** * Returns snapshot stage */ @@ -153,4 +166,71 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.endObject(); return builder; } + + // Todo: Standards check + public static SnapshotIndexShardStatus fromXContent(XContentParser parser, String indexId) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); + String shardName = parser.currentName(); + int shard; + try { + shard = Integer.parseInt(shardName); + } catch (NumberFormatException nfe) { + throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}], expected numeric shard id but got [{}]", indexId, shardName); + } + ShardId shardId = new ShardId(new Index(indexId, IndexMetaData.INDEX_UUID_NA_VALUE), shard); + XContentParser.Token token = parser.nextToken(); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + SnapshotIndexShardStage stage = null; + String nodeId = null; + String failure = null; + SnapshotStats stats = null; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token.equals(XContentParser.Token.FIELD_NAME)) { + String currentName = parser.currentName(); + if (currentName.equals(Fields.STAGE)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + try { + stage = SnapshotIndexShardStage.valueOf(parser.text()); + } catch (IllegalArgumentException iae) { + throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}], unknonwn stage [{}]", indexId, shardId.getId(), parser.text()); + } + } else if (currentName.equals(Fields.NODE)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + nodeId = parser.text(); + } else if (currentName.equals(Fields.REASON)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + failure = parser.text(); + } else if (currentName.equals(SnapshotStats.Fields.STATS)) { + stats = SnapshotStats.fromXContent(parser); + } else { + throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}], unknown field [{}]", indexId, shardId.getId(), currentName); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}]", indexId, shardId.getId()); + } + } + return new SnapshotIndexShardStatus(shardId, stage, stats, nodeId, failure); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotIndexShardStatus that = (SnapshotIndexShardStatus) o; + + if (stage != that.stage) return false; + if (stats != null ? !stats.equals(that.stats) : that.stats != null) return false; + if (nodeId != null ? !nodeId.equals(that.nodeId) : that.nodeId != null) return false; + return failure != null ? failure.equals(that.failure) : that.failure == null; + } + + @Override + public int hashCode() { + int result = stage != null ? stage.hashCode() : 0; + result = 31 * result + (stats != null ? stats.hashCode() : 0); + result = 31 * result + (nodeId != null ? nodeId.hashCode() : 0); + result = 31 * result + (failure != null ? failure.hashCode() : 0); + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index 1605e41dc61be..b755045a1fe21 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -19,9 +19,11 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.common.xcontent.ToXContent.Params; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; import java.util.Collection; @@ -57,6 +59,13 @@ public class SnapshotIndexStatus implements Iterable, this.indexShards = unmodifiableMap(indexShards); } + public SnapshotIndexStatus(String index, Map indexShards, SnapshotShardsStats shardsStats, SnapshotStats stats) { + this.index = index; + this.indexShards = indexShards; + this.shardsStats = shardsStats; + this.stats = stats; + } + /** * Returns the index name */ @@ -107,4 +116,57 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.endObject(); return builder; } + + public static SnapshotIndexStatus fromXContent(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); + String indexName = parser.currentName(); + XContentParser.Token token = parser.nextToken(); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + SnapshotShardsStats shardsStats = null; + SnapshotStats stats = null; + Map shards = new HashMap<>(); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token.equals(XContentParser.Token.FIELD_NAME)) { + String currentName = parser.currentName(); + if (currentName.equals(SnapshotShardsStats.Fields.SHARDS_STATS)) { + shardsStats = SnapshotShardsStats.fromXContent(parser); + } else if (currentName.equals(SnapshotStats.Fields.STATS)) { + stats = SnapshotStats.fromXContent(parser); + } else if (currentName.equals(Fields.SHARDS)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + SnapshotIndexShardStatus shardStatus = SnapshotIndexShardStatus.fromXContent(parser, indexName); + shards.put(shardStatus.getShardId().getId(), shardStatus); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot index status [{}], unknown field [{}]", indexName, currentName); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot index status [{}]", indexName); + } + } + return new SnapshotIndexStatus(indexName, shards, shardsStats, stats); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotIndexStatus that = (SnapshotIndexStatus) o; + + if (index != null ? !index.equals(that.index) : that.index != null) return false; + if (indexShards != null ? !indexShards.equals(that.indexShards) : that.indexShards != null) return false; + if (shardsStats != null ? !shardsStats.equals(that.shardsStats) : that.shardsStats != null) return false; + return stats != null ? stats.equals(that.stats) : that.stats == null; + } + + @Override + public int hashCode() { + int result = index != null ? index.hashCode() : 0; + result = 31 * result + (indexShards != null ? indexShards.hashCode() : 0); + result = 31 * result + (shardsStats != null ? shardsStats.hashCode() : 0); + result = 31 * result + (stats != null ? stats.hashCode() : 0); + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java index c74dd5af1eec9..ba84bb73290c5 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java @@ -19,9 +19,12 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; import java.util.Collection; @@ -63,6 +66,15 @@ public class SnapshotShardsStats implements ToXContentFragment { } } + public SnapshotShardsStats(int initializingShards, int startedShards, int finalizingShards, int doneShards, int failedShards, int totalShards) { + this.initializingShards = initializingShards; + this.startedShards = startedShards; + this.finalizingShards = finalizingShards; + this.doneShards = doneShards; + this.failedShards = failedShards; + this.totalShards = totalShards; + } + /** * Number of shards with the snapshot in the initializing stage */ @@ -128,4 +140,81 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par return builder; } + public static SnapshotShardsStats fromXContent(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParser.Token token; + int initializingShards = 0; + int startedShards = 0; + int finalizingShards = 0; + int doneShards = 0; + int failedShards = 0; + int totalShards = 0; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + String currentName = parser.currentName(); + if (currentName.equals(Fields.INITIALIZING)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + initializingShards = parser.intValue(); + } else if (currentName.equals(Fields.STARTED)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + startedShards = parser.intValue(); + } else if (currentName.equals(Fields.FINALIZING)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + finalizingShards = parser.intValue(); + } else if (currentName.equals(Fields.DONE)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + doneShards = parser.intValue(); + } else if (currentName.equals(Fields.FAILED)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + failedShards = parser.intValue(); + } else if (currentName.equals(Fields.TOTAL)) { + if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + } + totalShards = parser.intValue(); + } else { + throw new ElasticsearchParseException("failed to parse snapshot shards stats, unexpected field [{}]", currentName); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot shards stats"); + } + } + return new SnapshotShardsStats(initializingShards, startedShards, finalizingShards, doneShards, failedShards, totalShards); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotShardsStats that = (SnapshotShardsStats) o; + + if (initializingShards != that.initializingShards) return false; + if (startedShards != that.startedShards) return false; + if (finalizingShards != that.finalizingShards) return false; + if (doneShards != that.doneShards) return false; + if (failedShards != that.failedShards) return false; + return totalShards == that.totalShards; + } + + @Override + public int hashCode() { + int result = initializingShards; + result = 31 * result + startedShards; + result = 31 * result + finalizingShards; + result = 31 * result + doneShards; + result = 31 * result + failedShards; + result = 31 * result + totalShards; + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index 76f6b2191840d..eb71960829e8c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -19,6 +19,7 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -28,6 +29,8 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; @@ -205,6 +208,82 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par return builder.endObject(); } + public static SnapshotStats fromXContent(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParser.Token token; + long startTime = 0; + long time = 0; + int incrementalFileCount = 0; + int totalFileCount = 0; + int processedFileCount = 0; + long incrementalSize = 0; + long totalSize = 0; + long processedSize = 0; + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation); + String currentName = parser.currentName(); + token = parser.nextToken(); + if (currentName.equals(Fields.INCREMENTAL)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + incrementalFileCount = parser.intValue(); + } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + incrementalSize = parser.longValue(); + } else { + throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + } + } + } else if (currentName.equals(Fields.PROCESSED)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + processedFileCount = parser.intValue(); + } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + processedSize = parser.longValue(); + } else { + throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + } + } + } else if (currentName.equals(Fields.TOTAL)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, token, parser::getTokenLocation); + String innerName = parser.currentName(); + token = parser.nextToken(); + if (innerName.equals(Fields.FILE_COUNT)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + totalFileCount = parser.intValue(); + } else if (innerName.equals(Fields.SIZE_IN_BYTES)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + totalSize = parser.longValue(); + } else { + throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + } + } + } else if (currentName.equals(Fields.START_TIME_IN_MILLIS)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + startTime = parser.longValue(); + } else if (currentName.equals(Fields.TIME_IN_MILLIS)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); + time = parser.longValue(); + } else { + throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", currentName); + } + } + return new SnapshotStats(startTime, time, incrementalFileCount, totalFileCount, processedFileCount, incrementalSize, totalSize, processedSize); + } + void add(SnapshotStats stats) { incrementalFileCount += stats.incrementalFileCount; totalFileCount += stats.totalFileCount; @@ -229,4 +308,34 @@ void add(SnapshotStats stats) { time = endTime - startTime; } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotStats that = (SnapshotStats) o; + + if (startTime != that.startTime) return false; + if (time != that.time) return false; + if (incrementalFileCount != that.incrementalFileCount) return false; + if (totalFileCount != that.totalFileCount) return false; + if (processedFileCount != that.processedFileCount) return false; + if (incrementalSize != that.incrementalSize) return false; + if (totalSize != that.totalSize) return false; + return processedSize == that.processedSize; + } + + @Override + public int hashCode() { + int result = (int) (startTime ^ (startTime >>> 32)); + result = 31 * result + (int) (time ^ (time >>> 32)); + result = 31 * result + incrementalFileCount; + result = 31 * result + totalFileCount; + result = 31 * result + processedFileCount; + result = 31 * result + (int) (incrementalSize ^ (incrementalSize >>> 32)); + result = 31 * result + (int) (totalSize ^ (totalSize >>> 32)); + result = 31 * result + (int) (processedSize ^ (processedSize >>> 32)); + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index f7545ea0236a7..5ab1ab13f1134 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -19,7 +19,9 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; +import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.cluster.SnapshotsInProgress.State; import org.elasticsearch.common.Strings; import org.elasticsearch.common.Nullable; @@ -28,7 +30,10 @@ import org.elasticsearch.common.io.stream.Streamable; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.snapshots.Snapshot; +import org.elasticsearch.snapshots.SnapshotId; import java.io.IOException; import java.util.ArrayList; @@ -72,6 +77,18 @@ public class SnapshotStatus implements ToXContentObject, Streamable { updateShardStats(); } + private SnapshotStatus(Snapshot snapshot, State state, List shards, + Map indicesStatus, SnapshotShardsStats shardsStats, + SnapshotStats stats, Boolean includeGlobalState) { + this.snapshot = snapshot; + this.state = state; + this.shards = shards; + this.indicesStatus = indicesStatus; + this.shardsStats = shardsStats; + this.stats = stats; + this.includeGlobalState = includeGlobalState; + } + SnapshotStatus() { } @@ -218,6 +235,75 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } + public static SnapshotStatus fromXContent(XContentParser parser) throws IOException { + XContentParser.Token token = parser.currentToken(); + if (token == null) { + token = parser.nextToken(); + } + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); + String name = null; + String repository = null; + String uuid = null; + SnapshotsInProgress.State state = null; + Boolean includeGlobalState = null; + SnapshotShardsStats shardsStats = null; + SnapshotStats stats = null; + List shards = new ArrayList<>(); + Map indices = new HashMap<>(); + while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { + if (token == XContentParser.Token.FIELD_NAME) { + String currentFieldName = parser.currentName(); + if (SNAPSHOT.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + name = parser.text(); + } else if (REPOSITORY.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + repository = parser.text(); + } else if (UUID.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + uuid = parser.text(); + } else if (STATE.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + String stateRaw = parser.text(); + try { + state = SnapshotsInProgress.State.valueOf(stateRaw); + } catch (IllegalArgumentException iae) { + throw new ElasticsearchParseException("failed to parse snapshot status, unknown state value [{}]", iae, stateRaw); + } + } else if (INCLUDE_GLOBAL_STATE.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_BOOLEAN, parser.nextToken(), parser::getTokenLocation); + includeGlobalState = parser.booleanValue(); + } else if (SnapshotShardsStats.Fields.SHARDS_STATS.equals(currentFieldName)) { + shardsStats = SnapshotShardsStats.fromXContent(parser); + } else if (SnapshotStats.Fields.STATS.equals(currentFieldName)) { + stats = SnapshotStats.fromXContent(parser); + } else if (INDICES.equals(currentFieldName)) { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + SnapshotIndexStatus indexStatus = SnapshotIndexStatus.fromXContent(parser); + indices.put(indexStatus.getIndex(), indexStatus); + shards.addAll(indexStatus.getShards().values()); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot status, unknown field [{}]", currentFieldName); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshot status"); + } + } + if (name == null) { + throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot name"); + } else if (uuid == null) { + throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot uuid"); + } else if (repository == null) { + throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot repository"); + } else if (state == null) { + throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot state"); + } + Snapshot snapshot = new Snapshot(repository, new SnapshotId(name, uuid)); + return new SnapshotStatus(snapshot, state, shards, indices, shardsStats, stats, includeGlobalState); + } + private void updateShardStats() { stats = new SnapshotStats(); shardsStats = new SnapshotShardsStats(shards); @@ -225,4 +311,31 @@ private void updateShardStats() { stats.add(shard.getStats()); } } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotStatus that = (SnapshotStatus) o; + + if (snapshot != null ? !snapshot.equals(that.snapshot) : that.snapshot != null) return false; + if (state != that.state) return false; + if (indicesStatus != null ? !indicesStatus.equals(that.indicesStatus) : that.indicesStatus != null) + return false; + if (shardsStats != null ? !shardsStats.equals(that.shardsStats) : that.shardsStats != null) return false; + if (stats != null ? !stats.equals(that.stats) : that.stats != null) return false; + return includeGlobalState != null ? includeGlobalState.equals(that.includeGlobalState) : that.includeGlobalState == null; + } + + @Override + public int hashCode() { + int result = snapshot != null ? snapshot.hashCode() : 0; + result = 31 * result + (state != null ? state.hashCode() : 0); + result = 31 * result + (indicesStatus != null ? indicesStatus.hashCode() : 0); + result = 31 * result + (shardsStats != null ? shardsStats.hashCode() : 0); + result = 31 * result + (stats != null ? stats.hashCode() : 0); + result = 31 * result + (includeGlobalState != null ? includeGlobalState.hashCode() : 0); + return result; + } } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java index d44a490680c9b..8b6dbc6b16620 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java @@ -19,11 +19,15 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContentObject; +import org.elasticsearch.common.xcontent.XContent; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; import java.util.ArrayList; @@ -85,4 +89,40 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } + public static SnapshotsStatusResponse fromXContent(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + List statuses = new ArrayList<>(); + XContentParser.Token token = parser.nextToken(); + if (token == XContentParser.Token.FIELD_NAME) { + String snapshotField = parser.currentName(); + if (snapshotField.equals("snapshots")) { + token = parser.nextToken(); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, token, parser::getTokenLocation); + while (parser.nextToken() != XContentParser.Token.END_ARRAY) { + statuses.add(SnapshotStatus.fromXContent(parser)); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshots status, unknown field [{}]", snapshotField); + } + } else { + throw new ElasticsearchParseException("failed to parse snapshots status"); + } + XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + return new SnapshotsStatusResponse(statuses); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + SnapshotsStatusResponse response = (SnapshotsStatusResponse) o; + + return snapshots != null ? snapshots.equals(response.snapshots) : response.snapshots == null; + } + + @Override + public int hashCode() { + return snapshots != null ? snapshots.hashCode() : 0; + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java new file mode 100644 index 0000000000000..b9cf795c270df --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java @@ -0,0 +1,44 @@ +package org.elasticsearch.action.admin.cluster.snapshots.status; + +import java.io.IOException; + +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.index.Index; +import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.test.AbstractXContentTestCase; + +public class SnapshotIndexShardStatusTests extends AbstractXContentTestCase { + + @Override + protected SnapshotIndexShardStatus createTestInstance() { + return createForIndex(randomAlphaOfLength(10)); + } + + protected SnapshotIndexShardStatus createForIndex(String indexName) { + ShardId shardId = new ShardId(new Index(indexName, IndexMetaData.INDEX_UUID_NA_VALUE), randomIntBetween(0, 500)); + SnapshotIndexShardStage stage = randomFrom(SnapshotIndexShardStage.values()); + SnapshotStats stats = new SnapshotStatsTests().createTestInstance(); + String nodeId = randomAlphaOfLength(20); + String failure = null; + if (rarely()) { + failure = randomAlphaOfLength(200); + } + return new SnapshotIndexShardStatus(shardId, stage, stats, nodeId, failure); + } + + @Override + protected SnapshotIndexShardStatus doParseInstance(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); + SnapshotIndexShardStatus status = SnapshotIndexShardStatus.fromXContent(parser, parser.currentName()); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + return status; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java new file mode 100644 index 0000000000000..96b322d03f8d2 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java @@ -0,0 +1,38 @@ +package org.elasticsearch.action.admin.cluster.snapshots.status; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.test.AbstractXContentTestCase; + + +public class SnapshotIndexStatusTests extends AbstractXContentTestCase { + + @Override + protected SnapshotIndexStatus createTestInstance() { + String index = randomAlphaOfLength(10); + List shardStatuses = new ArrayList<>(); + SnapshotIndexShardStatusTests builder = new SnapshotIndexShardStatusTests(); + for (int idx = 0; idx < randomIntBetween(0, 10); idx++) { + shardStatuses.add(builder.createForIndex(index)); + } + return new SnapshotIndexStatus(index, shardStatuses); + } + + @Override + protected SnapshotIndexStatus doParseInstance(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); + SnapshotIndexStatus status = SnapshotIndexStatus.fromXContent(parser); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + return status; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java new file mode 100644 index 0000000000000..113b31cd051bb --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java @@ -0,0 +1,36 @@ +package org.elasticsearch.action.admin.cluster.snapshots.status; + +import java.io.IOException; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.test.AbstractXContentTestCase; + +public class SnapshotShardsStatsTests extends AbstractXContentTestCase { + + @Override + protected SnapshotShardsStats createTestInstance() { + int initializingShards = randomInt(); + int startedShards = randomInt(); + int finalizingShards = randomInt(); + int doneShards = randomInt(); + int failedShards = randomInt(); + int totalShards = randomInt(); + return new SnapshotShardsStats(initializingShards, startedShards, finalizingShards, doneShards, failedShards, totalShards); + } + + @Override + protected SnapshotShardsStats doParseInstance(XContentParser parser) throws IOException { + // TODO: standards check + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); + SnapshotShardsStats stats = SnapshotShardsStats.fromXContent(parser); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + return stats; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java new file mode 100644 index 0000000000000..8a606f0183b45 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -0,0 +1,39 @@ +package org.elasticsearch.action.admin.cluster.snapshots.status; + +import java.io.IOException; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.XContentParserUtils; +import org.elasticsearch.test.AbstractXContentTestCase; + +public class SnapshotStatsTests extends AbstractXContentTestCase { + + @Override + protected SnapshotStats createTestInstance() { + long startTime = randomNonNegativeLong(); + long time = randomNonNegativeLong(); + int incrementalFileCount = randomIntBetween(0, Integer.MAX_VALUE); + int totalFileCount = randomIntBetween(0, Integer.MAX_VALUE); + int processedFileCount = randomIntBetween(0, Integer.MAX_VALUE); + long incrementalSize = ((long)randomIntBetween(0, Integer.MAX_VALUE)) * 2; + long totalSize = ((long)randomIntBetween(0, Integer.MAX_VALUE)) * 2; + long processedSize = ((long)randomIntBetween(0, Integer.MAX_VALUE)) * 2; + return new SnapshotStats(startTime, time, incrementalFileCount, totalFileCount, + processedFileCount, incrementalSize, totalSize, processedSize); + } + + @Override + protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { + // TODO: standards check + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); + SnapshotStats stats = SnapshotStats.fromXContent(parser); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + return stats; + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } +} diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java index 3ece0f9f1072f..e4e537b57d814 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java @@ -21,16 +21,19 @@ import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.common.UUIDs; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; +import org.elasticsearch.test.AbstractXContentTestCase; import org.elasticsearch.test.ESTestCase; +import java.io.IOException; import java.util.ArrayList; import java.util.List; -public class SnapshotStatusTests extends ESTestCase { +public class SnapshotStatusTests extends AbstractXContentTestCase { public void testToString() throws Exception { @@ -146,4 +149,33 @@ public void testToString() throws Exception { "}"; assertEquals(expected, status.toString()); } + + @Override + protected SnapshotStatus createTestInstance() { + SnapshotsInProgress.State state = randomFrom(SnapshotsInProgress.State.values()); + String uuid = UUIDs.randomBase64UUID(); + SnapshotId id = new SnapshotId("test-snap", uuid); + Snapshot snapshot = new Snapshot("test-repo", id); + + SnapshotIndexShardStatusTests builder = new SnapshotIndexShardStatusTests(); + builder.createTestInstance(); + + List snapshotIndexShardStatuses = new ArrayList<>(); + for (int idx = 0; idx < randomIntBetween(0, 10); idx++) { + SnapshotIndexShardStatus snapshotIndexShardStatus = builder.createTestInstance(); + snapshotIndexShardStatuses.add(snapshotIndexShardStatus); + } + boolean includeGlobalState = randomBoolean(); + return new SnapshotStatus(snapshot, state, snapshotIndexShardStatuses, includeGlobalState); + } + + @Override + protected SnapshotStatus doParseInstance(XContentParser parser) throws IOException { + return SnapshotStatus.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java new file mode 100644 index 0000000000000..aad5884ac74da --- /dev/null +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java @@ -0,0 +1,31 @@ +package org.elasticsearch.action.admin.cluster.snapshots.status; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.test.AbstractXContentTestCase; + +public class SnapshotsStatusResponseTests extends AbstractXContentTestCase { + + @Override + protected SnapshotsStatusResponse doParseInstance(XContentParser parser) throws IOException { + return SnapshotsStatusResponse.fromXContent(parser); + } + + @Override + protected boolean supportsUnknownFields() { + return false; + } + + @Override + protected SnapshotsStatusResponse createTestInstance() { + SnapshotStatusTests statusBuilder = new SnapshotStatusTests(); + List snapshotStatuses = new ArrayList<>(); + for (int idx = 0; idx < randomIntBetween(0, 5); idx++) { + snapshotStatuses.add(statusBuilder.createTestInstance()); + } + return new SnapshotsStatusResponse(snapshotStatuses); + } +} From 0fad8d04c0a3ae1aa53854f4352ee7fca909efba Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 21 Jun 2018 15:11:41 -0400 Subject: [PATCH 02/14] Make checkstyle and forbidden apis happy --- .../status/SnapshotIndexShardStatus.java | 23 +++++++++++++------ .../snapshots/status/SnapshotIndexStatus.java | 9 +++++--- .../snapshots/status/SnapshotShardsStats.java | 21 +++++++++++------ .../snapshots/status/SnapshotStats.java | 3 ++- .../snapshots/status/SnapshotStatus.java | 18 ++++++++++----- .../status/SnapshotsStatusResponse.java | 1 - .../status/SnapshotIndexShardStatusTests.java | 19 +++++++++++++++ .../status/SnapshotIndexStatusTests.java | 19 +++++++++++++++ .../status/SnapshotShardsStatsTests.java | 19 +++++++++++++++ .../snapshots/status/SnapshotStatsTests.java | 19 +++++++++++++++ .../snapshots/status/SnapshotStatusTests.java | 1 - .../status/SnapshotsStatusResponseTests.java | 19 +++++++++++++++ 12 files changed, 145 insertions(+), 26 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index a4957870b22b8..b44b6014bdc83 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -175,7 +175,8 @@ public static SnapshotIndexShardStatus fromXContent(XContentParser parser, Strin try { shard = Integer.parseInt(shardName); } catch (NumberFormatException nfe) { - throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}], expected numeric shard id but got [{}]", indexId, shardName); + throw new ElasticsearchParseException( + "failed to parse snapshot index shard status [{}], expected numeric shard id but got [{}]", indexId, shardName); } ShardId shardId = new ShardId(new Index(indexId, IndexMetaData.INDEX_UUID_NA_VALUE), shard); XContentParser.Token token = parser.nextToken(); @@ -188,25 +189,33 @@ public static SnapshotIndexShardStatus fromXContent(XContentParser parser, Strin if (token.equals(XContentParser.Token.FIELD_NAME)) { String currentName = parser.currentName(); if (currentName.equals(Fields.STAGE)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); try { stage = SnapshotIndexShardStage.valueOf(parser.text()); } catch (IllegalArgumentException iae) { - throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}], unknonwn stage [{}]", indexId, shardId.getId(), parser.text()); + throw new ElasticsearchParseException( + "failed to parse snapshot index shard status [{}][{}], unknonwn stage [{}]", indexId, shardId.getId(), + parser.text()); } } else if (currentName.equals(Fields.NODE)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); nodeId = parser.text(); } else if (currentName.equals(Fields.REASON)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); failure = parser.text(); } else if (currentName.equals(SnapshotStats.Fields.STATS)) { stats = SnapshotStats.fromXContent(parser); } else { - throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}], unknown field [{}]", indexId, shardId.getId(), currentName); + throw new ElasticsearchParseException( + "failed to parse snapshot index shard status [{}][{}], unknown field [{}]", indexId, shardId.getId(), + currentName); } } else { - throw new ElasticsearchParseException("failed to parse snapshot index shard status [{}][{}]", indexId, shardId.getId()); + throw new ElasticsearchParseException( + "failed to parse snapshot index shard status [{}][{}]", indexId, shardId.getId()); } } return new SnapshotIndexShardStatus(shardId, stage, stats, nodeId, failure); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index b755045a1fe21..b9dbaa18b9783 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -59,7 +59,8 @@ public class SnapshotIndexStatus implements Iterable, this.indexShards = unmodifiableMap(indexShards); } - public SnapshotIndexStatus(String index, Map indexShards, SnapshotShardsStats shardsStats, SnapshotStats stats) { + public SnapshotIndexStatus(String index, Map indexShards, SnapshotShardsStats shardsStats, + SnapshotStats stats) { this.index = index; this.indexShards = indexShards; this.shardsStats = shardsStats; @@ -133,13 +134,15 @@ public static SnapshotIndexStatus fromXContent(XContentParser parser) throws IOE } else if (currentName.equals(SnapshotStats.Fields.STATS)) { stats = SnapshotStats.fromXContent(parser); } else if (currentName.equals(Fields.SHARDS)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), + parser::getTokenLocation); while (parser.nextToken() != XContentParser.Token.END_OBJECT) { SnapshotIndexShardStatus shardStatus = SnapshotIndexShardStatus.fromXContent(parser, indexName); shards.put(shardStatus.getShardId().getId(), shardStatus); } } else { - throw new ElasticsearchParseException("failed to parse snapshot index status [{}], unknown field [{}]", indexName, currentName); + throw new ElasticsearchParseException("failed to parse snapshot index status [{}], unknown field [{}]", indexName, + currentName); } } else { throw new ElasticsearchParseException("failed to parse snapshot index status [{}]", indexName); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java index ba84bb73290c5..a0093511974d3 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java @@ -66,7 +66,8 @@ public class SnapshotShardsStats implements ToXContentFragment { } } - public SnapshotShardsStats(int initializingShards, int startedShards, int finalizingShards, int doneShards, int failedShards, int totalShards) { + public SnapshotShardsStats(int initializingShards, int startedShards, int finalizingShards, int doneShards, int failedShards, + int totalShards) { this.initializingShards = initializingShards; this.startedShards = startedShards; this.finalizingShards = finalizingShards; @@ -154,32 +155,38 @@ public static SnapshotShardsStats fromXContent(XContentParser parser) throws IOE String currentName = parser.currentName(); if (currentName.equals(Fields.INITIALIZING)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } initializingShards = parser.intValue(); } else if (currentName.equals(Fields.STARTED)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } startedShards = parser.intValue(); } else if (currentName.equals(Fields.FINALIZING)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } finalizingShards = parser.intValue(); } else if (currentName.equals(Fields.DONE)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } doneShards = parser.intValue(); } else if (currentName.equals(Fields.FAILED)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } failedShards = parser.intValue(); } else if (currentName.equals(Fields.TOTAL)) { if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", currentName); + throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", + currentName); } totalShards = parser.intValue(); } else { diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index eb71960829e8c..c9b81a7b339db 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -281,7 +281,8 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", currentName); } } - return new SnapshotStats(startTime, time, incrementalFileCount, totalFileCount, processedFileCount, incrementalSize, totalSize, processedSize); + return new SnapshotStats(startTime, time, incrementalFileCount, totalFileCount, processedFileCount, incrementalSize, totalSize, + processedSize); } void add(SnapshotStats stats) { diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index 5ab1ab13f1134..eed356e90eaa0 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -254,16 +254,20 @@ public static SnapshotStatus fromXContent(XContentParser parser) throws IOExcept if (token == XContentParser.Token.FIELD_NAME) { String currentFieldName = parser.currentName(); if (SNAPSHOT.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); name = parser.text(); } else if (REPOSITORY.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); repository = parser.text(); } else if (UUID.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); uuid = parser.text(); } else if (STATE.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), + parser::getTokenLocation); String stateRaw = parser.text(); try { state = SnapshotsInProgress.State.valueOf(stateRaw); @@ -271,14 +275,16 @@ public static SnapshotStatus fromXContent(XContentParser parser) throws IOExcept throw new ElasticsearchParseException("failed to parse snapshot status, unknown state value [{}]", iae, stateRaw); } } else if (INCLUDE_GLOBAL_STATE.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_BOOLEAN, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_BOOLEAN, parser.nextToken(), + parser::getTokenLocation); includeGlobalState = parser.booleanValue(); } else if (SnapshotShardsStats.Fields.SHARDS_STATS.equals(currentFieldName)) { shardsStats = SnapshotShardsStats.fromXContent(parser); } else if (SnapshotStats.Fields.STATS.equals(currentFieldName)) { stats = SnapshotStats.fromXContent(parser); } else if (INDICES.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), + parser::getTokenLocation); while (parser.nextToken() != XContentParser.Token.END_OBJECT) { SnapshotIndexStatus indexStatus = SnapshotIndexStatus.fromXContent(parser); indices.put(indexStatus.getIndex(), indexStatus); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java index 8b6dbc6b16620..6a8cb301333bd 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java @@ -24,7 +24,6 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContentObject; -import org.elasticsearch.common.xcontent.XContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParserUtils; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java index b9cf795c270df..07a64c996eebb 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java @@ -1,3 +1,22 @@ +/* + * 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.cluster.snapshots.status; import java.io.IOException; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java index 96b322d03f8d2..41f0ee9dec32a 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java @@ -1,3 +1,22 @@ +/* + * 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.cluster.snapshots.status; import java.io.IOException; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java index 113b31cd051bb..c38dfbe41b9d4 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java @@ -1,3 +1,22 @@ +/* + * 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.cluster.snapshots.status; import java.io.IOException; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index 8a606f0183b45..a767c766e9418 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -1,3 +1,22 @@ +/* + * 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.cluster.snapshots.status; import java.io.IOException; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java index e4e537b57d814..88399c13d3fe4 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java @@ -26,7 +26,6 @@ import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; import org.elasticsearch.test.AbstractXContentTestCase; -import org.elasticsearch.test.ESTestCase; import java.io.IOException; import java.util.ArrayList; diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java index aad5884ac74da..295373d22ddef 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java @@ -1,3 +1,22 @@ +/* + * 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.cluster.snapshots.status; import java.io.IOException; From 2f054540241c553cc8152fc23fc4e5471b536dd0 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Thu, 21 Jun 2018 15:20:59 -0400 Subject: [PATCH 03/14] Remove todos --- .../admin/cluster/snapshots/status/SnapshotIndexShardStatus.java | 1 - .../admin/cluster/snapshots/status/SnapshotShardsStatsTests.java | 1 - .../admin/cluster/snapshots/status/SnapshotStatsTests.java | 1 - 3 files changed, 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index b44b6014bdc83..6350ef987ca7d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -167,7 +167,6 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - // Todo: Standards check public static SnapshotIndexShardStatus fromXContent(XContentParser parser, String indexId) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); String shardName = parser.currentName(); diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java index c38dfbe41b9d4..c159cf8b03d78 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java @@ -40,7 +40,6 @@ protected SnapshotShardsStats createTestInstance() { @Override protected SnapshotShardsStats doParseInstance(XContentParser parser) throws IOException { - // TODO: standards check XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); SnapshotShardsStats stats = SnapshotShardsStats.fromXContent(parser); diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index a767c766e9418..6de732060b5e7 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -43,7 +43,6 @@ protected SnapshotStats createTestInstance() { @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { - // TODO: standards check XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); SnapshotStats stats = SnapshotStats.fromXContent(parser); From c2a591df5810d59a5ef3d99e0818e7f48cf083b6 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Mon, 25 Jun 2018 11:58:19 -0400 Subject: [PATCH 04/14] Address reviewer comments. --- .../client/RequestConverters.java | 11 +++++-- .../org/elasticsearch/client/SnapshotIT.java | 31 ++++++++++--------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index 448d846b95461..c37b3f9fa884e 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -877,7 +877,7 @@ static Request snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest) { Params parameters = new Params(request); parameters.withMasterTimeout(snapshotsStatusRequest.masterNodeTimeout()); - parameters.putParam("ignore_unavailable", Boolean.toString(snapshotsStatusRequest.ignoreUnavailable())); + parameters.withIgnoreUnavailable(snapshotsStatusRequest.ignoreUnavailable()); return request; } @@ -1155,7 +1155,7 @@ Params withWaitForActiveShards(ActiveShardCount activeShardCount, ActiveShardCou } Params withIndicesOptions(IndicesOptions indicesOptions) { - putParam("ignore_unavailable", Boolean.toString(indicesOptions.ignoreUnavailable())); + withIgnoreUnavailable(indicesOptions.ignoreUnavailable()); putParam("allow_no_indices", Boolean.toString(indicesOptions.allowNoIndices())); String expandWildcards; if (indicesOptions.expandWildcardsOpen() == false && indicesOptions.expandWildcardsClosed() == false) { @@ -1174,6 +1174,13 @@ Params withIndicesOptions(IndicesOptions indicesOptions) { return this; } + Params withIgnoreUnavailable(boolean ignoreUnavailable) { + if (ignoreUnavailable) { + putParam("ignore_unavailable", Boolean.toString(ignoreUnavailable)); + } + return this; + } + Params withHuman(boolean human) { if (human) { putParam("human", Boolean.toString(human)); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java index ef82d7074bdd0..c9ebfc1e2e97f 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java @@ -55,12 +55,6 @@ private PutRepositoryResponse createTestRepository(String repository, String typ highLevelClient().snapshot()::createRepositoryAsync); } - private Response createTestSnapshot(String repository, String snapshot) throws IOException { - Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repository, snapshot)); - createSnapshot.addParameter("wait_for_completion", "true"); - return highLevelClient().getLowLevelClient().performRequest(createSnapshot); - } - private Response createTestSnapshot(String repository, String snapshot, String index) throws IOException { Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repository, snapshot)); createSnapshot.addParameter("wait_for_completion", "true"); @@ -132,33 +126,40 @@ public void testVerifyRepository() throws IOException { } public void testSnapshotsStatus() throws IOException { - PutRepositoryResponse putRepositoryResponse = createTestRepository("test", FsRepository.TYPE, "{\"location\": \".\"}"); + String testRepository = "test"; + String testSnapshot = "snapshot"; + String testIndex = "test_index"; + + PutRepositoryResponse putRepositoryResponse = createTestRepository(testRepository, FsRepository.TYPE, "{\"location\": \".\"}"); assertTrue(putRepositoryResponse.isAcknowledged()); - createIndex("test_index", Settings.EMPTY); + createIndex(testIndex, Settings.EMPTY); - Response snapshotResponse = createTestSnapshot("test", "snapshot", "test_index"); + Response snapshotResponse = createTestSnapshot(testRepository, testSnapshot, testIndex); assertEquals(2, snapshotResponse.getHttpResponse().getStatusLine().getStatusCode() / 100); SnapshotsStatusRequest request = new SnapshotsStatusRequest(); - request.repository("test"); - request.snapshots(new String[]{"snapshot"}); + request.repository(testRepository); + request.snapshots(new String[]{testSnapshot}); SnapshotsStatusResponse response = execute(request, highLevelClient().snapshot()::snapshotsStatus, highLevelClient().snapshot()::snapshotsStatusAsync); assertThat(response.getSnapshots().size(), equalTo(1)); - assertThat(response.getSnapshots().get(0).getSnapshot().getRepository(), equalTo("test")); - assertThat(response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo("snapshot")); - assertThat(response.getSnapshots().get(0).getIndices().containsKey("test_index"), is(true)); + assertThat(response.getSnapshots().get(0).getSnapshot().getRepository(), equalTo(testRepository)); + assertThat(response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo(testSnapshot)); + assertThat(response.getSnapshots().get(0).getIndices().containsKey(testIndex), is(true)); } public void testDeleteSnapshot() throws IOException { String repository = "test_repository"; String snapshot = "test_snapshot"; + String index = "test_index"; PutRepositoryResponse putRepositoryResponse = createTestRepository(repository, FsRepository.TYPE, "{\"location\": \".\"}"); assertTrue(putRepositoryResponse.isAcknowledged()); - Response putSnapshotResponse = createTestSnapshot(repository, snapshot); + createIndex(index, Settings.EMPTY); + + Response putSnapshotResponse = createTestSnapshot(repository, snapshot, index); // check that the request went ok without parsing JSON here. When using the high level client, check acknowledgement instead. assertEquals(200, putSnapshotResponse.getStatusLine().getStatusCode()); From 104b7230d89ef491346f443286a8c1fb3e01d3b7 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 13:15:11 -0400 Subject: [PATCH 05/14] Convert most of the parsing logic over to object parsers. --- .../status/SnapshotIndexShardStatus.java | 93 +++++++------ .../snapshots/status/SnapshotIndexStatus.java | 66 ++++----- .../snapshots/status/SnapshotShardsStats.java | 84 ++++-------- .../snapshots/status/SnapshotStats.java | 9 +- .../snapshots/status/SnapshotStatus.java | 126 ++++++++---------- .../status/SnapshotsStatusResponse.java | 37 +++-- .../snapshots/status/SnapshotStatsTests.java | 1 + 7 files changed, 187 insertions(+), 229 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index 6350ef987ca7d..10fc51c675392 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -22,8 +22,11 @@ import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.support.broadcast.BroadcastShardResponse; import org.elasticsearch.cluster.metadata.IndexMetaData; +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.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -34,6 +37,9 @@ import java.io.IOException; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg; + public class SnapshotIndexShardStatus extends BroadcastShardResponse implements ToXContentFragment { private SnapshotIndexShardStage stage = SnapshotIndexShardStage.INIT; @@ -167,57 +173,50 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public static SnapshotIndexShardStatus fromXContent(XContentParser parser, String indexId) throws IOException { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); - String shardName = parser.currentName(); - int shard; - try { - shard = Integer.parseInt(shardName); - } catch (NumberFormatException nfe) { - throw new ElasticsearchParseException( - "failed to parse snapshot index shard status [{}], expected numeric shard id but got [{}]", indexId, shardName); - } - ShardId shardId = new ShardId(new Index(indexId, IndexMetaData.INDEX_UUID_NA_VALUE), shard); - XContentParser.Token token = parser.nextToken(); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); - SnapshotIndexShardStage stage = null; - String nodeId = null; - String failure = null; - SnapshotStats stats = null; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token.equals(XContentParser.Token.FIELD_NAME)) { - String currentName = parser.currentName(); - if (currentName.equals(Fields.STAGE)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - try { - stage = SnapshotIndexShardStage.valueOf(parser.text()); - } catch (IllegalArgumentException iae) { - throw new ElasticsearchParseException( - "failed to parse snapshot index shard status [{}][{}], unknonwn stage [{}]", indexId, shardId.getId(), - parser.text()); - } - } else if (currentName.equals(Fields.NODE)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - nodeId = parser.text(); - } else if (currentName.equals(Fields.REASON)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - failure = parser.text(); - } else if (currentName.equals(SnapshotStats.Fields.STATS)) { - stats = SnapshotStats.fromXContent(parser); - } else { + static final ObjectParser.NamedObjectParser PARSER; + static { + ConstructingObjectParser innerParser = new ConstructingObjectParser<>( + "snapshot_index_shard_status", false, + (Object[] parsedObjects, ShardId shard) -> { + int i = 0; + String rawStage = (String) parsedObjects[i++]; + String nodeId = (String) parsedObjects[i++]; + String failure = (String) parsedObjects[i++]; + SnapshotStats stats = (SnapshotStats) parsedObjects[i]; + + SnapshotIndexShardStage stage; + try { + stage = SnapshotIndexShardStage.valueOf(rawStage); + } catch (IllegalArgumentException iae) { throw new ElasticsearchParseException( - "failed to parse snapshot index shard status [{}][{}], unknown field [{}]", indexId, shardId.getId(), - currentName); + "failed to parse snapshot index shard status [{}][{}], unknonwn stage [{}]", + shard.getIndex().getName(), shard.getId(), rawStage); } - } else { + return new SnapshotIndexShardStatus(shard, stage, stats, nodeId, failure); + } + ); + innerParser.declareString(constructorArg(), new ParseField(Fields.STAGE)); + innerParser.declareString(optionalConstructorArg(), new ParseField(Fields.NODE)); + innerParser.declareString(optionalConstructorArg(), new ParseField(Fields.REASON)); + innerParser.declareObject(constructorArg(), (p, c) -> SnapshotStats.fromXContent(p), new ParseField(SnapshotStats.Fields.STATS)); + PARSER = (p, indexId, shardName) -> { + // Combine the index name in the context with the shard name passed in for the named object parser + // into a ShardId to pass as context for the inner parser. + int shard; + try { + shard = Integer.parseInt(shardName); + } catch (NumberFormatException nfe) { throw new ElasticsearchParseException( - "failed to parse snapshot index shard status [{}][{}]", indexId, shardId.getId()); + "failed to parse snapshot index shard status [{}], expected numeric shard id but got [{}]", indexId, shardName); } - } - return new SnapshotIndexShardStatus(shardId, stage, stats, nodeId, failure); + ShardId shardId = new ShardId(new Index(indexId, IndexMetaData.INDEX_UUID_NA_VALUE), shard); + return innerParser.parse(p, shardId); + }; + } + + public static SnapshotIndexShardStatus fromXContent(XContentParser parser, String indexId) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); + return PARSER.parse(parser, indexId, parser.currentName()); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index b9dbaa18b9783..7b03dfc74b565 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -19,7 +19,9 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -29,9 +31,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; +import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; /** * Represents snapshot status of all shards in the index @@ -118,37 +123,38 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public static SnapshotIndexStatus fromXContent(XContentParser parser) throws IOException { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); - String indexName = parser.currentName(); - XContentParser.Token token = parser.nextToken(); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); - SnapshotShardsStats shardsStats = null; - SnapshotStats stats = null; - Map shards = new HashMap<>(); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token.equals(XContentParser.Token.FIELD_NAME)) { - String currentName = parser.currentName(); - if (currentName.equals(SnapshotShardsStats.Fields.SHARDS_STATS)) { - shardsStats = SnapshotShardsStats.fromXContent(parser); - } else if (currentName.equals(SnapshotStats.Fields.STATS)) { - stats = SnapshotStats.fromXContent(parser); - } else if (currentName.equals(Fields.SHARDS)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), - parser::getTokenLocation); - while (parser.nextToken() != XContentParser.Token.END_OBJECT) { - SnapshotIndexShardStatus shardStatus = SnapshotIndexShardStatus.fromXContent(parser, indexName); - shards.put(shardStatus.getShardId().getId(), shardStatus); - } + static final ObjectParser.NamedObjectParser PARSER; + static { + ConstructingObjectParser innerParser = new ConstructingObjectParser<>( + "snapshot_index_status", false, + (Object[] parsedObjects, String index) -> { + int i = 0; + SnapshotShardsStats shardsStats = ((SnapshotShardsStats) parsedObjects[i++]); + SnapshotStats stats = ((SnapshotStats) parsedObjects[i++]); + @SuppressWarnings("unchecked") List shardStatuses = (List) parsedObjects[i]; + + final Map indexShards; + if (shardStatuses == null || shardStatuses.isEmpty()) { + indexShards = emptyMap(); } else { - throw new ElasticsearchParseException("failed to parse snapshot index status [{}], unknown field [{}]", indexName, - currentName); + indexShards = new HashMap<>(shardStatuses.size()); + for (SnapshotIndexShardStatus shardStatus : shardStatuses) { + indexShards.put(shardStatus.getShardId().getId(), shardStatus); + } } - } else { - throw new ElasticsearchParseException("failed to parse snapshot index status [{}]", indexName); - } - } - return new SnapshotIndexStatus(indexName, shards, shardsStats, stats); + return new SnapshotIndexStatus(index, indexShards, shardsStats, stats); + }); + innerParser.declareObject(constructorArg(), (p, c) -> SnapshotShardsStats.PARSER.apply(p, null), + new ParseField(SnapshotShardsStats.Fields.SHARDS_STATS)); + innerParser.declareObject(constructorArg(), (p, c) -> SnapshotStats.fromXContent(p), + new ParseField(SnapshotStats.Fields.STATS)); + innerParser.declareNamedObjects(constructorArg(), SnapshotIndexShardStatus.PARSER, new ParseField(Fields.SHARDS)); + PARSER = ((p, c, name) -> innerParser.apply(p, name)); + } + + public static SnapshotIndexStatus fromXContent(XContentParser parser) throws IOException { + XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.currentToken(), parser::getTokenLocation); + return PARSER.parse(parser, null, parser.currentName()); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java index a0093511974d3..dea058a45db20 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java @@ -19,16 +19,18 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; import java.util.Collection; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * Status of a snapshot shards */ @@ -141,62 +143,30 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par return builder; } - public static SnapshotShardsStats fromXContent(XContentParser parser) throws IOException { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - XContentParser.Token token; - int initializingShards = 0; - int startedShards = 0; - int finalizingShards = 0; - int doneShards = 0; - int failedShards = 0; - int totalShards = 0; - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - String currentName = parser.currentName(); - if (currentName.equals(Fields.INITIALIZING)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - initializingShards = parser.intValue(); - } else if (currentName.equals(Fields.STARTED)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - startedShards = parser.intValue(); - } else if (currentName.equals(Fields.FINALIZING)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - finalizingShards = parser.intValue(); - } else if (currentName.equals(Fields.DONE)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - doneShards = parser.intValue(); - } else if (currentName.equals(Fields.FAILED)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - failedShards = parser.intValue(); - } else if (currentName.equals(Fields.TOTAL)) { - if (parser.nextToken() != XContentParser.Token.VALUE_NUMBER) { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, expected number for field [{}]", - currentName); - } - totalShards = parser.intValue(); - } else { - throw new ElasticsearchParseException("failed to parse snapshot shards stats, unexpected field [{}]", currentName); - } - } else { - throw new ElasticsearchParseException("failed to parse snapshot shards stats"); - } + static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + Fields.SHARDS_STATS, + (Object[] parsedObjects) -> { + int i = 0; + int initializingShards = (int) parsedObjects[i++]; + int startedShards = (int) parsedObjects[i++]; + int finalizingShards = (int) parsedObjects[i++]; + int doneShards = (int) parsedObjects[i++]; + int failedShards = (int) parsedObjects[i++]; + int totalShards = (int) parsedObjects[i]; + return new SnapshotShardsStats(initializingShards, startedShards, finalizingShards, doneShards, failedShards, totalShards); } - return new SnapshotShardsStats(initializingShards, startedShards, finalizingShards, doneShards, failedShards, totalShards); + ); + static { + PARSER.declareInt(constructorArg(), new ParseField(Fields.INITIALIZING)); + PARSER.declareInt(constructorArg(), new ParseField(Fields.STARTED)); + PARSER.declareInt(constructorArg(), new ParseField(Fields.FINALIZING)); + PARSER.declareInt(constructorArg(), new ParseField(Fields.DONE)); + PARSER.declareInt(constructorArg(), new ParseField(Fields.FAILED)); + PARSER.declareInt(constructorArg(), new ParseField(Fields.TOTAL)); + } + + public static SnapshotShardsStats fromXContent(XContentParser parser) throws IOException { + return PARSER.apply(parser, null); } @Override diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index c9b81a7b339db..839edecf50fee 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -209,8 +209,13 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par } public static SnapshotStats fromXContent(XContentParser parser) throws IOException { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - XContentParser.Token token; + // Parse this old school style instead of using the ObjectParser since there's an impedance mismatch between how the + // object has historically been written as JSON versus how it is structured in Java. + XContentParser.Token token = parser.currentToken(); + if (token == null) { + token = parser.nextToken(); + } + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); long startTime = 0; long time = 0; int incrementalFileCount = 0; diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index eed356e90eaa0..3b8ee11aa6305 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -23,15 +23,17 @@ import org.elasticsearch.Version; import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.cluster.SnapshotsInProgress.State; +import org.elasticsearch.common.ParseField; import org.elasticsearch.common.Strings; import org.elasticsearch.common.Nullable; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Streamable; +import org.elasticsearch.common.xcontent.ConstructingObjectParser; +import org.elasticsearch.common.xcontent.ObjectParser; import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; @@ -45,7 +47,11 @@ import java.util.Objects; import java.util.Set; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static java.util.Collections.unmodifiableMap; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.optionalConstructorArg; /** * Status of a snapshot @@ -235,79 +241,55 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public static SnapshotStatus fromXContent(XContentParser parser) throws IOException { - XContentParser.Token token = parser.currentToken(); - if (token == null) { - token = parser.nextToken(); - } - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation); - String name = null; - String repository = null; - String uuid = null; - SnapshotsInProgress.State state = null; - Boolean includeGlobalState = null; - SnapshotShardsStats shardsStats = null; - SnapshotStats stats = null; - List shards = new ArrayList<>(); - Map indices = new HashMap<>(); - while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { - if (token == XContentParser.Token.FIELD_NAME) { - String currentFieldName = parser.currentName(); - if (SNAPSHOT.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - name = parser.text(); - } else if (REPOSITORY.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - repository = parser.text(); - } else if (UUID.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - uuid = parser.text(); - } else if (STATE.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_STRING, parser.nextToken(), - parser::getTokenLocation); - String stateRaw = parser.text(); - try { - state = SnapshotsInProgress.State.valueOf(stateRaw); - } catch (IllegalArgumentException iae) { - throw new ElasticsearchParseException("failed to parse snapshot status, unknown state value [{}]", iae, stateRaw); - } - } else if (INCLUDE_GLOBAL_STATE.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_BOOLEAN, parser.nextToken(), - parser::getTokenLocation); - includeGlobalState = parser.booleanValue(); - } else if (SnapshotShardsStats.Fields.SHARDS_STATS.equals(currentFieldName)) { - shardsStats = SnapshotShardsStats.fromXContent(parser); - } else if (SnapshotStats.Fields.STATS.equals(currentFieldName)) { - stats = SnapshotStats.fromXContent(parser); - } else if (INDICES.equals(currentFieldName)) { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), - parser::getTokenLocation); - while (parser.nextToken() != XContentParser.Token.END_OBJECT) { - SnapshotIndexStatus indexStatus = SnapshotIndexStatus.fromXContent(parser); - indices.put(indexStatus.getIndex(), indexStatus); - shards.addAll(indexStatus.getShards().values()); - } - } else { - throw new ElasticsearchParseException("failed to parse snapshot status, unknown field [{}]", currentFieldName); - } + static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "snapshot_status", + (Object[] parsedObjects) -> { + int i = 0; + String name = (String) parsedObjects[i++]; + String repository = (String) parsedObjects[i++]; + String uuid = (String) parsedObjects[i++]; + String rawState = (String) parsedObjects[i++]; + Boolean includeGlobalState = (Boolean) parsedObjects[i++]; + SnapshotStats stats = ((SnapshotStats) parsedObjects[i++]); + SnapshotShardsStats shardsStats = ((SnapshotShardsStats) parsedObjects[i++]); + @SuppressWarnings("unchecked") List indices = ((List) parsedObjects[i]); + + Snapshot snapshot = new Snapshot(repository, new SnapshotId(name, uuid)); + SnapshotsInProgress.State state; + try { + state = SnapshotsInProgress.State.valueOf(rawState); + } catch (IllegalArgumentException iae) { + throw new ElasticsearchParseException("failed to parse snapshot status, unknown state value [{}]", iae, rawState); + } + Map indicesStatus; + List shards; + if (indices == null || indices.isEmpty()) { + indicesStatus = emptyMap(); + shards = emptyList(); } else { - throw new ElasticsearchParseException("failed to parse snapshot status"); + indicesStatus = new HashMap<>(indices.size()); + shards = new ArrayList<>(); + for (SnapshotIndexStatus index : indices) { + indicesStatus.put(index.getIndex(), index); + shards.addAll(index.getShards().values()); + } } - } - if (name == null) { - throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot name"); - } else if (uuid == null) { - throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot uuid"); - } else if (repository == null) { - throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot repository"); - } else if (state == null) { - throw new ElasticsearchParseException("failed to parse snapshot status, missing snapshot state"); - } - Snapshot snapshot = new Snapshot(repository, new SnapshotId(name, uuid)); - return new SnapshotStatus(snapshot, state, shards, indices, shardsStats, stats, includeGlobalState); + return new SnapshotStatus(snapshot, state, shards, indicesStatus, shardsStats, stats, includeGlobalState); + }); + static { + PARSER.declareString(constructorArg(), new ParseField(SNAPSHOT)); + PARSER.declareString(constructorArg(), new ParseField(REPOSITORY)); + PARSER.declareString(constructorArg(), new ParseField(UUID)); + PARSER.declareString(constructorArg(), new ParseField(STATE)); + PARSER.declareBoolean(optionalConstructorArg(), new ParseField(INCLUDE_GLOBAL_STATE)); + PARSER.declareField(constructorArg(), SnapshotStats::fromXContent, new ParseField(SnapshotStats.Fields.STATS), + ObjectParser.ValueType.OBJECT); + PARSER.declareObject(constructorArg(), SnapshotShardsStats.PARSER, new ParseField(SnapshotShardsStats.Fields.SHARDS_STATS)); + PARSER.declareNamedObjects(constructorArg(), SnapshotIndexStatus.PARSER, new ParseField(INDICES)); + } + + public static SnapshotStatus fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); } private void updateShardStats() { diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java index 6a8cb301333bd..8e989a646834d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java @@ -19,20 +19,22 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.action.ActionResponse; +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.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import static org.elasticsearch.common.xcontent.ConstructingObjectParser.constructorArg; + /** * Snapshot status response */ @@ -88,26 +90,19 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - public static SnapshotsStatusResponse fromXContent(XContentParser parser) throws IOException { - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - List statuses = new ArrayList<>(); - XContentParser.Token token = parser.nextToken(); - if (token == XContentParser.Token.FIELD_NAME) { - String snapshotField = parser.currentName(); - if (snapshotField.equals("snapshots")) { - token = parser.nextToken(); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, token, parser::getTokenLocation); - while (parser.nextToken() != XContentParser.Token.END_ARRAY) { - statuses.add(SnapshotStatus.fromXContent(parser)); - } - } else { - throw new ElasticsearchParseException("failed to parse snapshots status, unknown field [{}]", snapshotField); - } - } else { - throw new ElasticsearchParseException("failed to parse snapshots status"); + static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "snapshots_status_response", + (Object[] parsedObjects) -> { + @SuppressWarnings("unchecked") List snapshots = (List) parsedObjects[0]; + return new SnapshotsStatusResponse(snapshots); } - XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); - return new SnapshotsStatusResponse(statuses); + ); + static { + PARSER.declareObjectArray(constructorArg(), SnapshotStatus.PARSER, new ParseField("snapshots")); + } + + public static SnapshotsStatusResponse fromXContent(XContentParser parser) throws IOException { + return PARSER.parse(parser, null); } @Override diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index 6de732060b5e7..c652106365fd3 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -45,6 +45,7 @@ protected SnapshotStats createTestInstance() { protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); + XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); SnapshotStats stats = SnapshotStats.fromXContent(parser); XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); return stats; From 1a85d5bf7df1bb07c39f7947b45d2ff09ad8c58e Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 13:21:59 -0400 Subject: [PATCH 06/14] Fix test, address reviewer comments. --- .../org/elasticsearch/client/RequestConvertersTests.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index 9946eb2559ac1..b670cb1b4dfd9 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -167,6 +167,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.Matchers.hasEntry; import static org.hamcrest.Matchers.hasKey; +import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; @@ -1958,12 +1959,15 @@ public void testSnapshotsStatus() { SnapshotsStatusRequest snapshotsStatusRequest = new SnapshotsStatusRequest(repository, snapshots); setRandomMasterTimeout(snapshotsStatusRequest, expectedParams); snapshotsStatusRequest.ignoreUnavailable(ignoreUnavailable); - expectedParams.put("ignore_unavailable", Boolean.toString(ignoreUnavailable)); + if (ignoreUnavailable) { + expectedParams.put("ignore_unavailable", Boolean.toString(true)); + } Request request = RequestConverters.snapshotsStatus(snapshotsStatusRequest); assertThat(request.getEndpoint(), equalTo(endpoint)); assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME)); assertThat(request.getParameters(), equalTo(expectedParams)); + assertThat(request.getEntity(), is(nullValue())); } public void testDeleteSnapshot() { From a58e5923fc74d79f1c8ef7d50fa95009b1fa1c6d Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 14:05:00 -0400 Subject: [PATCH 07/14] Change parsers to be lenient on unknown fields. --- .../status/SnapshotIndexShardStatus.java | 2 +- .../snapshots/status/SnapshotIndexStatus.java | 2 +- .../snapshots/status/SnapshotShardsStats.java | 2 +- .../snapshots/status/SnapshotStats.java | 20 +++++++++++++++---- .../snapshots/status/SnapshotStatus.java | 2 +- .../status/SnapshotsStatusResponse.java | 4 ++-- .../status/SnapshotIndexShardStatusTests.java | 9 ++++++++- .../status/SnapshotIndexStatusTests.java | 9 ++++++++- .../status/SnapshotShardsStatsTests.java | 18 +++++++++++++---- .../snapshots/status/SnapshotStatsTests.java | 20 ++++++++++++++----- .../snapshots/status/SnapshotStatusTests.java | 9 ++++++++- .../status/SnapshotsStatusResponseTests.java | 9 ++++++++- 12 files changed, 83 insertions(+), 23 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index 10fc51c675392..9ec326162180d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -176,7 +176,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws static final ObjectParser.NamedObjectParser PARSER; static { ConstructingObjectParser innerParser = new ConstructingObjectParser<>( - "snapshot_index_shard_status", false, + "snapshot_index_shard_status", true, (Object[] parsedObjects, ShardId shard) -> { int i = 0; String rawStage = (String) parsedObjects[i++]; diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index 7b03dfc74b565..d52b5f4befb0c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -126,7 +126,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws static final ObjectParser.NamedObjectParser PARSER; static { ConstructingObjectParser innerParser = new ConstructingObjectParser<>( - "snapshot_index_status", false, + "snapshot_index_status", true, (Object[] parsedObjects, String index) -> { int i = 0; SnapshotShardsStats shardsStats = ((SnapshotShardsStats) parsedObjects[i++]); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java index dea058a45db20..55ba776211268 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java @@ -144,7 +144,7 @@ public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params par } static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( - Fields.SHARDS_STATS, + Fields.SHARDS_STATS, true, (Object[] parsedObjects) -> { int i = 0; int initializingShards = (int) parsedObjects[i++]; diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index 839edecf50fee..781b6bb33ad6f 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -241,7 +241,10 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); incrementalSize = parser.longValue(); } else { - throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } } } } else if (currentName.equals(Fields.PROCESSED)) { @@ -257,7 +260,10 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); processedSize = parser.longValue(); } else { - throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } } } } else if (currentName.equals(Fields.TOTAL)) { @@ -273,7 +279,10 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); totalSize = parser.longValue(); } else { - throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", innerName); + // Unknown sub field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } } } } else if (currentName.equals(Fields.START_TIME_IN_MILLIS)) { @@ -283,7 +292,10 @@ public static SnapshotStats fromXContent(XContentParser parser) throws IOExcepti XContentParserUtils.ensureExpectedToken(XContentParser.Token.VALUE_NUMBER, token, parser::getTokenLocation); time = parser.longValue(); } else { - throw new ElasticsearchParseException("failed to parse snapshot stats, unknown field [{}]", currentName); + // Unknown field, skip + if (token == XContentParser.Token.START_OBJECT || token == XContentParser.Token.START_ARRAY) { + parser.skipChildren(); + } } } return new SnapshotStats(startTime, time, incrementalFileCount, totalFileCount, processedFileCount, incrementalSize, totalSize, diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index 3b8ee11aa6305..26139b068a15c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -242,7 +242,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws } static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( - "snapshot_status", + "snapshot_status", true, (Object[] parsedObjects) -> { int i = 0; String name = (String) parsedObjects[i++]; diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java index 8e989a646834d..ef1435e41080c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponse.java @@ -90,8 +90,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws return builder; } - static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( - "snapshots_status_response", + private static final ConstructingObjectParser PARSER = new ConstructingObjectParser<>( + "snapshots_status_response", true, (Object[] parsedObjects) -> { @SuppressWarnings("unchecked") List snapshots = (List) parsedObjects[0]; return new SnapshotsStatusResponse(snapshots); diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java index 07a64c996eebb..490319ef84074 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatusTests.java @@ -20,6 +20,7 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; import java.io.IOException; +import java.util.function.Predicate; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.xcontent.XContentParser; @@ -47,6 +48,12 @@ protected SnapshotIndexShardStatus createForIndex(String indexName) { return new SnapshotIndexShardStatus(shardId, stage, stats, nodeId, failure); } + @Override + protected Predicate getRandomFieldsExcludeFilter() { + // Do not place random fields in the root object since its fields correspond to shard names. + return String::isEmpty; + } + @Override protected SnapshotIndexShardStatus doParseInstance(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); @@ -58,6 +65,6 @@ protected SnapshotIndexShardStatus doParseInstance(XContentParser parser) throws @Override protected boolean supportsUnknownFields() { - return false; + return true; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java index 41f0ee9dec32a..92eb355f3a621 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatusTests.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParserUtils; @@ -41,6 +42,12 @@ protected SnapshotIndexStatus createTestInstance() { return new SnapshotIndexStatus(index, shardStatuses); } + @Override + protected Predicate getRandomFieldsExcludeFilter() { + // Do not place random fields in the root object or the shards field since their fields correspond to names. + return (s) -> s.isEmpty() || s.endsWith("shards"); + } + @Override protected SnapshotIndexStatus doParseInstance(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); @@ -52,6 +59,6 @@ protected SnapshotIndexStatus doParseInstance(XContentParser parser) throws IOEx @Override protected boolean supportsUnknownFields() { - return false; + return true; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java index c159cf8b03d78..245bf4ab09d3d 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java @@ -21,6 +21,7 @@ import java.io.IOException; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.test.AbstractXContentTestCase; @@ -40,15 +41,24 @@ protected SnapshotShardsStats createTestInstance() { @Override protected SnapshotShardsStats doParseInstance(XContentParser parser) throws IOException { + // SnapshotShardsStats serializes its own name, and thus, is nested in another object in this test. XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); - SnapshotShardsStats stats = SnapshotShardsStats.fromXContent(parser); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + SnapshotShardsStats stats = null; + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + if (parser.currentName().equals(SnapshotShardsStats.Fields.SHARDS_STATS)) { + stats = SnapshotShardsStats.fromXContent(parser); + } else { + parser.skipChildren(); + } + } + if (stats == null) { + throw new ElasticsearchParseException("could not find stats"); + } return stats; } @Override protected boolean supportsUnknownFields() { - return false; + return true; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index c652106365fd3..b7ee713f1f44d 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -21,6 +21,7 @@ import java.io.IOException; +import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.test.AbstractXContentTestCase; @@ -43,16 +44,25 @@ protected SnapshotStats createTestInstance() { @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { + // SnapshotStats serializes its own name, and thus, is nested in another object in this test. XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.FIELD_NAME, parser.nextToken(), parser::getTokenLocation); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - SnapshotStats stats = SnapshotStats.fromXContent(parser); - XContentParserUtils.ensureExpectedToken(XContentParser.Token.END_OBJECT, parser.nextToken(), parser::getTokenLocation); + SnapshotStats stats = null; + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + if (parser.currentName().equals(SnapshotStats.Fields.STATS)) { + parser.nextToken(); // Advance to START_OBJECT + stats = SnapshotStats.fromXContent(parser); + } else { + parser.skipChildren(); + } + } + if (stats == null) { + throw new ElasticsearchParseException("could not find stats"); + } return stats; } @Override protected boolean supportsUnknownFields() { - return false; + return true; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java index 88399c13d3fe4..dbd45640c7b69 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatusTests.java @@ -30,6 +30,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; public class SnapshotStatusTests extends AbstractXContentTestCase { @@ -168,6 +169,12 @@ protected SnapshotStatus createTestInstance() { return new SnapshotStatus(snapshot, state, snapshotIndexShardStatuses, includeGlobalState); } + @Override + protected Predicate getRandomFieldsExcludeFilter() { + // Do not place random fields in the indices field or shards field since their fields correspond to names. + return (s) -> s.endsWith("shards") || s.endsWith("indices"); + } + @Override protected SnapshotStatus doParseInstance(XContentParser parser) throws IOException { return SnapshotStatus.fromXContent(parser); @@ -175,6 +182,6 @@ protected SnapshotStatus doParseInstance(XContentParser parser) throws IOExcepti @Override protected boolean supportsUnknownFields() { - return false; + return true; } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java index 295373d22ddef..d1ad028296ddb 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotsStatusResponseTests.java @@ -22,6 +22,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.AbstractXContentTestCase; @@ -33,9 +34,15 @@ protected SnapshotsStatusResponse doParseInstance(XContentParser parser) throws return SnapshotsStatusResponse.fromXContent(parser); } + @Override + protected Predicate getRandomFieldsExcludeFilter() { + // Do not place random fields in the indices field or shards field since their fields correspond to names. + return (s) -> s.endsWith("shards") || s.endsWith("indices"); + } + @Override protected boolean supportsUnknownFields() { - return false; + return true; } @Override From b89f8ca5ccb9a1f8ce51dc3b98581309f81af955 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 14:07:12 -0400 Subject: [PATCH 08/14] Fix a line length issue that IDEA hid from me... --- .../admin/cluster/snapshots/status/SnapshotIndexStatus.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index d52b5f4befb0c..db7d26e078bfa 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -131,7 +131,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws int i = 0; SnapshotShardsStats shardsStats = ((SnapshotShardsStats) parsedObjects[i++]); SnapshotStats stats = ((SnapshotStats) parsedObjects[i++]); - @SuppressWarnings("unchecked") List shardStatuses = (List) parsedObjects[i]; + @SuppressWarnings("unchecked") List shardStatuses = + (List) parsedObjects[i]; final Map indexShards; if (shardStatuses == null || shardStatuses.isEmpty()) { From f0615998563cb3a1bc6349c846a2a5265527949c Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 14:27:00 -0400 Subject: [PATCH 09/14] Unused import --- .../action/admin/cluster/snapshots/status/SnapshotStats.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index 781b6bb33ad6f..a33cee8dae1a7 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -19,7 +19,6 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; From 9024aad1b54955a8055c8942394ea970ffdef794 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Tue, 26 Jun 2018 15:41:41 -0400 Subject: [PATCH 10/14] Always explicitly set ignore_unavailable. --- .../java/org/elasticsearch/client/RequestConverters.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java index c37b3f9fa884e..d02afcfe49c91 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java @@ -1175,9 +1175,8 @@ Params withIndicesOptions(IndicesOptions indicesOptions) { } Params withIgnoreUnavailable(boolean ignoreUnavailable) { - if (ignoreUnavailable) { - putParam("ignore_unavailable", Boolean.toString(ignoreUnavailable)); - } + // Always explicitly place the ignore_unavailable value. + putParam("ignore_unavailable", Boolean.toString(ignoreUnavailable)); return this; } From d9d35a67e43f97adb5a3811c0749558835f76bda Mon Sep 17 00:00:00 2001 From: James Baiera Date: Fri, 29 Jun 2018 13:27:06 -0400 Subject: [PATCH 11/14] Address reviewer comments. Convert the stats objects to objects instead of fragments. Simplify unit tests. Add more response uses to the documentation Rename api method to 'status' --- .../elasticsearch/client/SnapshotClient.java | 12 ++-- .../org/elasticsearch/client/SnapshotIT.java | 8 +-- .../SnapshotClientDocumentationIT.java | 20 ++++++- .../snapshot/snapshots_status.asciidoc | 15 +++-- .../status/SnapshotIndexShardStatus.java | 2 +- .../snapshots/status/SnapshotIndexStatus.java | 4 +- .../snapshots/status/SnapshotShardsStats.java | 20 ++++--- .../snapshots/status/SnapshotStats.java | 57 ++++++++++--------- .../snapshots/status/SnapshotStatus.java | 11 +--- .../status/SnapshotShardsStatsTests.java | 17 +----- .../snapshots/status/SnapshotStatsTests.java | 18 +----- 11 files changed, 84 insertions(+), 100 deletions(-) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java index aa9eb0c991d79..158f84f32c73f 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java @@ -167,8 +167,7 @@ public void verifyRepositoryAsync(VerifyRepositoryRequest verifyRepositoryReques } /** - * Gets the status of any snapshots currently in progress. If snapshot names are provided, this will return detailed status information - * for them even if they are not currently running. + * Gets the status of requested snapshots. * See Snapshot and Restore * API on elastic.co * @param snapshotsStatusRequest the request @@ -176,23 +175,22 @@ public void verifyRepositoryAsync(VerifyRepositoryRequest verifyRepositoryReques * @return the response * @throws IOException in case there is a problem sending the request or parsing back the response */ - public SnapshotsStatusResponse snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options) + public SnapshotsStatusResponse status(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options) throws IOException { return restHighLevelClient.performRequestAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options, SnapshotsStatusResponse::fromXContent, emptySet()); } /** - * Asynchronously gets the status of any snapshots currently in progress. If snapshot names are provided, this will return detailed - * status information for them even if they are not currently running. + * Asynchronously gets the status of requested snapshots. * See Snapshot and Restore * API on elastic.co * @param snapshotsStatusRequest the request * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized * @param listener the listener to be notified upon request completion */ - public void snapshotsStatusAsync(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options, - ActionListener listener) { + public void statusAsync(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options, + ActionListener listener) { restHighLevelClient.performRequestAsyncAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options, SnapshotsStatusResponse::fromXContent, listener, emptySet()); } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java index c9ebfc1e2e97f..046739af00055 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java @@ -19,8 +19,6 @@ package org.elasticsearch.client; -import org.apache.http.entity.ContentType; -import org.apache.http.nio.entity.NStringEntity; import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest; import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryResponse; @@ -58,7 +56,7 @@ private PutRepositoryResponse createTestRepository(String repository, String typ private Response createTestSnapshot(String repository, String snapshot, String index) throws IOException { Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repository, snapshot)); createSnapshot.addParameter("wait_for_completion", "true"); - createSnapshot.setEntity(new NStringEntity("{\"indices\":\""+index+"\"}", ContentType.APPLICATION_JSON)); + createSnapshot.setJsonEntity("{\"indices\":\""+index+"\"}"); return highLevelClient().getLowLevelClient().performRequest(createSnapshot); } @@ -141,8 +139,8 @@ public void testSnapshotsStatus() throws IOException { SnapshotsStatusRequest request = new SnapshotsStatusRequest(); request.repository(testRepository); request.snapshots(new String[]{testSnapshot}); - SnapshotsStatusResponse response = execute(request, highLevelClient().snapshot()::snapshotsStatus, - highLevelClient().snapshot()::snapshotsStatusAsync); + SnapshotsStatusResponse response = execute(request, highLevelClient().snapshot()::status, + highLevelClient().snapshot()::statusAsync); assertThat(response.getSnapshots().size(), equalTo(1)); assertThat(response.getSnapshots().get(0).getSnapshot().getRepository(), equalTo(testRepository)); assertThat(response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo(testSnapshot)); diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java index 8cee53c34c6de..760e68ad5112c 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java @@ -31,6 +31,7 @@ import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse; +import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStats; import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus; import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest; import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse; @@ -39,6 +40,7 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.cluster.metadata.RepositoryMetaData; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; @@ -77,6 +79,7 @@ public class SnapshotClientDocumentationIT extends ESRestHighLevelClientTestCase private static final String repositoryName = "test_repository"; private static final String snapshotName = "test_snapshot"; + private static final String indexName = "test_index"; public void testSnapshotCreateRepository() throws IOException { RestHighLevelClient client = highLevelClient(); @@ -372,6 +375,7 @@ public void onFailure(Exception e) { public void testSnapshotSnapshotsStatus() throws IOException { RestHighLevelClient client = highLevelClient(); createTestRepositories(); + createTestIndex(); createTestSnapshots(); // tag::snapshots-status-request @@ -394,15 +398,19 @@ public void testSnapshotSnapshotsStatus() throws IOException { // end::snapshots-status-request-masterTimeout // tag::snapshots-status-execute - SnapshotsStatusResponse response = client.snapshot().snapshotsStatus(request, RequestOptions.DEFAULT); + SnapshotsStatusResponse response = client.snapshot().status(request, RequestOptions.DEFAULT); // end::snapshots-status-execute // tag::snapshots-status-response List snapshotStatusesResponse = response.getSnapshots(); + SnapshotStatus snapshotStatus = snapshotStatusesResponse.get(0); // <1> + SnapshotsInProgress.State snapshotState = snapshotStatus.getState(); // <2> + SnapshotStats shardStats = snapshotStatus.getIndices().get(indexName).getShards().get(0).getStats(); // <3> // end::snapshots-status-response assertThat(snapshotStatusesResponse.size(), equalTo(1)); - assertThat(snapshotStatusesResponse.get(0).getSnapshot().getRepository(), equalTo(repositoryName)); + assertThat(snapshotStatusesResponse.get(0).getSnapshot().getRepository(), equalTo(SnapshotClientDocumentationIT.repositoryName)); assertThat(snapshotStatusesResponse.get(0).getSnapshot().getSnapshotId().getName(), equalTo(snapshotName)); + assertThat(snapshotState.completed(), equalTo(true)); } public void testSnapshotSnapshotsStatusAsync() throws InterruptedException { @@ -430,7 +438,7 @@ public void onFailure(Exception e) { listener = new LatchedActionListener<>(listener, latch); // tag::snapshots-status-execute-async - client.snapshot().snapshotsStatusAsync(request, RequestOptions.DEFAULT, listener); // <1> + client.snapshot().statusAsync(request, RequestOptions.DEFAULT, listener); // <1> // end::snapshots-status-execute-async assertTrue(latch.await(30L, TimeUnit.SECONDS)); @@ -441,6 +449,7 @@ public void testSnapshotDeleteSnapshot() throws IOException { RestHighLevelClient client = highLevelClient(); createTestRepositories(); + createTestIndex(); createTestSnapshots(); // tag::delete-snapshot-request @@ -502,9 +511,14 @@ private void createTestRepositories() throws IOException { assertTrue(highLevelClient().snapshot().createRepository(request, RequestOptions.DEFAULT).isAcknowledged()); } + private void createTestIndex() throws IOException { + createIndex(indexName, Settings.EMPTY); + } + private void createTestSnapshots() throws IOException { Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repositoryName, snapshotName)); createSnapshot.addParameter("wait_for_completion", "true"); + createSnapshot.setJsonEntity("{\"indices\":\"" + indexName + "\"}"); Response response = highLevelClient().getLowLevelClient().performRequest(createSnapshot); // check that the request went ok without parsing JSON here. When using the high level client, check acknowledgement instead. assertEquals(200, response.getStatusLine().getStatusCode()); diff --git a/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc b/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc index bd13416891e31..8f91d774f4e19 100644 --- a/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc +++ b/docs/java-rest/high-level/snapshot/snapshots_status.asciidoc @@ -13,21 +13,23 @@ A `SnapshotsStatusRequest`: include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request] -------------------------------------------------- -==== Optional Arguments -The following arguments can optionally be provided: +==== Required Arguments +The following arguments must be provided: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-repository] -------------------------------------------------- -<1> Sets the repository to check for snapshot statuses currently in progress +<1> Sets the repository to check for snapshot statuses ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-request-snapshots] -------------------------------------------------- -<1> The list of snapshot names to check the status of. If this is set, the status for the snapshots -is returned, even if they are not currently in progress +<1> The list of snapshot names to check the status of + +==== Optional Arguments +The following arguments can optionally be provided: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- @@ -90,3 +92,6 @@ executed operation as follows: -------------------------------------------------- include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[snapshots-status-response] -------------------------------------------------- +<1> Request contains a list of snapshot statuses +<2> Each status contains information about the snapshot +<3> Example of reading snapshot statistics about a specific index and shard diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java index 9ec326162180d..834e238e4a0d3 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexShardStatus.java @@ -162,7 +162,7 @@ static final class Fields { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(Integer.toString(getShardId().getId())); builder.field(Fields.STAGE, getStage()); - stats.toXContent(builder, params); + builder.field(SnapshotStats.Fields.STATS, stats, params); if (getNodeId() != null) { builder.field(Fields.NODE, getNodeId()); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java index db7d26e078bfa..ba85849598060 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotIndexStatus.java @@ -112,8 +112,8 @@ static final class Fields { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { builder.startObject(getIndex()); - shardsStats.toXContent(builder, params); - stats.toXContent(builder, params); + builder.field(SnapshotShardsStats.Fields.SHARDS_STATS, shardsStats, params); + builder.field(SnapshotStats.Fields.STATS, stats, params); builder.startObject(Fields.SHARDS); for (SnapshotIndexShardStatus shard : indexShards.values()) { shard.toXContent(builder, params); diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java index 55ba776211268..c0ac432292ddc 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStats.java @@ -22,7 +22,7 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -34,7 +34,7 @@ /** * Status of a snapshot shards */ -public class SnapshotShardsStats implements ToXContentFragment { +public class SnapshotShardsStats implements ToXContentObject { private int initializingShards; private int startedShards; @@ -132,13 +132,15 @@ static final class Fields { @Override public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { - builder.startObject(Fields.SHARDS_STATS); - builder.field(Fields.INITIALIZING, getInitializingShards()); - builder.field(Fields.STARTED, getStartedShards()); - builder.field(Fields.FINALIZING, getFinalizingShards()); - builder.field(Fields.DONE, getDoneShards()); - builder.field(Fields.FAILED, getFailedShards()); - builder.field(Fields.TOTAL, getTotalShards()); + builder.startObject(); + { + builder.field(Fields.INITIALIZING, getInitializingShards()); + builder.field(Fields.STARTED, getStartedShards()); + builder.field(Fields.FINALIZING, getFinalizingShards()); + builder.field(Fields.DONE, getDoneShards()); + builder.field(Fields.FAILED, getFailedShards()); + builder.field(Fields.TOTAL, getTotalShards()); + } builder.endObject(); return builder; } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java index a33cee8dae1a7..6cb56bd88dcd9 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStats.java @@ -26,14 +26,14 @@ import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.ToXContent; -import org.elasticsearch.common.xcontent.ToXContentFragment; +import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParserUtils; import java.io.IOException; -public class SnapshotStats implements Streamable, ToXContentFragment { +public class SnapshotStats implements Streamable, ToXContentObject { private long startTime; private long time; @@ -178,32 +178,35 @@ static final class Fields { @Override public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException { - builder.startObject(Fields.STATS) - // incremental starts - .startObject(Fields.INCREMENTAL) - .field(Fields.FILE_COUNT, getIncrementalFileCount()) - .humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getIncrementalSize())) - // incremental ends - .endObject(); - - if (getProcessedFileCount() != getIncrementalFileCount()) { - // processed starts - builder.startObject(Fields.PROCESSED) - .field(Fields.FILE_COUNT, getProcessedFileCount()) - .humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getProcessedSize())) - // processed ends - .endObject(); - } - // total starts - builder.startObject(Fields.TOTAL) - .field(Fields.FILE_COUNT, getTotalFileCount()) - .humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getTotalSize())) - // total ends - .endObject(); - // timings stats - builder.field(Fields.START_TIME_IN_MILLIS, getStartTime()) - .humanReadableField(Fields.TIME_IN_MILLIS, Fields.TIME, new TimeValue(getTime())); + builder.startObject(); + { + builder.startObject(Fields.INCREMENTAL); + { + builder.field(Fields.FILE_COUNT, getIncrementalFileCount()); + builder.humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getIncrementalSize())); + } + builder.endObject(); + + if (getProcessedFileCount() != getIncrementalFileCount()) { + builder.startObject(Fields.PROCESSED); + { + builder.field(Fields.FILE_COUNT, getProcessedFileCount()); + builder.humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getProcessedSize())); + } + builder.endObject(); + } + + builder.startObject(Fields.TOTAL); + { + builder.field(Fields.FILE_COUNT, getTotalFileCount()); + builder.humanReadableField(Fields.SIZE_IN_BYTES, Fields.SIZE, new ByteSizeValue(getTotalSize())); + } + builder.endObject(); + // timings stats + builder.field(Fields.START_TIME_IN_MILLIS, getStartTime()); + builder.humanReadableField(Fields.TIME_IN_MILLIS, Fields.TIME, new TimeValue(getTime())); + } return builder.endObject(); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index 26139b068a15c..cdd2437c0eb3d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -230,8 +230,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (includeGlobalState != null) { builder.field(INCLUDE_GLOBAL_STATE, includeGlobalState); } - shardsStats.toXContent(builder, params); - stats.toXContent(builder, params); + builder.field(SnapshotShardsStats.Fields.SHARDS_STATS, shardsStats, params); + builder.field(SnapshotStats.Fields.STATS, stats, params); builder.startObject(INDICES); for (SnapshotIndexStatus indexStatus : getIndices().values()) { indexStatus.toXContent(builder, params); @@ -255,12 +255,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws @SuppressWarnings("unchecked") List indices = ((List) parsedObjects[i]); Snapshot snapshot = new Snapshot(repository, new SnapshotId(name, uuid)); - SnapshotsInProgress.State state; - try { - state = SnapshotsInProgress.State.valueOf(rawState); - } catch (IllegalArgumentException iae) { - throw new ElasticsearchParseException("failed to parse snapshot status, unknown state value [{}]", iae, rawState); - } + SnapshotsInProgress.State state = SnapshotsInProgress.State.valueOf(rawState); Map indicesStatus; List shards; if (indices == null || indices.isEmpty()) { diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java index 245bf4ab09d3d..ac00896983d14 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotShardsStatsTests.java @@ -21,9 +21,7 @@ import java.io.IOException; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.test.AbstractXContentTestCase; public class SnapshotShardsStatsTests extends AbstractXContentTestCase { @@ -41,20 +39,7 @@ protected SnapshotShardsStats createTestInstance() { @Override protected SnapshotShardsStats doParseInstance(XContentParser parser) throws IOException { - // SnapshotShardsStats serializes its own name, and thus, is nested in another object in this test. - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - SnapshotShardsStats stats = null; - while (parser.nextToken() != XContentParser.Token.END_OBJECT) { - if (parser.currentName().equals(SnapshotShardsStats.Fields.SHARDS_STATS)) { - stats = SnapshotShardsStats.fromXContent(parser); - } else { - parser.skipChildren(); - } - } - if (stats == null) { - throw new ElasticsearchParseException("could not find stats"); - } - return stats; + return SnapshotShardsStats.fromXContent(parser); } @Override diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java index b7ee713f1f44d..2822a9661fd15 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatsTests.java @@ -21,9 +21,7 @@ import java.io.IOException; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.test.AbstractXContentTestCase; public class SnapshotStatsTests extends AbstractXContentTestCase { @@ -44,21 +42,7 @@ protected SnapshotStats createTestInstance() { @Override protected SnapshotStats doParseInstance(XContentParser parser) throws IOException { - // SnapshotStats serializes its own name, and thus, is nested in another object in this test. - XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation); - SnapshotStats stats = null; - while (parser.nextToken() != XContentParser.Token.END_OBJECT) { - if (parser.currentName().equals(SnapshotStats.Fields.STATS)) { - parser.nextToken(); // Advance to START_OBJECT - stats = SnapshotStats.fromXContent(parser); - } else { - parser.skipChildren(); - } - } - if (stats == null) { - throw new ElasticsearchParseException("could not find stats"); - } - return stats; + return SnapshotStats.fromXContent(parser); } @Override From 36ae8562f12a7b38e970cf39cf54f9eb2a0f3d76 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Fri, 29 Jun 2018 14:57:56 -0400 Subject: [PATCH 12/14] Make checkstyle happy --- .../action/admin/cluster/snapshots/status/SnapshotStatus.java | 1 - 1 file changed, 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java index cdd2437c0eb3d..618bb54c9015d 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java +++ b/server/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/status/SnapshotStatus.java @@ -19,7 +19,6 @@ package org.elasticsearch.action.admin.cluster.snapshots.status; -import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.Version; import org.elasticsearch.cluster.SnapshotsInProgress; import org.elasticsearch.cluster.SnapshotsInProgress.State; From 1615f0a800ddc8aa882b9982d4e981c0ce45a74b Mon Sep 17 00:00:00 2001 From: James Baiera Date: Fri, 29 Jun 2018 17:04:45 -0400 Subject: [PATCH 13/14] Fix test failures --- .../client/documentation/SnapshotClientDocumentationIT.java | 1 + 1 file changed, 1 insertion(+) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java index 58b15a4926578..b1a292fa15747 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java @@ -468,6 +468,7 @@ public void testSnapshotGetSnapshots() throws IOException { RestHighLevelClient client = highLevelClient(); createTestRepositories(); + createTestIndex(); createTestSnapshots(); // tag::get-snapshots-request From 8d5c9991e310f4c0b22e409e6bded016a59ffe31 Mon Sep 17 00:00:00 2001 From: James Baiera Date: Mon, 2 Jul 2018 11:34:53 -0400 Subject: [PATCH 14/14] Fix test error --- .../java/org/elasticsearch/client/RequestConvertersTests.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java index cfe8acb1ecbb7..5cc0e830446e0 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java @@ -2127,9 +2127,7 @@ public void testSnapshotsStatus() { SnapshotsStatusRequest snapshotsStatusRequest = new SnapshotsStatusRequest(repository, snapshots); setRandomMasterTimeout(snapshotsStatusRequest, expectedParams); snapshotsStatusRequest.ignoreUnavailable(ignoreUnavailable); - if (ignoreUnavailable) { - expectedParams.put("ignore_unavailable", Boolean.toString(true)); - } + expectedParams.put("ignore_unavailable", Boolean.toString(ignoreUnavailable)); Request request = RequestConverters.snapshotsStatus(snapshotsStatusRequest); assertThat(request.getEndpoint(), equalTo(endpoint));