1414import org .elasticsearch .cluster .ClusterName ;
1515import org .elasticsearch .cluster .ClusterState ;
1616import org .elasticsearch .cluster .ClusterStateUpdateTask ;
17+ import org .elasticsearch .cluster .metadata .IndexMetaData ;
1718import org .elasticsearch .cluster .metadata .MetaData ;
1819import org .elasticsearch .cluster .node .DiscoveryNode ;
1920import org .elasticsearch .cluster .node .DiscoveryNodes ;
2021import org .elasticsearch .cluster .service .ClusterService ;
22+ import org .elasticsearch .common .collect .ImmutableOpenMap ;
2123import org .elasticsearch .common .settings .Settings ;
2224import org .elasticsearch .common .transport .TransportAddress ;
2325import org .elasticsearch .common .unit .TimeValue ;
26+ import org .elasticsearch .index .Index ;
2427import org .elasticsearch .test .ESTestCase ;
28+ import org .elasticsearch .test .rest .yaml .section .Assertion ;
2529import org .elasticsearch .threadpool .ThreadPool ;
2630import org .elasticsearch .xpack .core .indexlifecycle .IndexLifecycleMetadata ;
31+ import org .elasticsearch .xpack .core .indexlifecycle .LifecyclePolicy ;
32+ import org .elasticsearch .xpack .core .indexlifecycle .LifecyclePolicyMetadata ;
2733import org .elasticsearch .xpack .core .indexlifecycle .LifecycleSettings ;
34+ import org .elasticsearch .xpack .core .indexlifecycle .MockAction ;
2835import org .elasticsearch .xpack .core .indexlifecycle .OperationMode ;
36+ import org .elasticsearch .xpack .core .indexlifecycle .Phase ;
37+ import org .elasticsearch .xpack .core .indexlifecycle .ShrinkAction ;
38+ import org .elasticsearch .xpack .core .indexlifecycle .Step ;
39+ import org .elasticsearch .xpack .core .indexlifecycle .TestLifecycleType ;
2940import org .elasticsearch .xpack .core .scheduler .SchedulerEngine ;
3041import org .junit .After ;
3142import org .junit .Before ;
3243import org .mockito .Mockito ;
3344
34- import java .io .IOException ;
3545import java .time .Clock ;
3646import java .time .Instant ;
3747import java .time .ZoneId ;
3848import java .util .Collections ;
49+ import java .util .SortedMap ;
50+ import java .util .TreeMap ;
3951import java .util .concurrent .ExecutorService ;
4052
4153import static org .elasticsearch .node .Node .NODE_MASTER_SETTING ;
54+ import static org .elasticsearch .xpack .core .indexlifecycle .AbstractStepTestCase .randomStepKey ;
4255import static org .hamcrest .Matchers .equalTo ;
4356import static org .mockito .Matchers .any ;
4457import static org .mockito .Matchers .anyString ;
@@ -84,12 +97,18 @@ public void prepareServices() {
8497 indicesClient = mock (IndicesAdminClient .class );
8598 when (client .admin ()).thenReturn (adminClient );
8699 when (adminClient .indices ()).thenReturn (indicesClient );
100+ when (client .settings ()).thenReturn (Settings .EMPTY );
87101
88102 indexLifecycleService = new IndexLifecycleService (Settings .EMPTY , client , clusterService , clock ,
89103 threadPool , () -> now );
90104 Mockito .verify (clusterService ).addListener (indexLifecycleService );
91105 }
92106
107+ @ After
108+ public void cleanup () {
109+ indexLifecycleService .close ();
110+ }
111+
93112 public void testOnlyChangesStateOnMaster () throws Exception {
94113 MetaData metaData = MetaData .builder ()
95114 .persistentSettings (settings (Version .CURRENT )
@@ -110,7 +129,7 @@ public void testElectUnElectMaster() throws Exception {
110129 MetaData metaData = MetaData .builder ()
111130 .persistentSettings (settings (Version .CURRENT )
112131 .put (LifecycleSettings .LIFECYCLE_POLL_INTERVAL_SETTING .getKey (), TimeValue .timeValueSeconds (3 )).build ())
113- .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (Collections .emptySortedMap (), OperationMode .OUT ))
132+ .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (Collections .emptySortedMap (), OperationMode .NORMAL ))
114133 .build ();
115134
116135 // First check that when the node has never been master the scheduler
@@ -197,15 +216,10 @@ public void testServiceSetupOnFirstClusterChange() {
197216 assertNull (indexLifecycleService .getScheduler ());
198217 }
199218
200- @ After
201- public void cleanup () throws IOException {
202- indexLifecycleService .close ();
203- }
204-
205219 public void testSchedulerInitializationAndUpdate () {
206220 TimeValue pollInterval = TimeValue .timeValueSeconds (randomIntBetween (1 , 59 ));
207221 MetaData metaData = MetaData .builder ()
208- .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (Collections .emptySortedMap (), OperationMode .OUT ))
222+ .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (Collections .emptySortedMap (), OperationMode .NORMAL ))
209223 .persistentSettings (settings (Version .CURRENT ).build ())
210224 .build ();
211225 MetaData updatedPollMetaData = MetaData .builder (metaData ).persistentSettings (settings (Version .CURRENT )
@@ -256,6 +270,126 @@ public void testInstallMetadataFail() {
256270 assertNull (indexLifecycleService .getScheduler ());
257271 }
258272
273+ public void testMaintenanceModeSkip () {
274+ String policyName = randomAlphaOfLengthBetween (1 , 20 );
275+ IndexLifecycleRunnerTests .MockInitializePolicyContextStep mockStep =
276+ new IndexLifecycleRunnerTests .MockInitializePolicyContextStep (randomStepKey (), randomStepKey ());
277+ MockAction mockAction = new MockAction (Collections .singletonList (mockStep ));
278+ Phase phase = new Phase ("phase" , TimeValue .ZERO , Collections .singletonMap ("action" , mockAction ));
279+ LifecyclePolicy policy = new LifecyclePolicy (TestLifecycleType .INSTANCE , policyName ,
280+ Collections .singletonMap (phase .getName (), phase ));
281+ SortedMap <String , LifecyclePolicyMetadata > policyMap = new TreeMap <>();
282+ policyMap .put (policyName , new LifecyclePolicyMetadata (policy , Collections .emptyMap ()));
283+ Index index = new Index (randomAlphaOfLengthBetween (1 , 20 ), randomAlphaOfLengthBetween (1 , 20 ));
284+ IndexMetaData indexMetadata = IndexMetaData .builder (index .getName ())
285+ .settings (settings (Version .CURRENT ).put (LifecycleSettings .LIFECYCLE_NAME_SETTING .getKey (), policyName ))
286+ .numberOfShards (randomIntBetween (1 , 5 )).numberOfReplicas (randomIntBetween (0 , 5 )).build ();
287+ ImmutableOpenMap .Builder <String , IndexMetaData > indices = ImmutableOpenMap .<String , IndexMetaData > builder ()
288+ .fPut (index .getName (), indexMetadata );
289+ MetaData metaData = MetaData .builder ()
290+ .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (policyMap , OperationMode .MAINTENANCE ))
291+ .indices (indices .build ())
292+ .persistentSettings (settings (Version .CURRENT ).build ())
293+ .build ();
294+ ClusterState currentState = ClusterState .builder (ClusterName .DEFAULT )
295+ .metaData (metaData )
296+ .nodes (DiscoveryNodes .builder ().localNodeId (nodeId ).masterNodeId (nodeId ).add (masterNode ).build ())
297+ .build ();
298+ indexLifecycleService .triggerPolicies (currentState , randomBoolean ());
299+ assertThat (mockStep .getExecuteCount (), equalTo (0L ));
300+ }
301+
302+ public void testRequestedMaintenanceOnShrink () {
303+ Step .StepKey mockShrinkStep = new Step .StepKey (randomAlphaOfLength (4 ), ShrinkAction .NAME , randomAlphaOfLength (5 ));
304+ String policyName = randomAlphaOfLengthBetween (1 , 20 );
305+ IndexLifecycleRunnerTests .MockInitializePolicyContextStep mockStep =
306+ new IndexLifecycleRunnerTests .MockInitializePolicyContextStep (mockShrinkStep , randomStepKey ());
307+ MockAction mockAction = new MockAction (Collections .singletonList (mockStep ));
308+ Phase phase = new Phase ("phase" , TimeValue .ZERO , Collections .singletonMap ("action" , mockAction ));
309+ LifecyclePolicy policy = new LifecyclePolicy (TestLifecycleType .INSTANCE , policyName ,
310+ Collections .singletonMap (phase .getName (), phase ));
311+ SortedMap <String , LifecyclePolicyMetadata > policyMap = new TreeMap <>();
312+ policyMap .put (policyName , new LifecyclePolicyMetadata (policy , Collections .emptyMap ()));
313+ Index index = new Index (randomAlphaOfLengthBetween (1 , 20 ), randomAlphaOfLengthBetween (1 , 20 ));
314+ IndexMetaData indexMetadata = IndexMetaData .builder (index .getName ())
315+ .settings (settings (Version .CURRENT ).put (LifecycleSettings .LIFECYCLE_NAME_SETTING .getKey (), policyName )
316+ .put (LifecycleSettings .LIFECYCLE_PHASE , mockShrinkStep .getPhase ())
317+ .put (LifecycleSettings .LIFECYCLE_ACTION , mockShrinkStep .getAction ())
318+ .put (LifecycleSettings .LIFECYCLE_STEP , mockShrinkStep .getName ()))
319+ .numberOfShards (randomIntBetween (1 , 5 )).numberOfReplicas (randomIntBetween (0 , 5 )).build ();
320+ ImmutableOpenMap .Builder <String , IndexMetaData > indices = ImmutableOpenMap .<String , IndexMetaData > builder ()
321+ .fPut (index .getName (), indexMetadata );
322+ MetaData metaData = MetaData .builder ()
323+ .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (policyMap , OperationMode .MAINTENANCE_REQUESTED ))
324+ .indices (indices .build ())
325+ .persistentSettings (settings (Version .CURRENT ).build ())
326+ .build ();
327+ ClusterState currentState = ClusterState .builder (ClusterName .DEFAULT )
328+ .metaData (metaData )
329+ .nodes (DiscoveryNodes .builder ().localNodeId (nodeId ).masterNodeId (nodeId ).add (masterNode ).build ())
330+ .build ();
331+
332+ ClusterChangedEvent event = new ClusterChangedEvent ("_source" , currentState , ClusterState .EMPTY_STATE );
333+ SetOnce <Boolean > executedShrink = new SetOnce <>();
334+ doAnswer (invocationOnMock -> {
335+ executedShrink .set (true );
336+ return null ;
337+ }).when (clusterService ).submitStateUpdateTask (anyString (), any (ExecuteStepsUpdateTask .class ));
338+ indexLifecycleService .clusterChanged (event );
339+ assertTrue (executedShrink .get ());
340+ }
341+
342+ public void testRequestedMaintenanceOnSafeAction () {
343+ String policyName = randomAlphaOfLengthBetween (1 , 20 );
344+ Step .StepKey currentStepKey = randomStepKey ();
345+ IndexLifecycleRunnerTests .MockInitializePolicyContextStep mockStep =
346+ new IndexLifecycleRunnerTests .MockInitializePolicyContextStep (currentStepKey , randomStepKey ());
347+ MockAction mockAction = new MockAction (Collections .singletonList (mockStep ));
348+ Phase phase = new Phase ("phase" , TimeValue .ZERO , Collections .singletonMap ("action" , mockAction ));
349+ LifecyclePolicy policy = new LifecyclePolicy (TestLifecycleType .INSTANCE , policyName ,
350+ Collections .singletonMap (phase .getName (), phase ));
351+ SortedMap <String , LifecyclePolicyMetadata > policyMap = new TreeMap <>();
352+ policyMap .put (policyName , new LifecyclePolicyMetadata (policy , Collections .emptyMap ()));
353+ Index index = new Index (randomAlphaOfLengthBetween (1 , 20 ), randomAlphaOfLengthBetween (1 , 20 ));
354+ IndexMetaData indexMetadata = IndexMetaData .builder (index .getName ())
355+ .settings (settings (Version .CURRENT ).put (LifecycleSettings .LIFECYCLE_NAME_SETTING .getKey (), policyName )
356+ .put (LifecycleSettings .LIFECYCLE_PHASE , currentStepKey .getPhase ())
357+ .put (LifecycleSettings .LIFECYCLE_ACTION , currentStepKey .getAction ())
358+ .put (LifecycleSettings .LIFECYCLE_STEP , currentStepKey .getName ()))
359+ .numberOfShards (randomIntBetween (1 , 5 )).numberOfReplicas (randomIntBetween (0 , 5 )).build ();
360+ ImmutableOpenMap .Builder <String , IndexMetaData > indices = ImmutableOpenMap .<String , IndexMetaData > builder ()
361+ .fPut (index .getName (), indexMetadata );
362+ MetaData metaData = MetaData .builder ()
363+ .putCustom (IndexLifecycleMetadata .TYPE , new IndexLifecycleMetadata (policyMap , OperationMode .MAINTENANCE_REQUESTED ))
364+ .indices (indices .build ())
365+ .persistentSettings (settings (Version .CURRENT ).build ())
366+ .build ();
367+ ClusterState currentState = ClusterState .builder (ClusterName .DEFAULT )
368+ .metaData (metaData )
369+ .nodes (DiscoveryNodes .builder ().localNodeId (nodeId ).masterNodeId (nodeId ).add (masterNode ).build ())
370+ .build ();
371+
372+ ClusterChangedEvent event = new ClusterChangedEvent ("_source" , currentState , ClusterState .EMPTY_STATE );
373+
374+ SetOnce <Boolean > ranPolicy = new SetOnce <>();
375+ SetOnce <Boolean > moveToMaintenance = new SetOnce <>();
376+ doAnswer (invocationOnMock -> {
377+ ranPolicy .set (true );
378+ throw new AssertionError ("invalid invocation" );
379+ }).when (clusterService ).submitStateUpdateTask (anyString (), any (ExecuteStepsUpdateTask .class ));
380+
381+ doAnswer (invocationOnMock -> {
382+ MaintenanceModeUpdateTask task = (MaintenanceModeUpdateTask ) invocationOnMock .getArguments ()[1 ];
383+ assertThat (task .getOperationMode (), equalTo (OperationMode .MAINTENANCE ));
384+ moveToMaintenance .set (true );
385+ return null ;
386+ }).when (clusterService ).submitStateUpdateTask (anyString (), any (MaintenanceModeUpdateTask .class ));
387+
388+ indexLifecycleService .clusterChanged (event );
389+ assertNull (ranPolicy .get ());
390+ assertTrue (moveToMaintenance .get ());
391+ }
392+
259393// /**
260394// * Checks that a new index does the following successfully:
261395// *
0 commit comments