[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.
This commit is contained in:
Martijn van Groningen 2018-10-23 15:48:51 +02:00 committed by GitHub
parent 583f2852f0
commit 36baf3823d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 324 additions and 186 deletions

View File

@ -50,8 +50,8 @@ public class CcrMultiClusterLicenseIT extends ESRestTestCase {
public void testAutoFollow() throws Exception {
assumeFalse("windows is the worst", Constants.WINDOWS);
if (runningAgainstLeaderCluster == false) {
final Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
request.setJsonEntity("{\"leader_index_patterns\":[\"*\"]}");
final Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
request.setJsonEntity("{\"leader_index_patterns\":[\"*\"], \"leader_cluster\": \"leader_cluster\"}");
client().performRequest(request);
// parse the logs and ensure that the auto-coordinator skipped coordination on the leader cluster
@ -64,7 +64,7 @@ public class CcrMultiClusterLicenseIT extends ESRestTestCase {
while (it.hasNext()) {
final String line = it.next();
if (line.matches(".*\\[WARN\\s*\\]\\[o\\.e\\.x\\.c\\.a\\.AutoFollowCoordinator\\s*\\] \\[node-0\\] " +
"failure occurred while fetching cluster state in leader cluster \\[leader_cluster\\]")) {
"failure occurred while fetching cluster state for auto follow pattern \\[test_pattern\\]")) {
warn = true;
break;
}

View File

@ -146,14 +146,14 @@ public class FollowIndexSecurityIT extends ESRestTestCase {
String disallowedIndex = "logs-us-20190101";
{
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"]}");
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"], \"leader_cluster\": \"leader_cluster\"}");
Exception e = expectThrows(ResponseException.class, () -> assertOK(client().performRequest(request)));
assertThat(e.getMessage(), containsString("insufficient privileges to follow index [logs-*]"));
}
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-eu-*\"]}");
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-eu-*\"], \"leader_cluster\": \"leader_cluster\"}");
assertOK(client().performRequest(request));
try (RestClient leaderClient = buildLeaderClient()) {
@ -185,7 +185,7 @@ public class FollowIndexSecurityIT extends ESRestTestCase {
});
// Cleanup by deleting auto follow pattern and pause following:
request = new Request("DELETE", "/_ccr/auto_follow/leader_cluster");
request = new Request("DELETE", "/_ccr/auto_follow/test_pattern");
assertOK(client().performRequest(request));
pauseFollow(allowedIndex);
}

View File

@ -103,8 +103,8 @@ public class FollowIndexIT extends ESRestTestCase {
public void testAutoFollowPatterns() throws Exception {
assumeFalse("Test should only run when both clusters are running", runningAgainstLeaderCluster);
Request request = new Request("PUT", "/_ccr/auto_follow/leader_cluster");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"]}");
Request request = new Request("PUT", "/_ccr/auto_follow/test_pattern");
request.setJsonEntity("{\"leader_index_patterns\": [\"logs-*\"], \"leader_cluster\": \"leader_cluster\"}");
assertOK(client().performRequest(request));
try (RestClient leaderClient = buildLeaderClient()) {

View File

@ -21,29 +21,32 @@
- do:
ccr.put_auto_follow_pattern:
leader_cluster: local
name: my_pattern
body:
leader_cluster: local
leader_index_patterns: ['logs-*']
max_concurrent_read_batches: 2
- is_true: acknowledged
- do:
ccr.get_auto_follow_pattern:
leader_cluster: local
- match: { local.leader_index_patterns: ['logs-*'] }
- match: { local.max_concurrent_read_batches: 2 }
name: my_pattern
- match: { my_pattern.leader_cluster: 'local' }
- match: { my_pattern.leader_index_patterns: ['logs-*'] }
- match: { my_pattern.max_concurrent_read_batches: 2 }
- do:
ccr.get_auto_follow_pattern: {}
- match: { local.leader_index_patterns: ['logs-*'] }
- match: { local.max_concurrent_read_batches: 2 }
- match: { my_pattern.leader_cluster: 'local' }
- match: { my_pattern.leader_index_patterns: ['logs-*'] }
- match: { my_pattern.max_concurrent_read_batches: 2 }
- do:
ccr.delete_auto_follow_pattern:
leader_cluster: local
name: my_pattern
- is_true: acknowledged
- do:
catch: missing
ccr.get_auto_follow_pattern:
leader_cluster: local
name: my_pattern

View File

@ -47,6 +47,7 @@ import java.util.TreeMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* A component that runs only on the elected master node and follows leader indices automatically
@ -105,19 +106,19 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
synchronized void updateStats(List<AutoFollowResult> results) {
for (AutoFollowResult result : results) {
if (result.clusterStateFetchException != null) {
recentAutoFollowErrors.put(result.clusterAlias,
recentAutoFollowErrors.put(result.autoFollowPatternName,
new ElasticsearchException(result.clusterStateFetchException));
numberOfFailedRemoteClusterStateRequests++;
LOGGER.warn(new ParameterizedMessage("failure occurred while fetching cluster state in leader cluster [{}]",
result.clusterAlias), result.clusterStateFetchException);
LOGGER.warn(new ParameterizedMessage("failure occurred while fetching cluster state for auto follow pattern [{}]",
result.autoFollowPatternName), result.clusterStateFetchException);
} else {
for (Map.Entry<Index, Exception> entry : result.autoFollowExecutionResults.entrySet()) {
if (entry.getValue() != null) {
numberOfFailedIndicesAutoFollowed++;
recentAutoFollowErrors.put(result.clusterAlias + ":" + entry.getKey().getName(),
recentAutoFollowErrors.put(result.autoFollowPatternName + ":" + entry.getKey().getName(),
ExceptionsHelper.convertToElastic(entry.getValue()));
LOGGER.warn(new ParameterizedMessage("failure occurred while auto following index [{}] in leader cluster [{}]",
entry.getKey(), result.clusterAlias), entry.getValue());
LOGGER.warn(new ParameterizedMessage("failure occurred while auto following index [{}] for auto follow " +
"pattern [{}]", entry.getKey(), result.autoFollowPatternName), entry.getValue());
} else {
numberOfSuccessfulIndicesAutoFollowed++;
}
@ -243,34 +244,45 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
int i = 0;
for (Map.Entry<String, AutoFollowPattern> entry : autoFollowMetadata.getPatterns().entrySet()) {
final int slot = i;
final String clusterAlias = entry.getKey();
final String autoFollowPattenName = entry.getKey();
final AutoFollowPattern autoFollowPattern = entry.getValue();
final String leaderCluster = autoFollowPattern.getLeaderCluster();
Map<String, String> headers = autoFollowMetadata.getHeaders().get(clusterAlias);
getLeaderClusterState(headers, clusterAlias, (leaderClusterState, e) -> {
Map<String, String> headers = autoFollowMetadata.getHeaders().get(autoFollowPattenName);
getLeaderClusterState(headers, leaderCluster, (leaderClusterState, e) -> {
if (leaderClusterState != null) {
assert e == null;
final List<String> followedIndices = autoFollowMetadata.getFollowedLeaderIndexUUIDs().get(clusterAlias);
final List<Index> leaderIndicesToFollow = getLeaderIndicesToFollow(clusterAlias, autoFollowPattern,
final List<String> followedIndices = autoFollowMetadata.getFollowedLeaderIndexUUIDs().get(autoFollowPattenName);
final List<Index> leaderIndicesToFollow = getLeaderIndicesToFollow(leaderCluster, autoFollowPattern,
leaderClusterState, followerClusterState, followedIndices);
if (leaderIndicesToFollow.isEmpty()) {
finalise(slot, new AutoFollowResult(clusterAlias));
finalise(slot, new AutoFollowResult(autoFollowPattenName));
} else {
List<Tuple<String, AutoFollowPattern>> patternsForTheSameLeaderCluster = autoFollowMetadata.getPatterns()
.entrySet().stream()
.filter(item -> autoFollowPattenName.equals(item.getKey()) == false)
.filter(item -> leaderCluster.equals(item.getValue().getLeaderCluster()))
.map(item -> new Tuple<>(item.getKey(), item.getValue()))
.collect(Collectors.toList());
Consumer<AutoFollowResult> resultHandler = result -> finalise(slot, result);
checkAutoFollowPattern(clusterAlias, autoFollowPattern, leaderIndicesToFollow, headers, resultHandler);
checkAutoFollowPattern(autoFollowPattenName, leaderCluster, autoFollowPattern, leaderIndicesToFollow, headers,
patternsForTheSameLeaderCluster, resultHandler);
}
} else {
finalise(slot, new AutoFollowResult(clusterAlias, e));
finalise(slot, new AutoFollowResult(autoFollowPattenName, e));
}
});
i++;
}
}
private void checkAutoFollowPattern(String clusterAlias,
private void checkAutoFollowPattern(String autoFollowPattenName,
String clusterAlias,
AutoFollowPattern autoFollowPattern,
List<Index> leaderIndicesToFollow,
Map<String, String> headers,
List<Tuple<String, AutoFollowPattern>> patternsForTheSameLeaderCluster,
Consumer<AutoFollowResult> resultHandler) {
final CountDown leaderIndicesCountDown = new CountDown(leaderIndicesToFollow.size());
@ -278,16 +290,31 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
for (int i = 0; i < leaderIndicesToFollow.size(); i++) {
final Index indexToFollow = leaderIndicesToFollow.get(i);
final int slot = i;
followLeaderIndex(clusterAlias, indexToFollow, autoFollowPattern, headers, error -> {
results.set(slot, new Tuple<>(indexToFollow, error));
List<String> otherMatchingPatterns = patternsForTheSameLeaderCluster.stream()
.filter(otherPattern -> otherPattern.v2().match(indexToFollow.getName()))
.map(Tuple::v1)
.collect(Collectors.toList());
if (otherMatchingPatterns.size() != 0) {
results.set(slot, new Tuple<>(indexToFollow, new ElasticsearchException("index to follow [" + indexToFollow.getName() +
"] for pattern [" + autoFollowPattenName + "] matches with other patterns " + otherMatchingPatterns + "")));
if (leaderIndicesCountDown.countDown()) {
resultHandler.accept(new AutoFollowResult(clusterAlias, results.asList()));
resultHandler.accept(new AutoFollowResult(autoFollowPattenName, results.asList()));
}
});
} else {
followLeaderIndex(autoFollowPattenName, clusterAlias, indexToFollow, autoFollowPattern, headers, error -> {
results.set(slot, new Tuple<>(indexToFollow, error));
if (leaderIndicesCountDown.countDown()) {
resultHandler.accept(new AutoFollowResult(autoFollowPattenName, results.asList()));
}
});
}
}
}
private void followLeaderIndex(String clusterAlias,
private void followLeaderIndex(String autoFollowPattenName,
String clusterAlias,
Index indexToFollow,
AutoFollowPattern pattern,
Map<String,String> headers,
@ -313,7 +340,7 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
// This function updates the auto follow metadata in the cluster to record that the leader index has been followed:
// (so that we do not try to follow it in subsequent auto follow runs)
Function<ClusterState, ClusterState> function = recordLeaderIndexAsFollowFunction(clusterAlias, indexToFollow);
Function<ClusterState, ClusterState> function = recordLeaderIndexAsFollowFunction(autoFollowPattenName, indexToFollow);
// The coordinator always runs on the elected master node, so we can update cluster state here:
updateAutoFollowMetadata(function, onResult);
};
@ -356,12 +383,12 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
}
}
static Function<ClusterState, ClusterState> recordLeaderIndexAsFollowFunction(String clusterAlias,
static Function<ClusterState, ClusterState> recordLeaderIndexAsFollowFunction(String name,
Index indexToFollow) {
return currentState -> {
AutoFollowMetadata currentAutoFollowMetadata = currentState.metaData().custom(AutoFollowMetadata.TYPE);
Map<String, List<String>> newFollowedIndexUUIDS = new HashMap<>(currentAutoFollowMetadata.getFollowedLeaderIndexUUIDs());
newFollowedIndexUUIDS.compute(clusterAlias, (key, existingUUIDs) -> {
newFollowedIndexUUIDS.compute(name, (key, existingUUIDs) -> {
assert existingUUIDs != null;
List<String> newUUIDs = new ArrayList<>(existingUUIDs);
newUUIDs.add(indexToFollow.getUUID());
@ -405,12 +432,12 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
static class AutoFollowResult {
final String clusterAlias;
final String autoFollowPatternName;
final Exception clusterStateFetchException;
final Map<Index, Exception> autoFollowExecutionResults;
AutoFollowResult(String clusterAlias, List<Tuple<Index, Exception>> results) {
this.clusterAlias = clusterAlias;
AutoFollowResult(String autoFollowPatternName, List<Tuple<Index, Exception>> results) {
this.autoFollowPatternName = autoFollowPatternName;
Map<Index, Exception> autoFollowExecutionResults = new HashMap<>();
for (Tuple<Index, Exception> result : results) {
@ -421,14 +448,14 @@ public class AutoFollowCoordinator implements ClusterStateApplier {
this.autoFollowExecutionResults = Collections.unmodifiableMap(autoFollowExecutionResults);
}
AutoFollowResult(String clusterAlias, Exception e) {
this.clusterAlias = clusterAlias;
AutoFollowResult(String autoFollowPatternName, Exception e) {
this.autoFollowPatternName = autoFollowPatternName;
this.clusterStateFetchException = e;
this.autoFollowExecutionResults = Collections.emptyMap();
}
AutoFollowResult(String clusterAlias) {
this(clusterAlias, (Exception) null);
AutoFollowResult(String autoFollowPatternName) {
this(autoFollowPatternName, (Exception) null);
}
}
}

View File

@ -54,7 +54,7 @@ public class TransportDeleteAutoFollowPatternAction extends
protected void masterOperation(DeleteAutoFollowPatternAction.Request request,
ClusterState state,
ActionListener<AcknowledgedResponse> listener) throws Exception {
clusterService.submitStateUpdateTask("put-auto-follow-pattern-" + request.getLeaderCluster(),
clusterService.submitStateUpdateTask("put-auto-follow-pattern-" + request.getName(),
new AckedClusterStateUpdateTask<AcknowledgedResponse>(request, listener) {
@Override
@ -72,23 +72,23 @@ public class TransportDeleteAutoFollowPatternAction extends
static ClusterState innerDelete(DeleteAutoFollowPatternAction.Request request, ClusterState currentState) {
AutoFollowMetadata currentAutoFollowMetadata = currentState.metaData().custom(AutoFollowMetadata.TYPE);
if (currentAutoFollowMetadata == null) {
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found",
request.getLeaderCluster());
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing",
request.getName());
}
Map<String, AutoFollowPattern> patterns = currentAutoFollowMetadata.getPatterns();
AutoFollowPattern autoFollowPatternToRemove = patterns.get(request.getLeaderCluster());
AutoFollowPattern autoFollowPatternToRemove = patterns.get(request.getName());
if (autoFollowPatternToRemove == null) {
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found",
request.getLeaderCluster());
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing",
request.getName());
}
final Map<String, AutoFollowPattern> patternsCopy = new HashMap<>(patterns);
final Map<String, List<String>> followedLeaderIndexUUIDSCopy =
new HashMap<>(currentAutoFollowMetadata.getFollowedLeaderIndexUUIDs());
final Map<String, Map<String, String>> headers = new HashMap<>(currentAutoFollowMetadata.getHeaders());
patternsCopy.remove(request.getLeaderCluster());
followedLeaderIndexUUIDSCopy.remove(request.getLeaderCluster());
headers.remove(request.getLeaderCluster());
patternsCopy.remove(request.getName());
followedLeaderIndexUUIDSCopy.remove(request.getName());
headers.remove(request.getName());
AutoFollowMetadata newAutoFollowMetadata = new AutoFollowMetadata(patternsCopy, followedLeaderIndexUUIDSCopy, headers);
ClusterState.Builder newState = ClusterState.builder(currentState);

View File

@ -55,7 +55,7 @@ public class TransportGetAutoFollowPatternAction
protected void masterOperation(GetAutoFollowPatternAction.Request request,
ClusterState state,
ActionListener<GetAutoFollowPatternAction.Response> listener) throws Exception {
Map<String, AutoFollowPattern> autoFollowPatterns = getAutoFollowPattern(state.metaData(), request.getLeaderCluster());
Map<String, AutoFollowPattern> autoFollowPatterns = getAutoFollowPattern(state.metaData(), request.getName());
listener.onResponse(new GetAutoFollowPatternAction.Response(autoFollowPatterns));
}
@ -64,20 +64,20 @@ public class TransportGetAutoFollowPatternAction
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
}
static Map<String, AutoFollowPattern> getAutoFollowPattern(MetaData metaData, String leaderClusterAlias) {
static Map<String, AutoFollowPattern> getAutoFollowPattern(MetaData metaData, String name) {
AutoFollowMetadata autoFollowMetadata = metaData.custom(AutoFollowMetadata.TYPE);
if (autoFollowMetadata == null) {
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found", leaderClusterAlias);
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing", name);
}
if (leaderClusterAlias == null) {
if (name == null) {
return autoFollowMetadata.getPatterns();
}
AutoFollowPattern autoFollowPattern = autoFollowMetadata.getPatterns().get(leaderClusterAlias);
AutoFollowPattern autoFollowPattern = autoFollowMetadata.getPatterns().get(name);
if (autoFollowPattern == null) {
throw new ResourceNotFoundException("no auto-follow patterns for cluster alias [{}] found", leaderClusterAlias);
throw new ResourceNotFoundException("auto-follow pattern [{}] is missing", name);
}
return Collections.singletonMap(leaderClusterAlias, autoFollowPattern);
return Collections.singletonMap(name, autoFollowPattern);
}
}

View File

@ -135,14 +135,14 @@ public class TransportPutAutoFollowPatternAction extends
headers = new HashMap<>();
}
AutoFollowPattern previousPattern = patterns.get(request.getLeaderCluster());
AutoFollowPattern previousPattern = patterns.get(request.getName());
final List<String> followedIndexUUIDs;
if (followedLeaderIndices.containsKey(request.getLeaderCluster())) {
followedIndexUUIDs = new ArrayList<>(followedLeaderIndices.get(request.getLeaderCluster()));
if (followedLeaderIndices.containsKey(request.getName())) {
followedIndexUUIDs = new ArrayList<>(followedLeaderIndices.get(request.getName()));
} else {
followedIndexUUIDs = new ArrayList<>();
}
followedLeaderIndices.put(request.getLeaderCluster(), followedIndexUUIDs);
followedLeaderIndices.put(request.getName(), followedIndexUUIDs);
// Mark existing leader indices as already auto followed:
if (previousPattern != null) {
markExistingIndicesAsAutoFollowedForNewPatterns(request.getLeaderIndexPatterns(), leaderClusterState.metaData(),
@ -153,10 +153,11 @@ public class TransportPutAutoFollowPatternAction extends
}
if (filteredHeaders != null) {
headers.put(request.getLeaderCluster(), filteredHeaders);
headers.put(request.getName(), filteredHeaders);
}
AutoFollowPattern autoFollowPattern = new AutoFollowPattern(
request.getLeaderCluster(),
request.getLeaderIndexPatterns(),
request.getFollowIndexNamePattern(),
request.getMaxBatchOperationCount(),
@ -166,7 +167,7 @@ public class TransportPutAutoFollowPatternAction extends
request.getMaxWriteBufferSize(),
request.getMaxRetryDelay(),
request.getPollTimeout());
patterns.put(request.getLeaderCluster(), autoFollowPattern);
patterns.put(request.getName(), autoFollowPattern);
ClusterState.Builder newState = ClusterState.builder(localState);
newState.metaData(MetaData.builder(localState.getMetaData())
.putCustom(AutoFollowMetadata.TYPE, new AutoFollowMetadata(patterns, followedLeaderIndices, headers))

View File

@ -21,7 +21,7 @@ public class RestDeleteAutoFollowPatternAction extends BaseRestHandler {
public RestDeleteAutoFollowPatternAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.DELETE, "/_ccr/auto_follow/{leader_cluster}", this);
controller.registerHandler(RestRequest.Method.DELETE, "/_ccr/auto_follow/{name}", this);
}
@Override
@ -32,7 +32,7 @@ public class RestDeleteAutoFollowPatternAction extends BaseRestHandler {
@Override
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
Request request = new Request();
request.setLeaderCluster(restRequest.param("leader_cluster"));
request.setName(restRequest.param("name"));
return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel));
}

View File

@ -21,7 +21,7 @@ public class RestGetAutoFollowPatternAction extends BaseRestHandler {
public RestGetAutoFollowPatternAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.GET, "/_ccr/auto_follow/{leader_cluster}", this);
controller.registerHandler(RestRequest.Method.GET, "/_ccr/auto_follow/{name}", this);
controller.registerHandler(RestRequest.Method.GET, "/_ccr/auto_follow", this);
}
@ -33,7 +33,7 @@ public class RestGetAutoFollowPatternAction extends BaseRestHandler {
@Override
protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
Request request = new Request();
request.setLeaderCluster(restRequest.param("leader_cluster"));
request.setName(restRequest.param("name"));
return channel -> client.execute(INSTANCE, request, new RestToXContentListener<>(channel));
}

View File

@ -22,7 +22,7 @@ public class RestPutAutoFollowPatternAction extends BaseRestHandler {
public RestPutAutoFollowPatternAction(Settings settings, RestController controller) {
super(settings);
controller.registerHandler(RestRequest.Method.PUT, "/_ccr/auto_follow/{leader_cluster}", this);
controller.registerHandler(RestRequest.Method.PUT, "/_ccr/auto_follow/{name}", this);
}
@Override
@ -38,7 +38,7 @@ public class RestPutAutoFollowPatternAction extends BaseRestHandler {
static Request createRequest(RestRequest restRequest) throws IOException {
try (XContentParser parser = restRequest.contentOrSourceParamParser()) {
return Request.fromXContent(parser, restRequest.param("leader_cluster"));
return Request.fromXContent(parser, restRequest.param("name"));
}
}
}

View File

@ -5,6 +5,7 @@
*/
package org.elasticsearch.xpack.ccr;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest;
import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -26,6 +27,7 @@ import java.util.Arrays;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.notNullValue;
public class AutoFollowIT extends CcrIntegTestCase {
@ -45,7 +47,12 @@ public class AutoFollowIT extends CcrIntegTestCase {
createLeaderIndex("logs-201812", leaderIndexSettings);
// Enabling auto following:
putAutoFollowPatterns("logs-*", "transactions-*");
if (randomBoolean()) {
putAutoFollowPatterns("my-pattern", new String[] {"logs-*", "transactions-*"});
} else {
putAutoFollowPatterns("my-pattern1", new String[] {"logs-*"});
putAutoFollowPatterns("my-pattern2", new String[] {"transactions-*"});
}
createLeaderIndex("metrics-201901", leaderIndexSettings);
@ -76,7 +83,7 @@ public class AutoFollowIT extends CcrIntegTestCase {
.put(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0)
.build();
putAutoFollowPatterns("logs-*");
putAutoFollowPatterns("my-pattern", new String[] {"logs-*"});
int numIndices = randomIntBetween(4, 32);
for (int i = 0; i < numIndices; i++) {
createLeaderIndex("logs-" + i, leaderIndexSettings);
@ -90,7 +97,7 @@ public class AutoFollowIT extends CcrIntegTestCase {
deleteAutoFollowPatternSetting();
createLeaderIndex("logs-does-not-count", leaderIndexSettings);
putAutoFollowPatterns("logs-*");
putAutoFollowPatterns("my-pattern", new String[] {"logs-*"});
int i = numIndices;
numIndices = numIndices + randomIntBetween(4, 32);
for (; i < numIndices; i++) {
@ -113,6 +120,7 @@ public class AutoFollowIT extends CcrIntegTestCase {
// Enabling auto following:
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName("my-pattern");
request.setLeaderCluster("leader_cluster");
request.setLeaderIndexPatterns(Collections.singletonList("logs-*"));
// Need to set this, because following an index in the same cluster
@ -173,8 +181,53 @@ public class AutoFollowIT extends CcrIntegTestCase {
});
}
private void putAutoFollowPatterns(String... patterns) {
public void testConflictingPatterns() throws Exception {
Settings leaderIndexSettings = Settings.builder()
.put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true)
.put(IndexMetaData.INDEX_NUMBER_OF_SHARDS_SETTING.getKey(), 1)
.put(IndexMetaData.INDEX_NUMBER_OF_REPLICAS_SETTING.getKey(), 0)
.build();
// Enabling auto following:
putAutoFollowPatterns("my-pattern1", new String[] {"logs-*"});
putAutoFollowPatterns("my-pattern2", new String[] {"logs-2018*"});
createLeaderIndex("logs-201701", leaderIndexSettings);
assertBusy(() -> {
AutoFollowStats autoFollowStats = getAutoFollowStats();
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(1L));
assertThat(autoFollowStats.getNumberOfFailedFollowIndices(), equalTo(0L));
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(0L));
});
IndicesExistsRequest request = new IndicesExistsRequest("copy-logs-201701");
assertTrue(followerClient().admin().indices().exists(request).actionGet().isExists());
createLeaderIndex("logs-201801", leaderIndexSettings);
assertBusy(() -> {
AutoFollowStats autoFollowStats = getAutoFollowStats();
assertThat(autoFollowStats.getNumberOfSuccessfulFollowIndices(), equalTo(1L));
assertThat(autoFollowStats.getNumberOfFailedFollowIndices(), greaterThanOrEqualTo(1L));
assertThat(autoFollowStats.getNumberOfFailedRemoteClusterStateRequests(), equalTo(0L));
assertThat(autoFollowStats.getRecentAutoFollowErrors().size(), equalTo(2));
ElasticsearchException autoFollowError1 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern1:logs-201801");
assertThat(autoFollowError1, notNullValue());
assertThat(autoFollowError1.getRootCause().getMessage(), equalTo("index to follow [logs-201801] for pattern [my-pattern1] " +
"matches with other patterns [my-pattern2]"));
ElasticsearchException autoFollowError2 = autoFollowStats.getRecentAutoFollowErrors().get("my-pattern2:logs-201801");
assertThat(autoFollowError2, notNullValue());
assertThat(autoFollowError2.getRootCause().getMessage(), equalTo("index to follow [logs-201801] for pattern [my-pattern2] " +
"matches with other patterns [my-pattern1]"));
});
request = new IndicesExistsRequest("copy-logs-201801");
assertFalse(followerClient().admin().indices().exists(request).actionGet().isExists());
}
private void putAutoFollowPatterns(String name, String[] patterns) {
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName(name);
request.setLeaderCluster("leader_cluster");
request.setLeaderIndexPatterns(Arrays.asList(patterns));
// Need to set this, because following an index in the same cluster
@ -184,7 +237,7 @@ public class AutoFollowIT extends CcrIntegTestCase {
private void deleteAutoFollowPatternSetting() {
DeleteAutoFollowPatternAction.Request request = new DeleteAutoFollowPatternAction.Request();
request.setLeaderCluster("leader_cluster");
request.setName("my-pattern");
assertTrue(followerClient().execute(DeleteAutoFollowPatternAction.INSTANCE, request).actionGet().isAcknowledged());
}

View File

@ -41,6 +41,7 @@ public class AutoFollowMetadataTests extends AbstractSerializingTestCase<AutoFol
for (int i = 0; i < numEntries; i++) {
List<String> leaderPatterns = Arrays.asList(generateRandomStringArray(4, 4, false));
AutoFollowMetadata.AutoFollowPattern autoFollowPattern = new AutoFollowMetadata.AutoFollowPattern(
randomAlphaOfLength(4),
leaderPatterns,
randomAlphaOfLength(4),
randomIntBetween(0, Integer.MAX_VALUE),

View File

@ -118,6 +118,7 @@ public class CcrLicenseIT extends CcrSingleNodeTestCase {
public void testThatPutAutoFollowPatternsIsUnavailableWithNonCompliantLicense() throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName("name");
request.setLeaderCluster("leader");
request.setLeaderIndexPatterns(Collections.singletonList("*"));
client().execute(
@ -147,8 +148,8 @@ public class CcrLicenseIT extends CcrSingleNodeTestCase {
@Override
public ClusterState execute(ClusterState currentState) throws Exception {
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
AutoFollowPattern autoFollowPattern = new AutoFollowPattern("test_alias", Collections.singletonList("logs-*"),
null, null, null, null, null, null, null, null);
AutoFollowMetadata autoFollowMetadata = new AutoFollowMetadata(
Collections.singletonMap("test_alias", autoFollowPattern),
Collections.emptyMap(),

View File

@ -683,6 +683,7 @@ public class IndexFollowingIT extends CcrIntegTestCase {
() -> followerClient().execute(ResumeFollowAction.INSTANCE, followRequest.getFollowRequest()).actionGet());
assertThat(e.getMessage(), equalTo("unknown cluster alias [another_cluster]"));
PutAutoFollowPatternAction.Request putAutoFollowRequest = new PutAutoFollowPatternAction.Request();
putAutoFollowRequest.setName("name");
putAutoFollowRequest.setLeaderCluster("another_cluster");
putAutoFollowRequest.setLeaderIndexPatterns(Collections.singletonList("logs-*"));
e = expectThrows(IllegalArgumentException.class,

View File

@ -56,7 +56,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
.build();
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
new AutoFollowPattern("remote", Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("remote", autoFollowPattern);
Map<String, List<String>> followedLeaderIndexUUIDS = new HashMap<>();
@ -120,7 +120,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
when(client.getRemoteClusterClient(anyString())).thenReturn(client);
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
new AutoFollowPattern("remote", Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("remote", autoFollowPattern);
Map<String, List<String>> followedLeaderIndexUUIDS = new HashMap<>();
@ -178,7 +178,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
.build();
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
new AutoFollowPattern("remote", Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("remote", autoFollowPattern);
Map<String, List<String>> followedLeaderIndexUUIDS = new HashMap<>();
@ -241,7 +241,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
.build();
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
new AutoFollowPattern("remote", Collections.singletonList("logs-*"), null, null, null, null, null, null, null, null);
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("remote", autoFollowPattern);
Map<String, List<String>> followedLeaderIndexUUIDS = new HashMap<>();
@ -295,7 +295,7 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
public void testGetLeaderIndicesToFollow() {
AutoFollowPattern autoFollowPattern =
new AutoFollowPattern(Collections.singletonList("metrics-*"), null, null, null, null, null, null, null, null);
new AutoFollowPattern("remote", Collections.singletonList("metrics-*"), null, null, null, null, null, null, null, null);
Map<String, Map<String, String>> headers = new HashMap<>();
ClusterState followerState = ClusterState.builder(new ClusterName("remote"))
.metaData(MetaData.builder().putCustom(AutoFollowMetadata.TYPE,
@ -342,15 +342,15 @@ public class AutoFollowCoordinatorTests extends ESTestCase {
}
public void testGetFollowerIndexName() {
AutoFollowPattern autoFollowPattern = new AutoFollowPattern(Collections.singletonList("metrics-*"), null, null,
AutoFollowPattern autoFollowPattern = new AutoFollowPattern("remote", Collections.singletonList("metrics-*"), null, null,
null, null, null, null, null, null);
assertThat(AutoFollower.getFollowerIndexName(autoFollowPattern, "metrics-0"), equalTo("metrics-0"));
autoFollowPattern = new AutoFollowPattern(Collections.singletonList("metrics-*"), "eu-metrics-0", null, null,
autoFollowPattern = new AutoFollowPattern("remote", Collections.singletonList("metrics-*"), "eu-metrics-0", null, null,
null, null, null, null, null);
assertThat(AutoFollower.getFollowerIndexName(autoFollowPattern, "metrics-0"), equalTo("eu-metrics-0"));
autoFollowPattern = new AutoFollowPattern(Collections.singletonList("metrics-*"), "eu-{{leader_index}}", null,
autoFollowPattern = new AutoFollowPattern("remote", Collections.singletonList("metrics-*"), "eu-{{leader_index}}", null,
null, null, null, null, null, null);
assertThat(AutoFollower.getFollowerIndexName(autoFollowPattern, "metrics-0"), equalTo("eu-metrics-0"));
}

View File

@ -18,7 +18,7 @@ public class DeleteAutoFollowPatternRequestTests extends AbstractStreamableTestC
@Override
protected DeleteAutoFollowPatternAction.Request createTestInstance() {
DeleteAutoFollowPatternAction.Request request = new DeleteAutoFollowPatternAction.Request();
request.setLeaderCluster(randomAlphaOfLength(4));
request.setName(randomAlphaOfLength(4));
return request;
}
}

View File

@ -20,7 +20,7 @@ public class GetAutoFollowPatternRequestTests extends AbstractWireSerializingTes
protected GetAutoFollowPatternAction.Request createTestInstance() {
GetAutoFollowPatternAction.Request request = new GetAutoFollowPatternAction.Request();
if (randomBoolean()) {
request.setLeaderCluster(randomAlphaOfLength(4));
request.setName(randomAlphaOfLength(4));
}
return request;
}

View File

@ -29,6 +29,7 @@ public class GetAutoFollowPatternResponseTests extends AbstractStreamableTestCas
Map<String, AutoFollowPattern> patterns = new HashMap<>(numPatterns);
for (int i = 0; i < numPatterns; i++) {
AutoFollowPattern autoFollowPattern = new AutoFollowPattern(
"remote",
Collections.singletonList(randomAlphaOfLength(4)),
randomAlphaOfLength(4),
randomIntBetween(0, Integer.MAX_VALUE),

View File

@ -41,6 +41,7 @@ public class PutAutoFollowPatternRequestTests extends AbstractStreamableXContent
@Override
protected PutAutoFollowPatternAction.Request createTestInstance() {
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName(randomAlphaOfLength(4));
request.setLeaderCluster(randomAlphaOfLength(4));
request.setLeaderIndexPatterns(Arrays.asList(generateRandomStringArray(4, 4, false)));
if (randomBoolean()) {
@ -74,6 +75,11 @@ public class PutAutoFollowPatternRequestTests extends AbstractStreamableXContent
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
ActionRequestValidationException validationException = request.validate();
assertThat(validationException, notNullValue());
assertThat(validationException.getMessage(), containsString("[name] is missing"));
request.setName("name");
validationException = request.validate();
assertThat(validationException, notNullValue());
assertThat(validationException.getMessage(), containsString("[leader_cluster] is missing"));
request.setLeaderCluster("_alias");

View File

@ -10,6 +10,7 @@ import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata.AutoFollowPattern;
import org.elasticsearch.xpack.core.ccr.action.DeleteAutoFollowPatternAction.Request;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
@ -27,28 +28,28 @@ public class TransportDeleteAutoFollowPatternActionTests extends ESTestCase {
public void testInnerDelete() {
Map<String, List<String>> existingAlreadyFollowedIndexUUIDS = new HashMap<>();
Map<String, Map<String, String>> existingHeaders = new HashMap<>();
Map<String, AutoFollowMetadata.AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
Map<String, AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
{
List<String> existingPatterns = new ArrayList<>();
existingPatterns.add("transactions-*");
existingAutoFollowPatterns.put("eu_cluster",
new AutoFollowMetadata.AutoFollowPattern(existingPatterns, null, null, null, null, null, null, null, null));
existingAutoFollowPatterns.put("name1",
new AutoFollowPattern("eu_cluster", existingPatterns, null, null, null, null, null, null, null, null));
List<String> existingUUIDS = new ArrayList<>();
existingUUIDS.add("_val");
existingAlreadyFollowedIndexUUIDS.put("eu_cluster", existingUUIDS);
existingHeaders.put("eu_cluster", Collections.singletonMap("key", "val"));
existingAlreadyFollowedIndexUUIDS.put("name1", existingUUIDS);
existingHeaders.put("name1", Collections.singletonMap("key", "val"));
}
{
List<String> existingPatterns = new ArrayList<>();
existingPatterns.add("logs-*");
existingAutoFollowPatterns.put("asia_cluster",
new AutoFollowMetadata.AutoFollowPattern(existingPatterns, null, null, null, null, null, null, null, null));
existingAutoFollowPatterns.put("name2",
new AutoFollowPattern("asia_cluster", existingPatterns, null, null, null, null, null, null, null, null));
List<String> existingUUIDS = new ArrayList<>();
existingUUIDS.add("_val");
existingAlreadyFollowedIndexUUIDS.put("asia_cluster", existingUUIDS);
existingHeaders.put("asia_cluster", Collections.singletonMap("key", "val"));
existingAlreadyFollowedIndexUUIDS.put("name2", existingUUIDS);
existingHeaders.put("name2", Collections.singletonMap("key", "val"));
}
ClusterState clusterState = ClusterState.builder(new ClusterName("us_cluster"))
.metaData(MetaData.builder().putCustom(AutoFollowMetadata.TYPE,
@ -56,27 +57,28 @@ public class TransportDeleteAutoFollowPatternActionTests extends ESTestCase {
.build();
Request request = new Request();
request.setLeaderCluster("eu_cluster");
request.setName("name1");
AutoFollowMetadata result = TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState)
.getMetaData()
.custom(AutoFollowMetadata.TYPE);
assertThat(result.getPatterns().size(), equalTo(1));
assertThat(result.getPatterns().get("asia_cluster"), notNullValue());
assertThat(result.getPatterns().get("name2"), notNullValue());
assertThat(result.getPatterns().get("name2").getLeaderCluster(), equalTo("asia_cluster"));
assertThat(result.getFollowedLeaderIndexUUIDs().size(), equalTo(1));
assertThat(result.getFollowedLeaderIndexUUIDs().get("asia_cluster"), notNullValue());
assertThat(result.getFollowedLeaderIndexUUIDs().get("name2"), notNullValue());
assertThat(result.getHeaders().size(), equalTo(1));
assertThat(result.getHeaders().get("asia_cluster"), notNullValue());
assertThat(result.getHeaders().get("name2"), notNullValue());
}
public void testInnerDeleteDoesNotExist() {
Map<String, List<String>> existingAlreadyFollowedIndexUUIDS = new HashMap<>();
Map<String, AutoFollowMetadata.AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
Map<String, AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
Map<String, Map<String, String>> existingHeaders = new HashMap<>();
{
List<String> existingPatterns = new ArrayList<>();
existingPatterns.add("transactions-*");
existingAutoFollowPatterns.put("eu_cluster",
new AutoFollowMetadata.AutoFollowPattern(existingPatterns, null, null, null, null, null, null, null, null));
existingAutoFollowPatterns.put("name1",
new AutoFollowPattern("eu_cluster", existingPatterns, null, null, null, null, null, null, null, null));
existingHeaders.put("key", Collections.singletonMap("key", "val"));
}
ClusterState clusterState = ClusterState.builder(new ClusterName("us_cluster"))
@ -85,10 +87,10 @@ public class TransportDeleteAutoFollowPatternActionTests extends ESTestCase {
.build();
Request request = new Request();
request.setLeaderCluster("asia_cluster");
request.setName("name2");
Exception e = expectThrows(ResourceNotFoundException.class,
() -> TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState));
assertThat(e.getMessage(), equalTo("no auto-follow patterns for cluster alias [asia_cluster] found"));
assertThat(e.getMessage(), equalTo("auto-follow pattern [name2] is missing"));
}
public void testInnerDeleteNoAutoFollowMetadata() {
@ -97,10 +99,10 @@ public class TransportDeleteAutoFollowPatternActionTests extends ESTestCase {
.build();
Request request = new Request();
request.setLeaderCluster("asia_cluster");
request.setName("name1");
Exception e = expectThrows(ResourceNotFoundException.class,
() -> TransportDeleteAutoFollowPatternAction.innerDelete(request, clusterState));
assertThat(e.getMessage(), equalTo("no auto-follow patterns for cluster alias [asia_cluster] found"));
assertThat(e.getMessage(), equalTo("auto-follow pattern [name1] is missing"));
}
}

View File

@ -23,22 +23,22 @@ public class TransportGetAutoFollowPatternActionTests extends ESTestCase {
public void testGetAutoFollowPattern() {
Map<String, AutoFollowPattern> patterns = new HashMap<>();
patterns.put("test_alias1",
new AutoFollowPattern(Collections.singletonList("index-*"), null, null, null, null, null, null, null, null));
patterns.put("test_alias2",
new AutoFollowPattern(Collections.singletonList("index-*"), null, null, null, null, null, null, null, null));
patterns.put("name1",
new AutoFollowPattern("test_alias1", Collections.singletonList("index-*"), null, null, null, null, null, null, null, null));
patterns.put("name2",
new AutoFollowPattern("test_alias1", Collections.singletonList("index-*"), null, null, null, null, null, null, null, null));
MetaData metaData = MetaData.builder()
.putCustom(AutoFollowMetadata.TYPE, new AutoFollowMetadata(patterns, Collections.emptyMap(), Collections.emptyMap()))
.build();
Map<String, AutoFollowPattern> result = TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "test_alias1");
Map<String, AutoFollowPattern> result = TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "name1");
assertThat(result.size(), equalTo(1));
assertThat(result, hasEntry("test_alias1", patterns.get("test_alias1")));
assertThat(result, hasEntry("name1", patterns.get("name1")));
result = TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, null);
assertThat(result.size(), equalTo(2));
assertThat(result, hasEntry("test_alias1", patterns.get("test_alias1")));
assertThat(result, hasEntry("test_alias2", patterns.get("test_alias2")));
assertThat(result, hasEntry("name1", patterns.get("name1")));
assertThat(result, hasEntry("name2", patterns.get("name2")));
expectThrows(ResourceNotFoundException.class,
() -> TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "another_alias"));
@ -51,13 +51,13 @@ public class TransportGetAutoFollowPatternActionTests extends ESTestCase {
.putCustom(AutoFollowMetadata.TYPE, autoFollowMetadata)
.build();
expectThrows(ResourceNotFoundException.class,
() -> TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "test_alias"));
() -> TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "name1"));
}
public void testGetAutoFollowPatternNoAutoFollowMetadata() {
MetaData metaData = MetaData.builder().build();
expectThrows(ResourceNotFoundException.class,
() -> TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "test_alias"));
() -> TransportGetAutoFollowPatternAction.getAutoFollowPattern(metaData, "name1"));
}
}

View File

@ -12,6 +12,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata;
import org.elasticsearch.xpack.core.ccr.AutoFollowMetadata.AutoFollowPattern;
import org.elasticsearch.xpack.core.ccr.action.PutAutoFollowPatternAction;
import java.util.ArrayList;
@ -28,6 +29,7 @@ public class TransportPutAutoFollowPatternActionTests extends ESTestCase {
public void testInnerPut() {
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName("name1");
request.setLeaderCluster("eu_cluster");
request.setLeaderIndexPatterns(Collections.singletonList("logs-*"));
@ -43,14 +45,16 @@ public class TransportPutAutoFollowPatternActionTests extends ESTestCase {
AutoFollowMetadata autoFollowMetadata = result.metaData().custom(AutoFollowMetadata.TYPE);
assertThat(autoFollowMetadata, notNullValue());
assertThat(autoFollowMetadata.getPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderCluster(), equalTo("eu_cluster"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().size(), equalTo(1));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("eu_cluster").size(), equalTo(0));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("name1").size(), equalTo(0));
}
public void testInnerPut_existingLeaderIndices() {
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName("name1");
request.setLeaderCluster("eu_cluster");
request.setLeaderIndexPatterns(Collections.singletonList("logs-*"));
@ -82,28 +86,30 @@ public class TransportPutAutoFollowPatternActionTests extends ESTestCase {
AutoFollowMetadata autoFollowMetadata = result.metaData().custom(AutoFollowMetadata.TYPE);
assertThat(autoFollowMetadata, notNullValue());
assertThat(autoFollowMetadata.getPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderCluster(), equalTo("eu_cluster"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().size(), equalTo(1));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("eu_cluster").size(), equalTo(numMatchingLeaderIndices));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("name1").size(), equalTo(numMatchingLeaderIndices));
}
public void testInnerPut_existingLeaderIndicesAndAutoFollowMetadata() {
PutAutoFollowPatternAction.Request request = new PutAutoFollowPatternAction.Request();
request.setName("name1");
request.setLeaderCluster("eu_cluster");
request.setLeaderIndexPatterns(Arrays.asList("logs-*", "transactions-*"));
Map<String, AutoFollowMetadata.AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
Map<String, AutoFollowPattern> existingAutoFollowPatterns = new HashMap<>();
List<String> existingPatterns = new ArrayList<>();
existingPatterns.add("transactions-*");
existingAutoFollowPatterns.put("eu_cluster",
new AutoFollowMetadata.AutoFollowPattern(existingPatterns, null, null, null, null, null, null, null, null));
existingAutoFollowPatterns.put("name1",
new AutoFollowPattern("eu_cluster", existingPatterns, null, null, null, null, null, null, null, null));
Map<String, List<String>> existingAlreadyFollowedIndexUUIDS = new HashMap<>();
List<String> existingUUIDS = new ArrayList<>();
existingUUIDS.add("_val");
existingAlreadyFollowedIndexUUIDS.put("eu_cluster", existingUUIDS);
existingAlreadyFollowedIndexUUIDS.put("name1", existingUUIDS);
Map<String, Map<String, String>> existingHeaders = new HashMap<>();
existingHeaders.put("eu_cluster", Collections.singletonMap("key", "val"));
existingHeaders.put("name1", Collections.singletonMap("key", "val"));
ClusterState localState = ClusterState.builder(new ClusterName("us_cluster"))
.metaData(MetaData.builder().putCustom(AutoFollowMetadata.TYPE,
@ -127,13 +133,14 @@ public class TransportPutAutoFollowPatternActionTests extends ESTestCase {
AutoFollowMetadata autoFollowMetadata = result.metaData().custom(AutoFollowMetadata.TYPE);
assertThat(autoFollowMetadata, notNullValue());
assertThat(autoFollowMetadata.getPatterns().size(), equalTo(1));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().size(), equalTo(2));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getPatterns().get("eu_cluster").getLeaderIndexPatterns().get(1), equalTo("transactions-*"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderCluster(), equalTo("eu_cluster"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().size(), equalTo(2));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().get(0), equalTo("logs-*"));
assertThat(autoFollowMetadata.getPatterns().get("name1").getLeaderIndexPatterns().get(1), equalTo("transactions-*"));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().size(), equalTo(1));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("eu_cluster").size(), equalTo(numLeaderIndices + 1));
assertThat(autoFollowMetadata.getFollowedLeaderIndexUUIDs().get("name1").size(), equalTo(numLeaderIndices + 1));
assertThat(autoFollowMetadata.getHeaders().size(), equalTo(1));
assertThat(autoFollowMetadata.getHeaders().get("eu_cluster"), notNullValue());
assertThat(autoFollowMetadata.getHeaders().get("name1"), notNullValue());
}
}

View File

@ -175,6 +175,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
public static class AutoFollowPattern implements Writeable, ToXContentObject {
public static final ParseField LEADER_CLUSTER_FIELD = new ParseField("leader_cluster");
public static final ParseField LEADER_PATTERNS_FIELD = new ParseField("leader_index_patterns");
public static final ParseField FOLLOW_PATTERN_FIELD = new ParseField("follow_index_pattern");
public static final ParseField MAX_BATCH_OPERATION_COUNT = new ParseField("max_batch_operation_count");
@ -188,10 +189,12 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
@SuppressWarnings("unchecked")
private static final ConstructingObjectParser<AutoFollowPattern, Void> PARSER =
new ConstructingObjectParser<>("auto_follow_pattern",
args -> new AutoFollowPattern((List<String>) args[0], (String) args[1], (Integer) args[2], (Integer) args[3],
(ByteSizeValue) args[4], (Integer) args[5], (Integer) args[6], (TimeValue) args[7], (TimeValue) args[8]));
args -> new AutoFollowPattern((String) args[0], (List<String>) args[1], (String) args[2], (Integer) args[3],
(Integer) args[4], (ByteSizeValue) args[5], (Integer) args[6], (Integer) args[7], (TimeValue) args[8],
(TimeValue) args[9]));
static {
PARSER.declareString(ConstructingObjectParser.constructorArg(), LEADER_CLUSTER_FIELD);
PARSER.declareStringArray(ConstructingObjectParser.constructorArg(), LEADER_PATTERNS_FIELD);
PARSER.declareString(ConstructingObjectParser.optionalConstructorArg(), FOLLOW_PATTERN_FIELD);
PARSER.declareInt(ConstructingObjectParser.optionalConstructorArg(), MAX_BATCH_OPERATION_COUNT);
@ -211,6 +214,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
POLL_TIMEOUT, ObjectParser.ValueType.STRING);
}
private final String leaderCluster;
private final List<String> leaderIndexPatterns;
private final String followIndexPattern;
private final Integer maxBatchOperationCount;
@ -221,7 +225,8 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
private final TimeValue maxRetryDelay;
private final TimeValue pollTimeout;
public AutoFollowPattern(List<String> leaderIndexPatterns,
public AutoFollowPattern(String leaderCluster,
List<String> leaderIndexPatterns,
String followIndexPattern,
Integer maxBatchOperationCount,
Integer maxConcurrentReadBatches,
@ -230,6 +235,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
Integer maxWriteBufferSize,
TimeValue maxRetryDelay,
TimeValue pollTimeout) {
this.leaderCluster = leaderCluster;
this.leaderIndexPatterns = leaderIndexPatterns;
this.followIndexPattern = followIndexPattern;
this.maxBatchOperationCount = maxBatchOperationCount;
@ -242,6 +248,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
}
public AutoFollowPattern(StreamInput in) throws IOException {
leaderCluster = in.readString();
leaderIndexPatterns = in.readList(StreamInput::readString);
followIndexPattern = in.readOptionalString();
maxBatchOperationCount = in.readOptionalVInt();
@ -261,6 +268,10 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
return Regex.simpleMatch(leaderIndexPatterns, indexName);
}
public String getLeaderCluster() {
return leaderCluster;
}
public List<String> getLeaderIndexPatterns() {
return leaderIndexPatterns;
}
@ -299,6 +310,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(leaderCluster);
out.writeStringList(leaderIndexPatterns);
out.writeOptionalString(followIndexPattern);
out.writeOptionalVInt(maxBatchOperationCount);
@ -312,6 +324,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field(LEADER_CLUSTER_FIELD.getPreferredName(), leaderCluster);
builder.array(LEADER_PATTERNS_FIELD.getPreferredName(), leaderIndexPatterns.toArray(new String[0]));
if (followIndexPattern != null) {
builder.field(FOLLOW_PATTERN_FIELD.getPreferredName(), followIndexPattern);
@ -350,7 +363,8 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AutoFollowPattern that = (AutoFollowPattern) o;
return Objects.equals(leaderIndexPatterns, that.leaderIndexPatterns) &&
return Objects.equals(leaderCluster, that.leaderCluster) &&
Objects.equals(leaderIndexPatterns, that.leaderIndexPatterns) &&
Objects.equals(followIndexPattern, that.followIndexPattern) &&
Objects.equals(maxBatchOperationCount, that.maxBatchOperationCount) &&
Objects.equals(maxConcurrentReadBatches, that.maxConcurrentReadBatches) &&
@ -364,6 +378,7 @@ public class AutoFollowMetadata extends AbstractNamedDiffable<MetaData.Custom> i
@Override
public int hashCode() {
return Objects.hash(
leaderCluster,
leaderIndexPatterns,
followIndexPattern,
maxBatchOperationCount,

View File

@ -33,35 +33,35 @@ public class DeleteAutoFollowPatternAction extends Action<AcknowledgedResponse>
public static class Request extends AcknowledgedRequest<Request> {
private String leaderCluster;
private String name;
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (leaderCluster == null) {
validationException = addValidationError("leaderCluster is missing", validationException);
if (name == null) {
validationException = addValidationError("name is missing", validationException);
}
return validationException;
}
public String getLeaderCluster() {
return leaderCluster;
public String getName() {
return name;
}
public void setLeaderCluster(String leaderCluster) {
this.leaderCluster = leaderCluster;
public void setName(String name) {
this.name = name;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
leaderCluster = in.readString();
name = in.readString();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(leaderCluster);
out.writeString(name);
}
@Override
@ -69,12 +69,12 @@ public class DeleteAutoFollowPatternAction extends Action<AcknowledgedResponse>
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Request request = (Request) o;
return Objects.equals(leaderCluster, request.leaderCluster);
return Objects.equals(name, request.name);
}
@Override
public int hashCode() {
return Objects.hash(leaderCluster);
return Objects.hash(name);
}
}

View File

@ -36,14 +36,14 @@ public class GetAutoFollowPatternAction extends Action<GetAutoFollowPatternActio
public static class Request extends MasterNodeReadRequest<Request> {
private String leaderCluster;
private String name;
public Request() {
}
public Request(StreamInput in) throws IOException {
super(in);
this.leaderCluster = in.readOptionalString();
this.name = in.readOptionalString();
}
@Override
@ -51,18 +51,18 @@ public class GetAutoFollowPatternAction extends Action<GetAutoFollowPatternActio
return null;
}
public String getLeaderCluster() {
return leaderCluster;
public String getName() {
return name;
}
public void setLeaderCluster(String leaderCluster) {
this.leaderCluster = leaderCluster;
public void setName(String name) {
this.name = name;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeOptionalString(leaderCluster);
out.writeOptionalString(name);
}
@Override
@ -70,12 +70,12 @@ public class GetAutoFollowPatternAction extends Action<GetAutoFollowPatternActio
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Request request = (Request) o;
return Objects.equals(leaderCluster, request.leaderCluster);
return Objects.equals(name, request.name);
}
@Override
public int hashCode() {
return Objects.hash(leaderCluster);
return Objects.hash(name);
}
}

View File

@ -46,8 +46,11 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
private static final ObjectParser<Request, String> PARSER = new ObjectParser<>("put_auto_follow_pattern_request", Request::new);
private static final ParseField NAME_FIELD = new ParseField("name");
static {
PARSER.declareString(Request::setLeaderCluster, LEADER_CLUSTER_FIELD);
PARSER.declareString(Request::setName, NAME_FIELD);
PARSER.declareString(Request::setLeaderCluster, AutoFollowPattern.LEADER_CLUSTER_FIELD);
PARSER.declareStringArray(Request::setLeaderIndexPatterns, AutoFollowPattern.LEADER_PATTERNS_FIELD);
PARSER.declareString(Request::setFollowIndexNamePattern, AutoFollowPattern.FOLLOW_PATTERN_FIELD);
PARSER.declareInt(Request::setMaxBatchOperationCount, AutoFollowPattern.MAX_BATCH_OPERATION_COUNT);
@ -67,20 +70,21 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
AutoFollowPattern.POLL_TIMEOUT, ObjectParser.ValueType.STRING);
}
public static Request fromXContent(XContentParser parser, String remoteClusterAlias) throws IOException {
public static Request fromXContent(XContentParser parser, String name) throws IOException {
Request request = PARSER.parse(parser, null);
if (remoteClusterAlias != null) {
if (request.leaderCluster == null) {
request.leaderCluster = remoteClusterAlias;
if (name != null) {
if (request.name == null) {
request.name = name;
} else {
if (request.leaderCluster.equals(remoteClusterAlias) == false) {
throw new IllegalArgumentException("provided leaderCluster is not equal");
if (request.name.equals(name) == false) {
throw new IllegalArgumentException("provided name is not equal");
}
}
}
return request;
}
private String name;
private String leaderCluster;
private List<String> leaderIndexPatterns;
private String followIndexNamePattern;
@ -96,8 +100,11 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
@Override
public ActionRequestValidationException validate() {
ActionRequestValidationException validationException = null;
if (name == null) {
validationException = addValidationError("[" + NAME_FIELD.getPreferredName() + "] is missing", validationException);
}
if (leaderCluster == null) {
validationException = addValidationError("[" + LEADER_CLUSTER_FIELD.getPreferredName() +
validationException = addValidationError("[" + AutoFollowPattern.LEADER_CLUSTER_FIELD.getPreferredName() +
"] is missing", validationException);
}
if (leaderIndexPatterns == null || leaderIndexPatterns.isEmpty()) {
@ -120,6 +127,14 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
return validationException;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLeaderCluster() {
return leaderCluster;
}
@ -203,6 +218,7 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
name = in.readString();
leaderCluster = in.readString();
leaderIndexPatterns = in.readList(StreamInput::readString);
followIndexNamePattern = in.readOptionalString();
@ -218,6 +234,7 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeString(name);
out.writeString(leaderCluster);
out.writeStringList(leaderIndexPatterns);
out.writeOptionalString(followIndexNamePattern);
@ -234,7 +251,8 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
{
builder.field(LEADER_CLUSTER_FIELD.getPreferredName(), leaderCluster);
builder.field(NAME_FIELD.getPreferredName(), name);
builder.field(AutoFollowPattern.LEADER_CLUSTER_FIELD.getPreferredName(), leaderCluster);
builder.field(AutoFollowPattern.LEADER_PATTERNS_FIELD.getPreferredName(), leaderIndexPatterns);
if (followIndexNamePattern != null) {
builder.field(AutoFollowPattern.FOLLOW_PATTERN_FIELD.getPreferredName(), followIndexNamePattern);
@ -270,7 +288,8 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Request request = (Request) o;
return Objects.equals(leaderCluster, request.leaderCluster) &&
return Objects.equals(name, request.name) &&
Objects.equals(leaderCluster, request.leaderCluster) &&
Objects.equals(leaderIndexPatterns, request.leaderIndexPatterns) &&
Objects.equals(followIndexNamePattern, request.followIndexNamePattern) &&
Objects.equals(maxBatchOperationCount, request.maxBatchOperationCount) &&
@ -285,7 +304,8 @@ public class PutAutoFollowPatternAction extends Action<AcknowledgedResponse> {
@Override
public int hashCode() {
return Objects.hash(
leaderCluster,
name,
leaderCluster,
leaderIndexPatterns,
followIndexNamePattern,
maxBatchOperationCount,

View File

@ -3,13 +3,13 @@
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current",
"methods": [ "DELETE" ],
"url": {
"path": "/_ccr/auto_follow/{leader_cluster}",
"paths": [ "/_ccr/auto_follow/{leader_cluster}" ],
"path": "/_ccr/auto_follow/{name}",
"paths": [ "/_ccr/auto_follow/{name}" ],
"parts": {
"leader_cluster": {
"name": {
"type": "string",
"required": true,
"description": "The name of the leader cluster alias."
"description": "The name of the auto follow pattern."
}
}
}

View File

@ -3,12 +3,12 @@
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current",
"methods": [ "GET" ],
"url": {
"path": "/_ccr/auto_follow/{leader_cluster}",
"paths": [ "/_ccr/auto_follow", "/_ccr/auto_follow/{leader_cluster}" ],
"path": "/_ccr/auto_follow/{name}",
"paths": [ "/_ccr/auto_follow", "/_ccr/auto_follow/{name}" ],
"parts": {
"leader_cluster": {
"name": {
"type": "string",
"description": "The name of the leader cluster alias."
"description": "The name of the auto follow pattern."
}
}
}

View File

@ -3,13 +3,13 @@
"documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/current",
"methods": [ "PUT" ],
"url": {
"path": "/_ccr/auto_follow/{leader_cluster}",
"paths": [ "/_ccr/auto_follow/{leader_cluster}" ],
"path": "/_ccr/auto_follow/{name}",
"paths": [ "/_ccr/auto_follow/{name}" ],
"parts": {
"leader_cluster": {
"name": {
"type": "string",
"required": true,
"description": "The name of the leader cluster alias."
"description": "The name of the auto follow pattern."
}
}
},