Skip to content

Commit 36baf38

Browse files
authored
[CCR] Auto follow pattern APIs adjustments (#34518)
* Changed the resource id of auto follow patterns to be a user defined name instead of being the leader cluster alias name. * Fail when an unfollowed leader index matches with two or more auto follow patterns.
1 parent 583f285 commit 36baf38

30 files changed

+324
-186
lines changed

x-pack/plugin/ccr/qa/multi-cluster-with-non-compliant-license/src/test/java/org/elasticsearch/xpack/ccr/CcrMultiClusterLicenseIT.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public void testFollow() {
5050
public void testAutoFollow() throws Exception {
5151
assumeFalse("windows is the worst", Constants.WINDOWS);
5252
if (runningAgainstLeaderCluster == false) {
53-
final Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
54-
request.setJsonEntity("{\"leader_index_patterns\":[\"*\"]}");
53+
final Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
54+
request.setJsonEntity("{\"leader_index_patterns\":[\"*\"], \"leader_cluster\": \"leader_cluster\"}");
5555
client().performRequest(request);
5656

5757
// parse the logs and ensure that the auto-coordinator skipped coordination on the leader cluster
@@ -64,7 +64,7 @@ public void testAutoFollow() throws Exception {
6464
while (it.hasNext()) {
6565
final String line = it.next();
6666
if (line.matches(".*\\[WARN\\s*\\]\\[o\\.e\\.x\\.c\\.a\\.AutoFollowCoordinator\\s*\\] \\[node-0\\] " +
67-
"failure occurred while fetching cluster state in leader cluster \\[leader_cluster\\]")) {
67+
"failure occurred while fetching cluster state for auto follow pattern \\[test_pattern\\]")) {
6868
warn = true;
6969
break;
7070
}

x-pack/plugin/ccr/qa/multi-cluster-with-security/src/test/java/org/elasticsearch/xpack/ccr/FollowIndexSecurityIT.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,14 +146,14 @@ public void testAutoFollowPatterns() throws Exception {
146146
String disallowedIndex = "logs-us-20190101";
147147

148148
{
149-
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
150-
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"]}");
149+
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
150+
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"], \"leader_cluster\": \"leader_cluster\"}");
151151
Exception e = expectThrows(ResponseException.class, () -> assertOK(client().performRequest(request)));
152152
assertThat(e.getMessage(), containsString("insufficient privileges to follow index [logs-*]"));
153153
}
154154

155-
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
156-
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-eu-*\"]}");
155+
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
156+
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-eu-*\"], \"leader_cluster\": \"leader_cluster\"}");
157157
assertOK(client().performRequest(request));
158158

159159
try (RestClient leaderClient = buildLeaderClient()) {
@@ -185,7 +185,7 @@ public void testAutoFollowPatterns() throws Exception {
185185
});
186186

187187
// Cleanup by deleting auto follow pattern and pause following:
188-
request = new Request("DELETE", "/_ccr/auto_follow/leader_cluster");
188+
request = new Request("DELETE", "/_ccr/auto_follow/test_pattern");
189189
assertOK(client().performRequest(request));
190190
pauseFollow(allowedIndex);
191191
}

x-pack/plugin/ccr/qa/multi-cluster/src/test/java/org/elasticsearch/xpack/ccr/FollowIndexIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ public void testFollowNonExistingLeaderIndex() throws Exception {
103103
public void testAutoFollowPatterns() throws Exception {
104104
assumeFalse("Test should only run when both clusters are running", runningAgainstLeaderCluster);
105105

106-
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
107-
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"]}");
106+
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
107+
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"], \"leader_cluster\": \"leader_cluster\"}");
108108
assertOK(client().performRequest(request));
109109

110110
try (RestClient leaderClient = buildLeaderClient()) {

x-pack/plugin/ccr/qa/rest/src/test/resources/rest-api-spec/test/ccr/auto_follow.yml

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,32 @@
2121

2222
- do:
2323
ccr.put_auto_follow_pattern:
24-
leader_cluster: local
24+
name: my_pattern
2525
body:
26+
leader_cluster: local
2627
leader_index_patterns: ['logs-*']
2728
max_concurrent_read_batches: 2
2829
- is_true: acknowledged
2930

3031
- do:
3132
ccr.get_auto_follow_pattern:
32-
leader_cluster: local
33-
- match: { local.leader_index_patterns: ['logs-*'] }
34-
- match: { local.max_concurrent_read_batches: 2 }
33+
name: my_pattern
34+
- match: { my_pattern.leader_cluster: 'local' }
35+
- match: { my_pattern.leader_index_patterns: ['logs-*'] }
36+
- match: { my_pattern.max_concurrent_read_batches: 2 }
3537

3638
- do:
3739
ccr.get_auto_follow_pattern: {}
38-
- match: { local.leader_index_patterns: ['logs-*'] }
39-
- match: { local.max_concurrent_read_batches: 2 }
40+
- match: { my_pattern.leader_cluster: 'local' }
41+
- match: { my_pattern.leader_index_patterns: ['logs-*'] }
42+
- match: { my_pattern.max_concurrent_read_batches: 2 }
4043

4144
- do:
4245
ccr.delete_auto_follow_pattern:
43-
leader_cluster: local
46+
name: my_pattern
4447
- is_true: acknowledged
4548

4649
- do:
4750
catch: missing
4851
ccr.get_auto_follow_pattern:
49-
leader_cluster: local
52+
name: my_pattern

x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/AutoFollowCoordinator.java

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import java.util.function.BiConsumer;
4848
import java.util.function.Consumer;
4949
import java.util.function.Function;
50+
import java.util.stream.Collectors;
5051

5152
/**
5253
* A component that runs only on the elected master node and follows leader indices automatically
@@ -105,19 +106,19 @@ public synchronized AutoFollowStats getStats() {
105106
synchronized void updateStats(List<AutoFollowResult> results) {
106107
for (AutoFollowResult result : results) {
107108
if (result.clusterStateFetchException != null) {
108-
recentAutoFollowErrors.put(result.clusterAlias,
109+
recentAutoFollowErrors.put(result.autoFollowPatternName,
109110
new ElasticsearchException(result.clusterStateFetchException));
110111
numberOfFailedRemoteClusterStateRequests++;
111-
LOGGER.warn(new ParameterizedMessage("failure occurred while fetching cluster state in leader cluster [{}]",
112-
result.clusterAlias), result.clusterStateFetchException);
112+
LOGGER.warn(new ParameterizedMessage("failure occurred while fetching cluster state for auto follow pattern [{}]",
113+
result.autoFollowPatternName), result.clusterStateFetchException);
113114
} else {
114115
for (Map.Entry<Index, Exception> entry : result.autoFollowExecutionResults.entrySet()) {
115116
if (entry.getValue() != null) {
116117
numberOfFailedIndicesAutoFollowed++;
117-
recentAutoFollowErrors.put(result.clusterAlias + ":" + entry.getKey().getName(),
118+
recentAutoFollowErrors.put(result.autoFollowPatternName + ":" + entry.getKey().getName(),
118119
ExceptionsHelper.convertToElastic(entry.getValue()));
119-
LOGGER.warn(new ParameterizedMessage("failure occurred while auto following index [{}] in leader cluster [{}]",
120-
entry.getKey(), result.clusterAlias), entry.getValue());
120+
LOGGER.warn(new ParameterizedMessage("failure occurred while auto following index [{}] for auto follow " +
121+
"pattern [{}]", entry.getKey(), result.autoFollowPatternName), entry.getValue());
121122
} else {
122123
numberOfSuccessfulIndicesAutoFollowed++;
123124
}
@@ -243,51 +244,77 @@ void autoFollowIndices() {
243244
int i = 0;
244245
for (Map.Entry<String, AutoFollowPattern> entry : autoFollowMetadata.getPatterns().entrySet()) {
245246
final int slot = i;
246-
final String clusterAlias = entry.getKey();
247+
final String autoFollowPattenName = entry.getKey();
247248
final AutoFollowPattern autoFollowPattern = entry.getValue();
249+
final String leaderCluster = autoFollowPattern.getLeaderCluster();
248250

249-
Map<String, String> headers = autoFollowMetadata.getHeaders().get(clusterAlias);
250-
getLeaderClusterState(headers, clusterAlias, (leaderClusterState, e) -> {
251+
Map<String, String> headers = autoFollowMetadata.getHeaders().get(autoFollowPattenName);
252+
getLeaderClusterState(headers, leaderCluster, (leaderClusterState, e) -> {
251253
if (leaderClusterState != null) {
252254
assert e == null;
253-
final List<String> followedIndices = autoFollowMetadata.getFollowedLeaderIndexUUIDs().get(clusterAlias);
254-
final List<Index> leaderIndicesToFollow = getLeaderIndicesToFollow(clusterAlias, autoFollowPattern,
255+
final List<String> followedIndices = autoFollowMetadata.getFollowedLeaderIndexUUIDs().get(autoFollowPattenName);
256+
final List<Index> leaderIndicesToFollow = getLeaderIndicesToFollow(leaderCluster, autoFollowPattern,
255257
leaderClusterState, followerClusterState, followedIndices);
256258
if (leaderIndicesToFollow.isEmpty()) {
257-
finalise(slot, new AutoFollowResult(clusterAlias));
259+
finalise(slot, new AutoFollowResult(autoFollowPattenName));
258260
} else {
261+
List<Tuple<String, AutoFollowPattern>> patternsForTheSameLeaderCluster = autoFollowMetadata.getPatterns()
262+
.entrySet().stream()
263+
.filter(item -> autoFollowPattenName.equals(item.getKey()) == false)
264+
.filter(item -> leaderCluster.equals(item.getValue().getLeaderCluster()))
265+
.map(item -> new Tuple<>(item.getKey(), item.getValue()))
266+
.collect(Collectors.toList());
267+
259268
Consumer<AutoFollowResult> resultHandler = result -> finalise(slot, result);
260-
checkAutoFollowPattern(clusterAlias, autoFollowPattern, leaderIndicesToFollow, headers, resultHandler);
269+
checkAutoFollowPattern(autoFollowPattenName, leaderCluster, autoFollowPattern, leaderIndicesToFollow, headers,
270+
patternsForTheSameLeaderCluster, resultHandler);
261271
}
262272
} else {
263-
finalise(slot, new AutoFollowResult(clusterAlias, e));
273+
finalise(slot, new AutoFollowResult(autoFollowPattenName, e));
264274
}
265275
});
266276
i++;
267277
}
268278
}
269279

270-
private void checkAutoFollowPattern(String clusterAlias,
280+
private void checkAutoFollowPattern(String autoFollowPattenName,
281+
String clusterAlias,
271282
AutoFollowPattern autoFollowPattern,
272283
List<Index> leaderIndicesToFollow,
273284
Map<String, String> headers,
285+
List<Tuple<String, AutoFollowPattern>> patternsForTheSameLeaderCluster,
274286
Consumer<AutoFollowResult> resultHandler) {
275287

276288
final CountDown leaderIndicesCountDown = new CountDown(leaderIndicesToFollow.size());
277289
final AtomicArray<Tuple<Index, Exception>> results = new AtomicArray<>(leaderIndicesToFollow.size());
278290
for (int i = 0; i < leaderIndicesToFollow.size(); i++) {
279291
final Index indexToFollow = leaderIndicesToFollow.get(i);
280292
final int slot = i;
281-
followLeaderIndex(clusterAlias, indexToFollow, autoFollowPattern, headers, error -> {
282-
results.set(slot, new Tuple<>(indexToFollow, error));
293+
294+
List<String> otherMatchingPatterns = patternsForTheSameLeaderCluster.stream()
295+
.filter(otherPattern -> otherPattern.v2().match(indexToFollow.getName()))
296+
.map(Tuple::v1)
297+
.collect(Collectors.toList());
298+
if (otherMatchingPatterns.size() != 0) {
299+
results.set(slot, new Tuple<>(indexToFollow, new ElasticsearchException("index to follow [" + indexToFollow.getName() +
300+
"] for pattern [" + autoFollowPattenName + "] matches with other patterns " + otherMatchingPatterns + "")));
283301
if (leaderIndicesCountDown.countDown()) {
284-
resultHandler.accept(new AutoFollowResult(clusterAlias, results.asList()));
302+
resultHandler.accept(new AutoFollowResult(autoFollowPattenName, results.asList()));
285303
}
286-
});
304+
} else {
305+
followLeaderIndex(autoFollowPattenName, clusterAlias, indexToFollow, autoFollowPattern, headers, error -> {
306+
results.set(slot, new Tuple<>(indexToFollow, error));
307+
if (leaderIndicesCountDown.countDown()) {
308+
resultHandler.accept(new AutoFollowResult(autoFollowPattenName, results.asList()));
309+
}
310+
});
311+
}
312+
287313
}
288314
}
289315

290-
private void followLeaderIndex(String clusterAlias,
316+
private void followLeaderIndex(String autoFollowPattenName,
317+
String clusterAlias,
291318
Index indexToFollow,
292319
AutoFollowPattern pattern,
293320
Map<String,String> headers,
@@ -313,7 +340,7 @@ private void followLeaderIndex(String clusterAlias,
313340

314341
// This function updates the auto follow metadata in the cluster to record that the leader index has been followed:
315342
// (so that we do not try to follow it in subsequent auto follow runs)
316-
Function<ClusterState, ClusterState> function = recordLeaderIndexAsFollowFunction(clusterAlias, indexToFollow);
343+
Function<ClusterState, ClusterState> function = recordLeaderIndexAsFollowFunction(autoFollowPattenName, indexToFollow);
317344
// The coordinator always runs on the elected master node, so we can update cluster state here:
318345
updateAutoFollowMetadata(function, onResult);
319346
};
@@ -356,12 +383,12 @@ static String getFollowerIndexName(AutoFollowPattern autoFollowPattern, String l
356383
}
357384
}
358385

359-
static Function<ClusterState, ClusterState> recordLeaderIndexAsFollowFunction(String clusterAlias,
386+
static Function<ClusterState, ClusterState> recordLeaderIndexAsFollowFunction(String name,
360387
Index indexToFollow) {
361388
return currentState -> {
362389
AutoFollowMetadata currentAutoFollowMetadata = currentState.metaData().custom(AutoFollowMetadata.TYPE);
363390
Map<String, List<String>> newFollowedIndexUUIDS = new HashMap<>(currentAutoFollowMetadata.getFollowedLeaderIndexUUIDs());
364-
newFollowedIndexUUIDS.compute(clusterAlias, (key, existingUUIDs) -> {
391+
newFollowedIndexUUIDS.compute(name, (key, existingUUIDs) -> {
365392
assert existingUUIDs != null;
366393
List<String> newUUIDs = new ArrayList<>(existingUUIDs);
367394
newUUIDs.add(indexToFollow.getUUID());
@@ -405,12 +432,12 @@ abstract void updateAutoFollowMetadata(
405432

406433
static class AutoFollowResult {
407434

408-
final String clusterAlias;
435+
final String autoFollowPatternName;
409436
final Exception clusterStateFetchException;
410437
final Map<Index, Exception> autoFollowExecutionResults;
411438

412-
AutoFollowResult(String clusterAlias, List<Tuple<Index, Exception>> results) {
413-
this.clusterAlias = clusterAlias;
439+
AutoFollowResult(String autoFollowPatternName, List<Tuple<Index, Exception>> results) {
440+
this.autoFollowPatternName = autoFollowPatternName;
414441

415442
Map<Index, Exception> autoFollowExecutionResults = new HashMap<>();
416443
for (Tuple<Index, Exception> result : results) {
@@ -421,14 +448,14 @@ static class AutoFollowResult {
421448
this.autoFollowExecutionResults = Collections.unmodifiableMap(autoFollowExecutionResults);
422449
}
423450

424-
AutoFollowResult(String clusterAlias, Exception e) {
425-
this.clusterAlias = clusterAlias;
451+
AutoFollowResult(String autoFollowPatternName, Exception e) {
452+
this.autoFollowPatternName = autoFollowPatternName;
426453
this.clusterStateFetchException = e;
427454
this.autoFollowExecutionResults = Collections.emptyMap();
428455
}
429456

430-
AutoFollowResult(String clusterAlias) {
431-
this(clusterAlias, (Exception) null);
457+
AutoFollowResult(String autoFollowPatternName) {
458+
this(autoFollowPatternName, (Exception) null);
432459
}
433460
}
434461
}

x-pack/plugin/ccr/src/main/java/org/elasticsearch/xpack/ccr/action/TransportDeleteAutoFollowPatternAction.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ protected AcknowledgedResponse newResponse() {
5454
protected void masterOperation(DeleteAutoFollowPatternAction.Request request,
5555
ClusterState state,
5656
ActionListener<AcknowledgedResponse> listener) throws Exception {
57-
clusterService.submitStateUpdateTask("put-auto-follow-pattern-" + request.getLeaderCluster(),
57+
clusterService.submitStateUpdateTask("put-auto-follow-pattern-" + request.getName(),
5858
new AckedClusterStateUpdateTask<AcknowledgedResponse>(request, listener) {
5959

6060
@Override
@@ -72,23 +72,23 @@ public ClusterState execute(ClusterState currentState) throws Exception {
7272
static ClusterState innerDelete(DeleteAutoFollowPatternAction.Request request, ClusterState currentState) {
7373
AutoFollowMetadata currentAutoFollowMetadata = currentState.metaData().custom(AutoFollowMetadata.TYPE);
7474
if (currentAutoFollowMetadata == null) {
75-
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found",
76-
request.getLeaderCluster());
75+
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing",
76+
request.getName());
7777
}
7878
Map<String, AutoFollowPattern> patterns = currentAutoFollowMetadata.getPatterns();
79-
AutoFollowPattern autoFollowPatternToRemove = patterns.get(request.getLeaderCluster());
79+
AutoFollowPattern autoFollowPatternToRemove = patterns.get(request.getName());
8080
if (autoFollowPatternToRemove == null) {
81-
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found",
82-
request.getLeaderCluster());
81+
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing",
82+
request.getName());
8383
}
8484

8585
final Map<String, AutoFollowPattern> patternsCopy = new HashMap<>(patterns);
8686
final Map<String, List<String>> followedLeaderIndexUUIDSCopy =
8787
new HashMap<>(currentAutoFollowMetadata.getFollowedLeaderIndexUUIDs());
8888
final Map<String, Map<String, String>> headers = new HashMap<>(currentAutoFollowMetadata.getHeaders());
89-
patternsCopy.remove(request.getLeaderCluster());
90-
followedLeaderIndexUUIDSCopy.remove(request.getLeaderCluster());
91-
headers.remove(request.getLeaderCluster());
89+
patternsCopy.remove(request.getName());
90+
followedLeaderIndexUUIDSCopy.remove(request.getName());
91+
headers.remove(request.getName());
9292

9393
AutoFollowMetadata newAutoFollowMetadata = new AutoFollowMetadata(patternsCopy, followedLeaderIndexUUIDSCopy, headers);
9494
ClusterState.Builder newState = ClusterState.builder(currentState);

0 commit comments

Comments
 (0)