Skip to content

Commit a6647a2

Browse files
authored
[HLRC] Added support for CCR Unfollow API (#35693)
This change also adds documentation for the Unfollow API Relates to #33824
1 parent 30c5422 commit a6647a2

File tree

7 files changed

+229
-0
lines changed

7 files changed

+229
-0
lines changed

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

+46
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.elasticsearch.client.ccr.PauseFollowRequest;
2424
import org.elasticsearch.client.ccr.PutFollowRequest;
2525
import org.elasticsearch.client.ccr.PutFollowResponse;
26+
import org.elasticsearch.client.ccr.UnfollowRequest;
2627
import org.elasticsearch.client.core.AcknowledgedResponse;
2728

2829
import java.io.IOException;
@@ -130,4 +131,49 @@ public void pauseFollowAsync(PauseFollowRequest request,
130131
Collections.emptySet());
131132
}
132133

134+
/**
135+
* Instructs a follower index to unfollow and become a regular index.
136+
* Note that index following needs to be paused and the follower index needs to be closed.
137+
*
138+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-unfollow.html">
139+
* the docs</a> for more.
140+
*
141+
* @param request the request
142+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
143+
* @return the response
144+
* @throws IOException in case there is a problem sending the request or parsing back the response
145+
*/
146+
public AcknowledgedResponse unfollow(UnfollowRequest request, RequestOptions options) throws IOException {
147+
return restHighLevelClient.performRequestAndParseEntity(
148+
request,
149+
CcrRequestConverters::unfollow,
150+
options,
151+
AcknowledgedResponse::fromXContent,
152+
Collections.emptySet()
153+
);
154+
}
155+
156+
/**
157+
* Asynchronously instructs a follower index to unfollow and become a regular index.
158+
* Note that index following needs to be paused and the follower index needs to be closed.
159+
*
160+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-unfollow.html">
161+
* the docs</a> for more.
162+
*
163+
* @param request the request
164+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
165+
*/
166+
public void unfollowAsync(UnfollowRequest request,
167+
RequestOptions options,
168+
ActionListener<AcknowledgedResponse> listener) {
169+
restHighLevelClient.performRequestAsyncAndParseEntity(
170+
request,
171+
CcrRequestConverters::unfollow,
172+
options,
173+
AcknowledgedResponse::fromXContent,
174+
listener,
175+
Collections.emptySet()
176+
);
177+
}
178+
133179
}

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

+9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.apache.http.client.methods.HttpPut;
2424
import org.elasticsearch.client.ccr.PauseFollowRequest;
2525
import org.elasticsearch.client.ccr.PutFollowRequest;
26+
import org.elasticsearch.client.ccr.UnfollowRequest;
2627

2728
import java.io.IOException;
2829

@@ -49,4 +50,12 @@ static Request pauseFollow(PauseFollowRequest pauseFollowRequest) {
4950
return new Request(HttpPost.METHOD_NAME, endpoint);
5051
}
5152

53+
static Request unfollow(UnfollowRequest unfollowRequest) {
54+
String endpoint = new RequestConverters.EndpointBuilder()
55+
.addPathPart(unfollowRequest.getFollowerIndex())
56+
.addPathPartAsIs("_ccr", "unfollow")
57+
.build();
58+
return new Request(HttpPost.METHOD_NAME, endpoint);
59+
}
60+
5261
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.elasticsearch.client.ccr;
21+
22+
import org.elasticsearch.client.Validatable;
23+
24+
import java.util.Objects;
25+
26+
public final class UnfollowRequest implements Validatable {
27+
28+
private final String followerIndex;
29+
30+
public UnfollowRequest(String followerIndex) {
31+
this.followerIndex = Objects.requireNonNull(followerIndex);
32+
}
33+
34+
public String getFollowerIndex() {
35+
return followerIndex;
36+
}
37+
}

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

