Skip to content

Commit c6be3b4

Browse files
authored
Add Delete Repository High Level REST API (#30666)
This commit adds Delete Repository, the associated docs and tests for the high level REST API client. It also cleans up a seemingly innocuous line in the RestDeleteRepositoryAction and some naming in SnapshotIT. Relates #27205
1 parent 3ce2297 commit c6be3b4

File tree

10 files changed

+288
-10
lines changed

10 files changed

+288
-10
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.apache.lucene.util.BytesRef;
3131
import org.elasticsearch.action.DocWriteRequest;
3232
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
33+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest;
3334
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
3435
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
3536
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
@@ -711,6 +712,16 @@ static Request createRepository(PutRepositoryRequest putRepositoryRequest) throw
711712
return request;
712713
}
713714

715+
static Request deleteRepository(DeleteRepositoryRequest deleteRepositoryRequest) {
716+
String endpoint = new EndpointBuilder().addPathPartAsIs("_snapshot").addPathPart(deleteRepositoryRequest.name()).build();
717+
Request request = new Request(HttpDelete.METHOD_NAME, endpoint);
718+
719+
Params parameters = new Params(request);
720+
parameters.withMasterTimeout(deleteRepositoryRequest.masterNodeTimeout());
721+
parameters.withTimeout(deleteRepositoryRequest.timeout());
722+
return request;
723+
}
724+
714725
static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) throws IOException {
715726
String endpoint = new EndpointBuilder().addPathPartAsIs("_template").addPathPart(putIndexTemplateRequest.name()).build();
716727
Request request = new Request(HttpPut.METHOD_NAME, endpoint);

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import org.apache.http.Header;
2323
import org.elasticsearch.action.ActionListener;
24+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest;
25+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryResponse;
2426
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
2527
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
2628
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
@@ -90,4 +92,28 @@ public void createRepositoryAsync(PutRepositoryRequest putRepositoryRequest,
9092
restHighLevelClient.performRequestAsyncAndParseEntity(putRepositoryRequest, RequestConverters::createRepository,
9193
PutRepositoryResponse::fromXContent, listener, emptySet(), headers);
9294
}
95+
96+
/**
97+
* Deletes a snapshot repository.
98+
* <p>
99+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
100+
* API on elastic.co</a>
101+
*/
102+
public DeleteRepositoryResponse deleteRepository(DeleteRepositoryRequest deleteRepositoryRequest, Header... headers)
103+
throws IOException {
104+
return restHighLevelClient.performRequestAndParseEntity(deleteRepositoryRequest, RequestConverters::deleteRepository,
105+
DeleteRepositoryResponse::fromXContent, emptySet(), headers);
106+
}
107+
108+
/**
109+
* Asynchronously deletes a snapshot repository.
110+
* <p>
111+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-snapshots.html"> Snapshot and Restore
112+
* API on elastic.co</a>
113+
*/
114+
public void deleteRepositoryAsync(DeleteRepositoryRequest deleteRepositoryRequest,
115+
ActionListener<DeleteRepositoryResponse> listener, Header... headers) {
116+
restHighLevelClient.performRequestAsyncAndParseEntity(deleteRepositoryRequest, RequestConverters::deleteRepository,
117+
DeleteRepositoryResponse::fromXContent, listener, emptySet(), headers);
118+
}
93119
}

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.elasticsearch.action.ActionRequestValidationException;
3131
import org.elasticsearch.action.DocWriteRequest;
3232
import org.elasticsearch.action.admin.cluster.node.tasks.list.ListTasksRequest;
33+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest;
3334
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
3435
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
3536
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
@@ -1546,7 +1547,7 @@ public void testGetRepositories() {
15461547
}
15471548

15481549
public void testCreateRepository() throws IOException {
1549-
String repository = "repo";
1550+
String repository = randomIndicesNames(1, 1)[0];
15501551
String endpoint = "/_snapshot/" + repository;
15511552
Path repositoryLocation = PathUtils.get(".");
15521553
PutRepositoryRequest putRepositoryRequest = new PutRepositoryRequest(repository);
@@ -1555,17 +1556,35 @@ public void testCreateRepository() throws IOException {
15551556

15561557
putRepositoryRequest.settings(
15571558
Settings.builder()
1558-
.put(FsRepository.LOCATION_SETTING.getKey(), repositoryLocation)
1559-
.put(FsRepository.COMPRESS_SETTING.getKey(), randomBoolean())
1560-
.put(FsRepository.CHUNK_SIZE_SETTING.getKey(), randomIntBetween(100, 1000), ByteSizeUnit.BYTES)
1561-
.build());
1559+
.put(FsRepository.LOCATION_SETTING.getKey(), repositoryLocation)
1560+
.put(FsRepository.COMPRESS_SETTING.getKey(), randomBoolean())
1561+
.put(FsRepository.CHUNK_SIZE_SETTING.getKey(), randomIntBetween(100, 1000), ByteSizeUnit.BYTES)
1562+
.build());
15621563

15631564
Request request = RequestConverters.createRepository(putRepositoryRequest);
15641565
assertThat(endpoint, equalTo(request.getEndpoint()));
15651566
assertThat(HttpPut.METHOD_NAME, equalTo(request.getMethod()));
15661567
assertToXContentBody(putRepositoryRequest, request.getEntity());
15671568
}
15681569

