Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix composable templates with subobjects: false #97317

Merged
merged 48 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
76ab263
Fix composable templates with subobjects: false
eyalkoren Jul 3, 2023
d3b2923
Update docs/changelog/97317.yaml
eyalkoren Jul 3, 2023
baf2a18
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Jul 30, 2023
faf83a5
Add unit tests
eyalkoren Jul 31, 2023
c4fa163
Merge remote-tracking branch 'eyalkoren/fix2-subobjects-composable-te…
eyalkoren Jul 31, 2023
0ca0233
Change changelog summary
eyalkoren Jul 31, 2023
b45863e
Small refactor: switch from sequential to bulk component templates merge
eyalkoren Jul 31, 2023
a8cfed5
Merging mappings in raw map form
eyalkoren Aug 6, 2023
7e408c9
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Aug 7, 2023
699943e
Spoteless apply
eyalkoren Aug 7, 2023
90e9634
Use type that supports ignore_malformed in test
eyalkoren Aug 7, 2023
b28ab16
Temporarily disable a test
eyalkoren Aug 7, 2023
1eaf3d7
Handle routing settings
eyalkoren Aug 7, 2023
2073731
Adjust tests to use explicit routing disabling
eyalkoren Aug 7, 2023
f5f457c
Applying review comments
eyalkoren Aug 8, 2023
0e347b7
Adding test case and fix for CreateIndex as well
eyalkoren Aug 8, 2023
e23b2f2
spotless
eyalkoren Aug 8, 2023
6db4fa0
Fix test- use type that supports ignore_malformed
eyalkoren Aug 8, 2023
ad1d283
Extract mapping under root before merging
eyalkoren Aug 9, 2023
83347bd
Better normalization of multiple sources
eyalkoren Aug 9, 2023
849e624
Merge remote-tracking branch 'eyalkoren/fix2-subobjects-composable-te…
eyalkoren Aug 9, 2023
e60c6b7
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Aug 13, 2023
6d968a5
Merge additional usages of new merge from eyalkoren/mappings-bulk-mer…
eyalkoren Aug 13, 2023
a865e25
Never return null map from merge
eyalkoren Aug 13, 2023
67bb863
Spotless again :-(
eyalkoren Aug 13, 2023
4b8d20a
Restore null return, avoid empty map creation
eyalkoren Aug 14, 2023
11942fc
My god this spotless is annoying
eyalkoren Aug 14, 2023
d6c8fa6
Standardize mapping type conflicts error messages
eyalkoren Aug 14, 2023
cda0236
Adding comment
eyalkoren Aug 14, 2023
5f2451f
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Aug 22, 2023
e3d7e76
Add tests
eyalkoren Aug 22, 2023
5dbcf02
Apply algorithm changes
eyalkoren Aug 23, 2023
59be7ed
Restore test
eyalkoren Aug 23, 2023
ef7c9ec
Restore test
eyalkoren Aug 23, 2023
ac60c6d
Restore test
eyalkoren Aug 23, 2023
5e2b52f
Add test case
eyalkoren Aug 23, 2023
cd1d116
spotless
eyalkoren Aug 23, 2023
32ef7f2
Update skip version
eyalkoren Aug 24, 2023
5ff854b
Update skip version
eyalkoren Aug 24, 2023
39c7d04
Add raw mapping merge unit tests
eyalkoren Aug 24, 2023
c3b160c
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Aug 29, 2023
d54a8eb
Apply review proposals and add a test case
eyalkoren Aug 29, 2023
551685c
goddamned you spotless
eyalkoren Aug 29, 2023
a2e3d45
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Sep 5, 2023
e243d5f
Remove subobects contradiction invalidation
eyalkoren Sep 5, 2023
160f6a8
Merge remote-tracking branch 'upstream/main' into fix2-subobjects-com…
eyalkoren Sep 13, 2023
817a346
Apply review suggestions
eyalkoren Sep 13, 2023
5f11c39
Apply spotless suggestions
felixbarny Sep 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/97317.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 97317
summary: "Fix merges of mappings with `subobjects: false` for composable index templates"
area: Mapping
type: bug
issues:
- 96768
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ public void testTimeStampValidationInvalidFieldMapping() throws Exception {
{
"properties": {
"@timestamp": {
"type": "keyword"
"type": "long"
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
}
}
}""";
Expand All @@ -538,7 +538,7 @@ public void testTimeStampValidationInvalidFieldMapping() throws Exception {
);
assertThat(
e.getCause().getCause().getMessage(),
equalTo("data stream timestamp field [@timestamp] is of type [keyword], but [date,date_nanos] is expected")
equalTo("data stream timestamp field [@timestamp] is of type [long], but [date,date_nanos] is expected")
);
}

Expand Down Expand Up @@ -1988,18 +1988,13 @@ public void testPartitionedTemplate() throws IOException {
).actionGet();

/**
* routing enable with allow custom routing false
* routing settings with allow custom routing false
*/
template = new ComposableIndexTemplate(
List.of("logs"),
new Template(
Settings.builder().put("index.number_of_shards", "3").put("index.routing_partition_size", "2").build(),
new CompressedXContent("""
{
"_routing": {
"required": true
}
}"""),
null,
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
null
),
null,
Expand All @@ -2024,6 +2019,36 @@ public void testPartitionedTemplate() throws IOException {
);
}

public void testRoutingEnabledInMappingDisabledInDataStreamTemplate() throws IOException {
ComposableIndexTemplate template = new ComposableIndexTemplate(
List.of("logs"),
new Template(
Settings.builder().put("index.number_of_shards", "3").put("index.routing_partition_size", "2").build(),
new CompressedXContent("""
{
"_routing": {
"required": true
}
}"""),
null
),
null,
null,
null,
null,
new ComposableIndexTemplate.DataStreamTemplate(false, false)
);
Exception e = expectThrows(
IllegalArgumentException.class,
() -> client().execute(
PutComposableIndexTemplateAction.INSTANCE,
new PutComposableIndexTemplateAction.Request("my-it").indexTemplate(template)
).actionGet()
);
Exception actualException = (Exception) e.getCause();
assertTrue(Throwables.getRootCause(actualException).getMessage().contains("contradicting `_routing.required` settings"));
}

public void testSearchWithRouting() throws IOException, ExecutionException, InterruptedException {
/**
* partition size with routing required
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,7 @@ private List<String> findRoutingPaths(String indexName, Settings allSettings, Li
tmpIndexMetadata.settings(finalResolvedSettings);
// Create MapperService just to extract keyword dimension fields:
try (var mapperService = mapperServiceFactory.apply(tmpIndexMetadata.build())) {
for (var mapping : combinedTemplateMappings) {
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mapping, MapperService.MergeReason.INDEX_TEMPLATE);
}

mapperService.merge(MapperService.SINGLE_MAPPING_NAME, combinedTemplateMappings, MapperService.MergeReason.INDEX_TEMPLATE);
List<String> routingPaths = new ArrayList<>();
for (var fieldMapper : mapperService.documentMapper().mappers().fieldMappers()) {
extractPath(routingPaths, fieldMapper);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,3 +349,146 @@
index_patterns: ["purple-index"]
composed_of: ["red", "blue"]
ignore_missing_component_templates: ["foo"]

---
"Composable index templates that include subobjects: false at root":
- skip:
version: ' - 8.10.1'
reason: 'https://github.com/elastic/elasticsearch/issues/96768 fixed after 8.10.0'
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
features: allowed_warnings

- do:
cluster.put_component_template:
name: test-subobjects
body:
template:
mappings:
subobjects: false

- do:
cluster.put_component_template:
name: test-field
body:
template:
mappings:
properties:
parent.subfield:
type: keyword

- do:
allowed_warnings:
- "index template [test-composable-template] has index patterns [test-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [test-composable-template] will take precedence during new index creation"
indices.put_index_template:
name: test-composable-template
body:
index_patterns:
- test-*
composed_of:
- test-subobjects
- test-field
- is_true: acknowledged

- do:
indices.create:
index: test-generic

- do:
indices.get_mapping:
index: test-generic
- match: { test-generic.mappings.properties.parent\.subfield.type: "keyword" }

---
"Composable index templates that include subobjects: false on arbitrary field":
- skip:
version: ' - 8.10.1'
reason: 'https://github.com/elastic/elasticsearch/issues/96768 fixed after 8.10.0'
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
features: allowed_warnings

- do:
cluster.put_component_template:
name: test-subobjects
body:
template:
mappings:
properties:
parent:
type: object
subobjects: false

- do:
cluster.put_component_template:
name: test-subfield
body:
template:
mappings:
properties:
parent:
properties:
child.grandchild:
type: keyword

- do:
allowed_warnings:
- "index template [test-composable-template] has index patterns [test-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [test-composable-template] will take precedence during new index creation"
indices.put_index_template:
name: test-composable-template
body:
index_patterns:
- test-*
composed_of:
- test-subobjects
- test-subfield
- is_true: acknowledged

- do:
indices.create:
index: test-generic

- do:
indices.get_mapping:
index: test-generic
- match: { test-generic.mappings.properties.parent.properties.child\.grandchild.type: "keyword" }

---
"Composition of component templates with different legal field mappings":
- skip:
features: allowed_warnings

- do:
cluster.put_component_template:
name: mapping
body:
template:
mappings:
properties:
field:
type: long
coerce: true

- do:
allowed_warnings:
- "index template [test-composable-template] has index patterns [test-*] matching patterns from existing older templates [global] with patterns (global => [*]); this template [test-composable-template] will take precedence during new index creation"
indices.put_index_template:
name: test-composable-template
body:
index_patterns:
- test-*
composed_of:
- mapping
template:
mappings:
properties:
field:
type: keyword
ignore_above: 1024
- is_true: acknowledged

- do:
indices.create:
index: test-generic

- do:
indices.get_mapping:
index: test-generic
- match: { test-generic.mappings.properties.field.type: "keyword" }
- match: { test-generic.mappings.properties.field.ignore_above: 1024 }
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ reject @timestamp with wrong type:
reason: introduced in 8.1.0

- do:
catch: /data stream timestamp field \[@timestamp\] is of type \[keyword\], but \[date,date_nanos\] is expected/
catch: /data stream timestamp field \[@timestamp\] is of type \[long\], but \[date,date_nanos\] is expected/
indices.create:
index: test
body:
Expand All @@ -163,7 +163,7 @@ reject @timestamp with wrong type:
mappings:
properties:
"@timestamp":
type: keyword
type: long

---
reject timestamp meta field with wrong type:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,9 +294,7 @@ public static Template resolveTemplate(
indexMetadata,
tempIndexService -> {
MapperService mapperService = tempIndexService.mapperService();
for (CompressedXContent mapping : mappings) {
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mapping, MapperService.MergeReason.INDEX_TEMPLATE);
}
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mappings, MapperService.MergeReason.INDEX_TEMPLATE);

DocumentMapper documentMapper = mapperService.documentMapper();
return documentMapper != null ? documentMapper.mappingSource() : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1331,13 +1331,14 @@ private static void updateIndexMappingsAndBuildSortOrder(
) throws IOException {
MapperService mapperService = indexService.mapperService();
IndexMode indexMode = indexService.getIndexSettings() != null ? indexService.getIndexSettings().getMode() : IndexMode.STANDARD;
List<CompressedXContent> allMappings = new ArrayList<>();
final CompressedXContent defaultMapping = indexMode.getDefaultMapping();
if (defaultMapping != null) {
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, defaultMapping, MergeReason.INDEX_TEMPLATE);
}
for (CompressedXContent mapping : mappings) {
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mapping, MergeReason.INDEX_TEMPLATE);
allMappings.add(defaultMapping);
}
allMappings.addAll(mappings);
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, allMappings, MergeReason.INDEX_TEMPLATE);

indexMode.validateTimestampFieldMapping(request.dataStreamName() != null, mapperService.mappingLookup());

if (sourceMetadata == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
public class MetadataIndexTemplateService {

public static final String DEFAULT_TIMESTAMP_FIELD = "@timestamp";
public static final CompressedXContent DEFAULT_TIMESTAMP_MAPPING;
public static final CompressedXContent DEFAULT_TIMESTAMP_MAPPING_WITHOUT_ROUTING;

private static final CompressedXContent DEFAULT_TIMESTAMP_MAPPING_WITH_ROUTING;

Expand All @@ -96,8 +96,14 @@ public class MetadataIndexTemplateService {
Map.of("type", DateFieldMapper.CONTENT_TYPE, "ignore_malformed", "false")
);
try {
DEFAULT_TIMESTAMP_MAPPING = new CompressedXContent(
DEFAULT_TIMESTAMP_MAPPING_WITHOUT_ROUTING = new CompressedXContent(
(builder, params) -> builder.startObject(MapperService.SINGLE_MAPPING_NAME)
// adding explicit "_routing": {"required": false}, even though this is the default, because this snippet is used
// later for resolving a RoutingFieldMapper, where we need this information to validate that does not conflict with
// any mapping.
.startObject(RoutingFieldMapper.NAME)
.field("required", false)
.endObject()
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
.field("properties", defaultTimestampField)
.endObject()
);
Expand Down Expand Up @@ -1303,7 +1309,7 @@ public static List<CompressedXContent> collectMappings(
if (template.getDataStreamTemplate().isAllowCustomRouting()) {
mappings.add(0, DEFAULT_TIMESTAMP_MAPPING_WITH_ROUTING);
} else {
mappings.add(0, DEFAULT_TIMESTAMP_MAPPING);
mappings.add(0, DEFAULT_TIMESTAMP_MAPPING_WITHOUT_ROUTING);
eyalkoren marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down Expand Up @@ -1599,9 +1605,7 @@ private static void validateCompositeTemplate(
List<CompressedXContent> mappings = collectMappings(stateWithIndex, templateName, indexName);
try {
MapperService mapperService = tempIndexService.mapperService();
for (CompressedXContent mapping : mappings) {
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mapping, MapperService.MergeReason.INDEX_TEMPLATE);
}
mapperService.merge(MapperService.SINGLE_MAPPING_NAME, mappings, MapperService.MergeReason.INDEX_TEMPLATE);

if (template.getDataStreamTemplate() != null) {
validateTimestampFieldMapping(mapperService.mappingLookup());
Expand Down
Loading