Skip to content

Commit d94a3a9

Browse files
authored
[8.14] Disallow index.time_series.end_time setting from being set or updated in normal indices (#110372)
Backporting #110268 to 8.14 branch. The index.mode setting validates other index settings. When updating the index.time_series.end_time setting and the index.mode setting isn't wasn't defined at index creation time (meaning that default is active), then this validation is skipped which results into (worse) errors at a later point in time. This problem is fixed by enforced by making index.mode setting a dependency of index.time_series.end_time setting. Note that this problem doesn't exist for the index.time_series.start_time and index.routing_path index settings, because these index settings are final, which mean these can only be defined when an index is being created. Closes #110265
1 parent 309e60c commit d94a3a9

File tree

6 files changed

+133
-22
lines changed

6 files changed

+133
-22
lines changed

docs/changelog/110268.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 110268
2+
summary: Disallow index.time_series.end_time setting from being set or updated in normal indices
3+
area: TSDB
4+
type: bug
5+
issues:
6+
- 110265

modules/data-streams/src/test/java/org/elasticsearch/datastreams/DataStreamIndexSettingsProviderTests.java

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ public void testGetAdditionalIndexSettings() throws Exception {
8383
settings,
8484
List.of(new CompressedXContent(mapping))
8585
);
86-
assertThat(result.size(), equalTo(3));
86+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
87+
// (in production the index.mode setting is usually provided in an index or component template)
88+
result = builder().put(result).put("index.mode", "time_series").build();
89+
assertThat(result.size(), equalTo(4));
90+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
8791
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
8892
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
8993
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), contains("field3"));
@@ -124,7 +128,11 @@ public void testGetAdditionalIndexSettingsIndexRoutingPathAlreadyDefined() throw
124128
settings,
125129
List.of(new CompressedXContent(mapping))
126130
);
127-
assertThat(result.size(), equalTo(2));
131+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
132+
// (in production the index.mode setting is usually provided in an index or component template)
133+
result = builder().put(result).put("index.mode", "time_series").build();
134+
assertThat(result.size(), equalTo(3));
135+
assertThat(result.get(IndexSettings.MODE.getKey()), equalTo("time_series"));
128136
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
129137
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
130138
}
@@ -190,7 +198,11 @@ public void testGetAdditionalIndexSettingsMappingsMerging() throws Exception {
190198
settings,
191199
List.of(new CompressedXContent(mapping1), new CompressedXContent(mapping2), new CompressedXContent(mapping3))
192200
);
193-
assertThat(result.size(), equalTo(3));
201+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
202+
// (in production the index.mode setting is usually provided in an index or component template)
203+
result = builder().put(result).put("index.mode", "time_series").build();
204+
assertThat(result.size(), equalTo(4));
205+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
194206
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
195207
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
196208
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), containsInAnyOrder("field1", "field3"));
@@ -211,7 +223,11 @@ public void testGetAdditionalIndexSettingsNoMappings() {
211223
settings,
212224
List.of()
213225
);
214-
assertThat(result.size(), equalTo(2));
226+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
227+
// (in production the index.mode setting is usually provided in an index or component template)
228+
result = builder().put(result).put("index.mode", "time_series").build();
229+
assertThat(result.size(), equalTo(3));
230+
assertThat(result.get(IndexSettings.MODE.getKey()), equalTo("time_series"));
215231
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
216232
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
217233
}
@@ -232,7 +248,11 @@ public void testGetAdditionalIndexSettingsLookAheadTime() throws Exception {
232248
settings,
233249
List.of(new CompressedXContent("{}"))
234250
);
235-
assertThat(result.size(), equalTo(2));
251+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
252+
// (in production the index.mode setting is usually provided in an index or component template)
253+
result = builder().put(result).put("index.mode", "time_series").build();
254+
assertThat(result.size(), equalTo(3));
255+
assertThat(result.get(IndexSettings.MODE.getKey()), equalTo("time_series"));
236256
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
237257
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(lookAheadTime.getMillis())));
238258
}
@@ -253,7 +273,11 @@ public void testGetAdditionalIndexSettingsLookBackTime() throws Exception {
253273
settings,
254274
List.of(new CompressedXContent("{}"))
255275
);
256-
assertThat(result.size(), equalTo(2));
276+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
277+
// (in production the index.mode setting is usually provided in an index or component template)
278+
result = builder().put(result).put("index.mode", "time_series").build();
279+
assertThat(result.size(), equalTo(3));
280+
assertThat(result.get(IndexSettings.MODE.getKey()), equalTo("time_series"));
257281
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(lookBackTime.getMillis())));
258282
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
259283
}
@@ -363,7 +387,11 @@ public void testGetAdditionalIndexSettingsMigrateToTsdb() {
363387
settings,
364388
List.of()
365389
);
366-
assertThat(result.size(), equalTo(2));
390+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
391+
// (in production the index.mode setting is usually provided in an index or component template)
392+
result = builder().put(result).put("index.mode", "time_series").build();
393+
assertThat(result.size(), equalTo(3));
394+
assertThat(result.get(IndexSettings.MODE.getKey()), equalTo("time_series"));
367395
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
368396
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
369397
}
@@ -428,7 +456,8 @@ public void testGenerateRoutingPathFromDynamicTemplate() throws Exception {
428456
}
429457
""";
430458
Settings result = generateTsdbSettings(mapping, now);
431-
assertThat(result.size(), equalTo(3));
459+
assertThat(result.size(), equalTo(4));
460+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
432461
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
433462
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
434463
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), containsInAnyOrder("host.id", "prometheus.labels.*"));
@@ -467,7 +496,8 @@ public void testGenerateRoutingPathFromDynamicTemplateWithMultiplePathMatchEntri
467496
}
468497
""";
469498
Settings result = generateTsdbSettings(mapping, now);
470-
assertThat(result.size(), equalTo(3));
499+
assertThat(result.size(), equalTo(4));
500+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
471501
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
472502
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
473503
assertThat(
@@ -516,7 +546,8 @@ public void testGenerateRoutingPathFromDynamicTemplateWithMultiplePathMatchEntri
516546
}
517547
""";
518548
Settings result = generateTsdbSettings(mapping, now);
519-
assertThat(result.size(), equalTo(3));
549+
assertThat(result.size(), equalTo(4));
550+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
520551
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
521552
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
522553
assertThat(
@@ -569,7 +600,8 @@ public void testGenerateRoutingPathFromDynamicTemplate_templateWithNoPathMatch()
569600
}
570601
""";
571602
Settings result = generateTsdbSettings(mapping, now);
572-
assertThat(result.size(), equalTo(3));
603+
assertThat(result.size(), equalTo(4));
604+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
573605
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
574606
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
575607
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), containsInAnyOrder("host.id", "prometheus.labels.*"));
@@ -644,7 +676,8 @@ public void testGenerateRoutingPathFromPassThroughObject() throws Exception {
644676
}
645677
""";
646678
Settings result = generateTsdbSettings(mapping, now);
647-
assertThat(result.size(), equalTo(3));
679+
assertThat(result.size(), equalTo(4));
680+
assertThat(IndexSettings.MODE.get(result), equalTo(IndexMode.TIME_SERIES));
648681
assertThat(IndexSettings.TIME_SERIES_START_TIME.get(result), equalTo(now.minusMillis(DEFAULT_LOOK_BACK_TIME.getMillis())));
649682
assertThat(IndexSettings.TIME_SERIES_END_TIME.get(result), equalTo(now.plusMillis(DEFAULT_LOOK_AHEAD_TIME.getMillis())));
650683
assertThat(IndexMetadata.INDEX_ROUTING_PATH.get(result), containsInAnyOrder("labels.*"));
@@ -655,7 +688,7 @@ private Settings generateTsdbSettings(String mapping, Instant now) throws IOExce
655688
String dataStreamName = "logs-app1";
656689
Settings settings = Settings.EMPTY;
657690

658-
return provider.getAdditionalIndexSettings(
691+
var result = provider.getAdditionalIndexSettings(
659692
DataStream.getDefaultBackingIndexName(dataStreamName, 1),
660693
dataStreamName,
661694
true,
@@ -664,6 +697,9 @@ private Settings generateTsdbSettings(String mapping, Instant now) throws IOExce
664697
settings,
665698
List.of(new CompressedXContent(mapping))
666699
);
700+
// The index.time_series.end_time setting requires index.mode to be set to time_series adding it here so that we read this setting:
701+
// (in production the index.mode setting is usually provided in an index or component template)
702+
return builder().put(result).put("index.mode", "time_series").build();
667703
}
668704

669705
}

modules/data-streams/src/test/java/org/elasticsearch/datastreams/MetadataDataStreamRolloverServiceTests.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import org.elasticsearch.cluster.metadata.Metadata;
2525
import org.elasticsearch.cluster.metadata.Template;
2626
import org.elasticsearch.common.settings.Settings;
27-
import org.elasticsearch.common.time.DateUtils;
2827
import org.elasticsearch.index.Index;
2928
import org.elasticsearch.index.IndexMode;
3029
import org.elasticsearch.index.IndexSettings;
@@ -390,11 +389,9 @@ public void testRolloverClusterStateWithBrokenOlderTsdbDataStream() throws Excep
390389

391390
for (int i = 0; i < numberOfBackingIndices; i++) {
392391
var im = rolloverMetadata.index(rolloverMetadata.dataStreams().get(dataStreamName).getIndices().get(i));
393-
var startTime1 = IndexSettings.TIME_SERIES_START_TIME.get(im.getSettings());
394-
var endTime1 = IndexSettings.TIME_SERIES_END_TIME.get(im.getSettings());
395-
assertThat(startTime1.toEpochMilli(), equalTo(DateUtils.MAX_MILLIS_BEFORE_MINUS_9999));
396-
assertThat(endTime1.toEpochMilli(), equalTo(DateUtils.MAX_MILLIS_BEFORE_9999));
397-
assertThat(im.getIndexMode(), equalTo(null));
392+
assertThat(im.getTimeSeriesStart(), nullValue());
393+
assertThat(im.getTimeSeriesEnd(), nullValue());
394+
assertThat(im.getIndexMode(), nullValue());
398395
}
399396
{
400397
var im = rolloverMetadata.index(

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/tsdb/10_settings.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,67 @@ set start_time and end_time without timeseries mode:
334334
time_series:
335335
end_time: 1632625782000
336336

337+
---
338+
set start_time, end_time and routing_path via put settings api without time_series mode:
339+
- requires:
340+
cluster_features: [ "gte_v8.14.3" ]
341+
reason: bug fixed in 8.14.3
342+
343+
- do:
344+
indices.create:
345+
index: test-index
346+
- match: { acknowledged: true }
347+
348+
- do:
349+
catch: /\[index.time_series.end_time\] requires \[index.mode=time_series\]/
350+
indices.put_settings:
351+
index: test-index
352+
body:
353+
index.time_series.end_time: 1632625782000
354+
355+
- do:
356+
catch: /Can't update non dynamic settings \[\[index.time_series.start_time\]\] for open indices/
357+
indices.put_settings:
358+
index: test-index
359+
body:
360+
index.time_series.start_time: 1632625782000
361+
362+
- do:
363+
catch: /Can't update non dynamic settings \[\[index.routing_path\]\] for open indices/
364+
indices.put_settings:
365+
index: test-index
366+
body:
367+
settings:
368+
index:
369+
routing_path: foo
370+
371+
- do:
372+
indices.close:
373+
index: test-index
374+
375+
- do:
376+
catch: /\[index.time_series.end_time\] requires \[index.mode=time_series\]/
377+
indices.put_settings:
378+
index: test-index
379+
body:
380+
index.time_series.end_time: 1632625782000
381+
382+
- do:
383+
catch: /final test-index setting \[index.time_series.start_time\], not updateable/
384+
indices.put_settings:
385+
index: test-index
386+
body:
387+
index.time_series.start_time: 1632625782000
388+
389+
- do:
390+
catch: /final test-index setting \[index.routing_path\], not updateable/
391+
indices.put_settings:
392+
index: test-index
393+
body:
394+
settings:
395+
index:
396+
routing_path: foo
397+
337398
---
338399
set bad start_time and end_time:
339400
- requires:

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,9 @@ private void validateIndexTemplateV2(String name, ComposableIndexTemplate indexT
699699
)
700700
);
701701
}
702-
// Then apply settings resolved from templates:
702+
// Then apply setting from component templates:
703+
finalSettings.put(combinedSettings);
704+
// Then finally apply settings resolved from index template:
703705
finalSettings.put(finalTemplate.map(Template::settings).orElse(Settings.EMPTY));
704706

705707
var templateToValidate = indexTemplate.toBuilder()

server/src/main/java/org/elasticsearch/index/IndexSettings.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -607,16 +607,25 @@ public void validate(Instant value) {}
607607

608608
@Override
609609
public void validate(Instant value, Map<Setting<?>, Object> settings) {
610-
@SuppressWarnings("unchecked")
611610
Instant startTime = (Instant) settings.get(TIME_SERIES_START_TIME);
612611
if (startTime.toEpochMilli() > value.toEpochMilli()) {
613612
throw new IllegalArgumentException("index.time_series.end_time must be larger than index.time_series.start_time");
614613
}
614+
615+
// The index.time_series.end_time setting can only be specified if the index.mode setting has been set to time_series
616+
// This check here is specifically needed because in case of updating index settings the validation the gets executed
617+
// in IndexSettings constructor when reading the index.mode setting doesn't get executed.
618+
IndexMode indexMode = (IndexMode) settings.get(MODE);
619+
if (indexMode != IndexMode.TIME_SERIES) {
620+
throw new IllegalArgumentException(
621+
"[" + TIME_SERIES_END_TIME.getKey() + "] requires [index.mode=" + IndexMode.TIME_SERIES + "]"
622+
);
623+
}
615624
}
616625

617626
@Override
618627
public Iterator<Setting<?>> settings() {
619-
List<Setting<?>> settings = List.of(TIME_SERIES_START_TIME);
628+
List<Setting<?>> settings = List.of(TIME_SERIES_START_TIME, MODE);
620629
return settings.iterator();
621630
}
622631
},

0 commit comments

Comments
 (0)