Skip to content

Commit 5bcdff7

Browse files
authored
Add Snapshots Status API to High Level Rest Client (#31515)
This PR adds the Snapshots Status API to the Snapshot Client, as well as additional documentation for the status api.
1 parent 51bb27a commit 5bcdff7

File tree

19 files changed

+1154
-46
lines changed

19 files changed

+1154
-46
lines changed

client/rest-high-level/src/main/java/org/elasticsearch/client/RequestConverters.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
4444
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
4545
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
46+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
4647
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
4748
import org.elasticsearch.action.admin.indices.alias.get.GetAliasesRequest;
4849
import org.elasticsearch.action.admin.indices.analyze.AnalyzeRequest;
@@ -963,6 +964,20 @@ static Request getSnapshots(GetSnapshotsRequest getSnapshotsRequest) {
963964
return request;
964965
}
965966

967+
static Request snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest) {
968+
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
969+
.addPathPart(snapshotsStatusRequest.repository())
970+
.addCommaSeparatedPathParts(snapshotsStatusRequest.snapshots())
971+
.addPathPartAsIs("_status")
972+
.build();
973+
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
974+
975+
Params parameters = new Params(request);
976+
parameters.withMasterTimeout(snapshotsStatusRequest.masterNodeTimeout());
977+
parameters.withIgnoreUnavailable(snapshotsStatusRequest.ignoreUnavailable());
978+
return request;
979+
}
980+
966981
static Request deleteSnapshot(DeleteSnapshotRequest deleteSnapshotRequest) {
967982
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
968983
.addPathPart(deleteSnapshotRequest.repository())
@@ -1262,7 +1277,7 @@ Params withWaitForActiveShards(ActiveShardCount activeShardCount, ActiveShardCou
12621277
}
12631278

12641279
Params withIndicesOptions(IndicesOptions indicesOptions) {
1265-
putParam("ignore_unavailable", Boolean.toString(indicesOptions.ignoreUnavailable()));
1280+
withIgnoreUnavailable(indicesOptions.ignoreUnavailable());
12661281
putParam("allow_no_indices", Boolean.toString(indicesOptions.allowNoIndices()));
12671282
String expandWildcards;
12681283
if (indicesOptions.expandWildcardsOpen() == false && indicesOptions.expandWildcardsClosed() == false) {
@@ -1281,6 +1296,12 @@ Params withIndicesOptions(IndicesOptions indicesOptions) {
12811296
return this;
12821297
}
12831298

1299+
Params withIgnoreUnavailable(boolean ignoreUnavailable) {
1300+
// Always explicitly place the ignore_unavailable value.
1301+
putParam("ignore_unavailable", Boolean.toString(ignoreUnavailable));
1302+
return this;
1303+
}
1304+
12841305
Params withHuman(boolean human) {
12851306
if (human) {
12861307
putParam("human", Boolean.toString(human));

client/rest-high-level/src/main/java/org/elasticsearch/client/SnapshotClient.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse;
3131
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
3232
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
33+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
34+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
3335
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
3436
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse;
3537
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
@@ -221,6 +223,35 @@ public void getAsync(GetSnapshotsRequest getSnapshotsRequest, RequestOptions opt
221223
GetSnapshotsResponse::fromXContent, listener, emptySet());
222224
}
223225

226+
/**
227+
* Gets the status of requested snapshots.
228+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
229+
* API on elastic.co</a>
230+
* @param snapshotsStatusRequest the request
231+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
232+
* @return the response
233+
* @throws IOException in case there is a problem sending the request or parsing back the response
234+
*/
235+
public SnapshotsStatusResponse status(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options)
236+
throws IOException {
237+
return restHighLevelClient.performRequestAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options,
238+
SnapshotsStatusResponse::fromXContent, emptySet());
239+
}
240+
241+
/**
242+
* Asynchronously gets the status of requested snapshots.
243+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
244+
* API on elastic.co</a>
245+
* @param snapshotsStatusRequest the request
246+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
247+
* @param listener the listener to be notified upon request completion
248+
*/
249+
public void statusAsync(SnapshotsStatusRequest snapshotsStatusRequest, RequestOptions options,
250+
ActionListener<SnapshotsStatusResponse> listener) {
251+
restHighLevelClient.performRequestAsyncAndParseEntity(snapshotsStatusRequest, RequestConverters::snapshotsStatus, options,
252+
SnapshotsStatusResponse::fromXContent, listener, emptySet());
253+
}
254+
224255
/**
225256
* Deletes a snapshot.
226257
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore

client/rest-high-level/src/test/java/org/elasticsearch/client/RequestConvertersTests.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
4444
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
4545
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
46+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
4647
import org.elasticsearch.action.admin.indices.alias.Alias;
4748
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
4849
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest.AliasActions;
@@ -175,6 +176,7 @@
175176
import static org.hamcrest.CoreMatchers.equalTo;
176177
import static org.hamcrest.Matchers.hasEntry;
177178
import static org.hamcrest.Matchers.hasKey;
179+
import static org.hamcrest.Matchers.is;
178180
import static org.hamcrest.Matchers.notNullValue;
179181
import static org.hamcrest.Matchers.nullValue;
180182

@@ -2171,6 +2173,29 @@ public void testGetAllSnapshots() {
21712173
assertNull(request.getEntity());
21722174
}
21732175

2176+
public void testSnapshotsStatus() {
2177+
Map<String, String> expectedParams = new HashMap<>();
2178+
String repository = randomIndicesNames(1, 1)[0];
2179+
String[] snapshots = randomIndicesNames(1, 5);
2180+
StringBuilder snapshotNames = new StringBuilder(snapshots[0]);
2181+
for (int idx = 1; idx < snapshots.length; idx++) {
2182+
snapshotNames.append(",").append(snapshots[idx]);
2183+
}
2184+
boolean ignoreUnavailable = randomBoolean();
2185+
String endpoint = "/_snapshot/" + repository + "/" + snapshotNames.toString() + "/_status";
2186+
2187+
SnapshotsStatusRequest snapshotsStatusRequest = new SnapshotsStatusRequest(repository, snapshots);
2188+
setRandomMasterTimeout(snapshotsStatusRequest, expectedParams);
2189+
snapshotsStatusRequest.ignoreUnavailable(ignoreUnavailable);
2190+
expectedParams.put("ignore_unavailable", Boolean.toString(ignoreUnavailable));
2191+
2192+
Request request = RequestConverters.snapshotsStatus(snapshotsStatusRequest);
2193+
assertThat(request.getEndpoint(), equalTo(endpoint));
2194+
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
2195+
assertThat(request.getParameters(), equalTo(expectedParams));
2196+
assertThat(request.getEntity(), is(nullValue()));
2197+
}
2198+
21742199
public void testDeleteSnapshot() {
21752200
Map<String, String> expectedParams = new HashMap<>();
21762201
String repository = randomIndicesNames(1, 1)[0];

client/rest-high-level/src/test/java/org/elasticsearch/client/SnapshotIT.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@
2828
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryResponse;
2929
import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryRequest;
3030
import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse;
31+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
32+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
33+
import org.elasticsearch.common.settings.Settings;
3134
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
3235
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
3336
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -43,6 +46,7 @@
4346

4447
import static org.hamcrest.Matchers.contains;
4548
import static org.hamcrest.Matchers.equalTo;
49+
import static org.hamcrest.Matchers.is;
4650

4751
public class SnapshotIT extends ESRestHighLevelClientTestCase {
4852

@@ -173,6 +177,34 @@ public void testGetSnapshots() throws IOException {
173177
contains("test_snapshot1", "test_snapshot2"));
174178
}
175179

180+
public void testSnapshotsStatus() throws IOException {
181+
String testRepository = "test";
182+
String testSnapshot = "snapshot";
183+
String testIndex = "test_index";
184+
185+
PutRepositoryResponse putRepositoryResponse = createTestRepository(testRepository, FsRepository.TYPE, "{\"location\": \".\"}");
186+
assertTrue(putRepositoryResponse.isAcknowledged());
187+
188+
createIndex(testIndex, Settings.EMPTY);
189+
190+
CreateSnapshotRequest createSnapshotRequest = new CreateSnapshotRequest(testRepository, testSnapshot);
191+
createSnapshotRequest.indices(testIndex);
192+
createSnapshotRequest.waitForCompletion(true);
193+
CreateSnapshotResponse createSnapshotResponse = createTestSnapshot(createSnapshotRequest);
194+
// check that the request went ok without parsing JSON here. When using the high level client, check acknowledgement instead.
195+
assertEquals(RestStatus.OK, createSnapshotResponse.status());
196+
197+
SnapshotsStatusRequest request = new SnapshotsStatusRequest();
198+
request.repository(testRepository);
199+
request.snapshots(new String[]{testSnapshot});
200+
SnapshotsStatusResponse response = execute(request, highLevelClient().snapshot()::status,
201+
highLevelClient().snapshot()::statusAsync);
202+
assertThat(response.getSnapshots().size(), equalTo(1));
203+
assertThat(response.getSnapshots().get(0).getSnapshot().getRepository(), equalTo(testRepository));
204+
assertThat(response.getSnapshots().get(0).getSnapshot().getSnapshotId().getName(), equalTo(testSnapshot));
205+
assertThat(response.getSnapshots().get(0).getIndices().containsKey(testIndex), is(true));
206+
}
207+
176208
public void testDeleteSnapshot() throws IOException {
177209
String repository = "test_repository";
178210
String snapshot = "test_snapshot";

client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/SnapshotClientDocumentationIT.java

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,16 @@
3737
import org.elasticsearch.action.support.IndicesOptions;
3838
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
3939
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse;
40+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStats;
41+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotStatus;
42+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
43+
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
4044
import org.elasticsearch.client.ESRestHighLevelClientTestCase;
4145
import org.elasticsearch.client.Request;
4246
import org.elasticsearch.client.RequestOptions;
4347
import org.elasticsearch.client.Response;
4448
import org.elasticsearch.client.RestHighLevelClient;
49+
import org.elasticsearch.cluster.SnapshotsInProgress;
4550
import org.elasticsearch.cluster.metadata.RepositoryMetaData;
4651
import org.elasticsearch.common.settings.Settings;
4752
import org.elasticsearch.common.unit.TimeValue;
@@ -84,8 +89,8 @@
8489
public class SnapshotClientDocumentationIT extends ESRestHighLevelClientTestCase {
8590

8691
private static final String repositoryName = "test_repository";
87-
8892
private static final String snapshotName = "test_snapshot";
93+
private static final String indexName = "test_index";
8994

9095
public void testSnapshotCreateRepository() throws IOException {
9196
RestHighLevelClient client = highLevelClient();
@@ -466,6 +471,7 @@ public void testSnapshotGetSnapshots() throws IOException {
466471
RestHighLevelClient client = highLevelClient();
467472

468473
createTestRepositories();
474+
createTestIndex();
469475
createTestSnapshots();
470476

471477
// tag::get-snapshots-request
@@ -543,10 +549,84 @@ public void onFailure(Exception e) {
543549
}
544550
}
545551

552+
public void testSnapshotSnapshotsStatus() throws IOException {
553+
RestHighLevelClient client = highLevelClient();
554+
createTestRepositories();
555+
createTestIndex();
556+
createTestSnapshots();
557+
558+
// tag::snapshots-status-request
559+
SnapshotsStatusRequest request = new SnapshotsStatusRequest();
560+
// end::snapshots-status-request
561+
562+
// tag::snapshots-status-request-repository
563+
request.repository(repositoryName); // <1>
564+
// end::snapshots-status-request-repository
565+
// tag::snapshots-status-request-snapshots
566+
String [] snapshots = new String[] {snapshotName};
567+
request.snapshots(snapshots); // <1>
568+
// end::snapshots-status-request-snapshots
569+
// tag::snapshots-status-request-ignoreUnavailable
570+
request.ignoreUnavailable(true); // <1>
571+
// end::snapshots-status-request-ignoreUnavailable
572+
// tag::snapshots-status-request-masterTimeout
573+
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
574+
request.masterNodeTimeout("1m"); // <2>
575+
// end::snapshots-status-request-masterTimeout
576+
577+
// tag::snapshots-status-execute
578+
SnapshotsStatusResponse response = client.snapshot().status(request, RequestOptions.DEFAULT);
579+
// end::snapshots-status-execute
580+
581+
// tag::snapshots-status-response
582+
List<SnapshotStatus> snapshotStatusesResponse = response.getSnapshots();
583+
SnapshotStatus snapshotStatus = snapshotStatusesResponse.get(0); // <1>
584+
SnapshotsInProgress.State snapshotState = snapshotStatus.getState(); // <2>
585+
SnapshotStats shardStats = snapshotStatus.getIndices().get(indexName).getShards().get(0).getStats(); // <3>
586+
// end::snapshots-status-response
587+
assertThat(snapshotStatusesResponse.size(), equalTo(1));
588+
assertThat(snapshotStatusesResponse.get(0).getSnapshot().getRepository(), equalTo(SnapshotClientDocumentationIT.repositoryName));
589+
assertThat(snapshotStatusesResponse.get(0).getSnapshot().getSnapshotId().getName(), equalTo(snapshotName));
590+
assertThat(snapshotState.completed(), equalTo(true));
591+
}
592+
593+
public void testSnapshotSnapshotsStatusAsync() throws InterruptedException {
594+
RestHighLevelClient client = highLevelClient();
595+
{
596+
SnapshotsStatusRequest request = new SnapshotsStatusRequest();
597+
598+
// tag::snapshots-status-execute-listener
599+
ActionListener<SnapshotsStatusResponse> listener =
600+
new ActionListener<SnapshotsStatusResponse>() {
601+
@Override
602+
public void onResponse(SnapshotsStatusResponse snapshotsStatusResponse) {
603+
// <1>
604+
}
605+
606+
@Override
607+
public void onFailure(Exception e) {
608+
// <2>
609+
}
610+
};
611+
// end::snapshots-status-execute-listener
612+
613+
// Replace the empty listener with a blocking listener in test
614+
final CountDownLatch latch = new CountDownLatch(1);
615+
listener = new LatchedActionListener<>(listener, latch);
616+
617+
// tag::snapshots-status-execute-async
618+
client.snapshot().statusAsync(request, RequestOptions.DEFAULT, listener); // <1>
619+
// end::snapshots-status-execute-async
620+
621+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
622+
}
623+
}
624+
546625
public void testSnapshotDeleteSnapshot() throws IOException {
547626
RestHighLevelClient client = highLevelClient();
548627

549628
createTestRepositories();
629+
createTestIndex();
550630
createTestSnapshots();
551631

552632
// tag::delete-snapshot-request
@@ -608,9 +688,14 @@ private void createTestRepositories() throws IOException {
608688
assertTrue(highLevelClient().snapshot().createRepository(request, RequestOptions.DEFAULT).isAcknowledged());
609689
}
610690

691+
private void createTestIndex() throws IOException {
692+
createIndex(indexName, Settings.EMPTY);
693+
}
694+
611695
private void createTestSnapshots() throws IOException {
612696
Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repositoryName, snapshotName));
613697
createSnapshot.addParameter("wait_for_completion", "true");
698+
createSnapshot.setJsonEntity("{\"indices\":\"" + indexName + "\"}");
614699
Response response = highLevelClient().getLowLevelClient().performRequest(createSnapshot);
615700
// check that the request went ok without parsing JSON here. When using the high level client, check acknowledgement instead.
616701
assertEquals(200, response.getStatusLine().getStatusCode());

0 commit comments

Comments
 (0)