10
10
package org .elasticsearch .health .node ;
11
11
12
12
import org .elasticsearch .cluster .metadata .Metadata ;
13
+ import org .elasticsearch .cluster .node .DiscoveryNode ;
13
14
import org .elasticsearch .cluster .node .DiscoveryNodes ;
14
15
import org .elasticsearch .cluster .service .ClusterService ;
15
16
import org .elasticsearch .common .ReferenceDocs ;
25
26
import org .elasticsearch .health .metadata .HealthMetadata ;
26
27
import org .elasticsearch .indices .ShardLimitValidator ;
27
28
29
+ import java .util .ArrayList ;
30
+ import java .util .LinkedHashSet ;
28
31
import java .util .List ;
29
- import java .util .stream .Stream ;
30
32
31
33
/**
32
34
* This indicator reports health data about the shard capacity across the cluster.
@@ -45,8 +47,6 @@ public class ShardsCapacityHealthIndicatorService implements HealthIndicatorServ
45
47
46
48
static final String NAME = "shards_capacity" ;
47
49
48
- static final String DATA_NODE_NAME = "data" ;
49
- static final String FROZEN_NODE_NAME = "frozen" ;
50
50
private static final String UPGRADE_BLOCKED = "The cluster has too many used shards to be able to upgrade." ;
51
51
private static final String UPGRADE_AT_RISK =
52
52
"The cluster is running low on room to add new shard. Upgrading to a new version is at risk." ;
@@ -90,9 +90,11 @@ public class ShardsCapacityHealthIndicatorService implements HealthIndicatorServ
90
90
);
91
91
92
92
private final ClusterService clusterService ;
93
+ private final List <ShardLimitValidator .LimitGroup > shardLimitGroups ;
93
94
94
95
public ShardsCapacityHealthIndicatorService (ClusterService clusterService ) {
95
96
this .clusterService = clusterService ;
97
+ this .shardLimitGroups = ShardLimitValidator .applicableLimitGroups (DiscoveryNode .isStateless (clusterService .getSettings ()));
96
98
}
97
99
98
100
@ Override
@@ -109,26 +111,23 @@ public HealthIndicatorResult calculate(boolean verbose, int maxAffectedResources
109
111
}
110
112
111
113
var shardLimitsMetadata = healthMetadata .getShardLimitsMetadata ();
112
- return mergeIndicators (
113
- verbose ,
114
- calculateFrom (
115
- shardLimitsMetadata .maxShardsPerNode (),
116
- state .nodes (),
117
- state .metadata (),
118
- ShardLimitValidator ::checkShardLimitForNormalNodes
119
- ),
120
- calculateFrom (
121
- shardLimitsMetadata .maxShardsPerNodeFrozen (),
122
- state .nodes (),
123
- state .metadata (),
124
- ShardLimitValidator ::checkShardLimitForFrozenNodes
114
+ final List <StatusResult > statusResults = shardLimitGroups .stream ()
115
+ .map (
116
+ limitGroup -> calculateFrom (
117
+ ShardLimitValidator .getShardLimitPerNode (limitGroup , shardLimitsMetadata ),
118
+ state .nodes (),
119
+ state .metadata (),
120
+ limitGroup ::checkShardLimit
121
+ )
125
122
)
126
- );
123
+ .toList ();
124
+
125
+ return mergeIndicators (verbose , statusResults );
127
126
}
128
127
129
- private HealthIndicatorResult mergeIndicators (boolean verbose , StatusResult dataNodes , StatusResult frozenNodes ) {
130
- var finalStatus = HealthStatus .merge (Stream . of ( dataNodes . status , frozenNodes . status ));
131
- var diagnoses = List . <Diagnosis >of ();
128
+ private HealthIndicatorResult mergeIndicators (boolean verbose , List < StatusResult > statusResults ) {
129
+ var finalStatus = HealthStatus .merge (statusResults . stream (). map ( StatusResult :: status ));
130
+ var diagnoses = new LinkedHashSet <Diagnosis >();
132
131
var symptomBuilder = new StringBuilder ();
133
132
134
133
if (finalStatus == HealthStatus .GREEN ) {
@@ -139,19 +138,22 @@ private HealthIndicatorResult mergeIndicators(boolean verbose, StatusResult data
139
138
// frozen* nodes, so we have to check each of the groups in order of provide the right message.
140
139
if (finalStatus .indicatesHealthProblem ()) {
141
140
symptomBuilder .append ("Cluster is close to reaching the configured maximum number of shards for " );
142
- if (dataNodes .status == frozenNodes .status ) {
143
- symptomBuilder .append (DATA_NODE_NAME ).append (" and " ).append (FROZEN_NODE_NAME );
144
- diagnoses = List .of (SHARDS_MAX_CAPACITY_REACHED_DATA_NODES , SHARDS_MAX_CAPACITY_REACHED_FROZEN_NODES );
145
-
146
- } else if (dataNodes .status .indicatesHealthProblem ()) {
147
- symptomBuilder .append (DATA_NODE_NAME );
148
- diagnoses = List .of (SHARDS_MAX_CAPACITY_REACHED_DATA_NODES );
149
-
150
- } else if (frozenNodes .status .indicatesHealthProblem ()) {
151
- symptomBuilder .append (FROZEN_NODE_NAME );
152
- diagnoses = List .of (SHARDS_MAX_CAPACITY_REACHED_FROZEN_NODES );
141
+ final var nodeTypeNames = new ArrayList <String >();
142
+ for (var statusResult : statusResults ) {
143
+ if (statusResult .status .indicatesHealthProblem ()) {
144
+ nodeTypeNames .add (nodeTypeFroLimitGroup (statusResult .result .group ()));
145
+ diagnoses .add (diagnosisForLimitGroup (statusResult .result .group ()));
146
+ }
153
147
}
154
148
149
+ assert nodeTypeNames .isEmpty () == false ;
150
+ symptomBuilder .append (nodeTypeNames .getFirst ());
151
+ for (int i = 1 ; i < nodeTypeNames .size () - 1 ; i ++) {
152
+ symptomBuilder .append (", " ).append (nodeTypeNames .get (i ));
153
+ }
154
+ if (nodeTypeNames .size () > 1 ) {
155
+ symptomBuilder .append (" and " ).append (nodeTypeNames .getLast ());
156
+ }
155
157
symptomBuilder .append (" nodes." );
156
158
}
157
159
@@ -164,9 +166,9 @@ private HealthIndicatorResult mergeIndicators(boolean verbose, StatusResult data
164
166
return createIndicator (
165
167
finalStatus ,
166
168
symptomBuilder .toString (),
167
- verbose ? buildDetails (dataNodes . result , frozenNodes . result ) : HealthIndicatorDetails .EMPTY ,
169
+ verbose ? buildDetails (statusResults . stream (). map ( StatusResult :: result ). toList () ) : HealthIndicatorDetails .EMPTY ,
168
170
indicatorImpacts ,
169
- verbose ? diagnoses : List .of ()
171
+ verbose ? List . copyOf ( diagnoses ) : List .of ()
170
172
);
171
173
}
172
174
@@ -189,22 +191,14 @@ static StatusResult calculateFrom(
189
191
return new StatusResult (HealthStatus .GREEN , result );
190
192
}
191
193
192
- static HealthIndicatorDetails buildDetails (ShardLimitValidator .Result dataNodes , ShardLimitValidator . Result frozenNodes ) {
194
+ static HealthIndicatorDetails buildDetails (List < ShardLimitValidator .Result > results ) {
193
195
return (builder , params ) -> {
194
196
builder .startObject ();
195
- {
196
- builder .startObject (DATA_NODE_NAME );
197
- builder .field ("max_shards_in_cluster" , dataNodes .maxShardsInCluster ());
198
- if (dataNodes .currentUsedShards ().isPresent ()) {
199
- builder .field ("current_used_shards" , dataNodes .currentUsedShards ().get ());
200
- }
201
- builder .endObject ();
202
- }
203
- {
204
- builder .startObject ("frozen" );
205
- builder .field ("max_shards_in_cluster" , frozenNodes .maxShardsInCluster ());
206
- if (frozenNodes .currentUsedShards ().isPresent ()) {
207
- builder .field ("current_used_shards" , frozenNodes .currentUsedShards ().get ());
197
+ for (var result : results ) {
198
+ builder .startObject (nodeTypeFroLimitGroup (result .group ()));
199
+ builder .field ("max_shards_in_cluster" , result .maxShardsInCluster ());
200
+ if (result .currentUsedShards ().isPresent ()) {
201
+ builder .field ("current_used_shards" , result .currentUsedShards ().get ());
208
202
}
209
203
builder .endObject ();
210
204
}
@@ -223,6 +217,22 @@ private HealthIndicatorResult unknownIndicator() {
223
217
);
224
218
}
225
219
220
+ private static String nodeTypeFroLimitGroup (ShardLimitValidator .LimitGroup limitGroup ) {
221
+ return switch (limitGroup ) {
222
+ case NORMAL -> "data" ;
223
+ case FROZEN -> "frozen" ;
224
+ case INDEX -> "index" ;
225
+ case SEARCH -> "search" ;
226
+ };
227
+ }
228
+
229
+ private static Diagnosis diagnosisForLimitGroup (ShardLimitValidator .LimitGroup limitGroup ) {
230
+ return switch (limitGroup ) {
231
+ case NORMAL , INDEX , SEARCH -> SHARDS_MAX_CAPACITY_REACHED_DATA_NODES ;
232
+ case FROZEN -> SHARDS_MAX_CAPACITY_REACHED_FROZEN_NODES ;
233
+ };
234
+ }
235
+
226
236
record StatusResult (HealthStatus status , ShardLimitValidator .Result result ) {}
227
237
228
238
@ FunctionalInterface
0 commit comments