From ae65cc327c821dae43c08e23a76dde23fc35cf20 Mon Sep 17 00:00:00 2001 From: Martijn van Groningen Date: Mon, 19 Nov 2018 13:59:25 +0100 Subject: [PATCH] [HLRC] Added support for CCR Unfollow API This change also adds documentation for the Unfollow API Relates to #33824 --- .../org/elasticsearch/client/CcrClient.java | 46 ++++++++++ .../client/CcrRequestConverters.java | 9 ++ .../client/ccr/UnfollowRequest.java | 37 ++++++++ .../java/org/elasticsearch/client/CCRIT.java | 12 +++ .../documentation/CCRDocumentationIT.java | 87 +++++++++++++++++++ .../high-level/ccr/unfollow.asciidoc | 36 ++++++++ .../high-level/supported-apis.asciidoc | 2 + 7 files changed, 229 insertions(+) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/UnfollowRequest.java create mode 100644 docs/java-rest/high-level/ccr/unfollow.asciidoc diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java index 68933093ae794..eb6d6a4b4c8f7 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrClient.java @@ -23,6 +23,7 @@ import org.elasticsearch.client.ccr.PauseFollowRequest; import org.elasticsearch.client.ccr.PutFollowRequest; import org.elasticsearch.client.ccr.PutFollowResponse; +import org.elasticsearch.client.ccr.UnfollowRequest; import org.elasticsearch.client.core.AcknowledgedResponse; import java.io.IOException; @@ -130,4 +131,49 @@ public void pauseFollowAsync(PauseFollowRequest request, Collections.emptySet()); } + /** + * Instructs a follower index to unfollow and become a regular index. + * Note that index following needs to be paused and the follower index needs to be closed. + * + * See + * the docs for more. + * + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + * @return the response + * @throws IOException in case there is a problem sending the request or parsing back the response + */ + public AcknowledgedResponse unfollow(UnfollowRequest request, RequestOptions options) throws IOException { + return restHighLevelClient.performRequestAndParseEntity( + request, + CcrRequestConverters::unfollow, + options, + AcknowledgedResponse::fromXContent, + Collections.emptySet() + ); + } + + /** + * Asynchronously instructs a follower index to unfollow and become a regular index. + * Note that index following needs to be paused and the follower index needs to be closed. + * + * See + * the docs for more. + * + * @param request the request + * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized + */ + public void unfollowAsync(UnfollowRequest request, + RequestOptions options, + ActionListener listener) { + restHighLevelClient.performRequestAsyncAndParseEntity( + request, + CcrRequestConverters::unfollow, + options, + AcknowledgedResponse::fromXContent, + listener, + Collections.emptySet() + ); + } + } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java index eee5715d58629..9c81624d2c444 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/CcrRequestConverters.java @@ -23,6 +23,7 @@ import org.apache.http.client.methods.HttpPut; import org.elasticsearch.client.ccr.PauseFollowRequest; import org.elasticsearch.client.ccr.PutFollowRequest; +import org.elasticsearch.client.ccr.UnfollowRequest; import java.io.IOException; @@ -49,4 +50,12 @@ static Request pauseFollow(PauseFollowRequest pauseFollowRequest) { return new Request(HttpPost.METHOD_NAME, endpoint); } + static Request unfollow(UnfollowRequest unfollowRequest) { + String endpoint = new RequestConverters.EndpointBuilder() + .addPathPart(unfollowRequest.getFollowerIndex()) + .addPathPartAsIs("_ccr", "unfollow") + .build(); + return new Request(HttpPost.METHOD_NAME, endpoint); + } + } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/UnfollowRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/UnfollowRequest.java new file mode 100644 index 0000000000000..f3fb607006d90 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ccr/UnfollowRequest.java @@ -0,0 +1,37 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.client.ccr; + +import org.elasticsearch.client.Validatable; + +import java.util.Objects; + +public final class UnfollowRequest implements Validatable { + + private final String followerIndex; + + public UnfollowRequest(String followerIndex) { + this.followerIndex = Objects.requireNonNull(followerIndex); + } + + public String getFollowerIndex() { + return followerIndex; + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java index f98cbbb2b85c0..a9a0b240ad93e 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/CCRIT.java @@ -22,6 +22,7 @@ import org.apache.http.util.EntityUtils; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.index.IndexRequest; @@ -31,6 +32,7 @@ import org.elasticsearch.client.ccr.PauseFollowRequest; import org.elasticsearch.client.ccr.PutFollowRequest; import org.elasticsearch.client.ccr.PutFollowResponse; +import org.elasticsearch.client.ccr.UnfollowRequest; import org.elasticsearch.client.core.AcknowledgedResponse; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentType; @@ -95,6 +97,16 @@ public void testCCR() throws Exception { PauseFollowRequest pauseFollowRequest = new PauseFollowRequest("follower"); AcknowledgedResponse pauseFollowResponse = execute(pauseFollowRequest, ccrClient::pauseFollow, ccrClient::pauseFollowAsync); assertThat(pauseFollowResponse.isAcknowledged(), is(true)); + + // Need to close index prior to unfollowing it: + CloseIndexRequest closeIndexRequest = new CloseIndexRequest("follower"); + org.elasticsearch.action.support.master.AcknowledgedResponse closeIndexReponse = + highLevelClient().indices().close(closeIndexRequest, RequestOptions.DEFAULT); + assertThat(closeIndexReponse.isAcknowledged(), is(true)); + + UnfollowRequest unfollowRequest = new UnfollowRequest("follower"); + AcknowledgedResponse unfollowResponse = execute(unfollowRequest, ccrClient::unfollow, ccrClient::unfollowAsync); + assertThat(unfollowResponse.isAcknowledged(), is(true)); } private static Map toMap(Response response) throws IOException { diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java index 8df7e40fc9e77..36adfc9b5fa77 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/CCRDocumentationIT.java @@ -24,6 +24,7 @@ import org.elasticsearch.action.LatchedActionListener; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; +import org.elasticsearch.action.admin.indices.close.CloseIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexResponse; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; @@ -35,6 +36,7 @@ import org.elasticsearch.client.ccr.PauseFollowRequest; import org.elasticsearch.client.ccr.PutFollowRequest; import org.elasticsearch.client.ccr.PutFollowResponse; +import org.elasticsearch.client.ccr.UnfollowRequest; import org.elasticsearch.client.core.AcknowledgedResponse; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -217,6 +219,91 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } + public void testUnfollow() throws Exception { + RestHighLevelClient client = highLevelClient(); + { + // Create leader index: + CreateIndexRequest createIndexRequest = new CreateIndexRequest("leader"); + createIndexRequest.settings(Collections.singletonMap("index.soft_deletes.enabled", true)); + CreateIndexResponse response = client.indices().create(createIndexRequest, RequestOptions.DEFAULT); + assertThat(response.isAcknowledged(), is(true)); + } + String followIndex = "follower"; + // Follow index, pause and close, so that it can be unfollowed: + { + PutFollowRequest putFollowRequest = new PutFollowRequest("local", "leader", followIndex); + PutFollowResponse putFollowResponse = client.ccr().putFollow(putFollowRequest, RequestOptions.DEFAULT); + assertThat(putFollowResponse.isFollowIndexCreated(), is(true)); + assertThat(putFollowResponse.isFollowIndexShardsAcked(), is(true)); + assertThat(putFollowResponse.isIndexFollowingStarted(), is(true)); + + PauseFollowRequest pauseFollowRequest = new PauseFollowRequest(followIndex); + AcknowledgedResponse unfollowResponse = client.ccr().pauseFollow(pauseFollowRequest, RequestOptions.DEFAULT); + assertThat(unfollowResponse.isAcknowledged(), is(true)); + + CloseIndexRequest closeIndexRequest = new CloseIndexRequest(followIndex); + assertThat(client.indices().close(closeIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true)); + } + + // tag::ccr-unfollow-request + UnfollowRequest request = new UnfollowRequest(followIndex); // <1> + // end::ccr-unfollow-request + + // tag::ccr-unfollow-execute + AcknowledgedResponse response = + client.ccr().unfollow(request, RequestOptions.DEFAULT); + // end::ccr-unfollow-execute + + // tag::ccr-unfollow-response + boolean acknowledged = response.isAcknowledged(); // <1> + // end::ccr-unfollow-response + + // Delete, put follow index, pause and close, so that it can be unfollowed again: + { + DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(followIndex); + assertThat(client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true)); + + PutFollowRequest putFollowRequest = new PutFollowRequest("local", "leader", followIndex); + PutFollowResponse putFollowResponse = client.ccr().putFollow(putFollowRequest, RequestOptions.DEFAULT); + assertThat(putFollowResponse.isFollowIndexCreated(), is(true)); + assertThat(putFollowResponse.isFollowIndexShardsAcked(), is(true)); + assertThat(putFollowResponse.isIndexFollowingStarted(), is(true)); + + PauseFollowRequest pauseFollowRequest = new PauseFollowRequest(followIndex); + AcknowledgedResponse unfollowResponse = client.ccr().pauseFollow(pauseFollowRequest, RequestOptions.DEFAULT); + assertThat(unfollowResponse.isAcknowledged(), is(true)); + + CloseIndexRequest closeIndexRequest = new CloseIndexRequest(followIndex); + assertThat(client.indices().close(closeIndexRequest, RequestOptions.DEFAULT).isAcknowledged(), is(true)); + } + + // tag::ccr-unfollow-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(AcknowledgedResponse response) { + boolean acknowledged = response.isAcknowledged(); // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::ccr-unfollow-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::ccr-unfollow-execute-async + client.ccr() + .unfollowAsync(request, RequestOptions.DEFAULT, listener); // <1> + // end::ccr-unfollow-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + static Map toMap(Response response) throws IOException { return XContentHelper.convertToMap(JsonXContent.jsonXContent, EntityUtils.toString(response.getEntity()), false); } diff --git a/docs/java-rest/high-level/ccr/unfollow.asciidoc b/docs/java-rest/high-level/ccr/unfollow.asciidoc new file mode 100644 index 0000000000000..bb6dd654ed4d1 --- /dev/null +++ b/docs/java-rest/high-level/ccr/unfollow.asciidoc @@ -0,0 +1,36 @@ +-- +:api: ccr-unfollow +:request: UnfollowRequest +:response: UnfollowResponse +-- + +[id="{upid}-{api}"] +=== Unfollow API + + +[id="{upid}-{api}-request"] +==== Request + +The Unfollow API allows you to unfollow a follower index and make it a regular index. +Note that the follower index needs to be paused and the follower index needs to be closed. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-request] +-------------------------------------------------- +<1> The name of follow index to unfollow. + +[id="{upid}-{api}-response"] +==== Response + +The returned +{response}+ indicates if the unfollow request was received. + +["source","java",subs="attributes,callouts,macros"] +-------------------------------------------------- +include-tagged::{doc-tests-file}[{api}-response] +-------------------------------------------------- +<1> Whether or not the unfollow was acknowledge. + +include::../execution.asciidoc[] + + diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 5fa05135cc035..158dcbea7e33c 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -431,9 +431,11 @@ The Java High Level REST Client supports the following CCR APIs: * <<{upid}-ccr-put-follow>> * <<{upid}-ccr-pause-follow>> +* <<{upid}-ccr-unfollow>> include::ccr/put_follow.asciidoc[] include::ccr/pause_follow.asciidoc[] +include::ccr/unfollow.asciidoc[] == Index Lifecycle Management APIs