Replace PhaseAfterStep with PhaseCompleteStep (#33398)

This removes `PhaseAfterStep` in favor of a new `PhaseCompleteStep`. This step
in only a marker that the `LifecyclePolicyRunner` needs to halt until the time
indicated for entering the next phase.

This also fixes a bug where phase times were encapsulated into the policy
instead of dynamically adjusting to policy changes.

Supersedes #33140, which it replaces
Relates to #29823
This commit is contained in:
Lee Hinman 2018-09-05 16:37:45 -06:00 committed by GitHub
parent 8b8ff2bc6e
commit 96d515e3f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 250 additions and 287 deletions

View File

@ -145,35 +145,39 @@ public class IndexLifecycleIT extends ESRestHighLevelClientTestCase {
highLevelClient().indexLifecycle()::putLifecyclePolicyAsync); highLevelClient().indexLifecycle()::putLifecyclePolicyAsync);
assertTrue(putResponse.isAcknowledged()); assertTrue(putResponse.isAcknowledged());
createIndex("foo", Settings.builder().put("index.lifecycle.name", policy.getName()).build()); createIndex("foo-01", Settings.builder().put("index.lifecycle.name", policy.getName())
createIndex("baz", Settings.builder().put("index.lifecycle.name", policy.getName()).build()); .put("index.lifecycle.rollover_alias", "foo-alias").build(), "", "\"foo-alias\" : {}");
createIndex("baz-01", Settings.builder().put("index.lifecycle.name", policy.getName())
.put("index.lifecycle.rollover_alias", "baz-alias").build(), "", "\"baz-alias\" : {}");
createIndex("squash", Settings.EMPTY); createIndex("squash", Settings.EMPTY);
assertBusy(() -> { assertBusy(() -> {
GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices("foo", "baz"); GetSettingsRequest getSettingsRequest = new GetSettingsRequest().indices("foo-01", "baz-01");
GetSettingsResponse settingsResponse = highLevelClient().indices().getSettings(getSettingsRequest, RequestOptions.DEFAULT); GetSettingsResponse settingsResponse = highLevelClient().indices().getSettings(getSettingsRequest, RequestOptions.DEFAULT);
assertThat(settingsResponse.getSetting("foo", "index.lifecycle.name"), equalTo(policy.getName())); assertThat(settingsResponse.getSetting("foo-01", "index.lifecycle.name"), equalTo(policy.getName()));
assertThat(settingsResponse.getSetting("baz", "index.lifecycle.name"), equalTo(policy.getName())); assertThat(settingsResponse.getSetting("baz-01", "index.lifecycle.name"), equalTo(policy.getName()));
assertThat(settingsResponse.getSetting("foo", "index.lifecycle.phase"), equalTo("hot")); assertThat(settingsResponse.getSetting("foo-01", "index.lifecycle.phase"), equalTo("hot"));
assertThat(settingsResponse.getSetting("baz", "index.lifecycle.phase"), equalTo("hot")); assertThat(settingsResponse.getSetting("baz-01", "index.lifecycle.phase"), equalTo("hot"));
}); });
ExplainLifecycleRequest req = new ExplainLifecycleRequest(); ExplainLifecycleRequest req = new ExplainLifecycleRequest();
req.indices("foo", "baz", "squash"); req.indices("foo-01", "baz-01", "squash");
ExplainLifecycleResponse response = execute(req, highLevelClient().indexLifecycle()::explainLifecycle, ExplainLifecycleResponse response = execute(req, highLevelClient().indexLifecycle()::explainLifecycle,
highLevelClient().indexLifecycle()::explainLifecycleAsync); highLevelClient().indexLifecycle()::explainLifecycleAsync);
Map<String, IndexLifecycleExplainResponse> indexResponses = response.getIndexResponses(); Map<String, IndexLifecycleExplainResponse> indexResponses = response.getIndexResponses();
assertEquals(3, indexResponses.size()); assertEquals(3, indexResponses.size());
IndexLifecycleExplainResponse fooResponse = indexResponses.get("foo"); IndexLifecycleExplainResponse fooResponse = indexResponses.get("foo-01");
assertNotNull(fooResponse); assertNotNull(fooResponse);
assertTrue(fooResponse.managedByILM()); assertTrue(fooResponse.managedByILM());
assertEquals("foo", fooResponse.getIndex()); assertEquals("foo-01", fooResponse.getIndex());
assertEquals("hot", fooResponse.getPhase()); assertEquals("hot", fooResponse.getPhase());
assertEquals("rollover", fooResponse.getAction()); assertEquals("rollover", fooResponse.getAction());
assertEquals("attempt_rollover", fooResponse.getStep()); assertEquals("attempt_rollover", fooResponse.getStep());
IndexLifecycleExplainResponse bazResponse = indexResponses.get("baz"); IndexLifecycleExplainResponse bazResponse = indexResponses.get("baz-01");
assertNotNull(bazResponse); assertNotNull(bazResponse);
assertTrue(bazResponse.managedByILM()); assertTrue(bazResponse.managedByILM());
assertEquals("baz", bazResponse.getIndex()); assertEquals("baz-01", bazResponse.getIndex());
assertEquals("hot", bazResponse.getPhase()); assertEquals("hot", bazResponse.getPhase());
assertEquals("rollover", bazResponse.getAction()); assertEquals("rollover", bazResponse.getAction());
assertEquals("attempt_rollover", bazResponse.getStep()); assertEquals("attempt_rollover", bazResponse.getStep());

View File

