Skip to content

Commit 73a3889

Browse files
Add Restore Snapshot High Level REST API
With this commit we add the restore snapshot API to the Java high level REST client. Relates #27205 Relates #32155
1 parent 59cf600 commit 73a3889

File tree

13 files changed

+732
-12
lines changed

13 files changed

+732
-12
lines changed

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
4141
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
4242
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
43+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
4344
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
4445
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
4546
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -980,6 +981,20 @@ static Request snapshotsStatus(SnapshotsStatusRequest snapshotsStatusRequest) {
980981
return request;
981982
}
982983

984+
static Request restoreSnapshot(RestoreSnapshotRequest restoreSnapshotRequest) throws IOException {
985+
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
986+
.addPathPart(restoreSnapshotRequest.repository())
987+
.addPathPart(restoreSnapshotRequest.snapshot())
988+
.addPathPartAsIs("_restore")
989+
.build();
990+
Request request = new Request(HttpPost.METHOD_NAME, endpoint);
991+
Params parameters = new Params(request);
992+
parameters.withMasterTimeout(restoreSnapshotRequest.masterNodeTimeout());
993+
parameters.withWaitForCompletion(restoreSnapshotRequest.waitForCompletion());
994+
request.setEntity(createEntity(restoreSnapshotRequest, REQUEST_BODY_CONTENT_TYPE));
995+
return request;
996+
}
997+
983998
static Request deleteSnapshot(DeleteSnapshotRequest deleteSnapshotRequest) {
984999
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot")
9851000
.addPathPart(deleteSnapshotRequest.repository())

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

Lines changed: 32 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.restore.RestoreSnapshotRequest;
34+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
3335
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
3436
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
3537
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -252,6 +254,36 @@ public void statusAsync(SnapshotsStatusRequest snapshotsStatusRequest, RequestOp
252254
SnapshotsStatusResponse::fromXContent, listener, emptySet());
253255
}
254256

