Skip to content

Commit 6b22eb5

Browse files
authored
Index template: Add created_date and modified_date (#132083)
Add new system-managed properties to index templates: - `created_date`: when the template with a given ID was created - `modified_date`: when the template was updated
1 parent fd057bf commit 6b22eb5

File tree

10 files changed

+418
-103
lines changed

10 files changed

+418
-103
lines changed

docs/changelog/132083.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 132083
2+
summary: "Index template: Add created_date and modified_date"
3+
area: Ingest Node
4+
type: enhancement
5+
issues: []

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ public void testRequireRoutingPath() throws Exception {
8888
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false))
8989
.build();
9090
project = service.addIndexTemplateV2(project, false, "1", indexTemplate);
91-
assertThat(project.templatesV2().get("1"), equalTo(indexTemplate));
91+
var actualTemplate = project.templatesV2().get("1");
92+
assertTemplateActualIsExpected(actualTemplate, indexTemplate);
9293
}
9394
{
9495
// Routing path defined in component template
@@ -106,7 +107,8 @@ public void testRequireRoutingPath() throws Exception {
106107
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false))
107108
.build();
108109
project = service.addIndexTemplateV2(project, false, "1", indexTemplate);
109-
assertThat(project.templatesV2().get("1"), equalTo(indexTemplate));
110+
var actualTemplate = project.templatesV2().get("1");
111+
assertTemplateActualIsExpected(actualTemplate, indexTemplate);
110112
}
111113
{
112114
// Routing path defined in index template
@@ -118,7 +120,8 @@ public void testRequireRoutingPath() throws Exception {
118120
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false))
119121
.build();
120122
var project = service.addIndexTemplateV2(initialProject, false, "1", indexTemplate);
121-
assertThat(project.templatesV2().get("1"), equalTo(indexTemplate));
123+
var actualTemplate = project.templatesV2().get("1");
124+
assertTemplateActualIsExpected(actualTemplate, indexTemplate);
122125
}
123126
{
124127
// Routing fetched from mapping in index template
@@ -132,7 +135,8 @@ public void testRequireRoutingPath() throws Exception {
132135
.dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false))
133136
.build();
134137
var project = service.addIndexTemplateV2(initialProject, false, "1", indexTemplate);
135-
assertThat(project.templatesV2().get("1"), equalTo(indexTemplate));
138+
var actualTemplate = project.templatesV2().get("1");
139+
assertTemplateActualIsExpected(actualTemplate, indexTemplate);
136140
}
137141
}
138142

@@ -190,6 +194,21 @@ public void testLifecycleComposition() {
190194
}
191195
}
192196