@ -543,6 +543,14 @@ public abstract class ESRestTestCase extends ESTestCase {
client().performRequest(request); client().performRequest(request);
} }
protected static void createIndex(String name, Settings settings, String mapping, String aliases) throws IOException {
Request request = new Request("PUT", "/" + name);
request.setJsonEntity("{\n \"settings\": " + Strings.toString(settings)
+ ", \"mappings\" : {" + mapping + "}"
+ ", \"aliases\": {" + aliases + "} }");
client().performRequest(request);
}
protected static void deleteIndex(String name) throws IOException { protected static void deleteIndex(String name) throws IOException {
Request request = new Request("DELETE", "/" + name); Request request = new Request("DELETE", "/" + name);
client().performRequest(request); client().performRequest(request);

View File

@ -28,7 +28,6 @@ import java.util.ListIterator;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.LongSupplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -165,10 +164,9 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
* *
* @param client The Elasticsearch Client to use during execution of {@link AsyncActionStep} * @param client The Elasticsearch Client to use during execution of {@link AsyncActionStep}
* and {@link AsyncWaitStep} steps. * and {@link AsyncWaitStep} steps.
* @param nowSupplier The supplier of the current time for {@link PhaseAfterStep} steps.
* @return The list of {@link Step} objects in order of their execution. * @return The list of {@link Step} objects in order of their execution.
*/ */
public List<Step> toSteps(Client client, LongSupplier nowSupplier) { public List<Step> toSteps(Client client) {
List<Step> steps = new ArrayList<>(); List<Step> steps = new ArrayList<>();
List<Phase> orderedPhases = type.getOrderedPhases(phases); List<Phase> orderedPhases = type.getOrderedPhases(phases);
ListIterator<Phase> phaseIterator = orderedPhases.listIterator(orderedPhases.size()); ListIterator<Phase> phaseIterator = orderedPhases.listIterator(orderedPhases.size());
@ -187,8 +185,8 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
if (phase != null) { if (phase != null) {
// after step should have the name of the previous phase since the index is still in the // after step should have the name of the previous phase since the index is still in the
// previous phase until the after condition is reached // previous phase until the after condition is reached
Step.StepKey afterStepKey = new Step.StepKey(previousPhase.getName(), PhaseAfterStep.NAME, PhaseAfterStep.NAME); Step.StepKey afterStepKey = new Step.StepKey(previousPhase.getName(), PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
Step phaseAfterStep = new PhaseAfterStep(nowSupplier, phase.getAfter(), afterStepKey, lastStepKey); Step phaseAfterStep = new PhaseCompleteStep(afterStepKey, lastStepKey);
steps.add(phaseAfterStep); steps.add(phaseAfterStep);
lastStepKey = phaseAfterStep.getKey(); lastStepKey = phaseAfterStep.getKey();
} }
@ -211,8 +209,8 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
if (phase != null) { if (phase != null) {
// The very first after step is in a phase before the hot phase so call this "new" // The very first after step is in a phase before the hot phase so call this "new"
Step.StepKey afterStepKey = new Step.StepKey("new", PhaseAfterStep.NAME, PhaseAfterStep.NAME); Step.StepKey afterStepKey = new Step.StepKey("new", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
Step phaseAfterStep = new PhaseAfterStep(nowSupplier, phase.getAfter(), afterStepKey, lastStepKey); Step phaseAfterStep = new PhaseCompleteStep(afterStepKey, lastStepKey);
steps.add(phaseAfterStep); steps.add(phaseAfterStep);
lastStepKey = phaseAfterStep.getKey(); lastStepKey = phaseAfterStep.getKey();
} }
@ -289,7 +287,7 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
// there are no more steps we should execute // there are no more steps we should execute
return TerminalPolicyStep.KEY; return TerminalPolicyStep.KEY;
} else { } else {
return new StepKey(currentPhaseName, PhaseAfterStep.NAME, PhaseAfterStep.NAME); return new StepKey(currentPhaseName, PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
} }
} }
@ -306,7 +304,7 @@ public class LifecyclePolicy extends AbstractDiffable<LifecyclePolicy>
// InitializePolicyContextStep // InitializePolicyContextStep
return InitializePolicyContextStep.KEY; return InitializePolicyContextStep.KEY;
} }
return new StepKey(prevPhaseName, PhaseAfterStep.NAME, PhaseAfterStep.NAME); return new StepKey(prevPhaseName, PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
} }
} }

View File

@ -1,60 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.Index;
import java.util.Objects;
import java.util.function.LongSupplier;
public class PhaseAfterStep extends ClusterStateWaitStep {
public static final String NAME = "after";
private final TimeValue after;
private final LongSupplier nowSupplier;
PhaseAfterStep(LongSupplier nowSupplier, TimeValue after, StepKey key, StepKey nextStepKey) {
super(key, nextStepKey);
this.nowSupplier = nowSupplier;
this.after = after;
}
@Override
public Result isConditionMet(Index index, ClusterState clusterState) {
IndexMetaData indexMetaData = clusterState.metaData().index(index);
long lifecycleDate = indexMetaData.getSettings()
.getAsLong(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, -1L);
return new Result(nowSupplier.getAsLong() >= lifecycleDate + after.getMillis(), null);
}
TimeValue getAfter() {
return after;
}
LongSupplier getNowSupplier() {
return nowSupplier;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), after);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
PhaseAfterStep other = (PhaseAfterStep) obj;
return super.equals(obj) &&
Objects.equals(after, other.after);
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
/**
* This is essentially a marker that a phase has ended, and we need to check
* the age of an index before proceeding to the next phase.
*/
public class PhaseCompleteStep extends Step {
public static final String NAME = "complete";
public PhaseCompleteStep(StepKey key, StepKey nextStepKey) {
super(key, nextStepKey);
}
}

View File

