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 {
@@ -567,6 +592,76 @@ public void testTaskCancellationOnceActionItIsDispatchedToMaster() throws Except
567592 expectThrows (CancellationException .class , listener ::actionGet );
568593 }
569594
595+ public void testGlobalBlocksAreCheckedAfterIndexNotFoundException () throws Exception {
596+ Request request = new Request ().masterNodeTimeout (TimeValue .timeValueSeconds (60 ));
597+ String indexRequestName = "my-index" ;
598+ request .indices (indexRequestName );
599+
600+ ClusterState stateWithBlockWithoutIndexMetadata =
601+ ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
602+ .blocks (ClusterBlocks .builder ().addGlobalBlock (STATE_NOT_RECOVERED_BLOCK ))
603+ .build ();
604+ setState (clusterService , stateWithBlockWithoutIndexMetadata );
605+
606+ Action action = new Action ("internal:testAction" , transportService , clusterService , threadPool , ThreadPool .Names .SAME ) {
607+ final IndexNameExpressionResolver indexNameExpressionResolver = TestIndexNameExpressionResolver .newInstance ();
608+
609+ @ Override
610+ protected ClusterBlockException checkBlock (Request request , ClusterState state ) {
611+ return state .blocks ().indicesBlockedException (ClusterBlockLevel .METADATA_READ ,
612+ indexNameExpressionResolver .concreteIndexNamesWithSystemIndexAccess (state , request ));
613+ }
614+
615+ };
616+
617+ PlainActionFuture <Response > listener = new PlainActionFuture <>();
618+ ActionTestUtils .execute (action , null , request , listener );
619+
620+ assertFalse (listener .isDone ());
621+ IndexMetadata .Builder indexMetadataBuilder =
622+ IndexMetadata .builder (indexRequestName )
623+ .settings (settings (Version .CURRENT ))
624+ .numberOfShards (1 )
625+ .numberOfReplicas (0 );
626+ ClusterState clusterStateWithoutBlocks = ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
627+ .metadata (Metadata .builder ().put (indexMetadataBuilder ).build ())
628+ .blocks (ClusterBlocks .EMPTY_CLUSTER_BLOCK )
629+ .build ();
630+ setState (clusterService , clusterStateWithoutBlocks );
631+ assertTrue (listener .isDone ());
632+ listener .get ();
633+ }
634+
635+ public void testGlobalBlocksAreCheckedAfterIndexNotFoundExceptionTimesOutIfIndexIsNotFound () {
636+ Request request = new Request ().masterNodeTimeout (TimeValue .timeValueMillis (50 ));
637+ String indexRequestName = "my-index" ;
638+ request .indices (indexRequestName );
639+
640+ ClusterState stateWithBlockWithoutIndexMetadata =
641+ ClusterState .builder (ClusterStateCreationUtils .state (localNode , localNode , allNodes ))
642+ .blocks (ClusterBlocks .builder ().addGlobalBlock (STATE_NOT_RECOVERED_BLOCK ))
643+ .build ();
644+ setState (clusterService , stateWithBlockWithoutIndexMetadata );
645+
646+ Action action = new Action ("internal:testAction" , transportService , clusterService , threadPool , ThreadPool .Names .SAME ) {
647+ final IndexNameExpressionResolver indexNameExpressionResolver = TestIndexNameExpressionResolver .newInstance ();
648+
649+ @ Override
650+ protected ClusterBlockException checkBlock (Request request , ClusterState state ) {
651+ return state .blocks ().indicesBlockedException (ClusterBlockLevel .METADATA_READ ,
652+ indexNameExpressionResolver .concreteIndexNamesWithSystemIndexAccess (state , request ));
653+ }
654+
655+ };
656+
657+ PlainActionFuture <Response > listener = new PlainActionFuture <>();
658+ ActionTestUtils .execute (action , null , request , listener );
659+
660+ ExecutionException ex = expectThrows (ExecutionException .class , listener ::get );
661+ assertThat (ex .getCause (), instanceOf (MasterNotDiscoveredException .class ));
662+ assertThat (ex .getCause ().getCause (), instanceOf (ClusterBlockException .class ));
663+ }
664+
570665 private Runnable blockAllThreads (String executorName ) throws Exception {
571666 final int numberOfThreads = threadPool .info (executorName ).getMax ();
572667 final EsThreadPoolExecutor executor = (EsThreadPoolExecutor ) threadPool .executor (executorName );
0 commit comments