197+
private void assertTemplateActualIsExpected(final ComposableIndexTemplate actual, final ComposableIndexTemplate expected) {
198+
// make sure arguments passed in right order
199+
assertTrue(actual.createdDateMillis().isPresent());
200+
assertTrue(actual.modifiedDateMillis().isPresent());
201+
assertTrue(expected.createdDateMillis().isEmpty());
202+
assertTrue(expected.modifiedDateMillis().isEmpty());
203+
204+
var expectedWithDates = expected.toBuilder()
205+
// can't inject timing into creation so carrying over the dates from created template
206+
.createdDate(actual.createdDateMillis().orElse(null))
207+
.modifiedDate(actual.modifiedDateMillis().orElse(null))
208+
.build();
209+
assertThat(actual, equalTo(expectedWithDates));
210+
}
211+
193212
private MetadataIndexTemplateService getMetadataIndexTemplateService() {
194213
var indicesService = getInstanceFromNode(IndicesService.class);
195214
var clusterService = getInstanceFromNode(ClusterService.class);
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
setup:
2+
- requires:
3+
test_runner_features: [capabilities, contains]
4+
capabilities:
5+
- method: PUT
6+
path: /_index_template/{id}
7+
capabilities: [ index_template_tracking_info ]
8+
reason: "Index templates have tracking info: modified_date and created_date"
9+
10+
---
11+
"Test PUT setting created_date":
12+
- do:
13+
catch: bad_request
14+
indices.put_index_template:
15+
name: test_tracking
16+
body:
17+
index_patterns: [ "test-*" ]
18+
template:
19+
settings:
20+
number_of_shards: 1
21+
created_date: "2025-07-04T12:50:48.415Z"
22+
- match: { status: 400 }
23+
- contains: { error.reason: "[index_template] unknown field [created_date] did you mean [created_date_millis]?" }
24+
25+
---
26+
"Test PUT setting created_date_millis":
27+
- do:
28+
catch: bad_request
29+
indices.put_index_template:
30+
name: test_tracking
31+
body:
32+
index_patterns: ["test-*"]
33+
template:
34+
settings:
35+
number_of_shards: 1
36+
created_date_millis: 0
37+
- match: { status: 400 }
38+
- match: { error.reason: "index_template [test_tracking] invalid, cause [provided a template property which is managed by the system: created_date]" }
39+
40+
---
41+
"Test PUT setting modified_date":
42+
- do:
43+
catch: bad_request
44+
indices.put_index_template:
45+
name: test_tracking
46+
body:
47+
index_patterns: ["test-*"]
48+
template:
49+
settings:
50+
number_of_shards: 1
51+
modified_date: "2025-07-04T12:50:48.415Z"
52+
- match: { status: 400 }
53+
- contains: { error.reason: "[index_template] unknown field [modified_date] did you mean [modified_date_millis]?" }
54+
55+
---
56+
"Test PUT setting modified_date_millis":
57+
- do:
58+
catch: bad_request
59+
indices.put_index_template:
60+
name: test_tracking
61+
body:
62+
index_patterns: ["test-*"]
63+
template:
64+
settings:
65+
number_of_shards: 1
66+
modified_date_millis: 0
67+
- match: { status: 400 }
68+
- match: { error.reason: "index_template [test_tracking] invalid, cause [provided a template property which is managed by the system: modified_date]" }
69+
70+
---
71+
"Test update preserves created_date but updates modified_date":
72+
- do:
73+
indices.put_index_template:
74+
name: test_tracking
75+
body:
76+
index_patterns: ["test-*"]
77+
template:
78+
settings:
79+
number_of_shards: 1
80+
- match: { acknowledged: true }
81+
82+
- do:
83+
indices.get_index_template:
84+
human: true
85+
name: test_tracking
86+
- set: { index_templates.0.index_template.created_date: first_created }
87+
- set: { index_templates.0.index_template.created_date_millis: first_created_millis }
88+
- set: { index_templates.0.index_template.modified_date: first_modified }
89+
- set: { index_templates.0.index_template.modified_date_millis: first_modified_millis }
90+
- match: { $first_created: "/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/" }
91+
- match: { $first_modified: "/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/" }
92+
- match: { $first_created: $first_modified }
93+
- match: { $first_created_millis: $first_modified_millis }
94+
- gte: { $first_created_millis: 0 }
95+
96+
- do:
97+
indices.put_index_template:
98+
name: test_tracking
99+
body:
100+
index_patterns: ["test-*"]
101+
template:
102+
settings:
103+
number_of_shards: 2
104+
105+
- do:
106+
indices.get_index_template:
107+
human: true
108+
name: test_tracking
109+
- set: { index_templates.0.index_template.created_date: second_created }
110+
- set: { index_templates.0.index_template.created_date_millis: second_created_millis }
111+
- match: { $second_created: $first_created }
112+
- match: { $second_created_millis: $first_created_millis }

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,7 @@ static TransportVersion def(int id) {
355355
public static final TransportVersion TO_CHILD_BLOCK_JOIN_QUERY = def(9_133_0_00);
356356
public static final TransportVersion ML_INFERENCE_AI21_COMPLETION_ADDED = def(9_134_0_00);
357357
public static final TransportVersion TRANSPORT_NODE_USAGE_STATS_FOR_THREAD_POOLS_ACTION = def(9_135_0_00);
358+
public static final TransportVersion INDEX_TEMPLATE_TRACKING_INFO = def(9_136_0_00);
358359

359360
/*
360361
* STOP! READ THIS FIRST! No, really,

0 commit comments

Comments
 (0)