@ -30,7 +30,6 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.LongSupplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
@ -170,11 +169,10 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
public void testFirstAndLastSteps() { public void testFirstAndLastSteps() {
Client client = mock(Client.class); Client client = mock(Client.class);
LongSupplier nowSupplier = () -> 0L;
lifecycleName = randomAlphaOfLengthBetween(1, 20); lifecycleName = randomAlphaOfLengthBetween(1, 20);
Map<String, Phase> phases = new LinkedHashMap<>(); Map<String, Phase> phases = new LinkedHashMap<>();
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
List<Step> steps = policy.toSteps(client, nowSupplier); List<Step> steps = policy.toSteps(client);
assertThat(steps.size(), equalTo(2)); assertThat(steps.size(), equalTo(2));
assertThat(steps.get(0), instanceOf(InitializePolicyContextStep.class)); assertThat(steps.get(0), instanceOf(InitializePolicyContextStep.class));
assertThat(steps.get(0).getKey(), equalTo(new StepKey("new", "init", "init"))); assertThat(steps.get(0).getKey(), equalTo(new StepKey("new", "init", "init")));
@ -184,7 +182,6 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
public void testToStepsWithOneStep() { public void testToStepsWithOneStep() {
Client client = mock(Client.class); Client client = mock(Client.class);
LongSupplier nowSupplier = () -> 0L;
MockStep mockStep = new MockStep( MockStep mockStep = new MockStep(
new Step.StepKey("test", "test", "test"), TerminalPolicyStep.KEY); new Step.StepKey("test", "test", "test"), TerminalPolicyStep.KEY);
@ -196,8 +193,8 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
phases.put(firstPhase.getName(), firstPhase); phases.put(firstPhase.getName(), firstPhase);
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
StepKey firstStepKey = InitializePolicyContextStep.KEY; StepKey firstStepKey = InitializePolicyContextStep.KEY;
StepKey secondStepKey = new StepKey("new", PhaseAfterStep.NAME, PhaseAfterStep.NAME); StepKey secondStepKey = new StepKey("new", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME);
List<Step> steps = policy.toSteps(client, nowSupplier); List<Step> steps = policy.toSteps(client);
assertThat(steps.size(), equalTo(4)); assertThat(steps.size(), equalTo(4));
assertSame(steps.get(0).getKey(), firstStepKey); assertSame(steps.get(0).getKey(), firstStepKey);
assertThat(steps.get(0).getNextStepKey(), equalTo(secondStepKey)); assertThat(steps.get(0).getNextStepKey(), equalTo(secondStepKey));
@ -210,13 +207,12 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
public void testToStepsWithTwoPhases() { public void testToStepsWithTwoPhases() {
Client client = mock(Client.class); Client client = mock(Client.class);
LongSupplier nowSupplier = () -> 0L;
MockStep secondActionStep = new MockStep(new StepKey("second_phase", "test2", "test"), TerminalPolicyStep.KEY); MockStep secondActionStep = new MockStep(new StepKey("second_phase", "test2", "test"), TerminalPolicyStep.KEY);
MockStep secondAfter = new MockStep(new StepKey("first_phase", PhaseAfterStep.NAME, PhaseAfterStep.NAME), MockStep secondAfter = new MockStep(new StepKey("first_phase", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME),
secondActionStep.getKey()); secondActionStep.getKey());
MockStep firstActionAnotherStep = new MockStep(new StepKey("first_phase", "test", "bar"), secondAfter.getKey()); MockStep firstActionAnotherStep = new MockStep(new StepKey("first_phase", "test", "bar"), secondAfter.getKey());
MockStep firstActionStep = new MockStep(new StepKey("first_phase", "test", "foo"), firstActionAnotherStep.getKey()); MockStep firstActionStep = new MockStep(new StepKey("first_phase", "test", "foo"), firstActionAnotherStep.getKey());
MockStep firstAfter = new MockStep(new StepKey("new", PhaseAfterStep.NAME, PhaseAfterStep.NAME), firstActionStep.getKey()); MockStep firstAfter = new MockStep(new StepKey("new", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME), firstActionStep.getKey());
MockStep init = new MockStep(InitializePolicyContextStep.KEY, firstAfter.getKey()); MockStep init = new MockStep(InitializePolicyContextStep.KEY, firstAfter.getKey());
lifecycleName = randomAlphaOfLengthBetween(1, 20); lifecycleName = randomAlphaOfLengthBetween(1, 20);
@ -231,17 +227,17 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
phases.put(secondPhase.getName(), secondPhase); phases.put(secondPhase.getName(), secondPhase);
LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases); LifecyclePolicy policy = new LifecyclePolicy(TestLifecycleType.INSTANCE, lifecycleName, phases);
List<Step> steps = policy.toSteps(client, nowSupplier); List<Step> steps = policy.toSteps(client);
assertThat(steps.size(), equalTo(7)); assertThat(steps.size(), equalTo(7));
assertThat(steps.get(0).getClass(), equalTo(InitializePolicyContextStep.class)); assertThat(steps.get(0).getClass(), equalTo(InitializePolicyContextStep.class));
assertThat(steps.get(0).getKey(), equalTo(init.getKey())); assertThat(steps.get(0).getKey(), equalTo(init.getKey()));
assertThat(steps.get(0).getNextStepKey(), equalTo(init.getNextStepKey())); assertThat(steps.get(0).getNextStepKey(), equalTo(init.getNextStepKey()));
assertThat(steps.get(1).getClass(), equalTo(PhaseAfterStep.class)); assertThat(steps.get(1).getClass(), equalTo(PhaseCompleteStep.class));
assertThat(steps.get(1).getKey(), equalTo(firstAfter.getKey())); assertThat(steps.get(1).getKey(), equalTo(firstAfter.getKey()));
assertThat(steps.get(1).getNextStepKey(), equalTo(firstAfter.getNextStepKey())); assertThat(steps.get(1).getNextStepKey(), equalTo(firstAfter.getNextStepKey()));
assertThat(steps.get(2), equalTo(firstActionStep)); assertThat(steps.get(2), equalTo(firstActionStep));
assertThat(steps.get(3), equalTo(firstActionAnotherStep)); assertThat(steps.get(3), equalTo(firstActionAnotherStep));
assertThat(steps.get(4).getClass(), equalTo(PhaseAfterStep.class)); assertThat(steps.get(4).getClass(), equalTo(PhaseCompleteStep.class));
assertThat(steps.get(4).getKey(), equalTo(secondAfter.getKey())); assertThat(steps.get(4).getKey(), equalTo(secondAfter.getKey()));
assertThat(steps.get(4).getNextStepKey(), equalTo(secondAfter.getNextStepKey())); assertThat(steps.get(4).getNextStepKey(), equalTo(secondAfter.getNextStepKey()));
assertThat(steps.get(5), equalTo(secondActionStep)); assertThat(steps.get(5), equalTo(secondActionStep));
@ -337,7 +333,7 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
currentStep = new StepKey("phase_1", "action_3", "step_missing"); currentStep = new StepKey("phase_1", "action_3", "step_missing");
nextStep = policy.getNextValidStep(currentStep); nextStep = policy.getNextValidStep(currentStep);
assertNotNull(nextStep); assertNotNull(nextStep);
assertEquals(new StepKey("phase_1", PhaseAfterStep.NAME, PhaseAfterStep.NAME), nextStep); assertEquals(new StepKey("phase_1", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME), nextStep);
// current action exists but step does not and action is last in the // current action exists but step does not and action is last in the
// last phase // last phase
@ -356,7 +352,7 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
currentStep = new StepKey("phase_1", "action_4", "step_2"); currentStep = new StepKey("phase_1", "action_4", "step_2");
nextStep = policy.getNextValidStep(currentStep); nextStep = policy.getNextValidStep(currentStep);
assertNotNull(nextStep); assertNotNull(nextStep);
assertEquals(new StepKey("phase_1", PhaseAfterStep.NAME, PhaseAfterStep.NAME), nextStep); assertEquals(new StepKey("phase_1", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME), nextStep);
// current action no longer exists and action was last in the last phase // current action no longer exists and action was last in the last phase
currentStep = new StepKey("phase_4", "action_4", "step_2"); currentStep = new StepKey("phase_4", "action_4", "step_2");
@ -368,7 +364,7 @@ public class LifecyclePolicyTests extends AbstractSerializingTestCase<LifecycleP
currentStep = new StepKey("phase_3", "action_2", "step_2"); currentStep = new StepKey("phase_3", "action_2", "step_2");
nextStep = policy.getNextValidStep(currentStep); nextStep = policy.getNextValidStep(currentStep);
assertNotNull(nextStep); assertNotNull(nextStep);
assertEquals(new StepKey("phase_2", PhaseAfterStep.NAME, PhaseAfterStep.NAME), nextStep); assertEquals(new StepKey("phase_2", PhaseCompleteStep.NAME, PhaseCompleteStep.NAME), nextStep);
// current phase no longer exists and was last phase // current phase no longer exists and was last phase
currentStep = new StepKey("phase_5", "action_2", "step_2"); currentStep = new StepKey("phase_5", "action_2", "step_2");

View File

@ -1,103 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.ClusterStateWaitStep.Result;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
import java.util.concurrent.TimeUnit;
public class PhaseAfterStepTests extends AbstractStepTestCase<PhaseAfterStep> {
@Override
public PhaseAfterStep createRandomInstance() {
StepKey stepKey = randomStepKey();
StepKey nextStepKey = randomStepKey();
TimeValue after = createRandomTimeValue();
return new PhaseAfterStep(null, after, stepKey, nextStepKey);
}
private TimeValue createRandomTimeValue() {
return new TimeValue(randomLongBetween(1, 10000), randomFrom(TimeUnit.SECONDS, TimeUnit.MINUTES, TimeUnit.HOURS, TimeUnit.DAYS));
}
@Override
public PhaseAfterStep mutateInstance(PhaseAfterStep instance) {
StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey();
TimeValue after = instance.getAfter();
switch (between(0, 2)) {
case 0:
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 1:
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
break;
case 2:
after = randomValueOtherThan(after, this::createRandomTimeValue);
break;
default:
throw new AssertionError("Illegal randomisation branch");
}
return new PhaseAfterStep(instance.getNowSupplier(), after, key, nextKey);
}
@Override
public PhaseAfterStep copyInstance(PhaseAfterStep instance) {
return new PhaseAfterStep(instance.getNowSupplier(), instance.getAfter(),
instance.getKey(), instance.getNextStepKey());
}
public void testConditionMet() {
long creationDate = randomNonNegativeLong();
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate))
.creationDate(creationDate)
.numberOfShards(1).numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
Index index = indexMetadata.getIndex();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
long after = randomNonNegativeLong();
long now = creationDate + after + randomIntBetween(0, 2);
PhaseAfterStep step = new PhaseAfterStep(() -> now, TimeValue.timeValueMillis(after), null, null);
Result result = step.isConditionMet(index, clusterState);
assertTrue(result.isComplete());
assertNull(result.getInfomationContext());
}
public void testConditionNotMet() {
long creationDate = randomNonNegativeLong();
IndexMetaData indexMetadata = IndexMetaData.builder(randomAlphaOfLength(5))
.settings(settings(Version.CURRENT).put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, creationDate))
.creationDate(creationDate)
.numberOfShards(1).numberOfReplicas(0).build();
MetaData metaData = MetaData.builder()
.persistentSettings(settings(Version.CURRENT).build())
.put(IndexMetaData.builder(indexMetadata))
.build();
Index index = indexMetadata.getIndex();
ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
long after = randomNonNegativeLong();
long now = creationDate + after - randomIntBetween(1, 1000);
PhaseAfterStep step = new PhaseAfterStep(() -> now, TimeValue.timeValueMillis(after), null, null);
Result result = step.isConditionMet(index, clusterState);
assertFalse(result.isComplete());
assertNull(result.getInfomationContext());
}
}

View File

@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
package org.elasticsearch.xpack.core.indexlifecycle;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
public class PhaseCompleteStepTests extends AbstractStepTestCase<PhaseCompleteStep> {
@Override
public PhaseCompleteStep createRandomInstance() {
StepKey stepKey = randomStepKey();
StepKey nextStepKey = randomStepKey();
return new PhaseCompleteStep(stepKey, nextStepKey);
}
@Override
public PhaseCompleteStep mutateInstance(PhaseCompleteStep instance) {
StepKey key = instance.getKey();
StepKey nextKey = instance.getNextStepKey();
if (randomBoolean()) {
key = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
} else {
nextKey = new StepKey(key.getPhase(), key.getAction(), key.getName() + randomAlphaOfLength(5));
}
return new PhaseCompleteStep(key, nextKey);
}
@Override
public PhaseCompleteStep copyInstance(PhaseCompleteStep instance) {
return new PhaseCompleteStep(instance.getKey(), instance.getNextStepKey());
}
}

View File

@ -16,6 +16,7 @@ import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
@ -30,6 +31,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.Phase; import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.PhaseCompleteStep;
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction; import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
import org.elasticsearch.xpack.core.indexlifecycle.Step; import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
@ -51,6 +53,31 @@ public class IndexLifecycleRunner {
this.nowSupplier = nowSupplier; this.nowSupplier = nowSupplier;
} }
/**
* Return true or false depending on whether the index is ready to be in {@code phase}
*/
boolean isReadyToTransitionToThisPhase(final String policy, final IndexMetaData indexMetaData, final String phase) {
final Settings indexSettings = indexMetaData.getSettings();
if (indexSettings.hasValue(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE) == false) {
logger.trace("no index creation date has been set yet");
return true;
}
final long lifecycleDate = indexSettings.getAsLong(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, -1L);
assert lifecycleDate >= 0 : "expected index to have a lifecycle date but it did not";
final TimeValue after = stepRegistry.getIndexAgeForPhase(policy, phase);
final long now = nowSupplier.getAsLong();
final TimeValue age = new TimeValue(now - lifecycleDate);
if (logger.isTraceEnabled()) {
logger.trace("[{}] checking for index age to be at least [{}] before performing actions in " +
"the \"{}\" phase. Now: {}, lifecycle date: {}, age: [{}/{}s]",
indexMetaData.getIndex().getName(), after, phase,
new TimeValue(now).seconds(),
new TimeValue(lifecycleDate).seconds(),
age, age.seconds());
}
return now >= lifecycleDate + after.getMillis();
}
public void runPolicy(String policy, IndexMetaData indexMetaData, ClusterState currentState, public void runPolicy(String policy, IndexMetaData indexMetaData, ClusterState currentState,
boolean fromClusterStateChange) { boolean fromClusterStateChange) {
Settings indexSettings = indexMetaData.getSettings(); Settings indexSettings = indexMetaData.getSettings();
@ -67,13 +94,23 @@ public class IndexLifecycleRunner {
+ "] with policy [" + policy + "] is not recognized"); + "] with policy [" + policy + "] is not recognized");
return; return;
} }
logger.debug("running policy with current-step[" + currentStep.getKey() + "]"); logger.debug("running policy with current-step [" + currentStep.getKey() + "]");
if (currentStep instanceof TerminalPolicyStep) { if (currentStep instanceof TerminalPolicyStep) {
logger.debug("policy [" + policy + "] for index [" + indexMetaData.getIndex().getName() + "] complete, skipping execution"); logger.debug("policy [" + policy + "] for index [" + indexMetaData.getIndex().getName() + "] complete, skipping execution");
return;
} else if (currentStep instanceof ErrorStep) { } else if (currentStep instanceof ErrorStep) {
logger.debug( logger.debug(
"policy [" + policy + "] for index [" + indexMetaData.getIndex().getName() + "] on an error step, skipping execution"); "policy [" + policy + "] for index [" + indexMetaData.getIndex().getName() + "] on an error step, skipping execution");
} else if (currentStep instanceof ClusterStateActionStep || currentStep instanceof ClusterStateWaitStep) { return;
} else if (currentStep instanceof PhaseCompleteStep) {
// Only proceed to the next step if enough time has elapsed to go into the next phase
if (isReadyToTransitionToThisPhase(policy, indexMetaData, currentStep.getNextStepKey().getPhase())) {
moveToStep(indexMetaData.getIndex(), policy, currentStep.getKey(), currentStep.getNextStepKey());
}
return;
}
if (currentStep instanceof ClusterStateActionStep || currentStep instanceof ClusterStateWaitStep) {
executeClusterStateSteps(indexMetaData.getIndex(), policy, currentStep); executeClusterStateSteps(indexMetaData.getIndex(), policy, currentStep);
} else if (currentStep instanceof AsyncWaitStep) { } else if (currentStep instanceof AsyncWaitStep) {
if (fromClusterStateChange == false) { if (fromClusterStateChange == false) {

View File

@ -146,7 +146,7 @@ public class IndexLifecycleService extends AbstractComponent
policyRegistry.removeIndices(event.indicesDeleted()); policyRegistry.removeIndices(event.indicesDeleted());
} }
if (event.state().metaData().custom(IndexLifecycleMetadata.TYPE) != null) { if (event.state().metaData().custom(IndexLifecycleMetadata.TYPE) != null) {
policyRegistry.update(event.state(), client, nowSupplier); policyRegistry.update(event.state(), client);
} }
} }
} }

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.indexlifecycle;
import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.ClusterStateUpdateTask; import org.elasticsearch.cluster.ClusterStateUpdateTask;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
@ -51,7 +52,12 @@ public class MoveToNextStepUpdateTask extends ClusterStateUpdateTask {
@Override @Override
public ClusterState execute(ClusterState currentState) { public ClusterState execute(ClusterState currentState) {
Settings indexSettings = currentState.getMetaData().index(index).getSettings(); IndexMetaData indexMetaData = currentState.getMetaData().index(index);
if (indexMetaData == null) {
// Index must have been since deleted, ignore it
return currentState;
}
Settings indexSettings = indexMetaData.getSettings();
if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings)) if (policy.equals(LifecycleSettings.LIFECYCLE_NAME_SETTING.get(indexSettings))
&& currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(indexSettings))) { && currentStepKey.equals(IndexLifecycleRunner.getCurrentStepKey(indexSettings))) {
return IndexLifecycleRunner.moveClusterStateToNextStep(index, currentState, currentStepKey, nextStepKey, nowSupplier); return IndexLifecycleRunner.moveClusterStateToNextStep(index, currentState, currentStepKey, nextStepKey, nowSupplier);

View File

@ -16,6 +16,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.Nullable; import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.DeprecationHandler; import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
@ -39,7 +40,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.LongSupplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class PolicyStepsRegistry { public class PolicyStepsRegistry {
@ -97,7 +97,7 @@ public class PolicyStepsRegistry {
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
public void update(ClusterState clusterState, Client client, LongSupplier nowSupplier) { public void update(ClusterState clusterState, Client client) {
final IndexLifecycleMetadata meta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE); final IndexLifecycleMetadata meta = clusterState.metaData().custom(IndexLifecycleMetadata.TYPE);
assert meta != null : "IndexLifecycleMetadata cannot be null when updating the policy steps registry"; assert meta != null : "IndexLifecycleMetadata cannot be null when updating the policy steps registry";
@ -134,7 +134,7 @@ public class PolicyStepsRegistry {
LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client, ClientHelper.INDEX_LIFECYCLE_ORIGIN, LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client, ClientHelper.INDEX_LIFECYCLE_ORIGIN,
policyMetadata.getHeaders()); policyMetadata.getHeaders());
lifecyclePolicyMap.put(policyMetadata.getName(), policyMetadata); lifecyclePolicyMap.put(policyMetadata.getName(), policyMetadata);
List<Step> policyAsSteps = policyMetadata.getPolicy().toSteps(policyClient, nowSupplier); List<Step> policyAsSteps = policyMetadata.getPolicy().toSteps(policyClient);
if (policyAsSteps.isEmpty() == false) { if (policyAsSteps.isEmpty() == false) {
firstStepMap.put(policyMetadata.getName(), policyAsSteps.get(0)); firstStepMap.put(policyMetadata.getName(), policyAsSteps.get(0));
final Map<Step.StepKey, Step> stepMapForPolicy = new HashMap<>(); final Map<Step.StepKey, Step> stepMapForPolicy = new HashMap<>();
@ -192,7 +192,7 @@ public class PolicyStepsRegistry {
} }
LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client, LifecyclePolicySecurityClient policyClient = new LifecyclePolicySecurityClient(client,
ClientHelper.INDEX_LIFECYCLE_ORIGIN, lifecyclePolicyMap.get(policy).getHeaders()); ClientHelper.INDEX_LIFECYCLE_ORIGIN, lifecyclePolicyMap.get(policy).getHeaders());
final List<Step> steps = policyToExecute.toSteps(policyClient, nowSupplier); final List<Step> steps = policyToExecute.toSteps(policyClient);
// Build a list of steps that correspond with the phase the index is currently in // Build a list of steps that correspond with the phase the index is currently in
final List<Step> phaseSteps; final List<Step> phaseSteps;
if (steps == null) { if (steps == null) {
@ -257,4 +257,22 @@ public class PolicyStepsRegistry {
return firstStepMap.get(policy); return firstStepMap.get(policy);
} }
public TimeValue getIndexAgeForPhase(final String policy, final String phase) {
// These built in phases should never wait
if (InitializePolicyContextStep.INITIALIZATION_PHASE.equals(phase) || TerminalPolicyStep.COMPLETED_PHASE.equals(phase)) {
return TimeValue.ZERO;
}
final LifecyclePolicyMetadata meta = lifecyclePolicyMap.get(policy);
if (meta == null) {
throw new IllegalArgumentException("no policy found with name \"" + policy + "\"");
} else {
final Phase retrievedPhase = meta.getPolicy().getPhases().get(phase);
if (retrievedPhase == null) {
// We don't have that phase registered, proceed right through it
return TimeValue.ZERO;
} else {
return retrievedPhase.getAfter();
}
}
}
} }

View File

@ -15,15 +15,12 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress; import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.node.Node; import org.elasticsearch.node.Node;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.OperationMode;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata; import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
@ -31,6 +28,7 @@ import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.MockAction; import org.elasticsearch.xpack.core.indexlifecycle.MockAction;
import org.elasticsearch.xpack.core.indexlifecycle.MockStep; import org.elasticsearch.xpack.core.indexlifecycle.MockStep;
import org.elasticsearch.xpack.core.indexlifecycle.OperationMode;
import org.elasticsearch.xpack.core.indexlifecycle.Phase; import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.Step; import org.elasticsearch.xpack.core.indexlifecycle.Step;
import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey; import org.elasticsearch.xpack.core.indexlifecycle.Step.StepKey;
@ -129,44 +127,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
.metaData(metaData) .metaData(metaData)
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.build(); .build();
policyStepsRegistry.update(clusterState, client, () -> 0L); policyStepsRegistry.update(clusterState, client);
}
public void testExecuteAllUntilEndOfPhase() throws IOException {
NamedXContentRegistry registry = new NamedXContentRegistry(
Collections.singletonList(new NamedXContentRegistry.Entry(LifecycleAction.class, new ParseField(MockAction.NAME),
(p) -> {
MockAction.parse(p);
return new MockAction(Arrays.asList(firstStep, allClusterSecondStep));
})));
policyStepsRegistry = new PolicyStepsRegistry(registry);
setupIndexPolicy(allClusterPolicyName);
Step startStep = policyStepsRegistry.getFirstStep(allClusterPolicyName);
long now = randomNonNegativeLong();
// test execute start till end of phase `new`
ExecuteStepsUpdateTask task = new ExecuteStepsUpdateTask(allClusterPolicyName, index, startStep, policyStepsRegistry, () -> now);
ClusterState newState = task.execute(clusterState);
// Update the registry so the next phase's steps are loaded
policyStepsRegistry.update(newState, client, () -> now);
// verify that both the `new` phase was executed and the next phase is to begin
StepKey currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(firstStep.getKey()));
// test execute all actions in same phase
task = new ExecuteStepsUpdateTask(allClusterPolicyName, index, firstStep, policyStepsRegistry, () -> now);
newState = task.execute(newState);
policyStepsRegistry.update(newState, client, () -> now);
assertThat(firstStep.getExecuteCount(), equalTo(1L));
assertThat(allClusterSecondStep.getExecuteCount(), equalTo(1L));
currentStepKey = IndexLifecycleRunner.getCurrentStepKey(newState.metaData().index(index).getSettings());
assertThat(currentStepKey, equalTo(TerminalPolicyStep.KEY));
assertNull(policyStepsRegistry.getStep(index, currentStepKey).getNextStepKey());
assertThat(LifecycleSettings.LIFECYCLE_PHASE_TIME_SETTING.get(newState.metaData().index(index).getSettings()), equalTo(now));
assertThat(LifecycleSettings.LIFECYCLE_ACTION_TIME_SETTING.get(newState.metaData().index(index).getSettings()), equalTo(now));
assertThat(LifecycleSettings.LIFECYCLE_STEP_INFO_SETTING.get(newState.metaData().index(index).getSettings()), equalTo(""));
} }
public void testNeverExecuteNonClusterStateStep() throws IOException { public void testNeverExecuteNonClusterStateStep() throws IOException {
@ -201,7 +162,7 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
.put(LifecycleSettings.LIFECYCLE_PHASE, (String) null) .put(LifecycleSettings.LIFECYCLE_PHASE, (String) null)
.put(LifecycleSettings.LIFECYCLE_ACTION, (String) null) .put(LifecycleSettings.LIFECYCLE_ACTION, (String) null)
.put(LifecycleSettings.LIFECYCLE_STEP, (String) null).build()))).build(); .put(LifecycleSettings.LIFECYCLE_STEP, (String) null).build()))).build();
policyStepsRegistry.update(clusterState, client, () -> 0); policyStepsRegistry.update(clusterState, client);
Step invalidStep = new MockClusterStateActionStep(firstStepKey, secondStepKey); Step invalidStep = new MockClusterStateActionStep(firstStepKey, secondStepKey);
long now = randomNonNegativeLong(); long now = randomNonNegativeLong();
@ -266,6 +227,6 @@ public class ExecuteStepsUpdateTaskTests extends ESTestCase {
.put(LifecycleSettings.LIFECYCLE_PHASE, stepKey.getPhase()) .put(LifecycleSettings.LIFECYCLE_PHASE, stepKey.getPhase())
.put(LifecycleSettings.LIFECYCLE_ACTION, stepKey.getAction()) .put(LifecycleSettings.LIFECYCLE_ACTION, stepKey.getAction())
.put(LifecycleSettings.LIFECYCLE_STEP, stepKey.getName()).build()))).build(); .put(LifecycleSettings.LIFECYCLE_STEP, stepKey.getName()).build()))).build();
policyStepsRegistry.update(clusterState, client, () -> 0); policyStepsRegistry.update(clusterState, client);
} }
} }

