Browse Source

Add rolling upgrade tests for component and composable templates (#58867)

This adds rolling upgrade tests that component and composable templates can be read from older
versions of the cluster.

Relates to #58643
Lee Hinman 5 years ago
parent
commit
3ab3f48bd2

+ 5 - 0
qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/AbstractRollingTestCase.java

@@ -54,6 +54,11 @@ public abstract class AbstractRollingTestCase extends ESRestTestCase {
         return true;
     }
 
+    @Override
+    protected boolean preserveTemplatesUponCompletion() {
+        return true;
+    }
+
     @Override
     protected final Settings restClientSettings() {
         return Settings.builder().put(super.restClientSettings())

+ 5 - 0
qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/UpgradeClusterClientYamlTestSuiteIT.java

@@ -40,6 +40,11 @@ public class UpgradeClusterClientYamlTestSuiteIT extends ESClientYamlSuiteTestCa
         return true;
     }
 
+    @Override
+    protected boolean preserveTemplatesUponCompletion() {
+        return true;
+    }
+
     public UpgradeClusterClientYamlTestSuiteIT(ClientYamlTestCandidate testCandidate) {
         super(testCandidate);
     }

+ 26 - 0
qa/rolling-upgrade/src/test/resources/rest-api-spec/test/mixed_cluster/10_basic.yml

@@ -79,3 +79,29 @@
      indices.get:
        index: queries
   - match: { queries.mappings.properties.id.type: "keyword" }
+
+---
+"Component and composable templates can be retrieved":
+  - do:
+      cluster.get_component_template:
+        name: my-ct
+
+  - match: {component_templates.0.name: my-ct}
+  - match: {component_templates.0.component_template.version: 2}
+  - match: {component_templates.0.component_template._meta: {foo: bar, baz: {eggplant: true}}}
+  - match: {component_templates.0.component_template.template.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
+  - is_true: component_templates.0.component_template.template.mappings
+  - match: {component_templates.0.component_template.template.aliases: {aliasname: {}}}
+
+  - do:
+      indices.get_index_template:
+        name: my-it
+
+  - match: {index_templates.0.index_template.index_patterns: ["test-*"]}
+  - match: {index_templates.0.index_template.template.settings.index: {number_of_shards: '1', number_of_replicas: '0'}}
+  - is_true: index_templates.0.index_template.template.mappings
+  - length: {index_templates.0.index_template.template.aliases: 3}
+  - is_true: index_templates.0.index_template.template.aliases.test_alias
+  - match: {index_templates.0.index_template.template.aliases.test_blias.index_routing: "b" }
+  - match: {index_templates.0.index_template.template.aliases.test_blias.search_routing: "b" }
+  - match: {index_templates.0.index_template.template.aliases.test_clias.filter.term.user: "kimchy" }

+ 46 - 0
qa/rolling-upgrade/src/test/resources/rest-api-spec/test/old_cluster/10_basic.yml

@@ -205,3 +205,49 @@
         wait_for_completion: true
         task_id: $task
 
+---
+"Component and composable template validation":
+  - do:
+      cluster.put_component_template:
+        name: my-ct
+        body:
+          template:
+            settings:
+              number_of_shards:   1
+              number_of_replicas: 0
+            mappings:
+              dynamic: false
+            aliases:
+              aliasname: {}
+          version: 2
+          _meta:
+            foo: bar
+            baz:
+              eggplant: true
+
+  - do:
+      indices.put_index_template:
+        name: my-it
+        body:
+          index_patterns: [test-*]
+          composed_of: ["my-ct"]
+          template:
+            settings:
+              number_of_shards:   1
+              number_of_replicas: 0
+            mappings:
+              properties:
+                field:
+                  type: text
+            aliases:
+              test_alias: {}
+              test_blias: { routing: b }
+              test_clias: { filter: { term: { user: kimchy }}}
+
+  - do:
+      cluster.get_component_template:
+        name: my-ct
+
+  - do:
+      indices.get_index_template:
+        name: my-it

+ 52 - 0
qa/rolling-upgrade/src/test/resources/rest-api-spec/test/upgraded_cluster/10_basic.yml

@@ -126,4 +126,56 @@
         task_id: $task_id
   - match: { task.headers.X-Opaque-Id: "Reindexing Again" }
 
+---
+"Component and composable templates can be retrieved and updated":
+  - do:
+      cluster.get_component_template:
+        name: my-ct
+
+  - match: {component_templates.0.name: my-ct}
+  - match: {component_templates.0.component_template.version: 2}
+  - match: {component_templates.0.component_template._meta: {foo: bar, baz: {eggplant: true}}}
+  - match: {component_templates.0.component_template.template.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
+  - match: {component_templates.0.component_template.template.mappings: {dynamic: false}}
+  - match: {component_templates.0.component_template.template.aliases: {aliasname: {}}}
+
+  - do:
+      indices.get_index_template:
+        name: my-it
+
+  - match: {index_templates.0.index_template.index_patterns: ["test-*"]}
+  - match: {index_templates.0.index_template.template.settings.index: {number_of_shards: '1', number_of_replicas: '0'}}
+  - is_true: index_templates.0.index_template.template.mappings
+  - length: {index_templates.0.index_template.template.aliases: 3}
+  - is_true: index_templates.0.index_template.template.aliases.test_alias
+  - match: {index_templates.0.index_template.template.aliases.test_blias.index_routing: "b" }
+  - match: {index_templates.0.index_template.template.aliases.test_blias.search_routing: "b" }
+  - match: {index_templates.0.index_template.template.aliases.test_clias.filter.term.user: "kimchy" }
+  - do:
+      cluster.put_component_template:
+        name: my-ct
+        body:
+          template:
+            settings:
+              number_of_shards:   1
+              number_of_replicas: 0
+            mappings:
+              dynamic: true
+            aliases:
+              aliasname: {}
+          version: 2
+          _meta:
+            foo: bar
+            baz:
+              eggplant: true
+
+  - do:
+      cluster.get_component_template:
+        name: my-ct
 
+  - match: {component_templates.0.name: my-ct}
+  - match: {component_templates.0.component_template.version: 2}
+  - match: {component_templates.0.component_template._meta: {foo: bar, baz: {eggplant: true}}}
+  - match: {component_templates.0.component_template.template.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
+  - is_true: component_templates.0.component_template.template.mappings
+  - match: {component_templates.0.component_template.template.aliases: {aliasname: {}}}

+ 31 - 23
server/src/main/java/org/elasticsearch/cluster/metadata/MetadataIndexTemplateService.java

@@ -186,7 +186,7 @@ public class MetadataIndexTemplateService {
         }
 
         CompressedXContent mappings = template.template().mappings();
-        String stringMappings = mappings == null ? null : mappings.string();
+        String stringMappings = wrapMappingsIfNecessary(mappings == null ? null : mappings.string(), xContentRegistry);
 
         // We may need to normalize index settings, so do that also
         Settings finalSettings = template.template().settings();
@@ -225,17 +225,6 @@ public class MetadataIndexTemplateService {
             }
         }
 
-        // Mappings in component templates don't include _doc, so update the mappings to include this single type
-        if (stringMappings != null) {
-            Map<String, Object> parsedMappings = MapperService.parseMapping(xContentRegistry, stringMappings);
-            if (parsedMappings.size() > 0) {
-                stringMappings = Strings.toString(XContentFactory.jsonBuilder()
-                    .startObject()
-                    .field(MapperService.SINGLE_MAPPING_NAME, parsedMappings)
-                    .endObject());
-            }
-        }
-
         final Template finalTemplate = new Template(finalSettings,
             stringMappings == null ? null : new CompressedXContent(stringMappings), template.template().aliases());
         final ComponentTemplate finalComponentTemplate = new ComponentTemplate(finalTemplate, template.version(), template.metadata());
@@ -279,6 +268,35 @@ public class MetadataIndexTemplateService {
             .build();
     }
 
+    @Nullable
+    private static String wrapMappingsIfNecessary(@Nullable String mappings, NamedXContentRegistry xContentRegistry) throws Exception {
+        // Mappings in templates don't have to include _doc, so update
+        // the mappings to include this single type if necessary
+
+        String stringMappings = mappings;
+        if (stringMappings != null) {
+            Map<String, Object> parsedMappings = MapperService.parseMapping(xContentRegistry, stringMappings);
+            if (parsedMappings.size() > 0) {
+                if (parsedMappings.size() == 1) {
+                    final String keyName = parsedMappings.keySet().iterator().next();
+                    // Check if it's already wrapped in `_doc`, only rewrap if needed
+                    if (MapperService.SINGLE_MAPPING_NAME.equals(keyName) == false) {
+                        stringMappings = Strings.toString(XContentFactory.jsonBuilder()
+                            .startObject()
+                            .field(MapperService.SINGLE_MAPPING_NAME, parsedMappings)
+                            .endObject());
+                    }
+                } else {
+                    stringMappings = Strings.toString(XContentFactory.jsonBuilder()
+                        .startObject()
+                        .field(MapperService.SINGLE_MAPPING_NAME, parsedMappings)
+                        .endObject());
+                }
+            }
+        }
+        return stringMappings;
+    }
+
     /**
      * Remove the given component template from the cluster state. The component template name
      * supports simple regex wildcards for removing multiple component templates at a time.
@@ -462,18 +480,8 @@ public class MetadataIndexTemplateService {
             // If an inner template was specified, its mappings may need to be
             // adjusted (to add _doc) and it should be validated
             CompressedXContent mappings = innerTemplate.mappings();
-            String stringMappings = mappings == null ? null : mappings.string();
+            String stringMappings = wrapMappingsIfNecessary(mappings == null ? null : mappings.string(), xContentRegistry);
 
-            // Mappings in index templates don't include _doc, so update the mappings to include this single type
-            if (stringMappings != null) {
-                Map<String, Object> parsedMappings = MapperService.parseMapping(xContentRegistry, stringMappings);
-                if (parsedMappings.size() > 0) {
-                    stringMappings = Strings.toString(XContentFactory.jsonBuilder()
-                        .startObject()
-                        .field(MapperService.SINGLE_MAPPING_NAME, parsedMappings)
-                        .endObject());
-                }
-            }
             final Template finalTemplate = new Template(finalSettings,
                 stringMappings == null ? null : new CompressedXContent(stringMappings), innerTemplate.aliases());
             finalIndexTemplate = new ComposableIndexTemplate(template.indexPatterns(), finalTemplate, template.composedOf(),