+12
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.http.util.EntityUtils;
2323
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
2424
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
25+
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
2526
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
2627
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
2728
import org.elasticsearch.action.index.IndexRequest;
@@ -31,6 +32,7 @@
3132
import org.elasticsearch.client.ccr.PauseFollowRequest;
3233
import org.elasticsearch.client.ccr.PutFollowRequest;
3334
import org.elasticsearch.client.ccr.PutFollowResponse;
35+
import org.elasticsearch.client.ccr.UnfollowRequest;
3436
import org.elasticsearch.client.core.AcknowledgedResponse;
3537
import org.elasticsearch.common.xcontent.XContentHelper;
3638
import org.elasticsearch.common.xcontent.XContentType;
@@ -95,6 +97,16 @@ public void testCCR() throws Exception {
9597
PauseFollowRequest pauseFollowRequest = new PauseFollowRequest("follower");
9698
AcknowledgedResponse pauseFollowResponse = execute(pauseFollowRequest, ccrClient::pauseFollow, ccrClient::pauseFollowAsync);
9799
assertThat(pauseFollowResponse.isAcknowledged(), is(true));
100+
101+
// Need to close index prior to unfollowing it:
102+
CloseIndexRequest closeIndexRequest = new CloseIndexRequest("follower");
103+
org.elasticsearch.action.support.master.AcknowledgedResponse closeIndexReponse =
104+
highLevelClient().indices().close(closeIndexRequest, RequestOptions.DEFAULT);
105+
assertThat(closeIndexReponse.isAcknowledged(), is(true));
106+
107+
UnfollowRequest unfollowRequest = new UnfollowRequest("follower");
108+
AcknowledgedResponse unfollowResponse = execute(unfollowRequest, ccrClient::unfollow, ccrClient::unfollowAsync);
109+
assertThat(unfollowResponse.isAcknowledged(), is(true));
98110
}
99111

