From ff3ec376ef12ad2a385aa23ac7d520e6e603edc0 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Wed, 18 Jun 2025 09:30:39 -0300 Subject: [PATCH 1/4] Make `IndexLifecycleService` project-aware Updates the background service of ILM to process all projects in the cluster. --- .../xpack/ilm/IndexLifecycleService.java | 127 +++++++++--------- .../xpack/ilm/IndexLifecycleServiceTests.java | 70 +++++----- .../build.gradle | 5 - 3 files changed, 97 insertions(+), 105 deletions(-) diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java index 389bac89aaedb..8095b0bf8de0a 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java @@ -18,7 +18,6 @@ import org.elasticsearch.cluster.ProjectState; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.LifecycleExecutionState; -import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.metadata.SingleNodeShutdownMetadata; import org.elasticsearch.cluster.service.ClusterService; @@ -28,7 +27,6 @@ import org.elasticsearch.common.scheduler.TimeValueSchedule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; -import org.elasticsearch.core.FixForMultiProject; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.core.TimeValue; @@ -183,9 +181,12 @@ public ProjectMetadata moveIndicesToPreviouslyFailedStep(ProjectMetadata current void onMaster(ClusterState clusterState) { maybeScheduleJob(); - // TODO multi-project: this probably needs a per-project iteration - @FixForMultiProject - final ProjectState state = clusterState.projectState(Metadata.DEFAULT_PROJECT_ID); + for (var projectId : clusterState.metadata().projects().keySet()) { + onMaster(clusterState.projectState(projectId)); + } + } + + void onMaster(ProjectState state) { final ProjectMetadata projectMetadata = state.metadata(); final IndexLifecycleMetadata currentMetadata = projectMetadata.custom(IndexLifecycleMetadata.TYPE); if (currentMetadata != null) { @@ -416,20 +417,21 @@ public void applyClusterState(ClusterChangedEvent event) { return; } - @FixForMultiProject - final IndexLifecycleMetadata ilmMetadata = event.state() - .metadata() - .getProject(Metadata.DEFAULT_PROJECT_ID) - .custom(IndexLifecycleMetadata.TYPE); - if (ilmMetadata == null) { - return; - } - final IndexLifecycleMetadata previousIlmMetadata = event.previousState() - .metadata() - .getProject(Metadata.DEFAULT_PROJECT_ID) - .custom(IndexLifecycleMetadata.TYPE); - if (event.previousState().nodes().isLocalNodeElectedMaster() == false || ilmMetadata != previousIlmMetadata) { - policyRegistry.update(ilmMetadata); + // We're updating the policy registry cache here, which doesn't actually work with multiple projects because the policies from one + // project would overwrite the polices from another project. However, since we're not planning on running ILM in a multi-project + // cluster, we can ignore this. + for (var project : event.state().metadata().projects().values()) { + final IndexLifecycleMetadata ilmMetadata = project.custom(IndexLifecycleMetadata.TYPE); + if (ilmMetadata == null) { + continue; + } + final var previousProject = event.previousState().metadata().projects().get(project.id()); + final IndexLifecycleMetadata previousIlmMetadata = previousProject == null + ? null + : previousProject.custom(IndexLifecycleMetadata.TYPE); + if (event.previousState().nodes().isLocalNodeElectedMaster() == false || ilmMetadata != previousIlmMetadata) { + policyRegistry.update(ilmMetadata); + } } } @@ -461,10 +463,13 @@ public boolean policyExists(String policyId) { * @param clusterState the current cluster state * @param fromClusterStateChange whether things are triggered from the cluster-state-listener or the scheduler */ - @FixForMultiProject void triggerPolicies(ClusterState clusterState, boolean fromClusterStateChange) { - @FixForMultiProject - final var state = clusterState.projectState(Metadata.DEFAULT_PROJECT_ID); + for (var projectId : clusterState.metadata().projects().keySet()) { + triggerPolicies(clusterState.projectState(projectId), fromClusterStateChange); + } + } + + void triggerPolicies(ProjectState state, boolean fromClusterStateChange) { final var projectMetadata = state.metadata(); IndexLifecycleMetadata currentMetadata = projectMetadata.custom(IndexLifecycleMetadata.TYPE); @@ -585,7 +590,7 @@ PolicyStepsRegistry getPolicyRegistry() { return policyRegistry; } - static Set indicesOnShuttingDownNodesInDangerousStep(ClusterState state, String nodeId) { + static boolean indicesOnShuttingDownNodesInDangerousStep(ClusterState state, String nodeId) { final Set shutdownNodes = PluginShutdownService.shutdownTypeNodes( state, SingleNodeShutdownMetadata.Type.REMOVE, @@ -593,43 +598,46 @@ static Set indicesOnShuttingDownNodesInDangerousStep(ClusterState state, SingleNodeShutdownMetadata.Type.REPLACE ); if (shutdownNodes.isEmpty()) { - return Set.of(); + return true; } - // Returning a set of strings will cause weird behavior with multiple projects - @FixForMultiProject - Set indicesPreventingShutdown = state.metadata() - .projects() - .values() - .stream() - .flatMap(project -> project.indices().entrySet().stream()) - // Filter out to only consider managed indices - .filter(indexToMetadata -> Strings.hasText(indexToMetadata.getValue().getLifecyclePolicyName())) - // Only look at indices in the shrink action - .filter(indexToMetadata -> ShrinkAction.NAME.equals(indexToMetadata.getValue().getLifecycleExecutionState().action())) - // Only look at indices on a step that may potentially be dangerous if we removed the node - .filter(indexToMetadata -> { - String step = indexToMetadata.getValue().getLifecycleExecutionState().step(); - return SetSingleNodeAllocateStep.NAME.equals(step) - || CheckShrinkReadyStep.NAME.equals(step) - || ShrinkStep.NAME.equals(step) - || ShrunkShardsAllocatedStep.NAME.equals(step); - }) - // Only look at indices where the node picked for the shrink is the node marked as shutting down - .filter(indexToMetadata -> { - String nodePicked = indexToMetadata.getValue() - .getSettings() - .get(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_id"); - return nodeId.equals(nodePicked); - }) - .map(Map.Entry::getKey) - .collect(Collectors.toSet()); - logger.trace( - "with nodes marked as shutdown for removal {}, indices {} are preventing shutdown", - shutdownNodes, - indicesPreventingShutdown - ); - return indicesPreventingShutdown; + boolean result = true; + for (var project : state.metadata().projects().values()) { + Set indicesPreventingShutdown = project.indices() + .entrySet() + .stream() + // Filter out to only consider managed indices + .filter(indexToMetadata -> Strings.hasText(indexToMetadata.getValue().getLifecyclePolicyName())) + // Only look at indices in the shrink action + .filter(indexToMetadata -> ShrinkAction.NAME.equals(indexToMetadata.getValue().getLifecycleExecutionState().action())) + // Only look at indices on a step that may potentially be dangerous if we removed the node + .filter(indexToMetadata -> { + String step = indexToMetadata.getValue().getLifecycleExecutionState().step(); + return SetSingleNodeAllocateStep.NAME.equals(step) + || CheckShrinkReadyStep.NAME.equals(step) + || ShrinkStep.NAME.equals(step) + || ShrunkShardsAllocatedStep.NAME.equals(step); + }) + // Only look at indices where the node picked for the shrink is the node marked as shutting down + .filter(indexToMetadata -> { + String nodePicked = indexToMetadata.getValue() + .getSettings() + .get(IndexMetadata.INDEX_ROUTING_REQUIRE_GROUP_SETTING.getKey() + "_id"); + return nodeId.equals(nodePicked); + }) + .map(Map.Entry::getKey) + .collect(Collectors.toSet()); + logger.trace( + "with nodes marked as shutdown for removal {}, indices {} in project {} are preventing shutdown", + shutdownNodes, + indicesPreventingShutdown, + project.id() + ); + if (indicesPreventingShutdown.isEmpty() == false) { + result = false; + } + } + return result; } @Override @@ -641,8 +649,7 @@ public boolean safeToShutdown(String nodeId, SingleNodeShutdownMetadata.Type shu case REPLACE: case REMOVE: case SIGTERM: - Set indices = indicesOnShuttingDownNodesInDangerousStep(clusterService.state(), nodeId); - return indices.isEmpty(); + return indicesOnShuttingDownNodesInDangerousStep(clusterService.state(), nodeId); default: throw new IllegalArgumentException("unknown shutdown type: " + shutdownType); } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java index 68ab9613e9de6..24df3d5855b33 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java @@ -18,6 +18,7 @@ import org.elasticsearch.cluster.metadata.LifecycleExecutionState; import org.elasticsearch.cluster.metadata.Metadata; import org.elasticsearch.cluster.metadata.NodesShutdownMetadata; +import org.elasticsearch.cluster.metadata.ProjectMetadata; import org.elasticsearch.cluster.metadata.SingleNodeShutdownMetadata; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodeUtils; @@ -169,13 +170,11 @@ public void testStoppedModeSkip() { .numberOfReplicas(randomIntBetween(0, 5)) .build(); Map indices = Map.of(index.getName(), indexMetadata); - Metadata metadata = Metadata.builder() + var project = ProjectMetadata.builder(randomProjectIdOrDefault()) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPED)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); + .indices(indices); ClusterState currentState = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata(project) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .build(); ClusterChangedEvent event = new ClusterChangedEvent("_source", currentState, ClusterState.EMPTY_STATE); @@ -208,13 +207,11 @@ public void testRequestedStopOnShrink() { .numberOfReplicas(randomIntBetween(0, 5)) .build(); Map indices = Map.of(index.getName(), indexMetadata); - Metadata metadata = Metadata.builder() + var project = ProjectMetadata.builder(randomProjectIdOrDefault()) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPING)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); + .indices(indices); ClusterState currentState = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata(project) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .build(); @@ -264,13 +261,11 @@ private void verifyCanStopWithStep(String stoppableStep) { .numberOfReplicas(randomIntBetween(0, 5)) .build(); Map indices = Map.of(index.getName(), indexMetadata); - Metadata metadata = Metadata.builder() + var project = ProjectMetadata.builder(randomProjectIdOrDefault()) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPING)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); + .indices(indices); ClusterState currentState = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata(project) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .build(); @@ -312,13 +307,11 @@ public void testRequestedStopOnSafeAction() { .numberOfReplicas(randomIntBetween(0, 5)) .build(); Map indices = Map.of(index.getName(), indexMetadata); - Metadata metadata = Metadata.builder() + var project = ProjectMetadata.builder(randomProjectIdOrDefault()) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.STOPPING)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); + .indices(indices); ClusterState currentState = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata(project) .nodes(DiscoveryNodes.builder().localNodeId(nodeId).masterNodeId(nodeId).add(masterNode).build()) .build(); @@ -429,11 +422,9 @@ public void doTestExceptionStillProcessesOtherIndices(boolean useOnMaster) { .build(); Map indices = Map.of(index1.getName(), i1indexMetadata, index2.getName(), i2indexMetadata); - Metadata metadata = Metadata.builder() + var project = ProjectMetadata.builder(randomProjectIdOrDefault()) .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(policyMap, OperationMode.RUNNING)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); + .indices(indices); Settings settings = Settings.builder().put(LifecycleSettings.LIFECYCLE_POLL_INTERVAL, "1s").build(); var clusterSettings = new ClusterSettings( @@ -443,7 +434,7 @@ public void doTestExceptionStillProcessesOtherIndices(boolean useOnMaster) { ClusterService clusterService = ClusterServiceUtils.createClusterService(threadPool, clusterSettings); DiscoveryNode node = clusterService.localNode(); ClusterState currentState = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata(project) .nodes(DiscoveryNodes.builder().add(node).masterNodeId(node.getId()).localNodeId(node.getId())) .build(); ClusterServiceUtils.setState(clusterService, currentState); @@ -539,9 +530,10 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { SingleNodeShutdownMetadata.Type.SIGTERM, SingleNodeShutdownMetadata.Type.REPLACE )) { - ClusterState state = ClusterState.builder(ClusterName.DEFAULT).build(); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(Set.of())); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(Set.of())); + final var project = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); + ClusterState state = ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(project).build(); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(true)); IndexMetadata nonDangerousIndex = IndexMetadata.builder("no_danger") .settings(settings(IndexVersion.current()).put(LifecycleSettings.LIFECYCLE_NAME, "mypolicy")) @@ -583,14 +575,12 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { .build(); Map indices = Map.of("no_danger", nonDangerousIndex, "danger", dangerousIndex); - Metadata metadata = Metadata.builder() - .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(Map.of(), OperationMode.RUNNING)) - .indices(indices) - .persistentSettings(settings(IndexVersion.current()).build()) - .build(); - state = ClusterState.builder(ClusterName.DEFAULT) - .metadata(metadata) + .putProjectMetadata( + ProjectMetadata.builder(project) + .putCustom(IndexLifecycleMetadata.TYPE, new IndexLifecycleMetadata(Map.of(), OperationMode.RUNNING)) + .indices(indices) + ) .nodes( DiscoveryNodes.builder() .localNodeId(nodeId) @@ -613,8 +603,8 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { .build(); // No danger yet, because no node is shutting down - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(Set.of())); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(Set.of())); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(true)); state = ClusterState.builder(state) .metadata( @@ -638,12 +628,12 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { ) .build(); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(Set.of())); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); // No danger, because this is a "RESTART" type shutdown assertThat( "restart type shutdowns are not considered dangerous", IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), - equalTo(Set.of()) + equalTo(true) ); final String targetNodeName = type == SingleNodeShutdownMetadata.Type.REPLACE ? randomAlphaOfLengthBetween(10, 20) : null; @@ -673,7 +663,7 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { .build(); // The dangerous index should be calculated as being in danger now - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(Set.of("danger"))); + assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(false)); } } } diff --git a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle index 2a4ea94789162..40e146a07c21b 100644 --- a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle +++ b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle @@ -48,12 +48,7 @@ tasks.named("yamlRestTest").configure { '^esql/191_lookup_join_text/*', '^esql/192_lookup_join_on_aliases/*', '^health/10_usage/*', - '^ilm/10_basic/Test Undeletable Policy In Use', - '^ilm/20_move_to_step/*', - '^ilm/30_retry/*', '^ilm/60_operation_mode/*', - '^ilm/60_remove_policy_for_index/*', - '^ilm/70_downsampling/*', '^ilm/80_health/*', '^logsdb/10_usage/*', '^migrate/10_reindex/*', From 6acbb7c3738523999aa9213556ad436a53e2bb96 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Tue, 24 Jun 2025 14:55:15 -0300 Subject: [PATCH 2/4] Rename method --- .../xpack/ilm/IndexLifecycleService.java | 4 ++-- .../xpack/ilm/IndexLifecycleServiceTests.java | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java index 8095b0bf8de0a..bc55b1c49c4fa 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java @@ -590,7 +590,7 @@ PolicyStepsRegistry getPolicyRegistry() { return policyRegistry; } - static boolean indicesOnShuttingDownNodesInDangerousStep(ClusterState state, String nodeId) { + static boolean hasIndicesInDangerousStepForNodeShutdown(ClusterState state, String nodeId) { final Set shutdownNodes = PluginShutdownService.shutdownTypeNodes( state, SingleNodeShutdownMetadata.Type.REMOVE, @@ -649,7 +649,7 @@ public boolean safeToShutdown(String nodeId, SingleNodeShutdownMetadata.Type shu case REPLACE: case REMOVE: case SIGTERM: - return indicesOnShuttingDownNodesInDangerousStep(clusterService.state(), nodeId); + return hasIndicesInDangerousStepForNodeShutdown(clusterService.state(), nodeId); default: throw new IllegalArgumentException("unknown shutdown type: " + shutdownType); } diff --git a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java index 24df3d5855b33..61eb44ee5497f 100644 --- a/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java +++ b/x-pack/plugin/ilm/src/test/java/org/elasticsearch/xpack/ilm/IndexLifecycleServiceTests.java @@ -524,7 +524,7 @@ public void testParsingOriginationDateBeforeIndexCreation() { } } - public void testIndicesOnShuttingDownNodesInDangerousStep() { + public void testHasIndicesInDangerousStepForNodeShutdown() { for (SingleNodeShutdownMetadata.Type type : List.of( SingleNodeShutdownMetadata.Type.REMOVE, SingleNodeShutdownMetadata.Type.SIGTERM, @@ -532,8 +532,8 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { )) { final var project = ProjectMetadata.builder(randomProjectIdOrDefault()).build(); ClusterState state = ClusterState.builder(ClusterName.DEFAULT).putProjectMetadata(project).build(); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(true)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "regular_node"), equalTo(true)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "shutdown_node"), equalTo(true)); IndexMetadata nonDangerousIndex = IndexMetadata.builder("no_danger") .settings(settings(IndexVersion.current()).put(LifecycleSettings.LIFECYCLE_NAME, "mypolicy")) @@ -603,8 +603,8 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { .build(); // No danger yet, because no node is shutting down - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(true)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "regular_node"), equalTo(true)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "shutdown_node"), equalTo(true)); state = ClusterState.builder(state) .metadata( @@ -628,11 +628,11 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { ) .build(); - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "regular_node"), equalTo(true)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "regular_node"), equalTo(true)); // No danger, because this is a "RESTART" type shutdown assertThat( "restart type shutdowns are not considered dangerous", - IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), + IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "shutdown_node"), equalTo(true) ); @@ -663,7 +663,7 @@ public void testIndicesOnShuttingDownNodesInDangerousStep() { .build(); // The dangerous index should be calculated as being in danger now - assertThat(IndexLifecycleService.indicesOnShuttingDownNodesInDangerousStep(state, "shutdown_node"), equalTo(false)); + assertThat(IndexLifecycleService.hasIndicesInDangerousStepForNodeShutdown(state, "shutdown_node"), equalTo(false)); } } } From 67e3dbacaa2160d84720a93054105490abf4d729 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Tue, 24 Jun 2025 16:06:37 -0300 Subject: [PATCH 3/4] Remove ILM from multi-project YAML suite --- .../xpack-rest-tests-with-multiple-projects/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle index 40e146a07c21b..22b939700024f 100644 --- a/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle +++ b/x-pack/qa/multi-project/xpack-rest-tests-with-multiple-projects/build.gradle @@ -8,7 +8,6 @@ dependencies { testImplementation project(':test:yaml-rest-runner') testImplementation project(':x-pack:qa:multi-project:yaml-test-framework') testImplementation(testArtifact(project(":x-pack:plugin:security:qa:service-account"), "javaRestTest")) - restXpackTestConfig project(path: ':x-pack:plugin:ilm:qa:rest', configuration: "basicRestSpecs") restXpackTestConfig project(path: ':x-pack:plugin:downsample:qa:rest', configuration: "basicRestSpecs") restXpackTestConfig project(path: ':x-pack:plugin:stack', configuration: "basicRestSpecs") } From 59855efd216c10911ff9674653c323e32f5dd210 Mon Sep 17 00:00:00 2001 From: Niels Bauman Date: Wed, 25 Jun 2025 09:28:50 -0300 Subject: [PATCH 4/4] Add `NotMultiProjectCapable` --- .../java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java index bc55b1c49c4fa..ab9e79a2eb421 100644 --- a/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java +++ b/x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleService.java @@ -27,6 +27,7 @@ import org.elasticsearch.common.scheduler.TimeValueSchedule; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; +import org.elasticsearch.core.NotMultiProjectCapable; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.core.TimeValue; @@ -410,6 +411,7 @@ public boolean isForceExecution() { }); } + @NotMultiProjectCapable(description = "See comment inside the method") @Override public void applyClusterState(ClusterChangedEvent event) { // only act if we are master, otherwise keep idle until elected