Skip to content

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

Merged
merged 7 commits into from
Sep 19, 2018

Conversation

gwbrown
Copy link
Contributor

@gwbrown gwbrown commented Sep 17, 2018

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 the Map<String, String> that must be used for custom index metadata.

This PR is pretty big, so some areas to focus on for reviewers:

  1. The LifecycleExecutionState class and associated Tests
  2. The new ShrinkCopyExecutionState, which copies over the custom metadata after the shrunken index has been created, and surrounding machinery/tests.
  3. Changes to IndexLifecycleRunner, as GitHub collapses this and it's easy to miss.

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.
@gwbrown gwbrown added the :Data Management/ILM+SLM Index and Snapshot lifecycle management label Sep 17, 2018
@gwbrown gwbrown requested review from dakrone and talevy September 17, 2018 18:02
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-core-infra

Copy link
Member

@dakrone dakrone left a 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")))
Copy link
Member

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)

return Collections.unmodifiableMap(result);
}

public String getPhase() {
Copy link
Member

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 = "";
Copy link
Member

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 {
Copy link
Member

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?

Copy link
Member

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() +
Copy link
Member

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


// clear any step info or error-related settings from the current step
updatedState.setFailedStep("");
updatedState.setStepInfo("");
Copy link
Member

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 = "";
Copy link
Member

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)
Copy link
Member

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?

Copy link
Member

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()));
Copy link
Contributor Author

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.

@gwbrown
Copy link
Contributor Author

gwbrown commented Sep 18, 2018

@dakrone I believe I've made all the changes you requested, mind giving this another look?

Copy link
Member

@dakrone dakrone left a 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() {
Copy link
Member

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) {
Copy link
Member

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");
Copy link
Member

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();
Copy link
Member

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));
Copy link
Member

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)

@gwbrown gwbrown merged commit 90de436 into elastic:index-lifecycle Sep 19, 2018
gwbrown added a commit that referenced this pull request Sep 19, 2018
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.
@gwbrown gwbrown deleted the ilm-settings2metadata branch September 24, 2018 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Data Management/ILM+SLM Index and Snapshot lifecycle management
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants