Skip to content
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
6cb5948
Make shards_availability health indicator project aware
samxbr Mar 24, 2025
5d0bc27
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 24, 2025
d0699c5
fix compile
samxbr Mar 24, 2025
acc8ddf
[CI] Auto commit changes from spotless
Mar 24, 2025
5e084cc
clean up
samxbr Mar 24, 2025
8348130
clean up
samxbr Mar 24, 2025
a15324a
[CI] Auto commit changes from spotless
Mar 24, 2025
7953788
change num nodes
samxbr Mar 24, 2025
2f7442d
clean up
samxbr Mar 24, 2025
2f503f2
clean up
samxbr Mar 26, 2025
d2fc0d0
[CI] Auto commit changes from spotless
Mar 26, 2025
3b3ed20
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 26, 2025
9725775
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 26, 2025
ad3b6f2
Add locale
samxbr Mar 26, 2025
b07dee5
fix ordering
samxbr Mar 26, 2025
0d630ee
[CI] Auto commit changes from spotless
Mar 26, 2025
d3e5b27
Add yaml test
samxbr Mar 27, 2025
d33cfab
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 27, 2025
6a3f368
Update docs/changelog/125512.yaml
samxbr Mar 27, 2025
a8a76be
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 27, 2025
6be6ebe
empty commit to trigger CI
samxbr Mar 27, 2025
41ae620
Delete docs/changelog/125512.yaml
samxbr Mar 28, 2025
b813963
Address comments
samxbr Mar 28, 2025
6313024
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 28, 2025
13d002a
[CI] Auto commit changes from spotless
Mar 28, 2025
6a44ea2
Remove default project
samxbr Mar 28, 2025
dc8703e
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 28, 2025
24aebf0
[CI] Auto commit changes from spotless
Mar 28, 2025
985d5c7
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 29, 2025
f3fe9bd
address comments
samxbr Mar 31, 2025
71c0930
Merge branch 'main' into feature/multi-project/health-shards-availabi…
samxbr Mar 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.node.DiscoveryNodes;
import org.elasticsearch.cluster.project.DefaultProjectResolver;
import org.elasticsearch.cluster.routing.IndexRoutingTable;
import org.elasticsearch.cluster.routing.IndexShardRoutingTable;
import org.elasticsearch.cluster.routing.RecoverySource;
Expand Down Expand Up @@ -178,7 +179,12 @@ public void setUp() throws Exception {
new TaskManager(Settings.EMPTY, threadPool, Collections.emptySet())
);
clusterService.getClusterApplierService().setInitialState(initialClusterState);
indicatorService = new ShardsAvailabilityHealthIndicatorService(clusterService, allocationService, new SystemIndices(List.of()));
indicatorService = new ShardsAvailabilityHealthIndicatorService(
clusterService,
allocationService,
new SystemIndices(List.of()),
DefaultProjectResolver.INSTANCE
);
}