View File

@ -22,8 +22,6 @@ import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.index.Index; import org.elasticsearch.index.Index;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyTests;
import org.elasticsearch.xpack.core.indexlifecycle.OperationMode;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.AbstractStepTestCase; import org.elasticsearch.xpack.core.indexlifecycle.AbstractStepTestCase;
import org.elasticsearch.xpack.core.indexlifecycle.AsyncActionStep; import org.elasticsearch.xpack.core.indexlifecycle.AsyncActionStep;
@ -35,9 +33,11 @@ import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleAction;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata; import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyMetadata;
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicyTests;
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings; import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
import org.elasticsearch.xpack.core.indexlifecycle.MockAction; import org.elasticsearch.xpack.core.indexlifecycle.MockAction;
import org.elasticsearch.xpack.core.indexlifecycle.MockStep; import org.elasticsearch.xpack.core.indexlifecycle.MockStep;
import org.elasticsearch.xpack.core.indexlifecycle.OperationMode;
import org.elasticsearch.xpack.core.indexlifecycle.Phase; import org.elasticsearch.xpack.core.indexlifecycle.Phase;
import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction; import org.elasticsearch.xpack.core.indexlifecycle.RolloverAction;
import org.elasticsearch.xpack.core.indexlifecycle.Step; import org.elasticsearch.xpack.core.indexlifecycle.Step;
@ -54,6 +54,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -1058,6 +1060,47 @@ public class IndexLifecycleRunnerTests extends ESTestCase {
assertIndexNotManagedByILM(newClusterState, index); assertIndexNotManagedByILM(newClusterState, index);
} }
public void testIsReadyToTransition() {
String policyName = "async_action_policy";
StepKey stepKey = new StepKey("phase", MockAction.NAME, MockAction.NAME);
MockAsyncActionStep step = new MockAsyncActionStep(stepKey, null);
step.setWillComplete(true);
SortedMap<String, LifecyclePolicyMetadata> lifecyclePolicyMap = new TreeMap<>(Collections.singletonMap(policyName,
new LifecyclePolicyMetadata(createPolicy(policyName, null, step.getKey()), new HashMap<>())));
Index index = new Index("my_index", "uuid");
Map<String, Step> firstStepMap = Collections.singletonMap(policyName, step);
Map<StepKey, Step> policySteps = Collections.singletonMap(step.getKey(), step);
Map<String, Map<StepKey, Step>> stepMap = Collections.singletonMap(policyName, policySteps);
Map<Index, List<Step>> indexSteps = Collections.singletonMap(index, Collections.singletonList(step));
PolicyStepsRegistry policyStepsRegistry = new PolicyStepsRegistry(lifecyclePolicyMap, firstStepMap,
stepMap, indexSteps, NamedXContentRegistry.EMPTY);
ClusterService clusterService = mock(ClusterService.class);
final AtomicLong now = new AtomicLong(5);
IndexLifecycleRunner runner = new IndexLifecycleRunner(policyStepsRegistry, clusterService, now::get);
IndexMetaData indexMetaData = IndexMetaData.builder("my_index").settings(settings(Version.CURRENT))
.numberOfShards(randomIntBetween(1, 5))
.numberOfReplicas(randomIntBetween(0, 5))
.build();
// With no time, always transition
assertTrue("index should be able to transition with no creation date",
runner.isReadyToTransitionToThisPhase(policyName, indexMetaData, "phase"));
indexMetaData = IndexMetaData.builder(indexMetaData)
.settings(Settings.builder()
.put(indexMetaData.getSettings())
.put(LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE, 10L)
.build())
.build();
// Index is not old enough to transition
assertFalse("index is not able to transition if it isn't old enough",
runner.isReadyToTransitionToThisPhase(policyName, indexMetaData, "phase"));
// Set to the fuuuuuttuuuuuuurre
now.set(Long.MAX_VALUE);
assertTrue("index should be able to transition past phase's age",
runner.isReadyToTransitionToThisPhase(policyName, indexMetaData, "phase"));
}
public static void assertIndexNotManagedByILM(ClusterState clusterState, Index index) { public static void assertIndexNotManagedByILM(ClusterState clusterState, Index index) {
MetaData metadata = clusterState.metaData(); MetaData metadata = clusterState.metaData();
assertNotNull(metadata); assertNotNull(metadata);

View File

@ -59,7 +59,7 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
public void testExecuteSuccessfullyMoved() { public void testExecuteSuccessfullyMoved() {
long now = randomNonNegativeLong(); long now = randomNonNegativeLong();
List<Step> steps = lifecyclePolicy.toSteps(null, () -> now); List<Step> steps = lifecyclePolicy.toSteps(null);
StepKey currentStepKey = steps.get(0).getKey(); StepKey currentStepKey = steps.get(0).getKey();
StepKey nextStepKey = steps.get(0).getNextStepKey(); StepKey nextStepKey = steps.get(0).getNextStepKey();
@ -103,7 +103,7 @@ public class MoveToNextStepUpdateTaskTests extends ESTestCase {
public void testExecuteSuccessfulMoveWithInvalidNextStep() { public void testExecuteSuccessfulMoveWithInvalidNextStep() {
long now = randomNonNegativeLong(); long now = randomNonNegativeLong();
List<Step> steps = lifecyclePolicy.toSteps(null, () -> now); List<Step> steps = lifecyclePolicy.toSteps(null);
StepKey currentStepKey = steps.get(0).getKey(); StepKey currentStepKey = steps.get(0).getKey();
StepKey invalidNextStep = new StepKey("next-invalid", "next-invalid", "next-invalid"); StepKey invalidNextStep = new StepKey("next-invalid", "next-invalid", "next-invalid");

View File

@ -109,7 +109,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
String policyName = randomAlphaOfLength(5); String policyName = randomAlphaOfLength(5);
LifecyclePolicy newPolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policyName); LifecyclePolicy newPolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policyName);
logger.info("--> policy: {}", newPolicy); logger.info("--> policy: {}", newPolicy);
List<Step> policySteps = newPolicy.toSteps(client, () -> 0L); List<Step> policySteps = newPolicy.toSteps(client);
Map<String, String> headers = new HashMap<>(); Map<String, String> headers = new HashMap<>();
if (randomBoolean()) { if (randomBoolean()) {
headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10));
@ -149,7 +149,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY); PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY);
// add new policy // add new policy
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
assertThat(registry.getFirstStep(newPolicy.getName()), equalTo(policySteps.get(0))); assertThat(registry.getFirstStep(newPolicy.getName()), equalTo(policySteps.get(0)));
assertThat(registry.getLifecyclePolicyMap().size(), equalTo(1)); assertThat(registry.getLifecyclePolicyMap().size(), equalTo(1));
@ -167,7 +167,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
.put(LifecycleSettings.LIFECYCLE_PHASE, step.getKey().getPhase())))) .put(LifecycleSettings.LIFECYCLE_PHASE, step.getKey().getPhase()))))
.nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build())
.build(); .build();
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
assertThat(registeredStepsForPolicy.get(step.getKey()), equalTo(step)); assertThat(registeredStepsForPolicy.get(step.getKey()), equalTo(step));
assertThat(registry.getStep(index, step.getKey()), equalTo(step)); assertThat(registry.getStep(index, step.getKey()), equalTo(step));
} }
@ -175,7 +175,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
Map<String, LifecyclePolicyMetadata> registryPolicyMap = registry.getLifecyclePolicyMap(); Map<String, LifecyclePolicyMetadata> registryPolicyMap = registry.getLifecyclePolicyMap();
Map<String, Step> registryFirstStepMap = registry.getFirstStepMap(); Map<String, Step> registryFirstStepMap = registry.getFirstStepMap();
Map<String, Map<Step.StepKey, Step>> registryStepMap = registry.getStepMap(); Map<String, Map<Step.StepKey, Step>> registryStepMap = registry.getStepMap();
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
assertThat(registry.getLifecyclePolicyMap(), equalTo(registryPolicyMap)); assertThat(registry.getLifecyclePolicyMap(), equalTo(registryPolicyMap));
assertThat(registry.getFirstStepMap(), equalTo(registryFirstStepMap)); assertThat(registry.getFirstStepMap(), equalTo(registryFirstStepMap));
assertThat(registry.getStepMap(), equalTo(registryStepMap)); assertThat(registry.getStepMap(), equalTo(registryStepMap));
@ -186,7 +186,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
.metaData( .metaData(
MetaData.builder(metaData) MetaData.builder(metaData)
.putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata)).build(); .putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata)).build();
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
assertTrue(registry.getLifecyclePolicyMap().isEmpty()); assertTrue(registry.getLifecyclePolicyMap().isEmpty());
assertTrue(registry.getFirstStepMap().isEmpty()); assertTrue(registry.getFirstStepMap().isEmpty());
assertTrue(registry.getStepMap().isEmpty()); assertTrue(registry.getStepMap().isEmpty());
@ -219,7 +219,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
.build(); .build();
PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY); PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY);
// add new policy // add new policy
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
// swap out policy // swap out policy
newPolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policyName); newPolicy = LifecyclePolicyTests.randomTestLifecyclePolicy(policyName);
@ -227,7 +227,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())), OperationMode.RUNNING); new LifecyclePolicyMetadata(newPolicy, Collections.emptyMap())), OperationMode.RUNNING);
currentState = ClusterState.builder(currentState) currentState = ClusterState.builder(currentState)
.metaData(MetaData.builder(metaData).putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata)).build(); .metaData(MetaData.builder(metaData).putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata)).build();
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
// TODO(talevy): assert changes... right now we do not support updates to policies. will require internal cleanup // TODO(talevy): assert changes... right now we do not support updates to policies. will require internal cleanup
} }
@ -249,7 +249,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
LifecyclePolicy updatedPolicy = new LifecyclePolicy(policyName, phases); LifecyclePolicy updatedPolicy = new LifecyclePolicy(policyName, phases);
logger.info("--> policy: {}", newPolicy); logger.info("--> policy: {}", newPolicy);
logger.info("--> updated policy: {}", updatedPolicy); logger.info("--> updated policy: {}", updatedPolicy);
List<Step> policySteps = newPolicy.toSteps(client, () -> 0L); List<Step> policySteps = newPolicy.toSteps(client);
Map<String, String> headers = new HashMap<>(); Map<String, String> headers = new HashMap<>();
if (randomBoolean()) { if (randomBoolean()) {
headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10)); headers.put(randomAlphaOfLength(10), randomAlphaOfLength(10));
@ -289,7 +289,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY); PolicyStepsRegistry registry = new PolicyStepsRegistry(NamedXContentRegistry.EMPTY);
// add new policy // add new policy
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
Map<Step.StepKey, Step> registeredStepsForPolicy = registry.getStepMap().get(newPolicy.getName()); Map<Step.StepKey, Step> registeredStepsForPolicy = registry.getStepMap().get(newPolicy.getName());
Step shrinkStep = registeredStepsForPolicy.entrySet().stream() Step shrinkStep = registeredStepsForPolicy.entrySet().stream()
@ -314,7 +314,7 @@ public class PolicyStepsRegistryTests extends ESTestCase {
currentState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build(); currentState = ClusterState.builder(ClusterName.DEFAULT).metaData(metaData).build();
// Update the policies // Update the policies
registry.update(currentState, client, () -> 0L); registry.update(currentState, client);
registeredStepsForPolicy = registry.getStepMap().get(newPolicy.getName()); registeredStepsForPolicy = registry.getStepMap().get(newPolicy.getName());
shrinkStep = registeredStepsForPolicy.entrySet().stream() shrinkStep = registeredStepsForPolicy.entrySet().stream()

View File

@ -76,8 +76,8 @@ teardown:
body: body:
current_step: current_step:
phase: "new" phase: "new"
action: "after" action: "complete"
name: "after" name: "complete"
next_step: next_step:
phase: "warm" phase: "warm"
action: "forcemerge" action: "forcemerge"
@ -116,8 +116,8 @@ teardown:
indices.get: indices.get:
index: my_index index: my_index
- match: { my_index.settings.index.lifecycle.name: "my_moveable_timeseries_lifecycle" } - match: { my_index.settings.index.lifecycle.name: "my_moveable_timeseries_lifecycle" }
- match: { my_index.settings.index.lifecycle.step: "after" } - match: { my_index.settings.index.lifecycle.step: "complete" }
- match: { my_index.settings.index.lifecycle.action: "after" } - match: { my_index.settings.index.lifecycle.action: "complete" }
- match: { my_index.settings.index.lifecycle.phase: "new" } - match: { my_index.settings.index.lifecycle.phase: "new" }
--- ---
@ -130,8 +130,8 @@ teardown:
body: body:
current_step: current_step:
phase: "new" phase: "new"
action: "after" action: "complete"
name: "after" name: "complete"
next_step: next_step:
phase: "invalid" phase: "invalid"
action: "invalid" action: "invalid"
@ -144,8 +144,8 @@ teardown:
indices.get: indices.get:
index: my_index index: my_index
- match: { my_index.settings.index.lifecycle.name: "my_moveable_timeseries_lifecycle" } - match: { my_index.settings.index.lifecycle.name: "my_moveable_timeseries_lifecycle" }
- match: { my_index.settings.index.lifecycle.step: "after" } - match: { my_index.settings.index.lifecycle.step: "complete" }
- match: { my_index.settings.index.lifecycle.action: "after" } - match: { my_index.settings.index.lifecycle.action: "complete" }
- match: { my_index.settings.index.lifecycle.phase: "new" } - match: { my_index.settings.index.lifecycle.phase: "new" }
--- ---

View File

@ -73,8 +73,8 @@ teardown:
indices.get: indices.get:
index: my_index index: my_index
- match: { my_index.settings.index.lifecycle.name: "my_lifecycle" } - match: { my_index.settings.index.lifecycle.name: "my_lifecycle" }
- match: { my_index.settings.index.lifecycle.step: "after" } - match: { my_index.settings.index.lifecycle.step: "complete" }
- match: { my_index.settings.index.lifecycle.action: "after" } - match: { my_index.settings.index.lifecycle.action: "complete" }
- match: { my_index.settings.index.lifecycle.phase: "new" } - match: { my_index.settings.index.lifecycle.phase: "new" }

View File

@ -110,8 +110,8 @@ teardown:
- match: { indices.my_index.index: "my_index" } - match: { indices.my_index.index: "my_index" }
- match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.my_index.phase: "new" } - match: { indices.my_index.phase: "new" }
- match: { indices.my_index.action: "after" } - match: { indices.my_index.action: "complete" }
- match: { indices.my_index.step: "after" } - match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step - is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info - is_false: indices.my_index.step_info
@ -131,8 +131,8 @@ teardown:
- match: { indices.my_index.index: "my_index" } - match: { indices.my_index.index: "my_index" }
- match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.my_index.phase: "new" } - match: { indices.my_index.phase: "new" }
- match: { indices.my_index.action: "after" } - match: { indices.my_index.action: "complete" }
- match: { indices.my_index.step: "after" } - match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step - is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info - is_false: indices.my_index.step_info
@ -140,8 +140,8 @@ teardown:
- match: { indices.my_index2.index: "my_index2" } - match: { indices.my_index2.index: "my_index2" }
- match: { indices.my_index2.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.my_index2.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.my_index2.phase: "new" } - match: { indices.my_index2.phase: "new" }
- match: { indices.my_index2.action: "after" } - match: { indices.my_index2.action: "complete" }
- match: { indices.my_index2.step: "after" } - match: { indices.my_index2.step: "complete" }
- is_false: indices.my_index2.failed_step - is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info - is_false: indices.my_index2.step_info
@ -161,8 +161,8 @@ teardown:
- match: { indices.my_index.index: "my_index" } - match: { indices.my_index.index: "my_index" }
- match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.my_index.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.my_index.phase: "new" } - match: { indices.my_index.phase: "new" }
- match: { indices.my_index.action: "after" } - match: { indices.my_index.action: "complete" }
- match: { indices.my_index.step: "after" } - match: { indices.my_index.step: "complete" }
- is_false: indices.my_index.failed_step - is_false: indices.my_index.failed_step
- is_false: indices.my_index.step_info - is_false: indices.my_index.step_info
@ -170,8 +170,8 @@ teardown:
- match: { indices.my_index2.index: "my_index2" } - match: { indices.my_index2.index: "my_index2" }
- match: { indices.my_index2.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.my_index2.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.my_index2.phase: "new" } - match: { indices.my_index2.phase: "new" }
- match: { indices.my_index2.action: "after" } - match: { indices.my_index2.action: "complete" }
- match: { indices.my_index2.step: "after" } - match: { indices.my_index2.step: "complete" }
- is_false: indices.my_index2.failed_step - is_false: indices.my_index2.failed_step
- is_false: indices.my_index2.step_info - is_false: indices.my_index2.step_info
@ -179,8 +179,8 @@ teardown:
- match: { indices.another_index.index: "another_index" } - match: { indices.another_index.index: "another_index" }
- match: { indices.another_index.policy: "my_moveable_timeseries_lifecycle" } - match: { indices.another_index.policy: "my_moveable_timeseries_lifecycle" }
- match: { indices.another_index.phase: "new" } - match: { indices.another_index.phase: "new" }
- match: { indices.another_index.action: "after" } - match: { indices.another_index.action: "complete" }
- match: { indices.another_index.step: "after" } - match: { indices.another_index.step: "complete" }
- is_false: indices.another_index.failed_step - is_false: indices.another_index.failed_step
- is_false: indices.another_index.step_info - is_false: indices.another_index.step_info