- 
                Notifications
    You must be signed in to change notification settings 
- Fork 25.6k
ILM migrate data between tiers #61377
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
Changes from 2 commits
f4a37a9
              024a0de
              ca9800f
              07dc8de
              42900b2
              5d6729b
              28ccee9
              45d2eb3
              6c05591
              783061d
              ab3ac33
              6b74d7c
              61ed9eb
              6f83f91
              4bef9b2
              5024595
              41dc480
              d9b6390
              8e9a4f3
              996c747
              83c31b6
              c1746d4
              fe1fb8f
              e435a2f
              656afe5
              a24b0fc
              8d806e2
              2133715
              991fdc0
              be65929
              39b518e
              f3a64d3
              d119797
              8f855c5
              0636d0e
              500a275
              9b90555
              eddd223
              d733d72
              4da7379
              be17159
              b837718
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,112 @@ | ||
| /* | ||
| * 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.ilm; | ||
|  | ||
| import org.elasticsearch.client.Client; | ||
| import org.elasticsearch.common.ParseField; | ||
| import org.elasticsearch.common.Strings; | ||
| import org.elasticsearch.common.io.stream.StreamInput; | ||
| import org.elasticsearch.common.io.stream.StreamOutput; | ||
| import org.elasticsearch.common.xcontent.ConstructingObjectParser; | ||
| import org.elasticsearch.common.xcontent.XContentBuilder; | ||
| import org.elasticsearch.common.xcontent.XContentParser; | ||
| import org.elasticsearch.xpack.core.ilm.Step.StepKey; | ||
|  | ||
| import java.io.IOException; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
|  | ||
| /** | ||
| * A {@link LifecycleAction} which enables or disables the automatic migration of data between | ||
| * {@link org.elasticsearch.xpack.core.DataTier}s. | ||
| */ | ||
| public class MigrateAction implements LifecycleAction { | ||
| public static final String NAME = "migrate"; | ||
| public static final ParseField ENABLED_FIELD = new ParseField("enabled"); | ||
|  | ||
| private static final ConstructingObjectParser<MigrateAction, Void> PARSER = new ConstructingObjectParser<>(NAME, | ||
| a -> new MigrateAction((boolean) a[0])); | ||
|  | ||
| static { | ||
| PARSER.declareBoolean(ConstructingObjectParser.constructorArg(), ENABLED_FIELD); | ||
|         
                  andreidan marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| } | ||
|  | ||
| private final boolean enabled; | ||
|         
                  andreidan marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
|  | ||
| public static MigrateAction parse(XContentParser parser) { | ||
| return PARSER.apply(parser, null); | ||
| } | ||
|  | ||
| public MigrateAction(boolean enabled) { | ||
| this.enabled = enabled; | ||
| } | ||
|  | ||
| public MigrateAction(StreamInput in) throws IOException { | ||
| this(in.readBoolean()); | ||
| } | ||
|  | ||
| @Override | ||
| public void writeTo(StreamOutput out) throws IOException { | ||
| out.writeBoolean(enabled); | ||
| } | ||
|  | ||
| @Override | ||
| public String getWriteableName() { | ||
| return NAME; | ||
| } | ||
|  | ||
| public boolean isEnabled() { | ||
| return enabled; | ||
| } | ||
|  | ||
| @Override | ||
| public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { | ||
| builder.startObject(); | ||
| builder.field(ENABLED_FIELD.getPreferredName(), enabled); | ||
| builder.endObject(); | ||
| return builder; | ||
| } | ||
|  | ||
| @Override | ||
| public boolean isSafeAction() { | ||
| return true; | ||
| } | ||
|  | ||
| @Override | ||
| public List<Step> toSteps(Client client, String phase, StepKey nextStepKey) { | ||
| if (enabled) { | ||
| Map<String, String> include = Map.of("_tier", "data_" + phase); | ||
|         
                  andreidan marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
| AllocateAction migrateDataAction = new AllocateAction(null, include, null, null); | ||
|          | ||
| return migrateDataAction.toSteps(client, phase, nextStepKey); | ||
| } else { | ||
| return List.of(); | ||
| } | ||
| } | ||
|  | ||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(enabled); | ||
| } | ||
|  | ||
| @Override | ||
| public boolean equals(Object obj) { | ||
| if (obj == null) { | ||
| return false; | ||
| } | ||
| if (obj.getClass() != getClass()) { | ||
| return false; | ||
| } | ||
| MigrateAction other = (MigrateAction) obj; | ||
| return Objects.equals(enabled, other.enabled); | ||
| } | ||
|  | ||
| @Override | ||
| public String toString() { | ||
| return Strings.toString(this); | ||
| } | ||
|  | ||
| } | ||
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.
should we make this configurable and serializable for the step? (ie. use just the one allocation decider depending on where it is used)
I'd say we want a fully allocated index so verifying both always is alright. What do you think?
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.
Hmm... I actually think that we may want to split checking the allocation for the migrate action into a separate step. For example, the allocation routed step currently has a pretty generic message (
Waiting for [n] shards to be allocated to nodes matching the given filters). I think if we split this into a newMigrationRoutedstep we could give it a much better explanation, for example, something like:waiting [23m] for [3] shards to be allocated on nodes with the [data_warm] tieradditionally, I think we could also even throw an error to signal to the user when things were in a bad state, something like:
exception waiting for index to be moved to the [data_cold] tier, there are currently no [data_cold] nodes in the clusterThen the step could be retryable (so we check every 10 minutes) and it at least gives us a way of signaling to a user (alerting on the ilm-history index for example) when they are in an irreconcilable position and need to adjust their cluster.
What do you think?
Uh oh!
There was an error while loading. Please reload this page.
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 make a great point on validating if the cluster has any node with a particular role available. I'll create another step for the migrate action (the nicer messages will be a great UX improvement as well)