Skip to content

Commit 2661fff

Browse files
committed
[HLRC] Added support for CCR Put Auto Follow Pattern API (#35780)
This change also adds documentation for the Put Auto Follow Pattern API. Relates to #33824
1 parent 157df6f commit 2661fff

File tree

8 files changed

+418
-0
lines changed

8 files changed

+418
-0
lines changed

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

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

2222
import org.elasticsearch.action.ActionListener;
2323
import org.elasticsearch.client.ccr.PauseFollowRequest;
24+
import org.elasticsearch.client.ccr.PutAutoFollowPatternRequest;
2425
import org.elasticsearch.client.ccr.PutFollowRequest;
2526
import org.elasticsearch.client.ccr.PutFollowResponse;
2627
import org.elasticsearch.client.ccr.ResumeFollowRequest;
@@ -219,4 +220,46 @@ public void unfollowAsync(UnfollowRequest request,
219220
);
220221
}
221222

223+
/**
224+
* Stores an auto follow pattern.
225+
*
226+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-put-auto-follow-pattern.html">
227+
* the docs</a> for more.
228+
*
229+
* @param request the request
230+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
231+
* @return the response
232+
* @throws IOException in case there is a problem sending the request or parsing back the response
233+
*/
234+
public AcknowledgedResponse putAutoFollowPattern(PutAutoFollowPatternRequest request, RequestOptions options) throws IOException {
235+
return restHighLevelClient.performRequestAndParseEntity(
236+
request,
237+
CcrRequestConverters::putAutoFollowPattern,
238+
options,
239+
AcknowledgedResponse::fromXContent,
240+
Collections.emptySet()
241+
);
242+
}
243+
244+
/**
245+
* Asynchronously stores an auto follow pattern.
246+
*
247+
* See <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/ccr-put-auto-follow-pattern.html">
248+
* the docs</a> for more.
249+
*
250+
* @param request the request
251+
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
252+
*/
253+
public void putAutoFollowPatternAsync(PutAutoFollowPatternRequest request,
254+
RequestOptions options,
255+
ActionListener<AcknowledgedResponse> listener) {
256+
restHighLevelClient.performRequestAsyncAndParseEntity(
257+
request,
258+
CcrRequestConverters::putAutoFollowPattern,
259+
options,
260+
AcknowledgedResponse::fromXContent,
261+
listener,
262+
Collections.emptySet());
263+
}
264+
222265
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.apache.http.client.methods.HttpPost;
2323
import org.apache.http.client.methods.HttpPut;
2424
import org.elasticsearch.client.ccr.PauseFollowRequest;
25+
import org.elasticsearch.client.ccr.PutAutoFollowPatternRequest;
2526
import org.elasticsearch.client.ccr.PutFollowRequest;
2627
import org.elasticsearch.client.ccr.ResumeFollowRequest;
2728
import org.elasticsearch.client.ccr.UnfollowRequest;
@@ -69,4 +70,14 @@ static Request unfollow(UnfollowRequest unfollowRequest) {
6970
return new Request(HttpPost.METHOD_NAME, endpoint);
7071
}
7172

