1313import org .elasticsearch .action .ActionListener ;
1414import org .elasticsearch .action .ActionRequestValidationException ;
1515import org .elasticsearch .action .ActionResponse ;
16+ import org .elasticsearch .action .IndicesRequest ;
1617import org .elasticsearch .action .support .ActionFilters ;
1718import org .elasticsearch .action .support .ActionTestUtils ;
19+ import org .elasticsearch .action .support .IndicesOptions ;
1820import org .elasticsearch .action .support .PlainActionFuture ;
1921import org .elasticsearch .action .support .ThreadedActionListener ;
2022import org .elasticsearch .action .support .replication .ClusterStateCreationUtils ;
2527import org .elasticsearch .cluster .block .ClusterBlockLevel ;
2628import org .elasticsearch .cluster .block .ClusterBlocks ;
2729import org .elasticsearch .cluster .coordination .FailedToCommitClusterStateException ;
30+ import org .elasticsearch .cluster .metadata .IndexMetadata ;
31+ import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
32+ import org .elasticsearch .cluster .metadata .Metadata ;
2833import org .elasticsearch .cluster .node .DiscoveryNode ;
2934import org .elasticsearch .cluster .node .DiscoveryNodeRole ;
3035import org .elasticsearch .cluster .node .DiscoveryNodes ;
3136import org .elasticsearch .cluster .service .ClusterService ;
37+ import org .elasticsearch .common .Strings ;
3238import org .elasticsearch .common .io .stream .StreamInput ;
3339import org .elasticsearch .common .io .stream .StreamOutput ;
3440import org .elasticsearch .common .settings .Settings ;
35- import org .elasticsearch .core .TimeValue ;
3641import org .elasticsearch .common .util .concurrent .EsThreadPoolExecutor ;
42+ import org .elasticsearch .core .TimeValue ;
3743import org .elasticsearch .discovery .MasterNotDiscoveredException ;
3844import org .elasticsearch .indices .TestIndexNameExpressionResolver ;
3945import org .elasticsearch .node .NodeClosedException ;
6571import java .util .concurrent .ExecutionException ;
6672import java .util .concurrent .TimeUnit ;
6773
74+ import static org .elasticsearch .gateway .GatewayService .STATE_NOT_RECOVERED_BLOCK ;
6875import static org .elasticsearch .test .ClusterServiceUtils .createClusterService ;
6976import static org .elasticsearch .test .ClusterServiceUtils .setState ;
7077import static org .hamcrest .Matchers .equalTo ;
@@ -124,7 +131,9 @@ void assertListenerThrows(String msg, ActionFuture<?> listener, Class<?> klass)
124131 }
125132 }
126133
127- public static class Request extends MasterNodeRequest <Request > {
134+ public static class Request extends MasterNodeRequest <Request > implements IndicesRequest .Replaceable {
135+ private String [] indices = Strings .EMPTY_ARRAY ;
136+
128137 Request () {}
129138
130139 Request (StreamInput in ) throws IOException {
@@ -140,6 +149,22 @@ public ActionRequestValidationException validate() {
140149 public Task createTask (long id , String type , String action , TaskId parentTaskId , Map <String , String > headers ) {
141150 return new CancellableTask (id , type , action , "" , parentTaskId , headers );
142151 }
152+
153+ @ Override
154+ public String [] indices () {
155+ return indices ;
156+ }
157+
158+ @ Override
159+ public IndicesOptions indicesOptions () {
160+ return IndicesOptions .strictExpandOpen ();
161+ }
162+
163+ @ Override
164+ public IndicesRequest indices (String ... indices ) {
165+ this .indices = indices ;
166+ return this ;
167+ }
143168 }
144169
145170 class Response extends ActionResponse {
@@ -568,6 +593,76 @@ public void testTaskCancellationOnceActionItIsDispatchedToMaster() throws Except
568593 expectThrows (CancellationException .class , listener ::actionGet );
569594 }
570595
596+ public void testGlobalBlocksAreCheckedAfterIndexNotFoundException () throws Exception {
597+ Request request = new Request ().masterNodeTimeout (TimeValue .timeValueSeconds (60 ));
598+ String indexRequestName = "my-index" ;
599+ request .indices (indexRequestName );
600+
601+ ClusterState stateWithBlockWithoutIndexMetadata =
602+ ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
603+ .blocks (ClusterBlocks .builder ().addGlobalBlock (STATE_NOT_RECOVERED_BLOCK ))
604+ .build ();
605+ setState (clusterService , stateWithBlockWithoutIndexMetadata );
606+
607+ Action action = new Action ("internal:testAction" , transportService , clusterService , threadPool , ThreadPool .Names .SAME ) {
608+ final IndexNameExpressionResolver indexNameExpressionResolver = TestIndexNameExpressionResolver .newInstance ();
609+
610+ @ Override
611+ protected ClusterBlockException checkBlock (Request request , ClusterState state ) {
612+ return state .blocks ().indicesBlockedException (ClusterBlockLevel .METADATA_READ ,
613+ indexNameExpressionResolver .concreteIndexNamesWithSystemIndexAccess (state , request ));
614+ }
615+
616+ };
617+
618+ PlainActionFuture <Response > listener = new PlainActionFuture <>();
619+ ActionTestUtils .execute (action , null , request , listener );
620+
621+ assertFalse (listener .isDone ());
622+ IndexMetadata .Builder indexMetadataBuilder =
623+ IndexMetadata .builder (indexRequestName )
624+ .settings (settings (Version .CURRENT ))
625+ .numberOfShards (1 )
626+ .numberOfReplicas (0 );
627+ ClusterState clusterStateWithoutBlocks = ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
628+ .metadata (Metadata .builder ().put (indexMetadataBuilder ).build ())
629+ .blocks (ClusterBlocks .EMPTY_CLUSTER_BLOCK )
630+ .build ();
631+ setState (clusterService , clusterStateWithoutBlocks );
632+ assertTrue (listener .isDone ());
633+ listener .get ();
634+ }
635+
636+ public void testGlobalBlocksAreCheckedAfterIndexNotFoundExceptionTimesOutIfIndexIsNotFound () {
637+ Request request = new Request ().masterNodeTimeout (TimeValue .timeValueMillis (50 ));
638+ String indexRequestName = "my-index" ;
639+ request .indices (indexRequestName );
640+
641+ ClusterState stateWithBlockWithoutIndexMetadata =
642+ ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
643+ .blocks (ClusterBlocks .builder ().addGlobalBlock (STATE_NOT_RECOVERED_BLOCK ))
644+ .build ();
645+ setState (clusterService , stateWithBlockWithoutIndexMetadata );
646+
647+ Action action = new Action ("internal:testAction" , transportService , clusterService , threadPool , ThreadPool .Names .SAME ) {
648+ final IndexNameExpressionResolver indexNameExpressionResolver = TestIndexNameExpressionResolver .newInstance ();
649+
650+ @ Override
651+ protected ClusterBlockException checkBlock (Request request , ClusterState state ) {
652+ return state .blocks ().indicesBlockedException (ClusterBlockLevel .METADATA_READ ,
653+ indexNameExpressionResolver .concreteIndexNamesWithSystemIndexAccess (state , request ));
654+ }
655+
656+ };
657+
658+ PlainActionFuture <Response > listener = new PlainActionFuture <>();
659+ ActionTestUtils .execute (action , null , request , listener );
660+
661+ ExecutionException ex = expectThrows (ExecutionException .class , listener ::get );
662+ assertThat (ex .getCause (), instanceOf (MasterNotDiscoveredException .class ));
663+ assertThat (ex .getCause ().getCause (), instanceOf (ClusterBlockException .class ));
664+ }
665+
571666 private Runnable blockAllThreads (String executorName ) throws Exception {
572667 final int numberOfThreads = threadPool .info (executorName ).getMax ();
573668 final EsThreadPoolExecutor executor = (EsThreadPoolExecutor ) threadPool .executor (executorName );
0 commit comments