257+
/**
258+
* Restores a snapshot.
259+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
260+
* API on elastic.co</a>
261+
*
262+
* @param restoreSnapshotRequest the request
263+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
264+
* @return the response
265+
* @throws IOException in case there is a problem sending the request or parsing back the response
266+
*/
267+
public RestoreSnapshotResponse restore(RestoreSnapshotRequest restoreSnapshotRequest, RequestOptions options) throws IOException {
268+
return restHighLevelClient.performRequestAndParseEntity(restoreSnapshotRequest, RequestConverters::restoreSnapshot, options,
269+
RestoreSnapshotResponse::fromXContent, emptySet());
270+
}
271+
272+
/**
273+
* Asynchronously restores a snapshot.
274+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
275+
* API on elastic.co</a>
276+
*
277+
* @param restoreSnapshotRequest the request
278+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
279+
* @param listener the listener to be notified upon request completion
280+
*/
281+
public void restoreAsync(RestoreSnapshotRequest restoreSnapshotRequest, RequestOptions options,
282+
ActionListener<RestoreSnapshotResponse> listener) {
283+
restHighLevelClient.performRequestAsyncAndParseEntity(restoreSnapshotRequest, RequestConverters::restoreSnapshot, options,
284+
RestoreSnapshotResponse::fromXContent, listener, emptySet());
285+
}
286+
255287
/**
256288
* Deletes a snapshot.
257289
* 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: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotRequest;
4242
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
4343
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
44+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
4445
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
4546
import org.elasticsearch.action.admin.cluster.storedscripts.DeleteStoredScriptRequest;
4647
import org.elasticsearch.action.admin.cluster.storedscripts.GetStoredScriptRequest;
@@ -2198,6 +2199,31 @@ public void testSnapshotsStatus() {
21982199
assertThat(request.getEntity(), is(nullValue()));
21992200
}
22002201

2202+
public void testRestoreSnapshot() throws IOException {
2203+
Map<String, String> expectedParams = new HashMap<>();
2204+
String repository = randomIndicesNames(1, 1)[0];
2205+
String snapshot = "snapshot-" + randomAlphaOfLengthBetween(2, 5).toLowerCase(Locale.ROOT);
2206+
String endpoint = String.format(Locale.ROOT, "/_snapshot/%s/%s/_restore", repository, snapshot);
2207+
2208+
RestoreSnapshotRequest restoreSnapshotRequest = new RestoreSnapshotRequest(repository, snapshot);
2209+
setRandomMasterTimeout(restoreSnapshotRequest, expectedParams);
2210+
if (randomBoolean()) {
2211+
restoreSnapshotRequest.waitForCompletion(true);
2212+
expectedParams.put("wait_for_completion", "true");
2213+
}
2214+
if (randomBoolean()) {
2215+
String timeout = randomTimeValue();
2216+
restoreSnapshotRequest.masterNodeTimeout(timeout);
2217+
expectedParams.put("master_timeout", timeout);
2218+
}
2219+
2220+
Request request = RequestConverters.restoreSnapshot(restoreSnapshotRequest);
2221+
assertThat(endpoint, equalTo(request.getEndpoint()));
2222+
assertThat(HttpPost.METHOD_NAME, equalTo(request.getMethod()));
2223+
assertThat(expectedParams, equalTo(request.getParameters()));
2224+
assertToXContentBody(restoreSnapshotRequest, request.getEntity());
2225+
}
2226+
22012227
public void testDeleteSnapshot() {
22022228
Map<String, String> expectedParams = new HashMap<>();
22032229
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
@@ -665,7 +665,6 @@ public void testApiNamingConventions() throws Exception {
665665
"reindex_rethrottle",
666666
"render_search_template",
667667
"scripts_painless_execute",
668-
"snapshot.restore",
669668
"tasks.get",
670669
"termvectors",
671670
"update_by_query"

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
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.restore.RestoreSnapshotRequest;
32+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
3133
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusRequest;
3234
import org.elasticsearch.action.admin.cluster.snapshots.status.SnapshotsStatusResponse;
3335
import org.elasticsearch.common.settings.Settings;
@@ -40,12 +42,15 @@
4042
import org.elasticsearch.common.xcontent.XContentType;
4143
import org.elasticsearch.repositories.fs.FsRepository;
4244
import org.elasticsearch.rest.RestStatus;
45+
import org.elasticsearch.snapshots.RestoreInfo;
4346

4447
import java.io.IOException;
48+
import java.util.Collections;
4549
import java.util.stream.Collectors;
4650

4751
import static org.hamcrest.Matchers.contains;
4852
import static org.hamcrest.Matchers.equalTo;
53+
import static org.hamcrest.Matchers.greaterThan;
4954
import static org.hamcrest.Matchers.is;
5055

5156
public class SnapshotIT extends ESRestHighLevelClientTestCase {
@@ -205,6 +210,42 @@ public void testSnapshotsStatus() throws IOException {
205210
assertThat(response.getSnapshots().get(0).getIndices().containsKey(testIndex), is(true));
206211
}
207212

213+
public void testRestoreSnapshot() throws IOException {
214+
String testRepository = "test";
215+
String testSnapshot = "snapshot_1";
216+
String testIndex = "test_index";
217+
String restoredIndex = testIndex + "_restored";
218+
219+
PutRepositoryResponse putRepositoryResponse = createTestRepository(testRepository, FsRepository.TYPE, "{\"location\": \".\"}");
220+
assertTrue(putRepositoryResponse.isAcknowledged());
221+
222+
createIndex(testIndex, Settings.EMPTY);
223+
assertTrue("index [" + testIndex + "] should have been created", indexExists(testIndex));
224+
225+
CreateSnapshotRequest createSnapshotRequest = new CreateSnapshotRequest(testRepository, testSnapshot);
226+
createSnapshotRequest.indices(testIndex);
227+
createSnapshotRequest.waitForCompletion(true);
228+
CreateSnapshotResponse createSnapshotResponse = createTestSnapshot(createSnapshotRequest);
229+
assertEquals(RestStatus.OK, createSnapshotResponse.status());
230+
231+
deleteIndex(testIndex);
232+
assertFalse("index [" + testIndex + "] should have been deleted", indexExists(testIndex));
233+
234+
RestoreSnapshotRequest request = new RestoreSnapshotRequest(testRepository, testSnapshot);
235+
request.waitForCompletion(true);
236+
request.renamePattern(testIndex);
237+
request.renameReplacement(restoredIndex);
238+
239+
RestoreSnapshotResponse response = execute(request, highLevelClient().snapshot()::restore,
240+
highLevelClient().snapshot()::restoreAsync);
241+
242+
RestoreInfo restoreInfo = response.getRestoreInfo();
243+
assertThat(restoreInfo.name(), equalTo(testSnapshot));
244+
assertThat(restoreInfo.indices(), equalTo(Collections.singletonList(restoredIndex)));
245+
assertThat(restoreInfo.successfulShards(), greaterThan(0));
246+
assertThat(restoreInfo.failedShards(), equalTo(0));
247+
}
248+
208249
public void testDeleteSnapshot() throws IOException {
209250
String repository = "test_repository";
210251
String snapshot = "test_snapshot";

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

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse;
3434
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsRequest;
3535
import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse;
36+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotRequest;
37+
import org.elasticsearch.action.admin.cluster.snapshots.restore.RestoreSnapshotResponse;
3638
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
3739
import org.elasticsearch.action.support.IndicesOptions;
3840
import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotRequest;
@@ -53,12 +55,15 @@
5355
import org.elasticsearch.common.xcontent.XContentType;
5456
import org.elasticsearch.repositories.fs.FsRepository;
5557
import org.elasticsearch.rest.RestStatus;
58+
import org.elasticsearch.snapshots.RestoreInfo;
5659
import org.elasticsearch.snapshots.SnapshotId;
5760
import org.elasticsearch.snapshots.SnapshotInfo;
5861
import org.elasticsearch.snapshots.SnapshotShardFailure;
5962
import org.elasticsearch.snapshots.SnapshotState;
6063

6164
import java.io.IOException;
65+
import java.util.Collections;
66+
import java.util.EnumSet;
6267
import java.util.HashMap;
6368
import java.util.List;
6469
import java.util.Locale;
@@ -263,6 +268,107 @@ public void onFailure(Exception e) {
263268
}
264269
}
265270

271+
public void testRestoreSnapshot() throws IOException {
272+
RestHighLevelClient client = highLevelClient();
273+
274+
createTestRepositories();
275+
createTestIndex();
276+
createTestSnapshots();
277+
278+
// tag::restore-snapshot-request
279+
RestoreSnapshotRequest request = new RestoreSnapshotRequest(repositoryName, snapshotName);
280+
// end::restore-snapshot-request
281+
// we need to restore as a different index name
282+
283+
// tag::restore-snapshot-request-masterTimeout
284+
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
285+
request.masterNodeTimeout("1m"); // <2>
286+
// end::restore-snapshot-request-masterTimeout
287+
288+
// tag::restore-snapshot-request-waitForCompletion
289+
request.waitForCompletion(true); // <1>
290+
// end::restore-snapshot-request-waitForCompletion
291+
292+
// tag::restore-snapshot-request-partial
293+
request.partial(false); // <1>
294+
// end::restore-snapshot-request-partial
295+
296+
// tag::restore-snapshot-request-include-global-state
297+
request.includeGlobalState(false); // <1>
298+
// end::restore-snapshot-request-include-global-state
299+
300+
// tag::restore-snapshot-request-include-aliases
301+
request.includeAliases(false); // <1>
302+
// end::restore-snapshot-request-include-aliases
303+
304+
305+
// tag::restore-snapshot-request-indices
306+
request.indices("test_index");
307+
// end::restore-snapshot-request-indices
308+
309+
String restoredIndexName = "restored_index";
310+
// tag::restore-snapshot-request-rename
311+
request.renamePattern("test_(.+)"); // <1>
312+
request.renameReplacement("restored_$1"); // <2>
313+
// end::restore-snapshot-request-rename
314+
315+
// tag::restore-snapshot-request-index-settings
316+
request.indexSettings( // <1>
317+
Settings.builder()
318+
.put("index.number_of_replicas", 0)
319+
.build());
320+
321+
request.ignoreIndexSettings("index.refresh_interval", "index.search.idle.after"); // <2>
322+
request.indicesOptions(new IndicesOptions( // <3>
323+
EnumSet.of(IndicesOptions.Option.IGNORE_UNAVAILABLE),
324+
EnumSet.of(IndicesOptions.WildcardStates.OPEN)));
325+
// end::restore-snapshot-request-index-settings
326+
327+
// tag::restore-snapshot-execute
328+
RestoreSnapshotResponse response = client.snapshot().restore(request, RequestOptions.DEFAULT);
329+
// end::restore-snapshot-execute
330+
331+
// tag::restore-snapshot-response
332+
RestoreInfo restoreInfo = response.getRestoreInfo();
333+
List<String> indices = restoreInfo.indices(); // <1>
334+
// end::restore-snapshot-response
335+
assertEquals(Collections.singletonList(restoredIndexName), indices);
336+
assertEquals(0, restoreInfo.failedShards());
337+
assertTrue(restoreInfo.successfulShards() > 0);
338+
}
339+
340+
public void testRestoreSnapshotAsync() throws InterruptedException {
341+
RestHighLevelClient client = highLevelClient();
342+
{
343+
RestoreSnapshotRequest request = new RestoreSnapshotRequest();
344+
345+
// tag::restore-snapshot-execute-listener
346+
ActionListener<RestoreSnapshotResponse> listener =
347+
new ActionListener<RestoreSnapshotResponse>() {
348+
@Override
349+
public void onResponse(RestoreSnapshotResponse restoreSnapshotResponse) {
350+
// <1>
351+
}
352+
353+
@Override
354+
public void onFailure(Exception e) {
355+
// <2>
356+
}
357+
};
358+
// end::restore-snapshot-execute-listener
359+
360+
// Replace the empty listener by a blocking listener in test
361+
final CountDownLatch latch = new CountDownLatch(1);
362+
listener = new LatchedActionListener<>(listener, latch);
363+
364+
// tag::restore-snapshot-execute-async
365+
client.snapshot().restoreAsync(request, RequestOptions.DEFAULT, listener); // <1>
366+
// end::restore-snapshot-execute-async
367+
368+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
369+
}
370+
}
371+
266372
public void testSnapshotDeleteRepository() throws IOException {
267373
RestHighLevelClient client = highLevelClient();
268374

0 commit comments

Comments
 (0)