private int toInt(String v) {
Expand Down
5 changes: 5 additions & 0 deletions docs/changelog/125512.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 125512
summary: Add multi-project support for health indicator `shards_availability`
area: Health
type: enhancement
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ public ShardsAvailabilityPlugin() {}
@Override
public Collection<?> createComponents(PluginServices services) {
this.shardHealthService.set(
new ShardsAvailabilityHealthIndicatorService(services.clusterService(), services.allocationService(), services.systemIndices())
new ShardsAvailabilityHealthIndicatorService(
services.clusterService(),
services.allocationService(),
services.systemIndices(),
services.projectResolver()
)
);
return Set.of(this.shardHealthService.get());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.cluster.ClusterChangedEvent;
import org.elasticsearch.cluster.ClusterStateListener;
import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.routing.RoutingNodes;
import org.elasticsearch.cluster.routing.allocation.AllocationService;
import org.elasticsearch.cluster.service.ClusterService;
Expand Down Expand Up @@ -133,8 +134,9 @@ private void assertHealthDuring(Matcher<HealthStatus> statusMatcher, Runnable ac
var clusterService = internalCluster().getCurrentMasterNodeInstance(ClusterService.class);
var allocationService = internalCluster().getCurrentMasterNodeInstance(AllocationService.class);
var systemIndices = internalCluster().getCurrentMasterNodeInstance(SystemIndices.class);
var projectResolver = internalCluster().getCurrentMasterNodeInstance(ProjectResolver.class);

var service = new ShardsAvailabilityHealthIndicatorService(clusterService, allocationService, systemIndices);
var service = new ShardsAvailabilityHealthIndicatorService(clusterService, allocationService, systemIndices, projectResolver);
var states = new ArrayList<RoutingNodesAndHealth>();
var listener = new ClusterStateListener() {
@Override
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import org.elasticsearch.cluster.metadata.IndexMetadata;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.cluster.node.DiscoveryNode;

import java.util.Collection;
Expand Down Expand Up @@ -47,6 +48,7 @@ public static String getNodeName(DiscoveryNode node) {
* logging or user messages. The indices are sorted by priority and then by name to ensure a
* deterministic message. If there are more indices than 10, it adds the '...' suffix.
*/
@Deprecated
public static String getTruncatedIndices(Set<String> indices, Metadata clusterMetadata) {
final int maxIndices = 10;
String truncatedIndicesString = indices.stream()
Expand All @@ -59,6 +61,28 @@ public static String getTruncatedIndices(Set<String> indices, Metadata clusterMe
return truncatedIndicesString;
}

/**
* Creates a string that displays max 10 indices from the given set to be used as examples in
* logging or user messages. The indices are sorted by priority and then by name to ensure a
* deterministic message. If there are more indices than 10, it adds the '...' suffix.
*/
public static String getTruncatedProjectIndices(
Set<ProjectIndexName> indices,
Metadata clusterMetadata,
boolean supportsMultipleProjects
) {
final int maxIndices = 10;
String truncatedIndicesString = indices.stream()
.sorted(indicesComparatorByPriorityAndProjectIndex(clusterMetadata, supportsMultipleProjects))
.limit(maxIndices)
.map(projectIndexName -> toDisplayValue(projectIndexName, supportsMultipleProjects))
.collect(joining(", "));
if (maxIndices < indices.size()) {
truncatedIndicesString = truncatedIndicesString + ", ...";
}
return truncatedIndicesString;
}

/**
* Creates a string that displays all the values that fulfilled the predicate sorted in the natural order.
* @param values, the values to be displayed
Expand Down Expand Up @@ -119,11 +143,46 @@ public static String regularVerb(String verb, int count) {
* @param clusterMetadata Used to look up index priority.
* @return Comparator instance
*/
@Deprecated
public static Comparator<String> indicesComparatorByPriorityAndName(Metadata clusterMetadata) {
// We want to show indices with a numerically higher index.priority first (since lower priority ones might get truncated):
return Comparator.comparingInt((String indexName) -> {
IndexMetadata indexMetadata = clusterMetadata.getProject().index(indexName);
return indexMetadata == null ? -1 : indexMetadata.priority();
}).reversed().thenComparing(Comparator.naturalOrder());
}

/**
* Sorts index names by their priority first, then alphabetically by name. If the priority cannot be determined for an index then
* a priority of -1 is used to sort it behind other index names.
* @param clusterMetadata Used to look up index priority.
* @param supportsMultipleProjects Whether cluster supports multi-project
* @return Comparator instance
*/
public static Comparator<ProjectIndexName> indicesComparatorByPriorityAndProjectIndex(
Metadata clusterMetadata,
boolean supportsMultipleProjects
) {
// We want to show indices with a numerically higher index.priority first (since lower priority ones might get truncated):
return Comparator.comparingInt((ProjectIndexName projectIndexName) -> {
ProjectMetadata projectMetadata = clusterMetadata.getProject(projectIndexName.projectId());
IndexMetadata indexMetadata = projectMetadata.index(projectIndexName.indexName());
return indexMetadata == null ? -1 : indexMetadata.priority();
}).reversed().thenComparing(projectIndex -> toDisplayValue(projectIndex, supportsMultipleProjects));
}

/**
* Converts the project index name to display name based on whether the cluster supports multi-projects.
* If not for multi-project, the default project id is omitted.
* @param projectIndexName Project specific index
* @param supportsMultipleProjects Whether cluster supports multi-project
* @return display string value
*/
public static String toDisplayValue(ProjectIndexName projectIndexName, boolean supportsMultipleProjects) {
if (supportsMultipleProjects) {
return projectIndexName.toString(true);
} else {
return projectIndexName.toString(false);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.health.node;

import org.elasticsearch.cluster.metadata.ProjectId;

public record ProjectIndexName(ProjectId projectId, String indexName) implements Comparable<ProjectIndexName> {
// VisibleForTesting
public static final String DELIMITER = "/";

public static ProjectIndexName defaultProjectIndex(String indexName) {
return new ProjectIndexName(ProjectId.DEFAULT, indexName);
}

@Override
public String toString() {
return toString(true);
}

public String toString(boolean withProjectId) {
if (withProjectId) {
return projectId.id() + DELIMITER + indexName;
} else {
return indexName;
}
}

@Override
public int compareTo(ProjectIndexName other) {
return this.toString().compareTo(other.toString());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.elasticsearch.cluster.metadata.ComposableIndexTemplate;
import org.elasticsearch.cluster.metadata.DataStream;
import org.elasticsearch.cluster.metadata.Metadata;
import org.elasticsearch.cluster.metadata.ProjectMetadata;
import org.elasticsearch.index.Index;

import java.util.Collections;
Expand Down Expand Up @@ -106,8 +107,18 @@ public String getDataStreamName() {
* @param metadata Metadata in which to look for indices
* @return List of names of backing indices
*/
@Deprecated
public List<String> getBackingIndexNames(Metadata metadata) {
DataStream dataStream = metadata.getProject().dataStreams().get(dataStreamName);
return getBackingIndexNames(metadata.getProject());
}

/**
* Retrieve backing indices for this system data stream
* @param projectMetadata Project metadata in which to look for indices
* @return List of names of backing indices
*/
public List<String> getBackingIndexNames(ProjectMetadata projectMetadata) {
DataStream dataStream = projectMetadata.dataStreams().get(dataStreamName);
if (dataStream == null) {
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

package org.elasticsearch.cluster.routing.allocation;

import org.elasticsearch.cluster.project.ProjectResolver;
import org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.settings.ClusterSettings;
Expand Down Expand Up @@ -46,7 +47,12 @@ public ShardsAvailabilityActionGuideTests() {
ClusterService clusterService = mock(ClusterService.class);
when(clusterService.getClusterSettings()).thenReturn(ClusterSettings.createBuiltInClusterSettings());
when(clusterService.getSettings()).thenReturn(Settings.EMPTY);
service = new ShardsAvailabilityHealthIndicatorService(clusterService, mock(AllocationService.class), mock(SystemIndices.class));
service = new ShardsAvailabilityHealthIndicatorService(
clusterService,
mock(AllocationService.class),
mock(SystemIndices.class),
mock(ProjectResolver.class)
);
}

public void testRestoreFromSnapshotAction() {
Expand Down
Loading
Loading