Skip to content

Commit 36377d7

Browse files
probakowskidakrone
andauthored
Add validation for component templates (#54023)
* Add validation for component templates This change adds validation to make sure that settings and mappings are correct in component template. It's done the same way as in index templates - code is reused. Reletes to #53101 * Fix checkstyle violation * Update server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateService.java Co-Authored-By: Lee Hinman <[email protected]> * Update server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateServiceTests.java Co-Authored-By: Lee Hinman <[email protected]> * Update server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateServiceTests.java Co-Authored-By: Lee Hinman <[email protected]> * Update server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateServiceTests.java Co-Authored-By: Lee Hinman <[email protected]> * Update server/src/main/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateService.java Co-Authored-By: Lee Hinman <[email protected]> Co-authored-by: Lee Hinman <[email protected]>
1 parent 68f4297 commit 36377d7

File tree

4 files changed

+88
-50
lines changed

4 files changed

+88
-50
lines changed

server/src/main/java/org/elasticsearch/action/admin/indices/template/put/TransportPutComponentTemplateAction.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.elasticsearch.cluster.service.ClusterService;
3535
import org.elasticsearch.common.inject.Inject;
3636
import org.elasticsearch.common.io.stream.StreamInput;
37+
import org.elasticsearch.common.settings.IndexScopedSettings;
3738
import org.elasticsearch.common.settings.Settings;
3839
import org.elasticsearch.tasks.Task;
3940
import org.elasticsearch.threadpool.ThreadPool;
@@ -45,14 +46,17 @@ public class TransportPutComponentTemplateAction
4546
extends TransportMasterNodeAction<PutComponentTemplateAction.Request, AcknowledgedResponse> {
4647

4748
private final MetaDataIndexTemplateService indexTemplateService;
49+
private final IndexScopedSettings indexScopedSettings;
4850

4951
@Inject
5052
public TransportPutComponentTemplateAction(TransportService transportService, ClusterService clusterService,
5153
ThreadPool threadPool, MetaDataIndexTemplateService indexTemplateService,
52-
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
54+
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
55+
IndexScopedSettings indexScopedSettings) {
5356
super(PutComponentTemplateAction.NAME, transportService, clusterService, threadPool, actionFilters,
5457
PutComponentTemplateAction.Request::new, indexNameExpressionResolver);
5558
this.indexTemplateService = indexTemplateService;
59+
this.indexScopedSettings = indexScopedSettings;
5660
}
5761

5862
@Override
@@ -78,8 +82,10 @@ protected void masterOperation(Task task, final PutComponentTemplateAction.Reque
7882
Template template = componentTemplate.template();
7983
// Normalize the index settings if necessary
8084
if (template.settings() != null) {
81-
Settings.Builder settings = Settings.builder().put(template.settings()).normalizePrefix(IndexMetaData.INDEX_SETTING_PREFIX);
82-
template = new Template(settings.build(), template.mappings(), template.aliases());
85+
Settings.Builder builder = Settings.builder().put(template.settings()).normalizePrefix(IndexMetaData.INDEX_SETTING_PREFIX);
86+
Settings settings = builder.build();
87+
indexScopedSettings.validate(settings, true);
88+
template = new Template(settings, template.mappings(), template.aliases());
8389
componentTemplate = new ComponentTemplate(template, componentTemplate.version(), componentTemplate.metadata());
8490
}
8591
indexTemplateService.putComponentTemplate(request.cause(), request.create(), request.name(), request.masterNodeTimeout(),

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

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.common.Strings;
3636
import org.elasticsearch.common.UUIDs;
3737
import org.elasticsearch.common.ValidationException;
38+
import org.elasticsearch.common.compress.CompressedXContent;
3839
import org.elasticsearch.common.inject.Inject;
3940
import org.elasticsearch.common.regex.Regex;
4041
import org.elasticsearch.common.settings.IndexScopedSettings;
@@ -154,7 +155,7 @@ public void onFailure(String source, Exception e) {
154155
}
155156

156157
@Override
157-
public ClusterState execute(ClusterState currentState) {
158+
public ClusterState execute(ClusterState currentState) throws Exception {
158159
return addComponentTemplate(currentState, create, name, template);
159160
}
160161

@@ -166,14 +167,15 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS
166167
}
167168

168169
// Package visible for testing
169-
static ClusterState addComponentTemplate(final ClusterState currentState, final boolean create,
170-
final String name, final ComponentTemplate template) {
170+
ClusterState addComponentTemplate(final ClusterState currentState, final boolean create,
171+
final String name, final ComponentTemplate template) throws Exception {
171172
if (create && currentState.metaData().componentTemplates().containsKey(name)) {
172173
throw new IllegalArgumentException("component template [" + name + "] already exists");
173174
}
174175

175-
// TODO: validation of component template
176-
// validateAndAddTemplate(request, templateBuilder, indicesService, xContentRegistry);
176+
CompressedXContent mappings = template.template().mappings();
177+
String stringMappings = mappings == null ? null : mappings.string();
178+
validateTemplate(template.template().settings(), stringMappings, indicesService, xContentRegistry);
177179

178180
logger.info("adding component template [{}]", name);
179181
return ClusterState.builder(currentState)
@@ -274,7 +276,20 @@ public ClusterState execute(ClusterState currentState) throws Exception {
274276
throw new IllegalArgumentException("index_template [" + request.name + "] already exists");
275277
}
276278

277-
validateAndAddTemplate(request, templateBuilder, indicesService, xContentRegistry);
279+
templateBuilder.order(request.order);
280+
templateBuilder.version(request.version);
281+
templateBuilder.patterns(request.indexPatterns);
282+
templateBuilder.settings(request.settings);
283+
284+
if (request.mappings != null) {
285+
try {
286+
templateBuilder.putMapping(MapperService.SINGLE_MAPPING_NAME, request.mappings);
287+
} catch (Exception e) {
288+
throw new MapperParsingException("Failed to parse mapping: {}", e, request.mappings);
289+
}
290+
}
291+
292+
validateTemplate(request.settings, request.mappings, indicesService, xContentRegistry);
278293

279294
for (Alias alias : request.aliases) {
280295
AliasMetaData aliasMetaData = AliasMetaData.builder(alias.name()).filter(alias.filter())
@@ -355,20 +370,20 @@ public static List<IndexTemplateMetaData> findTemplates(MetaData metaData, Strin
355370
return matchedTemplates;
356371
}
357372

358-
private static void validateAndAddTemplate(final PutRequest request, IndexTemplateMetaData.Builder templateBuilder,
359-
IndicesService indicesService, NamedXContentRegistry xContentRegistry) throws Exception {
373+
private static void validateTemplate(Settings settings, String mappings,
374+
IndicesService indicesService, NamedXContentRegistry xContentRegistry) throws Exception {
360375
Index createdIndex = null;
361376
final String temporaryIndexName = UUIDs.randomBase64UUID();
362377
try {
363378
// use the provided values, otherwise just pick valid dummy values
364-
int dummyPartitionSize = IndexMetaData.INDEX_ROUTING_PARTITION_SIZE_SETTING.get(request.settings);
365-
int dummyShards = request.settings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS,
379+
int dummyPartitionSize = IndexMetaData.INDEX_ROUTING_PARTITION_SIZE_SETTING.get(settings);
380+
int dummyShards = settings.getAsInt(IndexMetaData.SETTING_NUMBER_OF_SHARDS,
366381
dummyPartitionSize == 1 ? 1 : dummyPartitionSize + 1);
367382

368383
//create index service for parsing and validating "mappings"
369384
Settings dummySettings = Settings.builder()
370385
.put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT)
371-
.put(request.settings)
386+
.put(settings)
372387
.put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, dummyShards)
373388
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
374389
.put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID())
@@ -378,19 +393,9 @@ private static void validateAndAddTemplate(final PutRequest request, IndexTempla
378393
IndexService dummyIndexService = indicesService.createIndex(tmpIndexMetadata, Collections.emptyList(), false);
379394
createdIndex = dummyIndexService.index();
380395

381-
templateBuilder.order(request.order);
382-
templateBuilder.version(request.version);
383-
templateBuilder.patterns(request.indexPatterns);
384-
templateBuilder.settings(request.settings);
385-
386-
if (request.mappings != null) {
387-
try {
388-
templateBuilder.putMapping(MapperService.SINGLE_MAPPING_NAME, request.mappings);
389-
} catch (Exception e) {
390-
throw new MapperParsingException("Failed to parse mapping: {}", e, request.mappings);
391-
}
396+
if (mappings != null) {
392397
dummyIndexService.mapperService().merge(MapperService.SINGLE_MAPPING_NAME,
393-
MapperService.parseMapping(xContentRegistry, request.mappings), MergeReason.MAPPING_UPDATE);
398+
MapperService.parseMapping(xContentRegistry, mappings), MergeReason.MAPPING_UPDATE);
394399
}
395400

396401
} finally {

server/src/test/java/org/elasticsearch/cluster/metadata/ComponentTemplateTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public static ComponentTemplate randomInstance() {
8585
return new ComponentTemplate(template, randomBoolean() ? null : randomNonNegativeLong(), meta);
8686
}
8787

88-
private static Map<String, AliasMetaData> randomAliases() {
88+
public static Map<String, AliasMetaData> randomAliases() {
8989
String aliasName = randomAlphaOfLength(5);
9090
AliasMetaData aliasMeta = AliasMetaData.builder(aliasName)
9191
.filter(Collections.singletonMap(randomAlphaOfLength(2), randomAlphaOfLength(2)))

server/src/test/java/org/elasticsearch/cluster/metadata/MetaDataIndexTemplateServiceTests.java

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919

2020
package org.elasticsearch.cluster.metadata;
2121

22+
import com.fasterxml.jackson.core.JsonParseException;
2223
import org.elasticsearch.action.admin.indices.alias.Alias;
2324
import org.elasticsearch.cluster.ClusterState;
2425
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService.PutRequest;
2526
import org.elasticsearch.cluster.service.ClusterService;
2627
import org.elasticsearch.common.Strings;
28+
import org.elasticsearch.common.compress.CompressedXContent;
2729
import org.elasticsearch.common.settings.IndexScopedSettings;
2830
import org.elasticsearch.common.settings.Settings;
2931
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
@@ -37,6 +39,7 @@
3739
import java.util.ArrayList;
3840
import java.util.Arrays;
3941
import java.util.Collections;
42+
import java.util.HashMap;
4043
import java.util.HashSet;
4144
import java.util.List;
4245
import java.util.Set;
@@ -197,21 +200,41 @@ public void testPutGlobalTemplateWithIndexHiddenSetting() throws Exception {
197200
assertThat(errors.get(0).getMessage(), containsString("global templates may not specify the setting index.hidden"));
198201
}
199202

200-
public void testAddComponentTemplate() {
203+
public void testAddComponentTemplate() throws Exception{
204+
MetaDataIndexTemplateService metaDataIndexTemplateService = getMetaDataIndexTemplateService();
201205
ClusterState state = ClusterState.EMPTY_STATE;
202-
ComponentTemplate template = ComponentTemplateTests.randomInstance();
203-
state = MetaDataIndexTemplateService.addComponentTemplate(state, false, "foo", template);
206+
Template template = new Template(Settings.builder().build(), null, ComponentTemplateTests.randomAliases());
207+
ComponentTemplate componentTemplate = new ComponentTemplate(template, 1L, new HashMap<>());
208+
state = metaDataIndexTemplateService.addComponentTemplate(state, false, "foo", componentTemplate);
204209

205210
assertNotNull(state.metaData().componentTemplates().get("foo"));
206-
assertThat(state.metaData().componentTemplates().get("foo"), equalTo(template));
211+
assertThat(state.metaData().componentTemplates().get("foo"), equalTo(componentTemplate));
207212

208213
final ClusterState throwState = ClusterState.builder(state).build();
209214
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
210-
() -> MetaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo", template));
215+
() -> metaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo", componentTemplate));
211216
assertThat(e.getMessage(), containsString("component template [foo] already exists"));
212217

213-
state = MetaDataIndexTemplateService.addComponentTemplate(state, randomBoolean(), "bar", template);
218+
state = metaDataIndexTemplateService.addComponentTemplate(state, randomBoolean(), "bar", componentTemplate);
214219
assertNotNull(state.metaData().componentTemplates().get("bar"));
220+
221+
template = new Template(Settings.builder().build(), new CompressedXContent("{\"invalid\"}"),
222+
ComponentTemplateTests.randomAliases());
223+
ComponentTemplate componentTemplate2 = new ComponentTemplate(template, 1L, new HashMap<>());
224+
expectThrows(JsonParseException.class,
225+
() -> metaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo2", componentTemplate2));
226+
227+
template = new Template(Settings.builder().build(), new CompressedXContent("{\"invalid\":\"invalid\"}"),
228+
ComponentTemplateTests.randomAliases());
229+
ComponentTemplate componentTemplate3 = new ComponentTemplate(template, 1L, new HashMap<>());
230+
expectThrows(MapperParsingException.class,
231+
() -> metaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo2", componentTemplate3));
232+
233+
template = new Template(Settings.builder().put("invalid", "invalid").build(), new CompressedXContent("{}"),
234+
ComponentTemplateTests.randomAliases());
235+
ComponentTemplate componentTemplate4 = new ComponentTemplate(template, 1L, new HashMap<>());
236+
expectThrows(IllegalArgumentException.class,
237+
() -> metaDataIndexTemplateService.addComponentTemplate(throwState, true, "foo2", componentTemplate4));
215238
}
216239

217240
private static List<Throwable> putTemplate(NamedXContentRegistry xContentRegistry, PutRequest request) {
@@ -247,23 +270,7 @@ public void onFailure(Exception e) {
247270
}
248271

249272
private List<Throwable> putTemplateDetail(PutRequest request) throws Exception {
250-
IndicesService indicesService = getInstanceFromNode(IndicesService.class);
251-
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
252-
MetaDataCreateIndexService createIndexService = new MetaDataCreateIndexService(
253-
Settings.EMPTY,
254-
clusterService,
255-
indicesService,
256-
null,
257-
null,
258-
new Environment(builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()).build(), null),
259-
IndexScopedSettings.DEFAULT_SCOPED_SETTINGS,
260-
null,
261-
xContentRegistry(),
262-
Collections.emptyList(),
263-
true);
264-
MetaDataIndexTemplateService service = new MetaDataIndexTemplateService(
265-
clusterService, createIndexService, new AliasValidator(), indicesService,
266-
new IndexScopedSettings(Settings.EMPTY, IndexScopedSettings.BUILT_IN_INDEX_SETTINGS), xContentRegistry());
273+
MetaDataIndexTemplateService service = getMetaDataIndexTemplateService();
267274

268275
final List<Throwable> throwables = new ArrayList<>();
269276
final CountDownLatch latch = new CountDownLatch(1);
@@ -282,4 +289,24 @@ public void onFailure(Exception e) {
282289
latch.await();
283290
return throwables;
284291
}
292+
293+
private MetaDataIndexTemplateService getMetaDataIndexTemplateService() {
294+
IndicesService indicesService = getInstanceFromNode(IndicesService.class);
295+
ClusterService clusterService = getInstanceFromNode(ClusterService.class);
296+
MetaDataCreateIndexService createIndexService = new MetaDataCreateIndexService(
297+
Settings.EMPTY,
298+
clusterService,
299+
indicesService,
300+
null,
301+
null,
302+
new Environment(builder().put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toString()).build(), null),
303+
IndexScopedSettings.DEFAULT_SCOPED_SETTINGS,
304+
null,
305+
xContentRegistry(),
306+
Collections.emptyList(),
307+
true);
308+
return new MetaDataIndexTemplateService(
309+
clusterService, createIndexService, new AliasValidator(), indicesService,
310+
new IndexScopedSettings(Settings.EMPTY, IndexScopedSettings.BUILT_IN_INDEX_SETTINGS), xContentRegistry());
311+
}
285312
}

0 commit comments

Comments
 (0)