-
Notifications
You must be signed in to change notification settings - Fork 25.3k
Use custom index metadata for ILM state #33783
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use custom index metadata for ILM state #33783
Conversation
Using index settings for ILM state is fragile and exposes too much information that doesn't need to be exposed. Using custom index metadata is more resilient and allows more controlled access to internal information.
Pinging @elastic/es-core-infra |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some comments, I think we should try to avoid using "" and "-1" for empty values, instead, removing them from the map entirely
.setFailedStep(customData.getOrDefault(FAILED_STEP, "")) | ||
.setStepInfo(customData.getOrDefault(STEP_INFO, "")) | ||
.setPhaseDefinition(customData.getOrDefault(PHASE_DEFINITION, "")) | ||
.setIndexCreationDate(Long.parseLong(customData.getOrDefault(INDEX_CREATION_DATE, "-1"))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add more descriptive parsing error messages in the event that these are incorrectly formatted as a long (ie, including the name)
.../core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/LifecycleExecutionState.java
Show resolved
Hide resolved
return Collections.unmodifiableMap(result); | ||
} | ||
|
||
public String getPhase() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be my (semi controversial) opinion, but I think we could ditch the getters and make the vars public since this class does nothing with the values; what do you think?
private String step = ""; | ||
private String failedStep = ""; | ||
private String stepInfo = ""; | ||
private String phaseDefinition = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my above comment, I think these should default to null
and not be written if they aren't present
|
||
import static org.elasticsearch.xpack.core.indexlifecycle.LifecycleExecutionState.ILM_CUSTOM_METADATA_KEY; | ||
|
||
public class ShrinkCopyExecutionState extends ClusterStateActionStep { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add javadocs for what this class is for please?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also think we could genericize the name, since we may want this for rollups in the future (so just call it CopyExecutionStateStep
)
|
||
Long lifecycleDate = LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE_SETTING.get(indexMetaData.getSettings()); | ||
if (lifecycleDate == null) { | ||
throw new IllegalStateException("source index[" + indexMetaData.getIndex().getName() + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You removed this validation but didn't re-add it in the copy state step that was added, do we want to remove this entirely? I don't think we want to
.../src/test/java/org/elasticsearch/xpack/core/indexlifecycle/LifecycleExecutionStateTests.java
Show resolved
Hide resolved
|
||
// clear any step info or error-related settings from the current step | ||
updatedState.setFailedStep(""); | ||
updatedState.setStepInfo(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should set these to null
so they are subsequently removed from the map rather than use an empty string
if (currentStep.getPhase().equals(nextStep.getPhase()) == false) { | ||
final String newPhaseDefinition; | ||
if ("new".equals(nextStep.getPhase()) || TerminalPolicyStep.KEY.equals(nextStep)) { | ||
newPhaseDefinition = nextStep.getPhase(); | ||
} else { | ||
Phase nextPhase = policy.getPhases().get(nextStep.getPhase()); | ||
if (nextPhase == null) { | ||
newPhaseDefinition = null; | ||
newPhaseDefinition = ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, I think we should use null and remove it from the map
Map<String, String> newCustomData = new HashMap<>(); | ||
|
||
return IndexMetaData.builder(indexMetadata) | ||
.putCustom(ILM_CUSTOM_METADATA_KEY, newCustomData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we do .putCustom("ilm", null)
here? Or that does break anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might rather want to add a .removeCustom("ilm")
method on the builder
lifecycleState.getPhaseTime() == null ? -1 : lifecycleState.getPhaseTime(), | ||
lifecycleState.getActionTime() == null ? -1 : lifecycleState.getActionTime(), | ||
lifecycleState.getStepTime() == null ? -1 : lifecycleState.getStepTime(), | ||
new BytesArray(lifecycleState.getStepInfo() == null ? "" : lifecycleState.getStepInfo())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I need to go back and do something else here because this is really ugly, but otherwise it throws NPEs and I wanted to get eyes on the rest of the code.
@dakrone I believe I've made all the changes you requested, mind giving this another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM thanks @gwbrown, I left a few more comments (no need for another review after addressing them)
return phaseDefinition; | ||
} | ||
|
||
public Long getIndexCreationDate() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think should should be getLifecycleDate()
because the creation date isn't always used (sometimes it's rollover). We should also change the var name from indexCreationDate
-> indexLifecycleDate
throw new IllegalStateException("source index[" + indexMetaData.getIndex().getName() + | ||
"] is missing setting[" + LifecycleSettings.LIFECYCLE_INDEX_CREATION_DATE); | ||
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData); | ||
if (lifecycleState == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be if (lifecycleState.getLifecycleDate() == null) {
rather than just checking if the state exists at all
LifecycleExecutionState lifecycleState = LifecycleExecutionState.fromIndexMetadata(indexMetaData); | ||
if (lifecycleState == null) { | ||
throw new IllegalStateException("source index [" + indexMetaData.getIndex().getName() + | ||
"] is missing creation date"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"creation date" -> "lifecycle date"
@@ -84,13 +84,14 @@ public void testPerformAction() throws Exception { | |||
String lifecycleName = randomAlphaOfLength(5); | |||
long creationDate = randomNonNegativeLong(); | |||
ShrinkStep step = createRandomInstance(); | |||
LifecycleExecutionState.Builder lifecycleState = LifecycleExecutionState.builder(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You create this lifecycleState but never use it in the test?
PhaseExecutionInfo phaseExecutionInfo = null; | ||
if (Strings.isNullOrEmpty(phaseDef) == false) { | ||
try (XContentParser parser = JsonXContent.jsonXContent.createParser(xContentRegistry, | ||
DeprecationHandler.THROW_UNSUPPORTED_OPERATION, phaseDef)) { | ||
phaseExecutionInfo = PhaseExecutionInfo.parse(parser, currentPhase); | ||
} catch (IOException e) { | ||
listener.onFailure(new ElasticsearchParseException( | ||
"failed to parse [" + LifecycleSettings.LIFECYCLE_PHASE_DEFINITION + "] for index [" + index + "]", e)); | ||
"failed to parse [phase_definition] for index [" + index + "]", e)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can probable just make this
failed to parse phase definition for index [foo]
rather than making "phase_definition" seem like a special thing (since it's not a setting any more)
Using index settings for ILM state is fragile and exposes too much information that doesn't need to be exposed. Using custom index metadata is more resilient and allows more controlled access to internal information. As part of these changes, moves away from using defaults for ILM-related values, in favor of using null values to clearly indicate that the value is not present.
Using index settings for ILM state is fragile and exposes too much
information that doesn't need to be exposed. Using custom index metadata
is more resilient and allows more controlled access to internal
information.
Also adds a class (
LifecycleExecutionState
) to handle serializing/deserializing information to/from theMap<String, String>
that must be used for custom index metadata.This PR is pretty big, so some areas to focus on for reviewers:
LifecycleExecutionState
class and associatedTests
ShrinkCopyExecutionState
, which copies over the custom metadata after the shrunken index has been created, and surrounding machinery/tests.IndexLifecycleRunner
, as GitHub collapses this and it's easy to miss.