100112
private static Map<String, Object> toMap(Response response) throws IOException {

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

+87
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.elasticsearch.action.LatchedActionListener;
2525
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest;
2626
import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse;
27+
import org.elasticsearch.action.admin.indices.close.CloseIndexRequest;
2728
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
2829
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
2930
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
@@ -35,6 +36,7 @@
3536
import org.elasticsearch.client.ccr.PauseFollowRequest;
3637
import org.elasticsearch.client.ccr.PutFollowRequest;
3738
import org.elasticsearch.client.ccr.PutFollowResponse;
39+
import org.elasticsearch.client.ccr.UnfollowRequest;
3840
import org.elasticsearch.client.core.AcknowledgedResponse;
3941
import org.elasticsearch.common.xcontent.XContentHelper;
4042
import org.elasticsearch.common.xcontent.json.JsonXContent;
@@ -217,6 +219,91 @@ public void onFailure(Exception e) {
217219
assertTrue(latch.await(30L, TimeUnit.SECONDS));
218220
}
219221

222+
public void testUnfollow() throws Exception {
223+
RestHighLevelClient client = highLevelClient();
224+
{
225+
// Create leader index:
226+
CreateIndexRequest createIndexRequest = new CreateIndexRequest("leader");
227+
createIndexRequest.settings(Collections.singletonMap("index.soft_deletes.enabled", true));
228+
CreateIndexResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);
229+
assertThat(response.isAcknowledged(), is(true));
230+
}
231+
String followIndex = "follower";
232+
// Follow index, pause and close, so that it can be unfollowed:
233+
{
234+
PutFollowRequest putFollowRequest = new PutFollowRequest("local", "leader", followIndex);
235+
PutFollowResponse putFollowResponse = client.ccr().putFollow(putFollowRequest, RequestOptions.DEFAULT);
236+
assertThat(putFollowResponse.isFollowIndexCreated(), is(true));
237+
assertThat(putFollowResponse.isFollowIndexShardsAcked(), is(true));
238+
assertThat(putFollowResponse.isIndexFollowingStarted(), is(true));
239+
240+
PauseFollowRequest pauseFollowRequest = new PauseFollowRequest(followIndex);
241+
AcknowledgedResponse unfollowResponse = client.ccr().pauseFollow(pauseFollowRequest, RequestOptions.DEFAULT);
242+
assertThat(unfollowResponse.isAcknowledged(), is(true));
243+
244+
CloseIndexRequest closeIndexRequest = new CloseIndexRequest(followIndex);
245+
assertThat(client.indices().close(closeIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true));
246+
}
247+
248+
// tag::ccr-unfollow-request
249+
UnfollowRequest request = new UnfollowRequest(followIndex); // <1>
250+
// end::ccr-unfollow-request
251+
252+
// tag::ccr-unfollow-execute
253+
AcknowledgedResponse response =
254+
client.ccr().unfollow(request, RequestOptions.DEFAULT);
255+
// end::ccr-unfollow-execute
256+
257+
// tag::ccr-unfollow-response
258+
boolean acknowledged = response.isAcknowledged(); // <1>
259+
// end::ccr-unfollow-response
260+
261+
// Delete, put follow index, pause and close, so that it can be unfollowed again:
262+
{
263+
DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(followIndex);
264+
assertThat(client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true));
265+
266+
PutFollowRequest putFollowRequest = new PutFollowRequest("local", "leader", followIndex);
267+
PutFollowResponse putFollowResponse = client.ccr().putFollow(putFollowRequest, RequestOptions.DEFAULT);
268+
assertThat(putFollowResponse.isFollowIndexCreated(), is(true));
269+
assertThat(putFollowResponse.isFollowIndexShardsAcked(), is(true));
270+
assertThat(putFollowResponse.isIndexFollowingStarted(), is(true));
271+
272+
PauseFollowRequest pauseFollowRequest = new PauseFollowRequest(followIndex);
273+
AcknowledgedResponse unfollowResponse = client.ccr().pauseFollow(pauseFollowRequest, RequestOptions.DEFAULT);
274+
assertThat(unfollowResponse.isAcknowledged(), is(true));
275+
276+
CloseIndexRequest closeIndexRequest = new CloseIndexRequest(followIndex);
277+
assertThat(client.indices().close(closeIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true));
278+
}
279+
280+
// tag::ccr-unfollow-execute-listener
281+
ActionListener<AcknowledgedResponse> listener =
282+
new ActionListener<AcknowledgedResponse>() {
283+
@Override
284+
public void onResponse(AcknowledgedResponse response) {
285+
boolean acknowledged = response.isAcknowledged(); // <1>
286+
}
287+
288+
@Override
289+
public void onFailure(Exception e) {
290+
// <2>
291+
}
292+
};
293+
// end::ccr-unfollow-execute-listener
294+
295+
// Replace the empty listener by a blocking listener in test
296+
final CountDownLatch latch = new CountDownLatch(1);
297+
listener = new LatchedActionListener<>(listener, latch);
298+
299+
// tag::ccr-unfollow-execute-async
300+
client.ccr()
301+
.unfollowAsync(request, RequestOptions.DEFAULT, listener); // <1>
302+
// end::ccr-unfollow-execute-async
303+
304+
assertTrue(latch.await(30L, TimeUnit.SECONDS));
305+
}
306+
220307
static Map<String, Object> toMap(Response response) throws IOException {
221308
return XContentHelper.convertToMap(JsonXContent.jsonXContent, EntityUtils.toString(response.getEntity()), false);
222309
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--
2+
:api: ccr-unfollow
3+
:request: UnfollowRequest
4+
:response: UnfollowResponse
5+
--
6+
7+
[id="{upid}-{api}"]
8+
=== Unfollow API
9+
10+
11+
[id="{upid}-{api}-request"]
12+
==== Request
13+
14+
The Unfollow API allows you to unfollow a follower index and make it a regular index.
15+
Note that the follower index needs to be paused and the follower index needs to be closed.
16+
17+
["source","java",subs="attributes,callouts,macros"]
18+
--------------------------------------------------
19+
include-tagged::{doc-tests-file}[{api}-request]
20+
--------------------------------------------------
21+
<1> The name of follow index to unfollow.
22+
23+
[id="{upid}-{api}-response"]
24+
==== Response
25+
26+
The returned +{response}+ indicates if the unfollow request was received.
27+
28+
["source","java",subs="attributes,callouts,macros"]
29+
--------------------------------------------------
30+
include-tagged::{doc-tests-file}[{api}-response]
31+
--------------------------------------------------
32+
<1> Whether or not the unfollow was acknowledge.
33+
34+
include::../execution.asciidoc[]
35+
36+

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

+2
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,11 @@ The Java High Level REST Client supports the following CCR APIs:
446446

447447
* <<{upid}-ccr-put-follow>>
448448
* <<{upid}-ccr-pause-follow>>
449+
* <<{upid}-ccr-unfollow>>
449450

450451
include::ccr/put_follow.asciidoc[]
451452
include::ccr/pause_follow.asciidoc[]
453+
include::ccr/unfollow.asciidoc[]
452454

453455
== Index Lifecycle Management APIs
454456

0 commit comments

Comments
 (0)