Skip to content

Commit

Permalink
Adding a deprecation info API warning for data streams with old indices
Browse files Browse the repository at this point in the history
  • Loading branch information
masseyke committed Nov 7, 2024
1 parent c8a8d4d commit 5aaa98a
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ static TransportVersion def(int id) {
public static final TransportVersion ESQL_CCS_EXEC_INFO_WITH_FAILURES = def(8_783_00_0);
public static final TransportVersion LOGSDB_TELEMETRY = def(8_784_00_0);
public static final TransportVersion LOGSDB_TELEMETRY_STATS = def(8_785_00_0);
public static final TransportVersion DATA_STREAM_INDEX_VERSION_DEPRECATION_CHECK = def(8_786_00_0);

/*
* STOP! READ THIS FIRST! No, really,
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugin/deprecation/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
requires org.apache.logging.log4j;
requires org.apache.logging.log4j.core;
requires log4j2.ecs.layout;
requires java.xml.crypto;

exports org.elasticsearch.xpack.deprecation to org.elasticsearch.server;
exports org.elasticsearch.xpack.deprecation.logging to org.elasticsearch.server;
Expand Down
Original file line number Diff line number Diff line change
@@ -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-8.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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

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;
Expand All @@ -16,6 +17,7 @@

import java.util.List;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -97,6 +99,10 @@ private 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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
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;
Expand All @@ -42,6 +43,7 @@
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;

Expand Down Expand Up @@ -144,17 +146,23 @@ private static Map<DeprecationIssue, List<String>> getMergedIssuesToNodesMap(
}

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_stream_settings");
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 {
super(in);
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<>();
Expand All @@ -168,11 +176,13 @@ public Response(
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(
Expand Down Expand Up @@ -205,6 +215,9 @@ public void writeTo(StreamOutput out) throws IOException {
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 {
Expand All @@ -219,6 +232,8 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
.array("node_settings", nodeSettingsIssues.toArray())
.field("index_settings")
.map(indexSettingsIssues)
.field("data_stream_settings")
.map(dataStreamIssues)
.mapContents(pluginSettingsIssues)
.endObject();
}
Expand Down Expand Up @@ -260,6 +275,7 @@ public static DeprecationInfoAction.Response from(
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
Expand All @@ -283,6 +299,19 @@ public static DeprecationInfoAction.Response from(
}
}

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
Expand All @@ -291,7 +320,13 @@ public static DeprecationInfoAction.Response from(
clusterSettingsIssues.addAll(transformDeprecations);
}

return new DeprecationInfoAction.Response(clusterSettingsIssues, nodeSettingsIssues, indexSettingsIssues, pluginSettingIssues);
return new DeprecationInfoAction.Response(
clusterSettingsIssues,
nodeSettingsIssues,
indexSettingsIssues,
dataStreamIssues,
pluginSettingIssues
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
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<
Expand Down Expand Up @@ -134,6 +135,7 @@ protected final void masterOperation(
request,
response,
INDEX_SETTINGS_CHECKS,
DATA_STREAM_CHECKS,
CLUSTER_SETTINGS_CHECKS,
deprecationIssues,
skipTheseDeprecations
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
randomNegativeLong(),
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-8.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)));
}
}
Loading

0 comments on commit 5aaa98a

Please sign in to comment.