73+
static Request putAutoFollowPattern(PutAutoFollowPatternRequest putAutoFollowPatternRequest) throws IOException {
74+
String endpoint = new RequestConverters.EndpointBuilder()
75+
.addPathPartAsIs("_ccr", "auto_follow")
76+
.addPathPart(putAutoFollowPatternRequest.getName())
77+
.build();
78+
Request request = new Request(HttpPut.METHOD_NAME, endpoint);
79+
request.setEntity(createEntity(putAutoFollowPatternRequest, REQUEST_BODY_CONTENT_TYPE));
80+
return request;
81+
}
82+
7283
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
import org.elasticsearch.common.ParseField;
24+
import org.elasticsearch.common.xcontent.ToXContentObject;
25+
import org.elasticsearch.common.xcontent.XContentBuilder;
26+
27+
import java.io.IOException;
28+
import java.util.List;
29+
import java.util.Objects;
30+
31+
public final class PutAutoFollowPatternRequest extends FollowConfig implements Validatable, ToXContentObject {
32+
33+
static final ParseField LEADER_PATTERNS_FIELD = new ParseField("leader_index_patterns");
34+
static final ParseField FOLLOW_PATTERN_FIELD = new ParseField("follow_index_pattern");
35+
36+
private final String name;
37+
private final String remoteCluster;
38+
private final List<String> leaderIndexPatterns;
39+
private String followIndexNamePattern;
40+
41+
public PutAutoFollowPatternRequest(String name, String remoteCluster, List<String> leaderIndexPatterns) {
42+
this.name = Objects.requireNonNull(name);
43+
this.remoteCluster = Objects.requireNonNull(remoteCluster);
44+
this.leaderIndexPatterns = Objects.requireNonNull(leaderIndexPatterns);
45+
}
46+
47+
public String getName() {
48+
return name;
49+
}
50+
51+
public String getRemoteCluster() {
52+
return remoteCluster;
53+
}
54+
55+
public List<String> getLeaderIndexPatterns() {
56+
return leaderIndexPatterns;
57+
}
58+
59+
public String getFollowIndexNamePattern() {
60+
return followIndexNamePattern;
61+
}
62+
63+
public void setFollowIndexNamePattern(String followIndexNamePattern) {
64+
this.followIndexNamePattern = followIndexNamePattern;
65+
}
66+
67+
@Override
68+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
69+
builder.startObject();
70+
builder.field(PutFollowRequest.REMOTE_CLUSTER_FIELD.getPreferredName(), remoteCluster);
71+
builder.field(LEADER_PATTERNS_FIELD.getPreferredName(), leaderIndexPatterns);
72+
if (followIndexNamePattern != null) {
73+
builder.field(FOLLOW_PATTERN_FIELD.getPreferredName(), followIndexNamePattern);
74+
}
75+
toXContentFragment(builder, params);
76+
builder.endObject();
77+
return builder;
78+
}
79+
80+
@Override
81+
public boolean equals(Object o) {
82+
if (this == o) return true;
83+
if (o == null || getClass() != o.getClass()) return false;
84+
if (!super.equals(o)) return false;
85+
PutAutoFollowPatternRequest that = (PutAutoFollowPatternRequest) o;
86+
return Objects.equals(name, that.name) &&
87+
Objects.equals(remoteCluster, that.remoteCluster) &&
88+
Objects.equals(leaderIndexPatterns, that.leaderIndexPatterns) &&
89+
Objects.equals(followIndexNamePattern, that.followIndexNamePattern);
90+
}
91+
92+
@Override
93+
public int hashCode() {
94+
return Objects.hash(
95+
super.hashCode(),
96+
name,
97+
remoteCluster,
98+
leaderIndexPatterns,
99+
followIndexNamePattern
100+
);
101+
}
102+
}

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

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.elasticsearch.action.search.SearchResponse;
3131
import org.elasticsearch.action.support.WriteRequest;
3232
import org.elasticsearch.client.ccr.PauseFollowRequest;
33+
import org.elasticsearch.client.ccr.PutAutoFollowPatternRequest;
3334
import org.elasticsearch.client.ccr.PutFollowRequest;
3435
import org.elasticsearch.client.ccr.PutFollowResponse;
3536
import org.elasticsearch.client.ccr.ResumeFollowRequest;
@@ -127,6 +128,35 @@ public void testIndexFollowing() throws Exception {
127128
assertThat(unfollowResponse.isAcknowledged(), is(true));
128129
}
129130

