2020package org .elasticsearch .action .admin .indices .rollover ;
2121
2222import org .elasticsearch .Version ;
23+ import org .elasticsearch .action .ActionListener ;
2324import org .elasticsearch .action .admin .indices .alias .IndicesAliasesClusterStateUpdateRequest ;
2425import org .elasticsearch .action .admin .indices .create .CreateIndexClusterStateUpdateRequest ;
2526import org .elasticsearch .action .admin .indices .stats .CommonStats ;
27+ import org .elasticsearch .action .admin .indices .stats .IndexStats ;
28+ import org .elasticsearch .action .admin .indices .stats .IndicesStatsRequestBuilder ;
2629import org .elasticsearch .action .admin .indices .stats .IndicesStatsResponse ;
30+ import org .elasticsearch .action .support .ActionFilters ;
2731import org .elasticsearch .action .support .ActiveShardCount ;
32+ import org .elasticsearch .action .support .PlainActionFuture ;
33+ import org .elasticsearch .client .AdminClient ;
34+ import org .elasticsearch .client .Client ;
35+ import org .elasticsearch .client .IndicesAdminClient ;
36+ import org .elasticsearch .cluster .ClusterName ;
37+ import org .elasticsearch .cluster .ClusterState ;
2838import org .elasticsearch .cluster .metadata .AliasAction ;
2939import org .elasticsearch .cluster .metadata .AliasMetaData ;
3040import org .elasticsearch .cluster .metadata .IndexMetaData ;
3141import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
3242import org .elasticsearch .cluster .metadata .IndexTemplateMetaData ;
3343import org .elasticsearch .cluster .metadata .MetaData ;
44+ import org .elasticsearch .cluster .metadata .MetaDataCreateIndexService ;
45+ import org .elasticsearch .cluster .metadata .MetaDataIndexAliasesService ;
46+ import org .elasticsearch .cluster .service .ClusterService ;
3447import org .elasticsearch .common .UUIDs ;
3548import org .elasticsearch .common .settings .Settings ;
3649import org .elasticsearch .common .unit .ByteSizeUnit ;
3952import org .elasticsearch .common .util .set .Sets ;
4053import org .elasticsearch .index .shard .DocsStats ;
4154import org .elasticsearch .test .ESTestCase ;
55+ import org .elasticsearch .threadpool .ThreadPool ;
56+ import org .elasticsearch .transport .TransportService ;
4257import org .mockito .ArgumentCaptor ;
4358
4459import java .util .Arrays ;
60+ import java .util .HashMap ;
4561import java .util .List ;
4662import java .util .Locale ;
4763import java .util .Map ;
5167import static org .hamcrest .Matchers .containsString ;
5268import static org .hamcrest .Matchers .equalTo ;
5369import static org .hamcrest .Matchers .hasSize ;
70+ import static org .hamcrest .Matchers .is ;
5471import static org .mockito .Matchers .any ;
72+ import static org .mockito .Mockito .doAnswer ;
5573import static org .mockito .Mockito .mock ;
5674import static org .mockito .Mockito .verify ;
5775import static org .mockito .Mockito .when ;
@@ -64,7 +82,9 @@ public void testDocStatsSelectionFromPrimariesOnly() {
6482 long docsInShards = 200 ;
6583
6684 final Condition <?> condition = createTestCondition ();
67- evaluateConditions (Sets .newHashSet (condition ), createMetaData (), createIndicesStatResponse (docsInShards , docsInPrimaryShards ));
85+ String indexName = randomAlphaOfLengthBetween (5 , 7 );
86+ evaluateConditions (Sets .newHashSet (condition ), createMetaData (indexName ),
87+ createIndicesStatResponse (indexName , docsInShards , docsInPrimaryShards ));
6888 final ArgumentCaptor <Condition .Stats > argument = ArgumentCaptor .forClass (Condition .Stats .class );
6989 verify (condition ).evaluate (argument .capture ());
7090
@@ -286,36 +306,150 @@ public void testRejectDuplicateAlias() {
286306 .patterns (Arrays .asList ("foo-*" , "bar-*" ))
287307 .putAlias (AliasMetaData .builder ("foo-write" )).putAlias (AliasMetaData .builder ("bar-write" ).writeIndex (randomBoolean ()))
288308 .build ();
289- final MetaData metaData = MetaData .builder ().put (createMetaData (), false ).put (template ).build ();
309+ final MetaData metaData = MetaData .builder ().put (createMetaData (randomAlphaOfLengthBetween ( 5 , 7 ) ), false ).put (template ).build ();
290310 String indexName = randomFrom ("foo-123" , "bar-xyz" );
291311 String aliasName = randomFrom ("foo-write" , "bar-write" );
292312 final IllegalArgumentException ex = expectThrows (IllegalArgumentException .class ,
293313 () -> TransportRolloverAction .checkNoDuplicatedAliasInIndexTemplate (metaData , indexName , aliasName ));
294314 assertThat (ex .getMessage (), containsString ("index template [test-template]" ));
295315 }
296316
297- private IndicesStatsResponse createIndicesStatResponse (long totalDocs , long primaryDocs ) {
317+ public void testConditionEvaluationWhenAliasToWriteAndReadIndicesConsidersOnlyPrimariesFromWriteIndex () {
318+ final TransportService mockTransportService = mock (TransportService .class );
319+ final ClusterService mockClusterService = mock (ClusterService .class );
320+ final ThreadPool mockThreadPool = mock (ThreadPool .class );
321+ final MetaDataCreateIndexService mockCreateIndexService = mock (MetaDataCreateIndexService .class );
322+ final IndexNameExpressionResolver mockIndexNameExpressionResolver = mock (IndexNameExpressionResolver .class );
323+ when (mockIndexNameExpressionResolver .resolveDateMathExpression (any ())).thenReturn ("logs-index-000003" );
324+ final ActionFilters mockActionFilters = mock (ActionFilters .class );
325+ final MetaDataIndexAliasesService mdIndexAliasesService = mock (MetaDataIndexAliasesService .class );
326+
327+ final Client mockClient = mock (Client .class );
328+ final AdminClient mockAdminClient = mock (AdminClient .class );
329+ final IndicesAdminClient mockIndicesAdminClient = mock (IndicesAdminClient .class );
330+ when (mockClient .admin ()).thenReturn (mockAdminClient );
331+ when (mockAdminClient .indices ()).thenReturn (mockIndicesAdminClient );
332+
333+ final IndicesStatsRequestBuilder mockIndicesStatsBuilder = mock (IndicesStatsRequestBuilder .class );
334+ when (mockIndicesAdminClient .prepareStats (any ())).thenReturn (mockIndicesStatsBuilder );
335+ final Map <String , IndexStats > indexStats = new HashMap <>();
336+ int total = randomIntBetween (500 , 1000 );
337+ indexStats .put ("logs-index-000001" , createIndexStats (200L , total ));
338+ indexStats .put ("logs-index-000002" , createIndexStats (300L , total ));
339+ final IndicesStatsResponse statsResponse = createAliasToMultipleIndicesStatsResponse (indexStats );
340+ when (mockIndicesStatsBuilder .clear ()).thenReturn (mockIndicesStatsBuilder );
341+ when (mockIndicesStatsBuilder .setDocs (true )).thenReturn (mockIndicesStatsBuilder );
342+
343+ assert statsResponse .getPrimaries ().getDocs ().getCount () == 500L ;
344+ assert statsResponse .getTotal ().getDocs ().getCount () == (total + total );
345+
346+ doAnswer (invocation -> {
347+ Object [] args = invocation .getArguments ();
348+ assert args .length == 1 ;
349+ ActionListener <IndicesStatsResponse > listener = (ActionListener <IndicesStatsResponse >) args [0 ];
350+ listener .onResponse (statsResponse );
351+ return null ;
352+ }).when (mockIndicesStatsBuilder ).execute (any (ActionListener .class ));
353+
354+ final IndexMetaData .Builder indexMetaData = IndexMetaData .builder ("logs-index-000001" )
355+ .putAlias (AliasMetaData .builder ("logs-alias" ).writeIndex (false ).build ()).settings (settings (Version .CURRENT ))
356+ .numberOfShards (1 ).numberOfReplicas (1 );
357+ final IndexMetaData .Builder indexMetaData2 = IndexMetaData .builder ("logs-index-000002" )
358+ .putAlias (AliasMetaData .builder ("logs-alias" ).writeIndex (true ).build ()).settings (settings (Version .CURRENT ))
359+ .numberOfShards (1 ).numberOfReplicas (1 );
360+ final ClusterState stateBefore = ClusterState .builder (ClusterName .DEFAULT )
361+ .metaData (MetaData .builder ().put (indexMetaData ).put (indexMetaData2 )).build ();
362+
363+ final TransportRolloverAction transportRolloverAction = new TransportRolloverAction (mockTransportService , mockClusterService ,
364+ mockThreadPool , mockCreateIndexService , mockActionFilters , mockIndexNameExpressionResolver , mdIndexAliasesService ,
365+ mockClient );
366+
367+ // For given alias, verify that condition evaluation fails when the condition doc count is greater than the primaries doc count
368+ // (primaries from only write index is considered)
369+ PlainActionFuture <RolloverResponse > future = new PlainActionFuture <>();
370+ RolloverRequest rolloverRequest = new RolloverRequest ("logs-alias" , "logs-index-000003" );
371+ rolloverRequest .addMaxIndexDocsCondition (500L );
372+ rolloverRequest .dryRun (true );
373+ transportRolloverAction .masterOperation (rolloverRequest , stateBefore , future );
374+
375+ RolloverResponse response = future .actionGet ();
376+ assertThat (response .getOldIndex (), equalTo ("logs-index-000002" ));
377+ assertThat (response .getNewIndex (), equalTo ("logs-index-000003" ));
378+ assertThat (response .isDryRun (), equalTo (true ));
379+ assertThat (response .isRolledOver (), equalTo (false ));
380+ assertThat (response .getConditionStatus ().size (), equalTo (1 ));
381+ assertThat (response .getConditionStatus ().get ("[max_docs: 500]" ), is (false ));
382+
383+ // For given alias, verify that the condition evaluation is successful when condition doc count is less than the primaries doc count
384+ // (primaries from only write index is considered)
385+ future = new PlainActionFuture <>();
386+ rolloverRequest = new RolloverRequest ("logs-alias" , "logs-index-000003" );
387+ rolloverRequest .addMaxIndexDocsCondition (300L );
388+ rolloverRequest .dryRun (true );
389+ transportRolloverAction .masterOperation (rolloverRequest , stateBefore , future );
390+
391+ response = future .actionGet ();
392+ assertThat (response .getOldIndex (), equalTo ("logs-index-000002" ));
393+ assertThat (response .getNewIndex (), equalTo ("logs-index-000003" ));
394+ assertThat (response .isDryRun (), equalTo (true ));
395+ assertThat (response .isRolledOver (), equalTo (false ));
396+ assertThat (response .getConditionStatus ().size (), equalTo (1 ));
397+ assertThat (response .getConditionStatus ().get ("[max_docs: 300]" ), is (true ));
398+ }
399+
400+ private IndicesStatsResponse createIndicesStatResponse (String indexName , long totalDocs , long primariesDocs ) {
298401 final CommonStats primaryStats = mock (CommonStats .class );
299- when (primaryStats .getDocs ()).thenReturn (new DocsStats (primaryDocs , 0 , between (1 , 10000 )));
402+ when (primaryStats .getDocs ()).thenReturn (new DocsStats (primariesDocs , 0 , between (1 , 10000 )));
300403
301404 final CommonStats totalStats = mock (CommonStats .class );
302405 when (totalStats .getDocs ()).thenReturn (new DocsStats (totalDocs , 0 , between (1 , 10000 )));
303406
304407 final IndicesStatsResponse response = mock (IndicesStatsResponse .class );
305408 when (response .getPrimaries ()).thenReturn (primaryStats );
306409 when (response .getTotal ()).thenReturn (totalStats );
410+ final IndexStats indexStats = mock (IndexStats .class );
411+ when (response .getIndex (indexName )).thenReturn (indexStats );
412+ when (indexStats .getPrimaries ()).thenReturn (primaryStats );
413+ when (indexStats .getTotal ()).thenReturn (totalStats );
414+ return response ;
415+ }
416+
417+ private IndicesStatsResponse createAliasToMultipleIndicesStatsResponse (Map <String , IndexStats > indexStats ) {
418+ final IndicesStatsResponse response = mock (IndicesStatsResponse .class );
419+ final CommonStats primariesStats = new CommonStats ();
420+ final CommonStats totalStats = new CommonStats ();
421+ for (String indexName : indexStats .keySet ()) {
422+ when (response .getIndex (indexName )).thenReturn (indexStats .get (indexName ));
423+ primariesStats .add (indexStats .get (indexName ).getPrimaries ());
424+ totalStats .add (indexStats .get (indexName ).getTotal ());
425+ }
307426
427+ when (response .getPrimaries ()).thenReturn (primariesStats );
428+ when (response .getTotal ()).thenReturn (totalStats );
308429 return response ;
309430 }
310431
311- private static IndexMetaData createMetaData () {
432+ private IndexStats createIndexStats (long primaries , long total ) {
433+ final CommonStats primariesCommonStats = mock (CommonStats .class );
434+ when (primariesCommonStats .getDocs ()).thenReturn (new DocsStats (primaries , 0 , between (1 , 10000 )));
435+
436+ final CommonStats totalCommonStats = mock (CommonStats .class );
437+ when (totalCommonStats .getDocs ()).thenReturn (new DocsStats (total , 0 , between (1 , 10000 )));
438+
439+ IndexStats indexStats = mock (IndexStats .class );
440+ when (indexStats .getPrimaries ()).thenReturn (primariesCommonStats );
441+ when (indexStats .getTotal ()).thenReturn (totalCommonStats );
442+ return indexStats ;
443+ }
444+
445+ private static IndexMetaData createMetaData (String indexName ) {
312446 final Settings settings = Settings .builder ()
313447 .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT )
314448 .put (IndexMetaData .SETTING_INDEX_UUID , UUIDs .randomBase64UUID ())
315449 .put (IndexMetaData .SETTING_NUMBER_OF_SHARDS , 1 )
316450 .put (IndexMetaData .SETTING_NUMBER_OF_REPLICAS , 0 )
317451 .build ();
318- return IndexMetaData .builder (randomAlphaOfLength ( 10 ) )
452+ return IndexMetaData .builder (indexName )
319453 .creationDate (System .currentTimeMillis () - TimeValue .timeValueHours (3 ).getMillis ())
320454 .settings (settings )
321455 .build ();
0 commit comments