Skip to content

Commit aed3a53

Browse files
authored
Backport - Add Snapshots Status API to High Level Rest Client (#32295)
This PR adds the Snapshots Status API to the Snapshot Client, as well as additional documentation for the status api.
1 parent 6d72314 commit aed3a53

File tree

20 files changed

+1161
-54
lines changed

20 files changed

+1161
-54
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;
@@ -976,6 +977,20 @@ static Request getSnapshots(GetSnapshotsRequest getSnapshotsRequest) {
976977
return request;
977978
}
978979

980+
static Request snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest) {
981+
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
982+
.addPathPart(snapshotsStatusRequest.repository())
983+
.addCommaSeparatedPathParts(snapshotsStatusRequest.snapshots())
984+
.addPathPartAsIs("_status")
985+
.build();
986+
Request request = new Request(HttpGet.METHOD_NAME, endpoint);
987+
988+
Params parameters = new Params(request);
989+
parameters.withMasterTimeout(snapshotsStatusRequest.masterNodeTimeout());
990+
parameters.withIgnoreUnavailable(snapshotsStatusRequest.ignoreUnavailable());
991+
return request;
992+
}
993+
979994
static Request deleteSnapshot(DeleteSnapshotRequest deleteSnapshotRequest) {
980995
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
981996
.addPathPart(deleteSnapshotRequest.repository())
@@ -1308,7 +1323,7 @@ Params withWaitForActiveShards(ActiveShardCount currentActiveShardCount, ActiveS
13081323
}
13091324

13101325
Params withIndicesOptions(IndicesOptions indicesOptions) {
1311-
putParam("ignore_unavailable", Boolean.toString(indicesOptions.ignoreUnavailable()));
1326+
withIgnoreUnavailable(indicesOptions.ignoreUnavailable());
13121327
putParam("allow_no_indices", Boolean.toString(indicesOptions.allowNoIndices()));
13131328
String expandWildcards;
13141329
if (indicesOptions.expandWildcardsOpen() == false && indicesOptions.expandWildcardsClosed() == false) {
@@ -1327,6 +1342,12 @@ Params withIndicesOptions(IndicesOptions indicesOptions) {
13271342
return this;
13281343
}
13291344

1345+
Params withIgnoreUnavailable(boolean ignoreUnavailable) {
1346+
// Always explicitly place the ignore_unavailable value.
1347+
putParam("ignore_unavailable", Boolean.toString(ignoreUnavailable));
1348+
return this;
1349+
}
1350+
13301351
Params withHuman(boolean human) {
13311352
if (human) {
13321353
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: 24 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;
@@ -2207,6 +2208,29 @@ public void testGetAllSnapshots() {
22072208
assertNull(request.getEntity());
22082209
}
22092210

2211+
public void testSnapshotsStatus() {
2212+
Map<String, String> expectedParams = new HashMap<>();
2213+
String repository = randomIndicesNames(1, 1)[0];
2214+
String[] snapshots = randomIndicesNames(1, 5);
2215+
StringBuilder snapshotNames = new StringBuilder(snapshots[0]);
2216+
for (int idx = 1; idx < snapshots.length; idx++) {
2217+
snapshotNames.append(",").append(snapshots[idx]);
2218+
}
2219+
boolean ignoreUnavailable = randomBoolean();
2220+
String endpoint = "/_snapshot/" + repository + "/" + snapshotNames.toString() + "/_status";
2221+
2222+
SnapshotsStatusRequest snapshotsStatusRequest = new SnapshotsStatusRequest(repository, snapshots);
2223+
setRandomMasterTimeout(snapshotsStatusRequest, expectedParams);
2224+
snapshotsStatusRequest.ignoreUnavailable(ignoreUnavailable);
2225+
expectedParams.put("ignore_unavailable", Boolean.toString(ignoreUnavailable));
2226+
2227+
Request request = RequestConverters.snapshotsStatus(snapshotsStatusRequest);
2228+
assertThat(request.getEndpoint(), equalTo(endpoint));
2229+
assertThat(request.getMethod(), equalTo(HttpGet.METHOD_NAME));
2230+
assertThat(request.getParameters(), equalTo(expectedParams));
2231+
assertThat(request.getEntity(), is(nullValue()));
2232+
}
2233+
22102234
public void testDeleteSnapshot() {
22112235
Map<String, String> expectedParams = new HashMap<>();
22122236
String repository = randomIndicesNames(1, 1)[0];

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,6 @@ public void testApiNamingConventions() throws Exception {
683683
"render_search_template",
684684
"scripts_painless_execute",
685685
"snapshot.restore",
686-
"snapshot.status",
687686
"tasks.get",
688687
"termvectors",
689688
"update_by_query"

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();
@@ -472,6 +477,7 @@ public void testSnapshotGetSnapshots() throws IOException {
472477
RestHighLevelClient client = highLevelClient();
473478

474479
createTestRepositories();
480+
createTestIndex();
475481
createTestSnapshots();
476482

477483
// tag::get-snapshots-request
@@ -549,10 +555,84 @@ public void onFailure(Exception e) {
549555
}
550556
}
551557

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

555634
createTestRepositories();
635+
createTestIndex();
556636
createTestSnapshots();
557637

558638
// tag::delete-snapshot-request
@@ -614,9 +694,14 @@ private void createTestRepositories() throws IOException {
614694
assertTrue(highLevelClient().snapshot().createRepository(request, RequestOptions.DEFAULT).isAcknowledged());
615695
}
616696

697+
private void createTestIndex() throws IOException {
698+
createIndex(indexName, Settings.EMPTY);
699+
}
700+
617701
private void createTestSnapshots() throws IOException {
618702
Request createSnapshot = new Request("put", String.format(Locale.ROOT, "_snapshot/%s/%s", repositoryName, snapshotName));
619703
createSnapshot.addParameter("wait_for_completion", "true");
704+
createSnapshot.setJsonEntity("{\"indices\":\"" + indexName + "\"}");
620705
Response response = highLevelClient().getLowLevelClient().performRequest(createSnapshot);
621706
// check that the request went ok without parsing JSON here. When using the high level client, check acknowledgement instead.
622707
assertEquals(200, response.getStatusLine().getStatusCode());

0 commit comments

Comments
 (0)