131+
public void testAutoFollowing() throws Exception {
132+
CcrClient ccrClient = highLevelClient().ccr();
133+
PutAutoFollowPatternRequest putAutoFollowPatternRequest =
134+
new PutAutoFollowPatternRequest("pattern1", "local", Collections.singletonList("logs-*"));
135+
putAutoFollowPatternRequest.setFollowIndexNamePattern("copy-{{leader_index}}");
136+
AcknowledgedResponse putAutoFollowPatternResponse =
137+
execute(putAutoFollowPatternRequest, ccrClient::putAutoFollowPattern, ccrClient::putAutoFollowPatternAsync);
138+
assertThat(putAutoFollowPatternResponse.isAcknowledged(), is(true));
139+
140+
CreateIndexRequest createIndexRequest = new CreateIndexRequest("logs-20200101");
141+
createIndexRequest.settings(Collections.singletonMap("index.soft_deletes.enabled", true));
142+
CreateIndexResponse response = highLevelClient().indices().create(createIndexRequest, RequestOptions.DEFAULT);
143+
assertThat(response.isAcknowledged(), is(true));
144+
145+
assertBusy(() -> {
146+
assertThat(indexExists("copy-logs-20200101"), is(true));
147+
});
148+
149+
// Cleanup:
150+
// TODO: replace with hlrc delete auto follow pattern when it is available:
151+
final Request deleteAutoFollowPatternRequest = new Request("DELETE", "/_ccr/auto_follow/pattern1");
152+
Map<?, ?> deleteAutoFollowPatternResponse = toMap(client().performRequest(deleteAutoFollowPatternRequest));
153+
assertThat(deleteAutoFollowPatternResponse.get("acknowledged"), is(true));
154+
155+
PauseFollowRequest pauseFollowRequest = new PauseFollowRequest("copy-logs-20200101");
156+
AcknowledgedResponse pauseFollowResponse = ccrClient.pauseFollow(pauseFollowRequest, RequestOptions.DEFAULT);
157+
assertThat(pauseFollowResponse.isAcknowledged(), is(true));
158+
}
159+
130160
private static Map<String, Object> toMap(Response response) throws IOException {
131161
return XContentHelper.convertToMap(JsonXContent.jsonXContent, EntityUtils.toString(response.getEntity()), false);
132162
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
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.common.unit.ByteSizeValue;
23+
import org.elasticsearch.common.unit.TimeValue;
24+
import org.elasticsearch.common.xcontent.ConstructingObjectParser;
25+
import org.elasticsearch.common.xcontent.ObjectParser;
26+
import org.elasticsearch.common.xcontent.XContentParser;
27+
import org.elasticsearch.test.AbstractXContentTestCase;
28+
29+
import java.io.IOException;
30+
import java.util.Arrays;
31+
import java.util.List;
32+
33+
public class PutAutoFollowPatternRequestTests extends AbstractXContentTestCase<PutAutoFollowPatternRequest> {
34+
35+
@SuppressWarnings("unchecked")
36+
private static final ConstructingObjectParser<PutAutoFollowPatternRequest, Void> PARSER = new ConstructingObjectParser<>("test_parser",
37+
true, (args) -> new PutAutoFollowPatternRequest("name", (String) args[0], (List<String>) args[1]));
38+
39+
static {
40+
PARSER.declareString(ConstructingObjectParser.constructorArg(), PutFollowRequest.REMOTE_CLUSTER_FIELD);
41+
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), PutAutoFollowPatternRequest.LEADER_PATTERNS_FIELD);
42+
PARSER.declareString(PutAutoFollowPatternRequest::setFollowIndexNamePattern, PutAutoFollowPatternRequest.FOLLOW_PATTERN_FIELD);
43+
PARSER.declareInt(PutAutoFollowPatternRequest::setMaxReadRequestOperationCount, FollowConfig.MAX_READ_REQUEST_OPERATION_COUNT);
44+
PARSER.declareField(
45+
PutAutoFollowPatternRequest::setMaxReadRequestSize,
46+
(p, c) -> ByteSizeValue.parseBytesSizeValue(p.text(), FollowConfig.MAX_READ_REQUEST_SIZE.getPreferredName()),
47+
PutFollowRequest.MAX_READ_REQUEST_SIZE,
48+
ObjectParser.ValueType.STRING);
49+
PARSER.declareInt(PutAutoFollowPatternRequest::setMaxOutstandingReadRequests, FollowConfig.MAX_OUTSTANDING_READ_REQUESTS);
50+
PARSER.declareInt(PutAutoFollowPatternRequest::setMaxWriteRequestOperationCount, FollowConfig.MAX_WRITE_REQUEST_OPERATION_COUNT);
51+
PARSER.declareField(
52+
PutAutoFollowPatternRequest::setMaxWriteRequestSize,
53+
(p, c) -> ByteSizeValue.parseBytesSizeValue(p.text(), FollowConfig.MAX_WRITE_REQUEST_SIZE.getPreferredName()),
54+
PutFollowRequest.MAX_WRITE_REQUEST_SIZE,
55+
ObjectParser.ValueType.STRING);
56+
PARSER.declareInt(PutAutoFollowPatternRequest::setMaxOutstandingWriteRequests, FollowConfig.MAX_OUTSTANDING_WRITE_REQUESTS);
57+
PARSER.declareInt(PutAutoFollowPatternRequest::setMaxWriteBufferCount, FollowConfig.MAX_WRITE_BUFFER_COUNT);
58+
PARSER.declareField(
59+
PutAutoFollowPatternRequest::setMaxWriteBufferSize,
60+
(p, c) -> ByteSizeValue.parseBytesSizeValue(p.text(), FollowConfig.MAX_WRITE_BUFFER_SIZE.getPreferredName()),
61+
PutFollowRequest.MAX_WRITE_BUFFER_SIZE,
62+
ObjectParser.ValueType.STRING);
63+
PARSER.declareField(
64+
PutAutoFollowPatternRequest::setMaxRetryDelay,
65+
(p, c) -> TimeValue.parseTimeValue(p.text(), FollowConfig.MAX_RETRY_DELAY_FIELD.getPreferredName()),
66+
PutFollowRequest.MAX_RETRY_DELAY_FIELD,
67+
ObjectParser.ValueType.STRING);
68+
PARSER.declareField(
69+
PutAutoFollowPatternRequest::setReadPollTimeout,
70+
(p, c) -> TimeValue.parseTimeValue(p.text(), FollowConfig.READ_POLL_TIMEOUT.getPreferredName()),
71+
PutFollowRequest.READ_POLL_TIMEOUT,
72+
ObjectParser.ValueType.STRING);
73+
}
74+
75+
@Override
76+
protected PutAutoFollowPatternRequest doParseInstance(XContentParser parser) throws IOException {
77+
return PARSER.apply(parser, null);
78+
}
79+
80+
@Override
81+
protected boolean supportsUnknownFields() {
82+
return true;
83+
}
84+
85+
@Override
86+
protected PutAutoFollowPatternRequest createTestInstance() {
87+
// Name isn't serialized, because it specified in url path, so no need to randomly generate it here.
88+
PutAutoFollowPatternRequest putAutoFollowPatternRequest = new PutAutoFollowPatternRequest("name",
89+
randomAlphaOfLength(4), Arrays.asList(generateRandomStringArray(4, 4, false)));
90+
if (randomBoolean()) {
91+
putAutoFollowPatternRequest.setFollowIndexNamePattern(randomAlphaOfLength(4));
92+
}
93+
if (randomBoolean()) {
94+
putAutoFollowPatternRequest.setMaxOutstandingReadRequests(randomIntBetween(0, Integer.MAX_VALUE));
95+
}
96+
if (randomBoolean()) {
97+
putAutoFollowPatternRequest.setMaxOutstandingWriteRequests(randomIntBetween(0, Integer.MAX_VALUE));
98+
}
99+
if (randomBoolean()) {
100+
putAutoFollowPatternRequest.setMaxReadRequestOperationCount(randomIntBetween(0, Integer.MAX_VALUE));
101+
}
102+
if (randomBoolean()) {
103+
putAutoFollowPatternRequest.setMaxReadRequestSize(new ByteSizeValue(randomNonNegativeLong()));
104+
}
105+
if (randomBoolean()) {
106+
putAutoFollowPatternRequest.setMaxWriteBufferCount(randomIntBetween(0, Integer.MAX_VALUE));
107+
}
108+
if (randomBoolean()) {
109+
putAutoFollowPatternRequest.setMaxWriteBufferSize(new ByteSizeValue(randomNonNegativeLong()));
110+
}
111+
if (randomBoolean()) {
112+
putAutoFollowPatternRequest.setMaxWriteRequestOperationCount(randomIntBetween(0, Integer.MAX_VALUE));
113+
}
114+
if (randomBoolean()) {
115+
putAutoFollowPatternRequest.setMaxWriteRequestSize(new ByteSizeValue(randomNonNegativeLong()));
116+
}
117+
if (randomBoolean()) {
118+
putAutoFollowPatternRequest.setMaxRetryDelay(new TimeValue(randomNonNegativeLong()));
119+
}
120+
if (randomBoolean()) {
121+
putAutoFollowPatternRequest.setReadPollTimeout(new TimeValue(randomNonNegativeLong()));
122+
}
123+
return putAutoFollowPatternRequest;
124+
}
125+
126+
}

0 commit comments

Comments
 (0)