1570+
public void testDeleteRepository() {
1571+
Map<String, String> expectedParams = new HashMap<>();
1572+
String repository = randomIndicesNames(1, 1)[0];
1573+
1574+
StringBuilder endpoint = new StringBuilder("/_snapshot/" + repository);
1575+
1576+
DeleteRepositoryRequest deleteRepositoryRequest = new DeleteRepositoryRequest();
1577+
deleteRepositoryRequest.name(repository);
1578+
setRandomMasterTimeout(deleteRepositoryRequest, expectedParams);
1579+
setRandomTimeout(deleteRepositoryRequest::timeout, AcknowledgedRequest.DEFAULT_ACK_TIMEOUT, expectedParams);
1580+
1581+
Request request = RequestConverters.deleteRepository(deleteRepositoryRequest);
1582+
assertThat(endpoint.toString(), equalTo(request.getEndpoint()));
1583+
assertThat(HttpDelete.METHOD_NAME, equalTo(request.getMethod()));
1584+
assertThat(expectedParams, equalTo(request.getParameters()));
1585+
assertNull(request.getEntity());
1586+
}
1587+
15691588
public void testPutTemplateRequest() throws Exception {
15701589
Map<String, String> names = new HashMap<>();
15711590
names.put("log", "log");

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

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
package org.elasticsearch.client;
2121

22+
import org.apache.http.entity.ContentType;
23+
import org.apache.http.entity.StringEntity;
2224
import org.elasticsearch.ElasticsearchException;
25+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest;
26+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryResponse;
2327
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
2428
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
2529
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
@@ -29,6 +33,7 @@
2933
import org.elasticsearch.rest.RestStatus;
3034

3135
import java.io.IOException;
36+
import java.util.Collections;
3237

3338
import static org.hamcrest.Matchers.equalTo;
3439

@@ -40,15 +45,14 @@ private PutRepositoryResponse createTestRepository(String repository, String typ
4045
request.type(type);
4146
return execute(request, highLevelClient().snapshot()::createRepository,
4247
highLevelClient().snapshot()::createRepositoryAsync);
43-
4448
}
4549

4650
public void testCreateRepository() throws IOException {
4751
PutRepositoryResponse response = createTestRepository("test", FsRepository.TYPE, "{\"location\": \".\"}");
4852
assertTrue(response.isAcknowledged());
4953
}
5054

51-
public void testModulesGetRepositoriesUsingParams() throws IOException {
55+
public void testSnapshotGetRepositoriesUsingParams() throws IOException {
5256
String testRepository = "test";
5357
assertTrue(createTestRepository(testRepository, FsRepository.TYPE, "{\"location\": \".\"}").isAcknowledged());
5458
assertTrue(createTestRepository("other", FsRepository.TYPE, "{\"location\": \".\"}").isAcknowledged());
@@ -60,7 +64,7 @@ public void testModulesGetRepositoriesUsingParams() throws IOException {
6064
assertThat(1, equalTo(response.repositories().size()));
6165
}
6266

63-
public void testModulesGetDefaultRepositories() throws IOException {
67+
public void testSnapshotGetDefaultRepositories() throws IOException {
6468
assertTrue(createTestRepository("other", FsRepository.TYPE, "{\"location\": \".\"}").isAcknowledged());
6569
assertTrue(createTestRepository("test", FsRepository.TYPE, "{\"location\": \".\"}").isAcknowledged());
6670

@@ -69,7 +73,7 @@ public void testModulesGetDefaultRepositories() throws IOException {
6973
assertThat(2, equalTo(response.repositories().size()));
7074
}
7175

72-
public void testModulesGetRepositoriesNonExistent() throws IOException {
76+
public void testSnapshotGetRepositoriesNonExistent() {
7377
String repository = "doesnotexist";
7478
GetRepositoriesRequest request = new GetRepositoriesRequest(new String[]{repository});
7579
ElasticsearchException exception = expectThrows(ElasticsearchException.class, () -> execute(request,
@@ -79,4 +83,23 @@ public void testModulesGetRepositoriesNonExistent() throws IOException {
7983
assertThat(exception.getMessage(), equalTo(
8084
"Elasticsearch exception [type=repository_missing_exception, reason=[" + repository + "] missing]"));
8185
}
86+
87+
public void testSnapshotDeleteRepository() throws IOException {
88+
String repository = "test";
89+
String repositorySettings = "{\"type\":\"fs\", \"settings\":{\"location\": \".\"}}";
90+
91+
highLevelClient().getLowLevelClient().performRequest("put", "_snapshot/" + repository,
92+
Collections.emptyMap(), new StringEntity(repositorySettings, ContentType.APPLICATION_JSON));
93+
94+
GetRepositoriesRequest request = new GetRepositoriesRequest();
95+
GetRepositoriesResponse response = execute(request, highLevelClient().snapshot()::getRepositories,
96+
highLevelClient().snapshot()::getRepositoriesAsync);
97+
assertThat(1, equalTo(response.repositories().size()));
98+
99+
DeleteRepositoryRequest deleteRequest = new DeleteRepositoryRequest(repository);
100+
DeleteRepositoryResponse deleteResponse = execute(deleteRequest, highLevelClient().snapshot()::deleteRepository,
101+
highLevelClient().snapshot()::deleteRepositoryAsync);
102+
103+
assertTrue(deleteResponse.isAcknowledged());
104+
}
82105
}

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

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import org.elasticsearch.action.ActionListener;
2323
import org.elasticsearch.action.LatchedActionListener;
24+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryRequest;
25+
import org.elasticsearch.action.admin.cluster.repositories.delete.DeleteRepositoryResponse;
2426
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesRequest;
2527
import org.elasticsearch.action.admin.cluster.repositories.get.GetRepositoriesResponse;
2628
import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryRequest;
@@ -235,6 +237,66 @@ public void onFailure(Exception e) {
235237
}
236238
}
237239

240+
public void testSnapshotDeleteRepository() throws IOException {
241+
RestHighLevelClient client = highLevelClient();
242+
243+
createTestRepositories();
244+
245+
// tag::delete-repository-request
246+
DeleteRepositoryRequest request = new DeleteRepositoryRequest(repositoryName);
247+
// end::delete-repository-request
248+
249+
// tag::delete-repository-request-masterTimeout
250+
request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1>
251+
request.masterNodeTimeout("1m"); // <2>
252+
// end::delete-repository-request-masterTimeout
253+
// tag::delete-repository-request-timeout
254+
request.timeout(TimeValue.timeValueMinutes(1)); // <1>
255+
request.timeout("1m"); // <2>
256+
// end::delete-repository-request-timeout
257+
258+
// tag::delete-repository-execute
259+
DeleteRepositoryResponse response = client.snapshot().deleteRepository(request);
260+
// end::delete-repository-execute
261+
262+
// tag::delete-repository-response
263+
boolean acknowledged = response.isAcknowledged(); // <1>
264+
// end::delete-repository-response
265+
assertTrue(acknowledged);
266+
}
267+
268+
public void testSnapshotDeleteRepositoryAsync() throws InterruptedException {
269+
RestHighLevelClient client = highLevelClient();
270+
{
271+
DeleteRepositoryRequest request = new DeleteRepositoryRequest();
272+
273+
// tag::delete-repository-execute-listener
274+
ActionListener<DeleteRepositoryResponse> listener =
275+
new ActionListener<DeleteRepositoryResponse>() {
276+
@Override
277+
public void onResponse(DeleteRepositoryResponse deleteRepositoryResponse) {
278+
// <1>
279+
}
280+
281+
@Override
282+
public void onFailure(Exception e) {
283+
// <2>
284+
}
285+
};
286+
// end::delete-repository-execute-listener
287+
288+
// Replace the empty listener by a blocking listener in test
289+
final CountDownLatch latch = new CountDownLatch(1);
290+
listener = new LatchedActionListener<>(listener, latch);
291+
292+
// tag::delete-repository-execute-async
293+
client.snapshot().deleteRepositoryAsync(request, listener); // <1>
294+
// end::delete-repository-execute-async
295+
296+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
297+
}
298+
}
299+
238300
private void createTestRepositories() throws IOException {
239301
PutRepositoryRequest request = new PutRepositoryRequest(repositoryName);
240302
request.type(FsRepository.TYPE);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
[[java-rest-high-snapshot-delete-repository]]
2+
=== Snapshot Delete Repository API
3+
4+
The Snapshot Delete Repository API allows to delete a registered repository.
5+
6+
[[java-rest-high-snapshot-delete-repository-request]]
7+
==== Snapshot Delete Repository Request
8+
9+
A `DeleteRepositoryRequest`:
10+
11+
["source","java",subs="attributes,callouts,macros"]
12+
--------------------------------------------------
13+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-request]
14+
--------------------------------------------------
15+
16+
==== Optional Arguments
17+
The following arguments can optionally be provided:
18+
19+
["source","java",subs="attributes,callouts,macros"]
20+
--------------------------------------------------
21+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[create-repository-request-timeout]
22+
--------------------------------------------------
23+
<1> Timeout to wait for the all the nodes to acknowledge the settings were applied
24+
as a `TimeValue`
25+
<2> Timeout to wait for the all the nodes to acknowledge the settings were applied
26+
as a `String`
27+
28+
["source","java",subs="attributes,callouts,macros"]
29+
--------------------------------------------------
30+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-request-masterTimeout]
31+
--------------------------------------------------
32+
<1> Timeout to connect to the master node as a `TimeValue`
33+
<2> Timeout to connect to the master node as a `String`
34+
35+
[[java-rest-high-snapshot-delete-repository-sync]]
36+
==== Synchronous Execution
37+
38+
["source","java",subs="attributes,callouts,macros"]
39+
--------------------------------------------------
40+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-execute]
41+
--------------------------------------------------
42+
43+
[[java-rest-high-snapshot-delete-repository-async]]
44+
==== Asynchronous Execution
45+
46+
The asynchronous execution of a snapshot delete repository requires both the
47+
`DeleteRepositoryRequest` instance and an `ActionListener` instance to be
48+
passed to the asynchronous method:
49+
50+
["source","java",subs="attributes,callouts,macros"]
51+
--------------------------------------------------
52+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-execute-async]
53+
--------------------------------------------------
54+
<1> The `DeleteRepositoryRequest` to execute and the `ActionListener`
55+
to use when the execution completes
56+
57+
The asynchronous method does not block and returns immediately. Once it is
58+
completed the `ActionListener` is called back using the `onResponse` method
59+
if the execution successfully completed or using the `onFailure` method if
60+
it failed.
61+
62+
A typical listener for `DeleteRepositoryResponse` looks like:
63+
64+
["source","java",subs="attributes,callouts,macros"]
65+
--------------------------------------------------
66+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-execute-listener]
67+
--------------------------------------------------
68+
<1> Called when the execution is successfully completed. The response is
69+
provided as an argument
70+
<2> Called in case of a failure. The raised exception is provided as an argument
71+
72+
[[java-rest-high-cluster-delete-repository-response]]
73+
==== Snapshot Delete Repository Response
74+
75+
The returned `DeleteRepositoryResponse` allows to retrieve information about the
76+
executed operation as follows:
77+
78+
["source","java",subs="attributes,callouts,macros"]
79+
--------------------------------------------------
80+
include-tagged::{doc-tests}/SnapshotClientDocumentationIT.java[delete-repository-response]
81+
--------------------------------------------------
82+
<1> Indicates the node has acknowledged the request

docs/java-rest/high-level/supported-apis.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ include::cluster/list_tasks.asciidoc[]
114114
The Java High Level REST Client supports the following Snapshot APIs:
115115

116116
* <<java-rest-high-snapshot-get-repository>>
117+
* <<java-rest-high-snapshot-create-repository>>
118+
* <<java-rest-high-snapshot-delete-repository>>
117119

118120
include::snapshot/get_repository.asciidoc[]
119121
include::snapshot/create_repository.asciidoc[]
122+
include::snapshot/delete_repository.asciidoc[]

server/src/main/java/org/elasticsearch/action/admin/cluster/repositories/delete/DeleteRepositoryResponse.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
import org.elasticsearch.action.support.master.AcknowledgedResponse;
2323
import org.elasticsearch.common.io.stream.StreamInput;
2424
import org.elasticsearch.common.io.stream.StreamOutput;
25+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
26+
import org.elasticsearch.common.xcontent.ToXContentObject;
27+
import org.elasticsearch.common.xcontent.XContentParser;
2528

2629
import java.io.IOException;
2730

@@ -30,6 +33,13 @@
3033
*/
3134
public class DeleteRepositoryResponse extends AcknowledgedResponse {
3235

36+
private static final ConstructingObjectParser<DeleteRepositoryResponse, Void> PARSER =
37+
new ConstructingObjectParser<>("delete_repository", true, args -> new DeleteRepositoryResponse((boolean) args[0]));
38+
39+
static {
40+
declareAcknowledgedField(PARSER);
41+
}
42+
3343
DeleteRepositoryResponse() {
3444
}
3545

@@ -49,4 +59,7 @@ public void writeTo(StreamOutput out) throws IOException {
4959
writeAcknowledged(out);
5060
}
5161

62+
public static DeleteRepositoryResponse fromXContent(XContentParser parser) {
63+
return PARSER.apply(parser, null);
64+
}
5265
}

0 commit comments

Comments
 (0)