Skip to content

Commit af5fa3f

Browse files
authored
[7.16] Fix data stream alias validation. (#81040) (#81136)
* Fix data stream alias validation. (#81040) In case of restoring a snapshot, it is possible to overwrite an existing data stream with a data stream alias from a snapshot. This change fixes this by improving the generic duplicate name validation. On top of this the lack of data stream alias validation in Metadata.Builder#build() method resulted in cases where data stream aliases could be added for existing index aliases, data streams or indices with the same name. Closes #80972 * adjust to 7.16 reality * Unmute DataStreamsSnapshotsIT#testRestoreDataStreamAliasWithConflictingIndicesAlias() test and fix the test problem, which is that testRestoreDataStreamAliasWithConflictingDataStream() test needs to remove the composable index template that it adds. The base test class doesn't remove any composable index templates and this template interferes with the testRestoreDataStreamAliasWithConflictingIndicesAlias() test. Relates to #81040
1 parent b6f463f commit af5fa3f

File tree

4 files changed

+340
-8
lines changed

4 files changed

+340
-8
lines changed

server/src/main/java/org/elasticsearch/cluster/metadata/Metadata.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,17 +1740,23 @@ public Metadata build(boolean builtIndicesLookupEagerly) {
17401740
indexMetadata.getAliases().keysIt().forEachRemaining(allAliases::add);
17411741
}
17421742

1743+
final ArrayList<String> duplicates = new ArrayList<>();
17431744
final Set<String> allDataStreams = new HashSet<>();
17441745
DataStreamMetadata dataStreamMetadata = (DataStreamMetadata) this.customs.get(DataStreamMetadata.TYPE);
17451746
if (dataStreamMetadata != null) {
17461747
for (DataStream dataStream : dataStreamMetadata.dataStreams().values()) {
17471748
allDataStreams.add(dataStream.getName());
17481749
}
1750+
// Adding data stream aliases:
1751+
for (String dataStreamAlias : dataStreamMetadata.getDataStreamAliases().keySet()) {
1752+
if (allAliases.add(dataStreamAlias) == false) {
1753+
duplicates.add("data stream alias and indices alias have the same name (" + dataStreamAlias + ")");
1754+
}
1755+
}
17491756
}
17501757

17511758
final Set<String> aliasDuplicatesWithIndices = new HashSet<>(allAliases);
17521759
aliasDuplicatesWithIndices.retainAll(allIndices);
1753-
ArrayList<String> duplicates = new ArrayList<>();
17541760
if (aliasDuplicatesWithIndices.isEmpty() == false) {
17551761
// iterate again and constructs a helpful message
17561762
for (ObjectCursor<IndexMetadata> cursor : indices.values()) {
@@ -1766,12 +1772,19 @@ public Metadata build(boolean builtIndicesLookupEagerly) {
17661772
aliasDuplicatesWithDataStreams.retainAll(allDataStreams);
17671773
if (aliasDuplicatesWithDataStreams.isEmpty() == false) {
17681774
// iterate again and constructs a helpful message
1769-
for (ObjectCursor<IndexMetadata> cursor : indices.values()) {
1770-
for (String alias : aliasDuplicatesWithDataStreams) {
1775+
for (String alias : aliasDuplicatesWithDataStreams) {
1776+
// reported var avoids adding a message twice if an index alias has the same name as a data stream.
1777+
boolean reported = false;
1778+
for (ObjectCursor<IndexMetadata> cursor : indices.values()) {
17711779
if (cursor.value.getAliases().containsKey(alias)) {
17721780
duplicates.add(alias + " (alias of " + cursor.value.getIndex() + ") conflicts with data stream");
1781+
reported = true;
17731782
}
17741783
}
1784+
// This is for adding an error message for when a data steam alias has the same name as a data stream.
1785+
if (reported == false && dataStreamMetadata != null && dataStreamMetadata.dataStreams().containsKey(alias)) {
1786+
duplicates.add("data stream alias and data stream have the same name (" + alias + ")");
1787+
}
17751788
}
17761789
}
17771790

server/src/test/java/org/elasticsearch/cluster/metadata/MetadataTests.java

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import java.util.concurrent.atomic.AtomicInteger;
4949
import java.util.stream.Collectors;
5050

51+
import static java.util.Collections.singletonList;
5152
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.createBackingIndex;
5253
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.createFirstBackingIndex;
5354
import static org.elasticsearch.cluster.metadata.DataStreamTestHelper.createTimestampField;
@@ -1231,9 +1232,7 @@ public void testOverlappingDataStreamNamesWithBackingIndexDatePattern() {
12311232
.numberOfReplicas(1)
12321233
.build();
12331234
b.put(ds2Index1, false);
1234-
b.put(
1235-
new DataStream(dataStreamName2, createTimestampField("@timestamp"), Collections.singletonList(ds2Index1.getIndex()), 1, null)
1236-
);
1235+
b.put(new DataStream(dataStreamName2, createTimestampField("@timestamp"), singletonList(ds2Index1.getIndex()), 1, null));
12371236

12381237
Metadata metadata = b.build();
12391238
assertThat(metadata.dataStreams().size(), equalTo(2));
@@ -1314,6 +1313,74 @@ public void testBuildIndicesLookupForDataStreamAliases() {
13141313
assertThat(value.getAliases(), nullValue());
13151314
}
13161315

1316+
public void testDataStreamAliasValidation() {
1317+
Metadata.Builder b = Metadata.builder();
1318+
addDataStream("my-alias", b);
1319+
b.put("my-alias", "my-alias", null, null);
1320+
Exception e = expectThrows(IllegalStateException.class, b::build);
1321+
assertThat(e.getMessage(), containsString("data stream alias and data stream have the same name (my-alias)"));
1322+
1323+
b = Metadata.builder();
1324+
addDataStream("d1", b);
1325+
addDataStream("my-alias", b);
1326+
b.put("my-alias", "d1", null, null);
1327+
e = expectThrows(IllegalStateException.class, b::build);
1328+
assertThat(e.getMessage(), containsString("data stream alias and data stream have the same name (my-alias)"));
1329+
1330+
b = Metadata.builder();
1331+
b.put(
1332+
IndexMetadata.builder("index1")
1333+
.settings(
1334+
Settings.builder()
1335+
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
1336+
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
1337+
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
1338+
)
1339+
.putAlias(new AliasMetadata.Builder("my-alias"))
1340+
);
1341+
1342+
addDataStream("d1", b);
1343+
b.put("my-alias", "d1", null, null);
1344+
e = expectThrows(IllegalStateException.class, b::build);
1345+
assertThat(e.getMessage(), containsString("data stream alias and indices alias have the same name (my-alias)"));
1346+
}
1347+
1348+
public void testDataStreamAliasValidationRestoreScenario() {
1349+
Metadata.Builder b = Metadata.builder();
1350+
b.dataStreams(
1351+
org.elasticsearch.core.Map.of("my-alias", createDataStream("my-alias")),
1352+
org.elasticsearch.core.Map.of("my-alias", new DataStreamAlias("my-alias", singletonList("my-alias"), null, null))
1353+
);
1354+
Exception e = expectThrows(IllegalStateException.class, b::build);
1355+
assertThat(e.getMessage(), containsString("data stream alias and data stream have the same name (my-alias)"));
1356+
1357+
b = Metadata.builder();
1358+
b.dataStreams(
1359+
org.elasticsearch.core.Map.of("d1", createDataStream("d1"), "my-alias", createDataStream("my-alias")),
1360+
org.elasticsearch.core.Map.of("my-alias", new DataStreamAlias("my-alias", singletonList("d1"), null, null))
1361+
);
1362+
e = expectThrows(IllegalStateException.class, b::build);
1363+
assertThat(e.getMessage(), containsString("data stream alias and data stream have the same name (my-alias)"));
1364+
1365+
b = Metadata.builder();
1366+
b.put(
1367+
IndexMetadata.builder("index1")
1368+
.settings(
1369+
Settings.builder()
1370+
.put(IndexMetadata.SETTING_VERSION_CREATED, Version.CURRENT)
1371+
.put(IndexMetadata.SETTING_NUMBER_OF_SHARDS, 1)
1372+
.put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0)
1373+
)
1374+
.putAlias(new AliasMetadata.Builder("my-alias"))
1375+
);
1376+
b.dataStreams(
1377+
org.elasticsearch.core.Map.of("d1", createDataStream("d1")),
1378+
org.elasticsearch.core.Map.of("my-alias", new DataStreamAlias("my-alias", singletonList("d1"), null, null))
1379+
);
1380+
e = expectThrows(IllegalStateException.class, b::build);
1381+
assertThat(e.getMessage(), containsString("data stream alias and indices alias have the same name (my-alias)"));
1382+
}
1383+
13171384
private void addDataStream(String name, Metadata.Builder b) {
13181385
int numBackingIndices = randomIntBetween(1, 4);
13191386
List<Index> indices = new ArrayList<>(numBackingIndices);
@@ -1325,6 +1392,16 @@ private void addDataStream(String name, Metadata.Builder b) {
13251392
b.put(new DataStream(name, createTimestampField("@timestamp"), indices));
13261393
}
13271394

1395+
private DataStream createDataStream(String name) {
1396+
int numBackingIndices = randomIntBetween(1, 4);
1397+
List<Index> indices = new ArrayList<>(numBackingIndices);
1398+
for (int j = 1; j <= numBackingIndices; j++) {
1399+
IndexMetadata idx = createBackingIndex(name, j).build();
1400+
indices.add(idx.getIndex());
1401+
}
1402+
return new DataStream(name, createTimestampField("@timestamp"), indices);
1403+
}
1404+
13281405
public void testIndicesLookupRecordsDataStreamForBackingIndices() {
13291406
final int numIndices = randomIntBetween(2, 5);
13301407
final int numBackingIndices = randomIntBetween(2, 5);
@@ -1772,7 +1849,7 @@ public void testReuseIndicesLookup() {
17721849
DataStream dataStream = new DataStream(
17731850
dataStreamName,
17741851
new DataStream.TimestampField("@timestamp"),
1775-
Collections.singletonList(idx.getIndex())
1852+
singletonList(idx.getIndex())
17761853
);
17771854
builder.put(dataStream);
17781855
Metadata metadata = builder.build();

0 commit comments

Comments
 (0)