Browse Source

Adding a deprecation info API warning for data streams with old indices (#116447) (#116626)

* Adding a deprecation info API warning for data streams with old indices (#116447)

* removing use of a method not available in 8.x
Keith Massey 11 months ago
parent
commit
7c3d4027cd

+ 5 - 0
docs/changelog/116447.yaml

@@ -0,0 +1,5 @@
+pr: 116447
+summary: Adding a deprecation info API warning for data streams with old indices
+area: Data streams
+type: enhancement
+issues: []

+ 2 - 1
server/src/main/java/org/elasticsearch/TransportVersions.java

@@ -191,7 +191,8 @@ public class TransportVersions {
     public static final TransportVersion LOGSDB_TELEMETRY_STATS = def(8_785_00_0);
     public static final TransportVersion KQL_QUERY_ADDED = def(8_786_00_0);
     public static final TransportVersion ROLE_MONITOR_STATS = def(8_787_00_0);
-    public static final TransportVersion ADD_COMPATIBILITY_VERSIONS_TO_NODE_INFO = def(8_788_00_0);
+    public static final TransportVersion DATA_STREAM_INDEX_VERSION_DEPRECATION_CHECK = def(8_788_00_0);
+    public static final TransportVersion ADD_COMPATIBILITY_VERSIONS_TO_NODE_INFO = def(8_789_00_0);
 
     /*
      * STOP! READ THIS FIRST! No, really,

+ 74 - 0
x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationChecks.java

@@ -0,0 +1,74 @@
+/*
+ * 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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.deprecation;
+
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.metadata.DataStream;
+import org.elasticsearch.index.Index;
+import org.elasticsearch.index.IndexVersions;
+import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
+
+import java.util.List;
+
+import static java.util.Map.entry;
+import static java.util.Map.ofEntries;
+
+public class DataStreamDeprecationChecks {
+    static DeprecationIssue oldIndicesCheck(DataStream dataStream, ClusterState clusterState) {
+        List<Index> backingIndices = dataStream.getIndices();
+        boolean hasOldIndices = backingIndices.stream()
+            .anyMatch(index -> clusterState.metadata().index(index).getCompatibilityVersion().before(IndexVersions.V_8_0_0));
+        if (hasOldIndices) {
+            long totalIndices = backingIndices.size();
+            List<Index> oldIndices = backingIndices.stream()
+                .filter(index -> clusterState.metadata().index(index).getCompatibilityVersion().before(IndexVersions.V_8_0_0))
+                .toList();
+            long totalOldIndices = oldIndices.size();
+            long totalOldSearchableSnapshots = oldIndices.stream()
+                .filter(index -> clusterState.metadata().index(index).isSearchableSnapshot())
+                .count();
+            long totalOldPartiallyMountedSearchableSnapshots = oldIndices.stream()
+                .filter(index -> clusterState.metadata().index(index).isPartialSearchableSnapshot())
+                .count();
+            long totalOldFullyMountedSearchableSnapshots = totalOldSearchableSnapshots - totalOldPartiallyMountedSearchableSnapshots;
+            return new DeprecationIssue(
+                DeprecationIssue.Level.CRITICAL,
+                "Old data stream with a compatibility version < 8.0",
+                "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html",
+                "This data stream has backing indices that were created before Elasticsearch 8.0.0",
+                false,
+                ofEntries(
+                    entry(
+                        "backing_indices",
+                        ofEntries(
+                            entry("count", totalIndices),
+                            entry(
+                                "need_upgrading",
+                                ofEntries(
+                                    entry("count", totalOldIndices),
+                                    entry(
+                                        "searchable_snapshots",
+                                        ofEntries(
+                                            entry("count", totalOldSearchableSnapshots),
+                                            entry("fully_mounted", ofEntries(entry("count", totalOldFullyMountedSearchableSnapshots))),
+                                            entry(
+                                                "partially_mounted",
+                                                ofEntries(entry("count", totalOldPartiallyMountedSearchableSnapshots))
+                                            )
+                                        )
+                                    )
+                                )
+                            )
+                        )
+                    )
+                )
+            );
+        }
+        return null;
+    }
+}

+ 6 - 0
x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/DeprecationChecks.java

@@ -8,6 +8,7 @@ package org.elasticsearch.xpack.deprecation;
 
 import org.elasticsearch.action.admin.cluster.node.info.PluginsAndModules;
 import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.metadata.DataStream;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.common.settings.Setting;
 import org.elasticsearch.common.settings.Settings;
@@ -16,6 +17,7 @@ import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
 
 import java.util.List;
 import java.util.Objects;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -98,6 +100,10 @@ public class DeprecationChecks {
         IndexDeprecationChecks::deprecatedCamelCasePattern
     );
 
+    static List<BiFunction<DataStream, ClusterState, DeprecationIssue>> DATA_STREAM_CHECKS = List.of(
+        DataStreamDeprecationChecks::oldIndicesCheck
+    );
+
     /**
      * helper utility function to reduce repeat of running a specific {@link List} of checks.
      *

+ 37 - 2
x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/DeprecationInfoAction.java

@@ -16,6 +16,7 @@ import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
 import org.elasticsearch.action.support.IndicesOptions;
 import org.elasticsearch.action.support.master.MasterNodeReadRequest;
 import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.metadata.DataStream;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
 import org.elasticsearch.cluster.metadata.Metadata;
@@ -42,6 +43,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
@@ -144,10 +146,11 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
     }
 
     public static class Response extends ActionResponse implements ToXContentObject {
-        static final Set<String> RESERVED_NAMES = Set.of("cluster_settings", "node_settings", "index_settings");
+        static final Set<String> RESERVED_NAMES = Set.of("cluster_settings", "node_settings", "index_settings", "data_streams");
         private final List<DeprecationIssue> clusterSettingsIssues;
         private final List<DeprecationIssue> nodeSettingsIssues;
         private final Map<String, List<DeprecationIssue>> indexSettingsIssues;
+        private final Map<String, List<DeprecationIssue>> dataStreamIssues;
         private final Map<String, List<DeprecationIssue>> pluginSettingsIssues;
 
         public Response(StreamInput in) throws IOException {
@@ -155,6 +158,11 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
             clusterSettingsIssues = in.readCollectionAsList(DeprecationIssue::new);
             nodeSettingsIssues = in.readCollectionAsList(DeprecationIssue::new);
             indexSettingsIssues = in.readMapOfLists(DeprecationIssue::new);
+            if (in.getTransportVersion().onOrAfter(TransportVersions.DATA_STREAM_INDEX_VERSION_DEPRECATION_CHECK)) {
+                dataStreamIssues = in.readMapOfLists(DeprecationIssue::new);
+            } else {
+                dataStreamIssues = Map.of();
+            }
             if (in.getTransportVersion().before(TransportVersions.V_7_11_0)) {
                 List<DeprecationIssue> mlIssues = in.readCollectionAsList(DeprecationIssue::new);
                 pluginSettingsIssues = new HashMap<>();
@@ -168,11 +176,13 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
             List<DeprecationIssue> clusterSettingsIssues,
             List<DeprecationIssue> nodeSettingsIssues,
             Map<String, List<DeprecationIssue>> indexSettingsIssues,
+            Map<String, List<DeprecationIssue>> dataStreamIssues,
             Map<String, List<DeprecationIssue>> pluginSettingsIssues
         ) {
             this.clusterSettingsIssues = clusterSettingsIssues;
             this.nodeSettingsIssues = nodeSettingsIssues;
             this.indexSettingsIssues = indexSettingsIssues;
+            this.dataStreamIssues = dataStreamIssues;
             Set<String> intersection = Sets.intersection(RESERVED_NAMES, pluginSettingsIssues.keySet());
             if (intersection.isEmpty() == false) {
                 throw new ElasticsearchStatusException(
@@ -205,6 +215,9 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
             out.writeCollection(clusterSettingsIssues);
             out.writeCollection(nodeSettingsIssues);
             out.writeMap(indexSettingsIssues, StreamOutput::writeCollection);
+            if (out.getTransportVersion().onOrAfter(TransportVersions.DATA_STREAM_INDEX_VERSION_DEPRECATION_CHECK)) {
+                out.writeMap(dataStreamIssues, StreamOutput::writeCollection);
+            }
             if (out.getTransportVersion().before(TransportVersions.V_7_11_0)) {
                 out.writeCollection(pluginSettingsIssues.getOrDefault("ml_settings", Collections.emptyList()));
             } else {
@@ -219,6 +232,8 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
                 .array("node_settings", nodeSettingsIssues.toArray())
                 .field("index_settings")
                 .map(indexSettingsIssues)
+                .field("data_streams")
+                .map(dataStreamIssues)
                 .mapContents(pluginSettingsIssues)
                 .endObject();
         }
@@ -260,6 +275,7 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
             Request request,
             NodesDeprecationCheckResponse nodeDeprecationResponse,
             List<Function<IndexMetadata, DeprecationIssue>> indexSettingsChecks,
+            List<BiFunction<DataStream, ClusterState, DeprecationIssue>> dataStreamChecks,
             List<Function<ClusterState, DeprecationIssue>> clusterSettingsChecks,
             Map<String, List<DeprecationIssue>> pluginSettingIssues,
             List<String> skipTheseDeprecatedSettings
@@ -283,6 +299,19 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
                 }
             }
 
+            List<String> dataStreamNames = indexNameExpressionResolver.dataStreamNames(
+                state,
+                IndicesOptions.LENIENT_EXPAND_OPEN_CLOSED_HIDDEN
+            );
+            Map<String, List<DeprecationIssue>> dataStreamIssues = new HashMap<>();
+            for (String dataStreamName : dataStreamNames) {
+                DataStream dataStream = stateWithSkippedSettingsRemoved.metadata().dataStreams().get(dataStreamName);
+                List<DeprecationIssue> issuesForSingleDataStream = filterChecks(dataStreamChecks, c -> c.apply(dataStream, state));
+                if (issuesForSingleDataStream.isEmpty() == false) {
+                    dataStreamIssues.put(dataStreamName, issuesForSingleDataStream);
+                }
+            }
+
             // WORKAROUND: move transform deprecation issues into cluster_settings
             List<DeprecationIssue> transformDeprecations = pluginSettingIssues.remove(
                 TransformDeprecationChecker.TRANSFORM_DEPRECATION_KEY
@@ -291,7 +320,13 @@ public class DeprecationInfoAction extends ActionType<DeprecationInfoAction.Resp
                 clusterSettingsIssues.addAll(transformDeprecations);
             }
 
-            return new DeprecationInfoAction.Response(clusterSettingsIssues, nodeSettingsIssues, indexSettingsIssues, pluginSettingIssues);
+            return new DeprecationInfoAction.Response(
+                clusterSettingsIssues,
+                nodeSettingsIssues,
+                indexSettingsIssues,
+                dataStreamIssues,
+                pluginSettingIssues
+            );
         }
     }
 

+ 2 - 0
x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/TransportDeprecationInfoAction.java

@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 import static org.elasticsearch.xpack.deprecation.DeprecationChecks.CLUSTER_SETTINGS_CHECKS;
+import static org.elasticsearch.xpack.deprecation.DeprecationChecks.DATA_STREAM_CHECKS;
 import static org.elasticsearch.xpack.deprecation.DeprecationChecks.INDEX_SETTINGS_CHECKS;
 
 public class TransportDeprecationInfoAction extends TransportMasterNodeReadAction<
@@ -134,6 +135,7 @@ public class TransportDeprecationInfoAction extends TransportMasterNodeReadActio
                                 request,
                                 response,
                                 INDEX_SETTINGS_CHECKS,
+                                DATA_STREAM_CHECKS,
                                 CLUSTER_SETTINGS_CHECKS,
                                 deprecationIssues,
                                 skipTheseDeprecations

+ 124 - 0
x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DataStreamDeprecationChecksTests.java

@@ -0,0 +1,124 @@
+/*
+ * 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; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.deprecation;
+
+import org.elasticsearch.cluster.ClusterName;
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.metadata.DataStream;
+import org.elasticsearch.cluster.metadata.DataStreamOptions;
+import org.elasticsearch.cluster.metadata.IndexMetadata;
+import org.elasticsearch.cluster.metadata.Metadata;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.index.Index;
+import org.elasticsearch.index.IndexMode;
+import org.elasticsearch.index.IndexVersion;
+import org.elasticsearch.test.ESTestCase;
+import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.util.Collections.singletonList;
+import static org.elasticsearch.xpack.deprecation.DeprecationChecks.DATA_STREAM_CHECKS;
+import static org.hamcrest.Matchers.equalTo;
+
+public class DataStreamDeprecationChecksTests extends ESTestCase {
+
+    public void testOldIndicesCheck() {
+        long oldIndexCount = randomIntBetween(1, 100);
+        long newIndexCount = randomIntBetween(1, 100);
+        long oldSearchableSnapshotCount = 0;
+        long oldFullyManagedSearchableSnapshotCount = 0;
+        long oldPartiallyManagedSearchableSnapshotCount = 0;
+        List<Index> allIndices = new ArrayList<>();
+        Map<String, IndexMetadata> nameToIndexMetadata = new HashMap<>();
+        for (int i = 0; i < oldIndexCount; i++) {
+            Settings.Builder settingsBuilder = settings(IndexVersion.fromId(7170099));
+            if (randomBoolean()) {
+                settingsBuilder.put("index.store.type", "snapshot");
+                if (randomBoolean()) {
+                    oldFullyManagedSearchableSnapshotCount++;
+                } else {
+                    settingsBuilder.put("index.store.snapshot.partial", true);
+                    oldPartiallyManagedSearchableSnapshotCount++;
+                }
+                oldSearchableSnapshotCount++;
+            }
+            IndexMetadata oldIndexMetadata = IndexMetadata.builder("old-data-stream-index-" + i)
+                .settings(settingsBuilder)
+                .numberOfShards(1)
+                .numberOfReplicas(0)
+                .build();
+            allIndices.add(oldIndexMetadata.getIndex());
+            nameToIndexMetadata.put(oldIndexMetadata.getIndex().getName(), oldIndexMetadata);
+        }
+        for (int i = 0; i < newIndexCount; i++) {
+            Settings.Builder settingsBuilder = settings(IndexVersion.current());
+            if (randomBoolean()) {
+                settingsBuilder.put("index.store.type", "snapshot");
+            }
+            IndexMetadata newIndexMetadata = IndexMetadata.builder("new-data-stream-index-" + i)
+                .settings(settingsBuilder)
+                .numberOfShards(1)
+                .numberOfReplicas(0)
+                .build();
+            allIndices.add(newIndexMetadata.getIndex());
+            nameToIndexMetadata.put(newIndexMetadata.getIndex().getName(), newIndexMetadata);
+        }
+        DataStream dataStream = new DataStream(
+            randomAlphaOfLength(10),
+            allIndices,
+            randomNonNegativeLong(),
+            Map.of(),
+            randomBoolean(),
+            false,
+            false,
+            randomBoolean(),
+            randomFrom(IndexMode.values()),
+            null,
+            randomFrom(DataStreamOptions.EMPTY, DataStreamOptions.FAILURE_STORE_DISABLED, DataStreamOptions.FAILURE_STORE_ENABLED, null),
+            List.of(),
+            randomBoolean(),
+            null
+        );
+        Metadata metadata = Metadata.builder().indices(nameToIndexMetadata).build();
+        ClusterState clusterState = ClusterState.builder(ClusterName.DEFAULT).metadata(metadata).build();
+        DeprecationIssue expected = new DeprecationIssue(
+            DeprecationIssue.Level.CRITICAL,
+            "Old data stream with a compatibility version < 8.0",
+            "https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-9.0.html",
+            "This data stream has backing indices that were created before Elasticsearch 8.0.0",
+            false,
+            Map.of(
+                "backing_indices",
+                Map.of(
+                    "count",
+                    oldIndexCount + newIndexCount,
+                    "need_upgrading",
+                    Map.of(
+                        "count",
+                        oldIndexCount,
+                        "searchable_snapshots",
+                        Map.of(
+                            "count",
+                            oldSearchableSnapshotCount,
+                            "fully_mounted",
+                            Map.of("count", oldFullyManagedSearchableSnapshotCount),
+                            "partially_mounted",
+                            Map.of("count", oldPartiallyManagedSearchableSnapshotCount)
+                        )
+                    )
+                )
+            )
+        );
+        List<DeprecationIssue> issues = DeprecationChecks.filterChecks(DATA_STREAM_CHECKS, c -> c.apply(dataStream, clusterState));
+        assertThat(issues, equalTo(singletonList(expected)));
+    }
+}

+ 45 - 2
x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/DeprecationInfoActionResponseTests.java

@@ -9,6 +9,7 @@ package org.elasticsearch.xpack.deprecation;
 import org.elasticsearch.ElasticsearchStatusException;
 import org.elasticsearch.cluster.ClusterName;
 import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.metadata.DataStream;
 import org.elasticsearch.cluster.metadata.IndexMetadata;
 import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
 import org.elasticsearch.cluster.metadata.Metadata;
@@ -36,7 +37,9 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -63,6 +66,13 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
                 .collect(Collectors.toList());
             indexIssues.put(randomAlphaOfLength(10), perIndexIssues);
         }
+        Map<String, List<DeprecationIssue>> dataStreamIssues = new HashMap<>();
+        for (int i = 0; i < randomIntBetween(0, 10); i++) {
+            List<DeprecationIssue> perDataStreamIssues = Stream.generate(DeprecationInfoActionResponseTests::createTestDeprecationIssue)
+                .limit(randomIntBetween(0, 10))
+                .collect(Collectors.toList());
+            dataStreamIssues.put(randomAlphaOfLength(10), perDataStreamIssues);
+        }
         Map<String, List<DeprecationIssue>> pluginIssues = new HashMap<>();
         for (int i = 0; i < randomIntBetween(0, 10); i++) {
             List<DeprecationIssue> perPluginIssues = Stream.generate(DeprecationInfoActionResponseTests::createTestDeprecationIssue)
@@ -70,7 +80,7 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
                 .collect(Collectors.toList());
             pluginIssues.put(randomAlphaOfLength(10), perPluginIssues);
         }
-        return new DeprecationInfoAction.Response(clusterIssues, nodeIssues, indexIssues, pluginIssues);
+        return new DeprecationInfoAction.Response(clusterIssues, nodeIssues, indexIssues, dataStreamIssues, pluginIssues);
     }
 
     @Override
@@ -104,9 +114,13 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
         boolean clusterIssueFound = randomBoolean();
         boolean nodeIssueFound = randomBoolean();
         boolean indexIssueFound = randomBoolean();
+        boolean dataStreamIssueFound = randomBoolean();
         DeprecationIssue foundIssue = createTestDeprecationIssue();
         List<Function<ClusterState, DeprecationIssue>> clusterSettingsChecks = List.of((s) -> clusterIssueFound ? foundIssue : null);
         List<Function<IndexMetadata, DeprecationIssue>> indexSettingsChecks = List.of((idx) -> indexIssueFound ? foundIssue : null);
+        List<BiFunction<DataStream, ClusterState, DeprecationIssue>> dataStreamChecks = List.of(
+            (ds, cs) -> dataStreamIssueFound ? foundIssue : null
+        );
 
         NodesDeprecationCheckResponse nodeDeprecationIssues = new NodesDeprecationCheckResponse(
             new ClusterName(randomAlphaOfLength(5)),
@@ -125,6 +139,7 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
             request,
             nodeDeprecationIssues,
             indexSettingsChecks,
+            dataStreamChecks,
             clusterSettingsChecks,
             Collections.emptyMap(),
             Collections.emptyList()
@@ -197,6 +212,7 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
         DeprecationIssue foundIssue2 = createTestDeprecationIssue(foundIssue1, metaMap2);
         List<Function<ClusterState, DeprecationIssue>> clusterSettingsChecks = Collections.emptyList();
         List<Function<IndexMetadata, DeprecationIssue>> indexSettingsChecks = List.of((idx) -> null);
+        List<BiFunction<DataStream, ClusterState, DeprecationIssue>> dataStreamChecks = List.of((ds, cs) -> null);
 
         NodesDeprecationCheckResponse nodeDeprecationIssues = new NodesDeprecationCheckResponse(
             new ClusterName(randomAlphaOfLength(5)),
@@ -214,6 +230,7 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
             request,
             nodeDeprecationIssues,
             indexSettingsChecks,
+            dataStreamChecks,
             clusterSettingsChecks,
             Collections.emptyMap(),
             Collections.emptyList()
@@ -239,8 +256,15 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
         settingsBuilder.put("some.undeprecated.property", "someValue3");
         settingsBuilder.putList("some.undeprecated.list.property", List.of("someValue4", "someValue5"));
         Settings inputSettings = settingsBuilder.build();
+        IndexMetadata dataStreamIndexMetadata = IndexMetadata.builder("ds-test-index-1")
+            .settings(inputSettings)
+            .numberOfShards(1)
+            .numberOfReplicas(0)
+            .build();
         Metadata metadata = Metadata.builder()
             .put(IndexMetadata.builder("test").settings(inputSettings).numberOfShards(1).numberOfReplicas(0))
+            .put(dataStreamIndexMetadata, true)
+            .put(DataStream.builder("ds-test", List.of(dataStreamIndexMetadata.getIndex())).build())
             .persistentSettings(inputSettings)
             .build();
 
@@ -256,6 +280,13 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
             visibleIndexSettings.set(idx.getSettings());
             return null;
         }));
+        AtomicInteger backingIndicesCount = new AtomicInteger(0);
+        List<BiFunction<DataStream, ClusterState, DeprecationIssue>> dataStreamChecks = Collections.unmodifiableList(
+            Arrays.asList((ds, cs) -> {
+                backingIndicesCount.set(ds.getIndices().size());
+                return null;
+            })
+        );
 
         NodesDeprecationCheckResponse nodeDeprecationIssues = new NodesDeprecationCheckResponse(
             new ClusterName(randomAlphaOfLength(5)),
@@ -270,6 +301,7 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
             request,
             nodeDeprecationIssues,
             indexSettingsChecks,
+            dataStreamChecks,
             clusterSettingsChecks,
             Collections.emptyMap(),
             List.of("some.deprecated.property", "some.other.*.deprecated.property")
@@ -288,19 +320,30 @@ public class DeprecationInfoActionResponseTests extends AbstractWireSerializingT
         Assert.assertTrue(resultIndexSettings.getAsList("some.undeprecated.list.property").equals(List.of("someValue4", "someValue5")));
         Assert.assertFalse(resultIndexSettings.hasValue("some.deprecated.property"));
         Assert.assertFalse(resultIndexSettings.hasValue("some.other.bad.deprecated.property"));
+
+        assertThat(backingIndicesCount.get(), equalTo(1));
     }
 
     public void testCtorFailure() {
         Map<String, List<DeprecationIssue>> indexNames = Stream.generate(() -> randomAlphaOfLength(10))
             .limit(10)
             .collect(Collectors.toMap(Function.identity(), (_k) -> Collections.emptyList()));
+        Map<String, List<DeprecationIssue>> dataStreamNames = Stream.generate(() -> randomAlphaOfLength(10))
+            .limit(10)
+            .collect(Collectors.toMap(Function.identity(), (_k) -> Collections.emptyList()));
         Set<String> shouldCauseFailure = new HashSet<>(RESERVED_NAMES);
         for (int i = 0; i < NUMBER_OF_TEST_RUNS; i++) {
             Map<String, List<DeprecationIssue>> pluginSettingsIssues = randomSubsetOf(3, shouldCauseFailure).stream()
                 .collect(Collectors.toMap(Function.identity(), (_k) -> Collections.emptyList()));
             expectThrows(
                 ElasticsearchStatusException.class,
-                () -> new DeprecationInfoAction.Response(Collections.emptyList(), Collections.emptyList(), indexNames, pluginSettingsIssues)
+                () -> new DeprecationInfoAction.Response(
+                    Collections.emptyList(),
+                    Collections.emptyList(),
+                    indexNames,
+                    dataStreamNames,
+                    pluginSettingsIssues
+                )
             );
         }
     }