Skip to content

Commit 80ab773

Browse files
authored
Move IndexLifecycleMetadata installation to put-lifecycle-action (#31346)
There is a problematic scenario with x-pack-cluster master-nodes attempting to install custom metadata into the cluster-state and broadcasting that to non-x-pack-enabled nodes. Since those nodes are not aware of this custom metadata, their cluster-state recovery will be broken. This change ensures that newly-elected x-pack master nodes bootstrap IndexLifecycleMetadata upon the first request to leverage its features. This means that PutLifecycleAction is now responsible for installing the metadata. Since this X-Pack API can only be called once all nodes in the cluster have x-pack enabled, it is safe to assume that the cluster will appropriately handle the cluster-state recovery with the new set of index-lifecycle metadata.
1 parent 2af05e5 commit 80ab773

File tree

9 files changed

+57
-114
lines changed

9 files changed

+57
-114
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/indexlifecycle/IndexLifecycleMetadata.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
public class IndexLifecycleMetadata implements XPackMetaDataCustom {
3535
public static final String TYPE = "index_lifecycle";
3636
public static final ParseField POLICIES_FIELD = new ParseField("policies");
37+
public static final IndexLifecycleMetadata EMPTY = new IndexLifecycleMetadata(Collections.emptySortedMap());
3738

3839
@SuppressWarnings("unchecked")
3940
public static final ConstructingObjectParser<IndexLifecycleMetadata, Void> PARSER = new ConstructingObjectParser<>(

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycle.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
import org.elasticsearch.xpack.indexlifecycle.action.RestPutLifecycleAction;
5050
import org.elasticsearch.xpack.indexlifecycle.action.RestRetryAction;
5151
import org.elasticsearch.xpack.indexlifecycle.action.TransportSetPolicyForIndexAction;
52-
import org.elasticsearch.xpack.indexlifecycle.action.TransportDeleteLifcycleAction;
52+
import org.elasticsearch.xpack.indexlifecycle.action.TransportDeleteLifecycleAction;
5353
import org.elasticsearch.xpack.indexlifecycle.action.TransportExplainLifecycleAction;
5454
import org.elasticsearch.xpack.indexlifecycle.action.TransportGetLifecycleAction;
5555
import org.elasticsearch.xpack.indexlifecycle.action.TransportMoveToStepAction;
@@ -124,7 +124,7 @@ public Collection<Object> createComponents(Client client, ClusterService cluster
124124
return emptyList();
125125
}
126126
indexLifecycleInitialisationService
127-
.set(new IndexLifecycleService(settings, client, clusterService, getClock(), threadPool, System::currentTimeMillis));
127+
.set(new IndexLifecycleService(settings, client, clusterService, getClock(), System::currentTimeMillis));
128128
return Collections.singletonList(indexLifecycleInitialisationService.get());
129129
}
130130

@@ -164,7 +164,7 @@ public List<RestHandler> getRestHandlers(Settings settings, RestController restC
164164
return Arrays.asList(
165165
new ActionHandler<>(PutLifecycleAction.INSTANCE, TransportPutLifecycleAction.class),
166166
new ActionHandler<>(GetLifecycleAction.INSTANCE, TransportGetLifecycleAction.class),
167-
new ActionHandler<>(DeleteLifecycleAction.INSTANCE, TransportDeleteLifcycleAction.class),
167+
new ActionHandler<>(DeleteLifecycleAction.INSTANCE, TransportDeleteLifecycleAction.class),
168168
new ActionHandler<>(ExplainLifecycleAction.INSTANCE, TransportExplainLifecycleAction.class),
169169
new ActionHandler<>(SetPolicyForIndexAction.INSTANCE, TransportSetPolicyForIndexAction.class),
170170
new ActionHandler<>(MoveToStepAction.INSTANCE, TransportMoveToStepAction.class),

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/IndexLifecycleService.java

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,12 @@
1212
import org.elasticsearch.cluster.ClusterState;
1313
import org.elasticsearch.cluster.ClusterStateApplier;
1414
import org.elasticsearch.cluster.ClusterStateListener;
15-
import org.elasticsearch.cluster.ClusterStateUpdateTask;
16-
import org.elasticsearch.cluster.metadata.MetaData;
1715
import org.elasticsearch.cluster.service.ClusterService;
1816
import org.elasticsearch.common.Strings;
1917
import org.elasticsearch.common.component.AbstractComponent;
2018
import org.elasticsearch.common.logging.ESLoggerFactory;
2119
import org.elasticsearch.common.settings.Settings;
2220
import org.elasticsearch.common.unit.TimeValue;
23-
import org.elasticsearch.threadpool.ThreadPool;
2421
import org.elasticsearch.xpack.core.indexlifecycle.IndexLifecycleMetadata;
2522
import org.elasticsearch.xpack.core.indexlifecycle.LifecyclePolicy;
2623
import org.elasticsearch.xpack.core.indexlifecycle.LifecycleSettings;
@@ -29,7 +26,6 @@
2926

3027
import java.io.Closeable;
3128
import java.time.Clock;
32-
import java.util.Collections;
3329
import java.util.function.LongSupplier;
3430

3531
/**
@@ -44,18 +40,15 @@ public class IndexLifecycleService extends AbstractComponent
4440
private final PolicyStepsRegistry policyRegistry;
4541
private Client client;
4642
private ClusterService clusterService;
47-
private ThreadPool threadPool;
4843
private LongSupplier nowSupplier;
4944
private SchedulerEngine.Job scheduledJob;
5045
private IndexLifecycleRunner lifecycleRunner;
5146

52-
public IndexLifecycleService(Settings settings, Client client, ClusterService clusterService, Clock clock,
53-
ThreadPool threadPool, LongSupplier nowSupplier) {
47+
public IndexLifecycleService(Settings settings, Client client, ClusterService clusterService, Clock clock, LongSupplier nowSupplier) {
5448
super(settings);
5549
this.client = client;
5650
this.clusterService = clusterService;
5751
this.clock = clock;
58-
this.threadPool = threadPool;
5952
this.nowSupplier = nowSupplier;
6053
this.scheduledJob = null;
6154
this.policyRegistry = new PolicyStepsRegistry();
@@ -91,19 +84,17 @@ public PolicyStepsRegistry getPolicyRegistry() {
9184

9285
@Override
9386
public void clusterChanged(ClusterChangedEvent event) {
94-
if (event.localNodeMaster()) { // only act if we are master, otherwise keep idle until elected
95-
IndexLifecycleMetadata lifecycleMetadata = event.state().metaData().custom(IndexLifecycleMetadata.TYPE);
87+
IndexLifecycleMetadata lifecycleMetadata = event.state().metaData().custom(IndexLifecycleMetadata.TYPE);
88+
if (event.localNodeMaster() && lifecycleMetadata != null) {
9689
TimeValue pollInterval = LifecycleSettings.LIFECYCLE_POLL_INTERVAL_SETTING
9790
.get(event.state().getMetaData().settings());
9891
TimeValue previousPollInterval = LifecycleSettings.LIFECYCLE_POLL_INTERVAL_SETTING
9992
.get(event.previousState().getMetaData().settings());
10093

10194
boolean pollIntervalSettingChanged = !pollInterval.equals(previousPollInterval);
10295

103-
if (lifecycleMetadata == null) { // no lifecycle metadata, install initial empty metadata state
104-
lifecycleMetadata = new IndexLifecycleMetadata(Collections.emptySortedMap());
105-
installMetadata(lifecycleMetadata);
106-
} else if (scheduler.get() == null) { // metadata installed and scheduler should be kicked off. start your engines.
96+
97+
if (scheduler.get() == null) { // metadata installed and scheduler should be kicked off. start your engines.
10798
scheduler.set(new SchedulerEngine(clock));
10899
scheduler.get().register(this);
109100
scheduleJob(pollInterval);
@@ -151,26 +142,7 @@ public void triggered(SchedulerEngine.Event event) {
151142
}
152143
}
153144

154-
private void installMetadata(IndexLifecycleMetadata lifecycleMetadata) {
155-
threadPool.executor(ThreadPool.Names.GENERIC)
156-
.execute(() -> clusterService.submitStateUpdateTask("install-index-lifecycle-metadata", new ClusterStateUpdateTask() {
157-
@Override
158-
public ClusterState execute(ClusterState currentState) throws Exception {
159-
ClusterState.Builder builder = new ClusterState.Builder(currentState);
160-
MetaData.Builder metadataBuilder = MetaData.builder(currentState.metaData());
161-
metadataBuilder.putCustom(IndexLifecycleMetadata.TYPE, lifecycleMetadata);
162-
builder.metaData(metadataBuilder.build());
163-
return builder.build();
164-
}
165-
166-
@Override
167-
public void onFailure(String source, Exception e) {
168-
logger.error("unable to install index lifecycle metadata", e);
169-
}
170-
}));
171-
}
172-
173-
public void triggerPolicies(ClusterState clusterState, boolean fromClusterStateChange) {
145+
void triggerPolicies(ClusterState clusterState, boolean fromClusterStateChange) {
174146
// loop through all indices in cluster state and filter for ones that are
175147
// managed by the Index Lifecycle Service they have a index.lifecycle.name setting
176148
// associated to a policy

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/PolicyStepsRegistry.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ Map<String, Map<Step.StepKey, Step>> getStepMap() {
5959
@SuppressWarnings({ "unchecked", "rawtypes" })
6060
public void update(ClusterState currentState, Client client, LongSupplier nowSupplier) {
6161
IndexLifecycleMetadata meta = currentState.metaData().custom(IndexLifecycleMetadata.TYPE);
62+
assert meta != null : "IndexLifecycleMetadata cannot be null when updating the policy steps registry";
63+
6264
Diff<Map<String, LifecyclePolicyMetadata>> diff = DiffableUtils.diff(lifecyclePolicyMap, meta.getPolicyMetadatas(),
6365
DiffableUtils.getStringKeySerializer());
6466
DiffableUtils.MapDiff<String, LifecyclePolicyMetadata, DiffableUtils.KeySerializer<String>> mapDiff = (DiffableUtils.MapDiff) diff;
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@
3232
import java.util.SortedMap;
3333
import java.util.TreeMap;
3434

35-
public class TransportDeleteLifcycleAction extends TransportMasterNodeAction<Request, Response> {
35+
public class TransportDeleteLifecycleAction extends TransportMasterNodeAction<Request, Response> {
3636

3737
@Inject
38-
public TransportDeleteLifcycleAction(Settings settings, TransportService transportService, ClusterService clusterService,
39-
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
38+
public TransportDeleteLifecycleAction(Settings settings, TransportService transportService, ClusterService clusterService,
39+
ThreadPool threadPool, ActionFilters actionFilters,
40+
IndexNameExpressionResolver indexNameExpressionResolver) {
4041
super(settings, DeleteLifecycleAction.NAME, transportService, clusterService, threadPool, actionFilters,
4142
indexNameExpressionResolver, Request::new);
4243
}
@@ -74,7 +75,8 @@ public ClusterState execute(ClusterState currentState) {
7475
}
7576
ClusterState.Builder newState = ClusterState.builder(currentState);
7677
IndexLifecycleMetadata currentMetadata = currentState.metaData().custom(IndexLifecycleMetadata.TYPE);
77-
if (currentMetadata.getPolicyMetadatas().containsKey(request.getPolicyName()) == false) {
78+
if (currentMetadata == null
79+
|| currentMetadata.getPolicyMetadatas().containsKey(request.getPolicyName()) == false) {
7880
throw new ResourceNotFoundException("Lifecycle policy not found: {}", request.getPolicyName());
7981
}
8082
SortedMap<String, LifecyclePolicyMetadata> newPolicies = new TreeMap<>(currentMetadata.getPolicyMetadatas());
@@ -91,4 +93,4 @@ public ClusterState execute(ClusterState currentState) {
9193
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
9294
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
9395
}
94-
}
96+
}

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportPutLifecycleAction.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
import java.util.TreeMap;
3333
import java.util.stream.Collectors;
3434

35+
/**
36+
* This class is responsible for bootstrapping {@link IndexLifecycleMetadata} into the cluster-state, as well
37+
* as adding the desired new policy to be inserted.
38+
*/
3539
public class TransportPutLifecycleAction extends TransportMasterNodeAction<Request, Response> {
3640

3741
@Inject
@@ -64,6 +68,9 @@ protected Response newResponse(boolean acknowledged) {
6468
public ClusterState execute(ClusterState currentState) throws Exception {
6569
ClusterState.Builder newState = ClusterState.builder(currentState);
6670
IndexLifecycleMetadata currentMetadata = currentState.metaData().custom(IndexLifecycleMetadata.TYPE);
71+
if (currentMetadata == null) { // first time using index-lifecycle feature, bootstrap metadata
72+
currentMetadata = IndexLifecycleMetadata.EMPTY;
73+
}
6774
if (currentMetadata.getPolicyMetadatas().containsKey(request.getPolicy().getName())) {
6875
throw new ResourceAlreadyExistsException("Lifecycle policy already exists: {}",
6976
request.getPolicy().getName());
@@ -87,4 +94,4 @@ public ClusterState execute(ClusterState currentState) throws Exception {
8794
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
8895
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
8996
}
90-
}
97+
}

x-pack/plugin/index-lifecycle/src/main/java/org/elasticsearch/xpack/indexlifecycle/action/TransportSetPolicyForIndexAction.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ protected void masterOperation(Request request, ClusterState state, ActionListen
6868
public ClusterState execute(ClusterState currentState) throws Exception {
6969
IndexLifecycleMetadata ilmMetadata = (IndexLifecycleMetadata) currentState.metaData()
7070
.custom(IndexLifecycleMetadata.TYPE);
71+
72+
if (ilmMetadata == null) {
73+
throw new ResourceNotFoundException("Policy does not exist [{}]", newPolicyName);
74+
}
75+
7176
LifecyclePolicy newPolicy = ilmMetadata.getPolicies().get(newPolicyName);
7277

7378
if (newPolicy == null) {

0 commit comments

Comments
 (0)