Skip to content

Commit 23a40e1

Browse files
committed
Introduce skip validation flag for index template API
Add flag and docs Related elastic#20479
1 parent 5acff4e commit 23a40e1

File tree

7 files changed

+132
-1
lines changed

7 files changed

+132
-1
lines changed

core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.elasticsearch.action.support.IndicesOptions;
2929
import org.elasticsearch.action.support.master.MasterNodeRequest;
3030
import org.elasticsearch.cluster.metadata.IndexMetaData;
31+
import org.elasticsearch.common.Booleans;
3132
import org.elasticsearch.common.bytes.BytesArray;
3233
import org.elasticsearch.common.bytes.BytesReference;
3334
import org.elasticsearch.common.collect.MapBuilder;
@@ -80,6 +81,10 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
8081

8182
private Integer version;
8283

84+
private boolean validation = DEFAULT_VALIDATION;
85+
86+
public static final boolean DEFAULT_VALIDATION = true;
87+
8388
public PutIndexTemplateRequest() {
8489
}
8590

@@ -316,6 +321,18 @@ public PutIndexTemplateRequest source(XContentBuilder templateBuilder) {
316321
}
317322
}
318323

324+
/**
325+
* Set to <tt>true</tt> to validate
326+
*/
327+
public PutIndexTemplateRequest validation(boolean validation) {
328+
this.validation = validation;
329+
return this;
330+
}
331+
332+
public boolean validation() {
333+
return validation;
334+
}
335+
319336
/**
320337
* The template source definition.
321338
*/
@@ -350,6 +367,12 @@ public PutIndexTemplateRequest source(Map templateSource) {
350367
}
351368
} else if (name.equals("aliases")) {
352369
aliases((Map<String, Object>) entry.getValue());
370+
} else if (name.equals("validate")) {
371+
if (entry.getValue() instanceof Boolean) {
372+
validation((Boolean)entry.getValue());
373+
} else if (entry.getValue() instanceof String) {
374+
validation(Booleans.parseBoolean((String)entry.getValue(), DEFAULT_VALIDATION));
375+
}
353376
} else {
354377
// maybe custom?
355378
IndexMetaData.Custom proto = IndexMetaData.lookupPrototype(name);
@@ -539,6 +562,9 @@ public void readFrom(StreamInput in) throws IOException {
539562
aliases.add(Alias.read(in));
540563
}
541564
version = in.readOptionalVInt();
565+
if (in.getVersion().onOrAfter(Version.V_5_1_0)) {
566+
validation = in.readBoolean();
567+
}
542568
}
543569

544570
@Override
@@ -565,5 +591,9 @@ public void writeTo(StreamOutput out) throws IOException {
565591
alias.writeTo(out);
566592
}
567593
out.writeOptionalVInt(version);
594+
if (out.getVersion().onOrAfter(Version.V_5_1_0)) {
595+
out.writeBoolean(validation);
596+
}
597+
568598
}
569599
}

core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,4 +303,12 @@ public PutIndexTemplateRequestBuilder setSource(byte[] templateSource, int offse
303303
request.source(templateSource, offset, length, xContentType);
304304
return this;
305305
}
306+
307+
/**
308+
* Set to <tt>true</tt> to validate
309+
*/
310+
public PutIndexTemplateRequestBuilder setValidation(boolean validation) {
311+
request.validation(validation);
312+
return this;
313+
}
306314
}

