10
10
import org .elasticsearch .ElasticsearchException ;
11
11
import org .elasticsearch .action .admin .indices .create .CreateIndexRequest ;
12
12
import org .elasticsearch .action .admin .indices .delete .DeleteIndexRequest ;
13
+ import org .elasticsearch .action .admin .indices .rollover .RolloverResponse ;
14
+ import org .elasticsearch .action .admin .indices .stats .IndicesStatsResponse ;
15
+ import org .elasticsearch .action .admin .indices .template .put .PutComposableIndexTemplateAction ;
16
+ import org .elasticsearch .action .datastreams .CreateDataStreamAction ;
17
+ import org .elasticsearch .action .datastreams .ModifyDataStreamsAction ;
13
18
import org .elasticsearch .client .internal .Client ;
19
+ import org .elasticsearch .cluster .metadata .ComposableIndexTemplate ;
20
+ import org .elasticsearch .cluster .metadata .DataStream ;
21
+ import org .elasticsearch .cluster .metadata .DataStreamAction ;
14
22
import org .elasticsearch .cluster .metadata .IndexMetadata ;
15
23
import org .elasticsearch .cluster .metadata .Metadata ;
24
+ import org .elasticsearch .cluster .metadata .MetadataIndexTemplateService ;
25
+ import org .elasticsearch .cluster .metadata .Template ;
16
26
import org .elasticsearch .common .Strings ;
17
27
import org .elasticsearch .common .regex .Regex ;
18
28
import org .elasticsearch .common .settings .Settings ;
19
29
import org .elasticsearch .common .unit .ByteSizeUnit ;
20
30
import org .elasticsearch .common .unit .ByteSizeValue ;
21
31
import org .elasticsearch .core .CheckedRunnable ;
22
32
import org .elasticsearch .core .TimeValue ;
33
+ import org .elasticsearch .datastreams .DataStreamsPlugin ;
23
34
import org .elasticsearch .index .IndexNotFoundException ;
24
35
import org .elasticsearch .indices .SystemIndexDescriptor ;
25
36
import org .elasticsearch .plugins .Plugin ;
51
62
import java .util .stream .Stream ;
52
63
53
64
import static org .elasticsearch .test .hamcrest .ElasticsearchAssertions .assertAcked ;
65
+ import static org .hamcrest .Matchers .aMapWithSize ;
54
66
import static org .hamcrest .Matchers .equalTo ;
55
67
import static org .hamcrest .Matchers .greaterThanOrEqualTo ;
68
+ import static org .hamcrest .Matchers .hasKey ;
56
69
import static org .hamcrest .Matchers .hasSize ;
57
70
import static org .hamcrest .Matchers .is ;
58
71
import static org .hamcrest .Matchers .notNullValue ;
@@ -67,7 +80,7 @@ protected boolean reuseClusters() {
67
80
68
81
@ Override
69
82
protected Collection <Class <? extends Plugin >> nodePlugins () {
70
- return Stream .concat (super .nodePlugins ().stream (), Stream .of (FakeSystemIndex .class )).collect ( Collectors . toList () );
83
+ return Stream .concat (super .nodePlugins ().stream (), Stream .of (FakeSystemIndex .class , DataStreamsPlugin . class )).toList ();
71
84
}
72
85
73
86
public static class FakeSystemIndex extends Plugin implements SystemIndexPlugin {
@@ -621,6 +634,98 @@ public void testAutoFollowExclusion() throws Exception {
621
634
assertFalse (ESIntegTestCase .indexExists ("copy-logs-201801" , followerClient ()));
622
635
}
623
636
637
+ public void testAutoFollowDatastreamWithClosingFollowerIndex () throws Exception {
638
+ final String datastream = "logs-1" ;
639
+ PutComposableIndexTemplateAction .Request request = new PutComposableIndexTemplateAction .Request ("template-id" );
640
+ request .indexTemplate (
641
+ new ComposableIndexTemplate (
642
+ List .of ("logs-*" ),
643
+ new Template (
644
+ Settings .builder ()
645
+ .put (IndexMetadata .SETTING_NUMBER_OF_SHARDS , 1 )
646
+ .put (IndexMetadata .SETTING_NUMBER_OF_REPLICAS , 0 )
647
+ .build (),
648
+ null ,
649
+ null
650
+ ),
651
+ null ,
652
+ null ,
653
+ null ,
654
+ null ,
655
+ new ComposableIndexTemplate .DataStreamTemplate (),
656
+ null
657
+ )
658
+ );
659
+ assertAcked (leaderClient ().execute (PutComposableIndexTemplateAction .INSTANCE , request ).get ());
660
+
661
+ CreateDataStreamAction .Request createDataStreamRequest = new CreateDataStreamAction .Request (datastream );
662
+ assertAcked (leaderClient ().execute (CreateDataStreamAction .INSTANCE , createDataStreamRequest ).get ());
663
+ leaderClient ().prepareIndex (datastream )
664
+ .setCreate (true )
665
+ .setSource ("foo" , "bar" , DataStream .TIMESTAMP_FIELD .getName (), randomNonNegativeLong ())
666
+ .get ();
667
+
668
+ PutAutoFollowPatternAction .Request followRequest = new PutAutoFollowPatternAction .Request ();
669
+ followRequest .setName ("pattern-1" );
670
+ followRequest .setRemoteCluster ("leader_cluster" );
671
+ followRequest .setLeaderIndexPatterns (List .of ("logs-*" ));
672
+ followRequest .setFollowIndexNamePattern ("{{leader_index}}" );
673
+ assertTrue (followerClient ().execute (PutAutoFollowPatternAction .INSTANCE , followRequest ).get ().isAcknowledged ());
674
+
675
+ logger .info ("--> roll over once and wait for the auto-follow to pick up the new index" );
676
+ leaderClient ().admin ().indices ().prepareRolloverIndex ("logs-1" ).get ();
677
+ assertLongBusy (() -> {
678
+ AutoFollowStats autoFollowStats = getAutoFollowStats ();
679
+ assertThat (autoFollowStats .getNumberOfSuccessfulFollowIndices (), equalTo (1L ));
680
+ });
681
+
682
+ ensureFollowerGreen ("*" );
683
+
684
+ final RolloverResponse rolloverResponse = leaderClient ().admin ().indices ().prepareRolloverIndex (datastream ).get ();
685
+ final String indexInDatastream = rolloverResponse .getOldIndex ();
686
+
687
+ logger .info ("--> closing [{}] on follower so it will be re-opened by crr" , indexInDatastream );
688
+ assertAcked (followerClient ().admin ().indices ().prepareClose (indexInDatastream ).setMasterNodeTimeout (TimeValue .MAX_VALUE ).get ());
689
+
690
+ logger .info ("--> deleting and recreating index [{}] on leader to change index uuid on leader" , indexInDatastream );
691
+ assertAcked (leaderClient ().admin ().indices ().prepareDelete (indexInDatastream ).get ());
692
+ assertAcked (
693
+ leaderClient ().admin ()
694
+ .indices ()
695
+ .prepareCreate (indexInDatastream )
696
+ .setMapping (MetadataIndexTemplateService .DEFAULT_TIMESTAMP_MAPPING .toString ())
697
+ .get ()
698
+ );
699
+ leaderClient ().prepareIndex (indexInDatastream )
700
+ .setCreate (true )
701
+ .setSource ("foo" , "bar" , DataStream .TIMESTAMP_FIELD .getName (), randomNonNegativeLong ())
702
+ .get ();
703
+ leaderClient ().execute (
704
+ ModifyDataStreamsAction .INSTANCE ,
705
+ new ModifyDataStreamsAction .Request (List .of (DataStreamAction .addBackingIndex (datastream , indexInDatastream )))
706
+ ).get ();
707
+
708
+ assertLongBusy (() -> {
709
+ AutoFollowStats autoFollowStats = getAutoFollowStats ();
710
+ assertThat (autoFollowStats .getNumberOfSuccessfulFollowIndices (), equalTo (3L ));
711
+ });
712
+
713
+ final Metadata metadata = followerClient ().admin ().cluster ().prepareState ().get ().getState ().metadata ();
714
+ final DataStream dataStream = metadata .dataStreams ().get (datastream );
715
+ assertTrue (dataStream .getIndices ().stream ().anyMatch (i -> i .getName ().equals (indexInDatastream )));
716
+ assertEquals (IndexMetadata .State .OPEN , metadata .index (indexInDatastream ).getState ());
717
+ ensureFollowerGreen ("*" );
718
+ final IndicesStatsResponse stats = followerClient ().admin ().indices ().prepareStats (datastream ).get ();
719
+ assertThat (stats .getIndices (), aMapWithSize (2 ));
720
+
721
+ assertAcked (leaderClient ().admin ().indices ().prepareDelete (indexInDatastream ).get ());
722
+ assertAcked (followerClient ().admin ().indices ().prepareDelete (indexInDatastream ).setMasterNodeTimeout (TimeValue .MAX_VALUE ).get ());
723
+ ensureFollowerGreen ("*" );
724
+ final IndicesStatsResponse statsAfterDelete = followerClient ().admin ().indices ().prepareStats (datastream ).get ();
725
+ assertThat (statsAfterDelete .getIndices (), aMapWithSize (1 ));
726
+ assertThat (statsAfterDelete .getIndices (), hasKey (rolloverResponse .getNewIndex ()));
727
+ }
728
+
624
729
private void putAutoFollowPatterns (String name , String [] patterns ) {
625
730
putAutoFollowPatterns (name , patterns , Collections .emptyList ());
626
731
}
0 commit comments