Skip to content

Commit 2ea8844

Browse files
authored
Fail earlier Put Follow requests for closed leader indices (#47582)
Today when following a new leader index, we fetch the remote cluster state, check the remote cluster license, check the user privileges, retrieve the index shard stats before initiating a CCR restore session. But if the leader index to follow is closed, we're executing a bunch of operations that would inevitability fail at some point (on retrieving the index shard stats, because this type of request forbid closed indices when resolving indices). We could fail a Put Follow request at the first step by checking the leader index state directly from the remote cluster state. This also helps the Resume Follow API to fail a bit earlier.
1 parent 413aad9 commit 2ea8844

File tree

2 files changed

+48
-1
lines changed

2 files changed

+48
-1
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.elasticsearch.index.engine.CommitStats;
3333
import org.elasticsearch.index.engine.Engine;
3434
import org.elasticsearch.index.shard.ShardId;
35+
import org.elasticsearch.indices.IndexClosedException;
3536
import org.elasticsearch.license.RemoteClusterLicenseChecker;
3637
import org.elasticsearch.license.XPackLicenseState;
3738
import org.elasticsearch.rest.RestStatus;
@@ -130,7 +131,10 @@ public void checkRemoteClusterLicenseAndFetchLeaderIndexMetadataAndHistoryUUIDs(
130131
onFailure.accept(new IndexNotFoundException(leaderIndex));
131132
return;
132133
}
133-
134+
if (leaderIndexMetaData.getState() == IndexMetaData.State.CLOSE) {
135+
onFailure.accept(new IndexClosedException(leaderIndexMetaData.getIndex()));
136+
return;
137+
}
134138
final Client remoteClient = client.getRemoteClusterClient(clusterAlias);
135139
hasPrivilegesToFollowIndices(remoteClient, new String[] {leaderIndex}, e -> {
136140
if (e == null) {

x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/ccr/IndexFollowingIT.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import org.elasticsearch.index.seqno.ReplicationTracker;
7171
import org.elasticsearch.index.seqno.RetentionLeaseActions;
7272
import org.elasticsearch.index.shard.ShardId;
73+
import org.elasticsearch.indices.IndexClosedException;
7374
import org.elasticsearch.persistent.PersistentTasksCustomMetaData;
7475
import org.elasticsearch.plugins.Plugin;
7576
import org.elasticsearch.rest.RestStatus;
@@ -109,6 +110,7 @@
109110
import java.util.function.BooleanSupplier;
110111
import java.util.function.Consumer;
111112
import java.util.stream.Collectors;
113+
import java.util.stream.IntStream;
112114
import java.util.stream.Stream;
113115

114116
import static java.util.Collections.singletonMap;
@@ -743,6 +745,47 @@ public void testDeleteLeaderIndex() throws Exception {
743745
ensureNoCcrTasks();
744746
}
745747

748+
public void testFollowClosedIndex() {
749+
final String leaderIndex = "test-index";
750+
assertAcked(leaderClient().admin().indices().prepareCreate(leaderIndex)
751+
.setSettings(Settings.builder()
752+
.put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true)
753+
.build()));
754+
assertAcked(leaderClient().admin().indices().prepareClose(leaderIndex));
755+
756+
final String followerIndex = "follow-test-index";
757+
expectThrows(IndexClosedException.class,
758+
() -> followerClient().execute(PutFollowAction.INSTANCE, putFollow(leaderIndex, followerIndex)).actionGet());
759+
assertFalse(ESIntegTestCase.indexExists(followerIndex, followerClient()));
760+
}
761+
762+
public void testResumeFollowOnClosedIndex() throws Exception {
763+
final String leaderIndex = "test-index";
764+
assertAcked(leaderClient().admin().indices().prepareCreate(leaderIndex)
765+
.setSettings(Settings.builder()
766+
.put(IndexSettings.INDEX_SOFT_DELETES_SETTING.getKey(), true)
767+
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, 1)
768+
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
769+
.build()));
770+
ensureLeaderGreen(leaderIndex);
771+
772+
final int nbDocs = randomIntBetween(10, 100);
773+
IntStream.of(nbDocs).forEach(i -> leaderClient().prepareIndex().setIndex(leaderIndex).setSource("field", i).get());
774+
775+
final String followerIndex = "follow-test-index";
776+
PutFollowAction.Response response =
777+
followerClient().execute(PutFollowAction.INSTANCE, putFollow(leaderIndex, followerIndex)).actionGet();
778+
assertTrue(response.isFollowIndexCreated());
779+
assertTrue(response.isFollowIndexShardsAcked());
780+
assertTrue(response.isIndexFollowingStarted());
781+
782+
pauseFollow(followerIndex);
783+
assertAcked(leaderClient().admin().indices().prepareClose(leaderIndex));
784+
785+
expectThrows(IndexClosedException.class, () ->
786+
followerClient().execute(ResumeFollowAction.INSTANCE, resumeFollow(followerIndex)).actionGet());
787+
}
788+
746789
public void testDeleteFollowerIndex() throws Exception {
747790
assertAcked(leaderClient().admin().indices().prepareCreate("index1")
748791
.setSettings(Settings.builder()

0 commit comments

Comments
 (0)