core/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutIndexTemplateAction.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ protected void masterOperation(final PutIndexTemplateRequest request, final Clus
8686
.aliases(request.aliases())
8787
.customs(request.customs())
8888
.create(request.create())
89+
.validation(request.validation())
8990
.masterTimeout(request.masterNodeTimeout())
9091
.version(request.version()),
9192

core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateService.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ private static void validateAndAddTemplate(final PutRequest request, IndexTempla
231231
mappingsForValidation.put(entry.getKey(), MapperService.parseMapping(xContentRegistry, entry.getValue()));
232232
}
233233

234-
dummyIndexService.mapperService().merge(mappingsForValidation, MergeReason.MAPPING_UPDATE, false);
234+
if (request.validation){
235+
dummyIndexService.mapperService().merge(mappingsForValidation, MergeReason.MAPPING_UPDATE, false);
236+
}
235237

236238
} finally {
237239
if (createdIndex != null) {
@@ -316,6 +318,7 @@ public static class PutRequest {
316318
Map<String, String> mappings = new HashMap<>();
317319
List<Alias> aliases = new ArrayList<>();
318320
Map<String, IndexMetaData.Custom> customs = new HashMap<>();
321+
boolean validation;
319322

320323
TimeValue masterTimeout = MasterNodeRequest.DEFAULT_MASTER_NODE_TIMEOUT;
321324

@@ -373,6 +376,11 @@ public PutRequest version(Integer version) {
373376
this.version = version;
374377
return this;
375378
}
379+
380+
public PutRequest validation(boolean validation) {
381+
this.validation = validation;
382+
return this;
383+
}
376384
}
377385

378386
public static class PutResponse {

core/src/test/java/org/elasticsearch/action/admin/indices/template/put/MetaDataIndexTemplateServiceTests.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ public void testIndexTemplateWithValidateEmptyMapping() throws Exception {
100100
PutRequest request = new PutRequest("api", "validate_template");
101101
request.template("validate_template");
102102
request.putMapping("type1", "{}");
103+
request.validation(true);
103104

104105
List<Throwable> errors = putTemplateDetail(request);
105106
assertThat(errors.size(), equalTo(1));
@@ -113,17 +114,43 @@ public void testIndexTemplateWithValidateMapping() throws Exception {
113114
request.putMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
114115
.startObject("field2").field("type", "string").field("analyzer", "custom_1").endObject()
115116
.endObject().endObject().endObject().string());
117+
request.validation(true);
116118

117119
List<Throwable> errors = putTemplateDetail(request);
118120
assertThat(errors.size(), equalTo(1));
119121
assertThat(errors.get(0), instanceOf(MapperParsingException.class));
120122
assertThat(errors.get(0).getMessage(), containsString("analyzer [custom_1] not found for field [field2]"));
121123
}
122124

125+
public void testIndexTemplateWrongMappingsWithNoValidation() throws Exception {
126+
PutRequest request = new PutRequest("api", "validate_template");
127+
request.template("te*");
128+
request.putMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
129+
.startObject("field2").field("type", "string").field("analyzer", "custom_1").endObject()
130+
.endObject().endObject().endObject().string());
131+
request.validation(false);
132+
133+
List<Throwable> errors = putTemplateDetail(request);
134+
assertThat(errors.size(), equalTo(0));
135+
}
136+
123137
public void testBrokenMapping() throws Exception {
124138
PutRequest request = new PutRequest("api", "broken_mapping");
125139
request.template("te*");
126140
request.putMapping("type1", "abcde");
141+
request.validation(false);
142+
143+
List<Throwable> errors = putTemplateDetail(request);
144+
assertThat(errors.size(), equalTo(1));
145+
assertThat(errors.get(0), instanceOf(MapperParsingException.class));
146+
assertThat(errors.get(0).getMessage(), containsString("Failed to parse mapping "));
147+
}
148+
149+
public void testBrokenMappingWithVlidation() throws Exception {
150+
PutRequest request = new PutRequest("api", "broken_mapping");
151+
request.template("te*");
152+
request.putMapping("type1", "abcde");
153+
request.validation(true);
127154

128155
List<Throwable> errors = putTemplateDetail(request);
129156
assertThat(errors.size(), equalTo(1));
@@ -135,6 +162,17 @@ public void testBlankMapping() throws Exception {
135162
PutRequest request = new PutRequest("api", "blank_mapping");
136163
request.template("te*");
137164
request.putMapping("type1", "{}");
165+
request.validation(false);
166+
167+
List<Throwable> errors = putTemplateDetail(request);
168+
assertThat(errors.size(), equalTo(0));
169+
}
170+
171+
public void testBlankMappingWithValidation() throws Exception {
172+
PutRequest request = new PutRequest("api", "blank_mapping");
173+
request.template("te*");
174+
request.putMapping("type1", "{}");
175+
request.validation(true);
138176

139177
List<Throwable> errors = putTemplateDetail(request);
140178
assertThat(errors.size(), equalTo(1));

core/src/test/java/org/elasticsearch/indices/template/SimpleIndexTemplateIT.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,48 @@ public void testCombineTemplates() throws Exception{
725725

726726
}
727727

728+
public void testCombineTemplatesWithoutValidation() throws Exception{
729+
// clean all templates setup by the framework.
730+
client().admin().indices().prepareDeleteTemplate("*").get();
731+
732+
// check get all templates on an empty index.
733+
GetIndexTemplatesResponse response = client().admin().indices().prepareGetTemplates().get();
734+
assertThat(response.getIndexTemplates(), empty());
735+
736+
//Now, a complete mapping with two separated templates is error
737+
// base template
738+
client().admin().indices().preparePutTemplate("template_1")
739+
.setTemplate("*")
740+
.setSettings(
741+
" {\n" +
742+
" \"index\" : {\n" +
743+
" \"analysis\" : {\n" +
744+
" \"analyzer\" : {\n" +
745+
" \"custom_1\" : {\n" +
746+
" \"tokenizer\" : \"whitespace\"\n" +
747+
" }\n" +
748+
" }\n" +
749+
" }\n" +
750+
" }\n" +
751+
" }\n")
752+
.get();
753+
754+
// put template using custom_1 analyzer
755+
client().admin().indices().preparePutTemplate("template_2")
756+
.setTemplate("test*")
757+
.setCreate(true)
758+
.setOrder(1)
759+
.setValidation(false)
760+
.addMapping("type1", XContentFactory.jsonBuilder().startObject().startObject("type1").startObject("properties")
761+
.startObject("field2").field("type", "string").field("analyzer", "custom_1").endObject()
762+
.endObject().endObject().endObject())
763+
.get();
764+
765+
response = client().admin().indices().prepareGetTemplates().get();
766+
assertThat(response.getIndexTemplates(), hasSize(2));
767+
768+
}
769+
728770
public void testOrderAndVersion() {
729771
int order = randomInt();
730772
Integer version = randomBoolean() ? randomInt() : null;

docs/reference/indices/templates.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ PUT _template/template_1
7575
<1> the `{index}` placeholder in the alias name will be replaced with the
7676
actual index name that the template gets applied to, during index creation.
7777

78+
NOTE: After 2.4, Elasticsearch validates each template as a complete mapping and settings.
79+
If you have some incomplete template, e.g. analyzer settings in a template and mappings in another template,
80+
you can set `validate` to `false` and skip validation that is `true` by default.
81+
7882
[float]
7983
[[delete]]
8084
=== Deleting a Template

0 commit comments

Comments
 (0)