1515import org .elasticsearch .action .support .master .TransportMasterNodeReadAction ;
1616import org .elasticsearch .client .internal .OriginSettingClient ;
1717import org .elasticsearch .client .internal .node .NodeClient ;
18+ import org .elasticsearch .cluster .ClusterInfo ;
19+ import org .elasticsearch .cluster .ClusterInfoService ;
1820import org .elasticsearch .cluster .ClusterState ;
21+ import org .elasticsearch .cluster .DiskUsage ;
1922import org .elasticsearch .cluster .block .ClusterBlockException ;
2023import org .elasticsearch .cluster .block .ClusterBlockLevel ;
2124import org .elasticsearch .cluster .metadata .ComponentTemplate ;
2427import org .elasticsearch .cluster .metadata .IndexNameExpressionResolver ;
2528import org .elasticsearch .cluster .metadata .Metadata ;
2629import org .elasticsearch .cluster .metadata .Template ;
30+ import org .elasticsearch .cluster .node .DiscoveryNode ;
31+ import org .elasticsearch .cluster .node .DiscoveryNodes ;
32+ import org .elasticsearch .cluster .routing .allocation .DiskThresholdSettings ;
2733import org .elasticsearch .cluster .service .ClusterService ;
2834import org .elasticsearch .common .regex .Regex ;
35+ import org .elasticsearch .common .settings .ClusterSettings ;
2936import org .elasticsearch .common .settings .Setting ;
3037import org .elasticsearch .common .settings .Settings ;
38+ import org .elasticsearch .common .unit .ByteSizeValue ;
39+ import org .elasticsearch .common .util .CollectionUtils ;
3140import org .elasticsearch .core .Tuple ;
3241import org .elasticsearch .injection .guice .Inject ;
3342import org .elasticsearch .tasks .Task ;
4453import java .util .Collections ;
4554import java .util .HashMap ;
4655import java .util .List ;
56+ import java .util .Locale ;
4757import java .util .Map ;
58+ import java .util .Objects ;
4859import java .util .stream .Collectors ;
4960import java .util .stream .Stream ;
5061
62+ import static org .elasticsearch .cluster .routing .allocation .DiskThresholdSettings .CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING ;
63+
5164public class TransportDeprecationInfoAction extends TransportMasterNodeReadAction <
5265 DeprecationInfoAction .Request ,
5366 DeprecationInfoAction .Response > {
@@ -62,6 +75,7 @@ public class TransportDeprecationInfoAction extends TransportMasterNodeReadActio
6275 private final IndexNameExpressionResolver indexNameExpressionResolver ;
6376 private final Settings settings ;
6477 private final NamedXContentRegistry xContentRegistry ;
78+ private final ClusterInfoService clusterInfoService ;
6579 private volatile List <String > skipTheseDeprecations ;
6680 private final NodeDeprecationChecker nodeDeprecationChecker ;
6781 private final ClusterDeprecationChecker clusterDeprecationChecker ;
@@ -76,7 +90,8 @@ public TransportDeprecationInfoAction(
7690 ActionFilters actionFilters ,
7791 IndexNameExpressionResolver indexNameExpressionResolver ,
7892 NodeClient client ,
79- NamedXContentRegistry xContentRegistry
93+ NamedXContentRegistry xContentRegistry ,
94+ ClusterInfoService clusterInfoService
8095 ) {
8196 super (
8297 DeprecationInfoAction .NAME ,
@@ -92,6 +107,7 @@ public TransportDeprecationInfoAction(
92107 this .indexNameExpressionResolver = indexNameExpressionResolver ;
93108 this .settings = settings ;
94109 this .xContentRegistry = xContentRegistry ;
110+ this .clusterInfoService = clusterInfoService ;
95111 skipTheseDeprecations = SKIP_DEPRECATIONS_SETTING .get (settings );
96112 nodeDeprecationChecker = new NodeDeprecationChecker (threadPool );
97113 clusterDeprecationChecker = new ClusterDeprecationChecker (xContentRegistry );
@@ -122,7 +138,13 @@ protected final void masterOperation(
122138 ClusterState state ,
123139 final ActionListener <DeprecationInfoAction .Response > listener
124140 ) {
125- PrecomputedData precomputedData = new PrecomputedData ();
141+ DeprecationIssue lowWatermarkIssue = checkDiskLowWatermark (
142+ clusterService .getClusterSettings (),
143+ clusterInfoService .getClusterInfo (),
144+ state .nodes ()
145+ );
146+ PrecomputedData precomputedData = new PrecomputedData (lowWatermarkIssue );
147+
126148 try (var refs = new RefCountingListener (checkAndCreateResponse (state , request , precomputedData , listener ))) {
127149 nodeDeprecationChecker .check (client , refs .acquire (precomputedData ::setOnceNodeSettingsIssues ));
128150 transformConfigs (refs .acquire (precomputedData ::setOnceTransformConfigs ));
@@ -149,7 +171,7 @@ protected final void masterOperation(
149171 * @return The listener that should be executed after all the remote requests have completed and the {@link PrecomputedData}
150172 * is initialised.
151173 */
152- public ActionListener <Void > checkAndCreateResponse (
174+ private ActionListener <Void > checkAndCreateResponse (
153175 ClusterState state ,
154176 DeprecationInfoAction .Request request ,
155177 PrecomputedData precomputedData ,
@@ -238,6 +260,11 @@ public static class PrecomputedData {
238260 private final SetOnce <List <DeprecationIssue >> nodeSettingsIssues = new SetOnce <>();
239261 private final SetOnce <Map <String , List <DeprecationIssue >>> pluginIssues = new SetOnce <>();
240262 private final SetOnce <List <TransformConfig >> transformConfigs = new SetOnce <>();
263+ private final DeprecationIssue diskWatermarkIssue ;
264+
265+ public PrecomputedData (DeprecationIssue diskWatermarkIssue ) {
266+ this .diskWatermarkIssue = diskWatermarkIssue ;
267+ }
241268
242269 public void setOnceNodeSettingsIssues (List <DeprecationIssue > nodeSettingsIssues ) {
243270 this .nodeSettingsIssues .set (nodeSettingsIssues );
@@ -252,7 +279,12 @@ public void setOnceTransformConfigs(List<TransformConfig> transformConfigs) {
252279 }
253280
254281 public List <DeprecationIssue > nodeSettingsIssues () {
255- return nodeSettingsIssues .get ();
282+ List <DeprecationIssue > deprecationIssues = nodeSettingsIssues .get ();
283+ assert deprecationIssues != null : "nodeSettingsIssues must be set before calling this method" ;
284+ if (diskWatermarkIssue == null ) {
285+ return deprecationIssues ;
286+ }
287+ return CollectionUtils .appendToCopy (deprecationIssues , diskWatermarkIssue );
256288 }
257289
258290 public Map <String , List <DeprecationIssue >> pluginIssues () {
@@ -395,4 +427,44 @@ private void transformConfigs(PageParams currentPage, ActionListener<Stream<Tran
395427 private <T > ActionListener <T > executeInGenericThreadpool (ActionListener <T > listener ) {
396428 return new ThreadedActionListener <>(threadPool .generic (), listener );
397429 }
430+
431+ static DeprecationIssue checkDiskLowWatermark (ClusterSettings clusterSettings , ClusterInfo clusterInfo , DiscoveryNodes discoveryNodes ) {
432+ Map <String , DiskUsage > nodeMostAvailableDiskUsages = clusterInfo .getNodeMostAvailableDiskUsages ();
433+
434+ List <String > impactedNodeNames = nodeMostAvailableDiskUsages .entrySet ()
435+ .stream ()
436+ .filter (e -> exceedsLowWatermark (clusterSettings , e .getValue ()))
437+ .map (Map .Entry ::getKey )
438+ .map (discoveryNodes ::get )
439+ .filter (Objects ::nonNull )
440+ .map (DiscoveryNode ::getName )
441+ .sorted ()
442+ .toList ();
443+
444+ if (impactedNodeNames .isEmpty ()) {
445+ return null ;
446+ }
447+
448+ return new DeprecationIssue (
449+ DeprecationIssue .Level .CRITICAL ,
450+ "Disk usage exceeds low watermark" ,
451+ "https://ela.st/es-deprecation-7-disk-watermark-exceeded" ,
452+ String .format (
453+ Locale .ROOT ,
454+ "Disk usage exceeds low watermark, which will prevent reindexing indices during upgrade. Get disk usage on "
455+ + "all nodes below the value specified in %s (nodes impacted: %s)" ,
456+ CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK_SETTING .getKey (),
457+ impactedNodeNames
458+ ),
459+ false ,
460+ null
461+ );
462+ }
463+
464+ private static boolean exceedsLowWatermark (ClusterSettings clusterSettings , DiskUsage usage ) {
465+ long freeBytes = usage .freeBytes ();
466+ long totalBytes = usage .totalBytes ();
467+ return freeBytes < DiskThresholdSettings .getFreeBytesThresholdLowStage (ByteSizeValue .ofBytes (totalBytes ), clusterSettings )
468+ .getBytes ();
469+ }
398470}
0 commit comments