1919package org .elasticsearch .cluster .metadata ;
2020
2121import com .carrotsearch .hppc .cursors .ObjectCursor ;
22+ import org .elasticsearch .Version ;
2223import org .elasticsearch .action .admin .indices .alias .Alias ;
2324import org .elasticsearch .action .support .master .MasterNodeRequest ;
2425import org .elasticsearch .cluster .ClusterState ;
2526import org .elasticsearch .cluster .ClusterStateUpdateTask ;
2627import org .elasticsearch .cluster .service .ClusterService ;
2728import org .elasticsearch .common .Priority ;
2829import org .elasticsearch .common .Strings ;
30+ import org .elasticsearch .common .UUIDs ;
2931import org .elasticsearch .common .ValidationException ;
3032import org .elasticsearch .common .component .AbstractComponent ;
3133import org .elasticsearch .common .inject .Inject ;
3234import org .elasticsearch .common .regex .Regex ;
3335import org .elasticsearch .common .settings .Settings ;
3436import org .elasticsearch .common .unit .TimeValue ;
37+ import org .elasticsearch .index .Index ;
38+ import org .elasticsearch .index .NodeServicesProvider ;
39+ import org .elasticsearch .index .IndexService ;
40+ import org .elasticsearch .index .mapper .MapperParsingException ;
41+ import org .elasticsearch .index .mapper .MapperService ;
3542import org .elasticsearch .indices .IndexTemplateAlreadyExistsException ;
3643import org .elasticsearch .indices .IndexTemplateMissingException ;
44+ import org .elasticsearch .indices .IndicesService ;
3745import org .elasticsearch .indices .InvalidIndexTemplateException ;
3846
3947import java .util .ArrayList ;
48+ import java .util .Collections ;
4049import java .util .HashMap ;
4150import java .util .HashSet ;
4251import java .util .List ;
@@ -51,14 +60,18 @@ public class MetaDataIndexTemplateService extends AbstractComponent {
5160
5261 private final ClusterService clusterService ;
5362 private final AliasValidator aliasValidator ;
63+ private final IndicesService indicesService ;
5464 private final MetaDataCreateIndexService metaDataCreateIndexService ;
65+ private final NodeServicesProvider nodeServicesProvider ;
5566
5667 @ Inject
57- public MetaDataIndexTemplateService (Settings settings , ClusterService clusterService , MetaDataCreateIndexService metaDataCreateIndexService , AliasValidator aliasValidator ) {
68+ public MetaDataIndexTemplateService (Settings settings , ClusterService clusterService , MetaDataCreateIndexService metaDataCreateIndexService , AliasValidator aliasValidator , IndicesService indicesService , NodeServicesProvider nodeServicesProvider ) {
5869 super (settings );
5970 this .clusterService = clusterService ;
6071 this .aliasValidator = aliasValidator ;
72+ this .indicesService = indicesService ;
6173 this .metaDataCreateIndexService = metaDataCreateIndexService ;
74+ this .nodeServicesProvider = nodeServicesProvider ;
6275 }
6376
6477 public void removeTemplates (final RemoveRequest request , final RemoveListener listener ) {
@@ -126,28 +139,7 @@ public void putTemplate(final PutRequest request, final PutListener listener) {
126139 return ;
127140 }
128141
129- IndexTemplateMetaData .Builder templateBuilder ;
130- try {
131- templateBuilder = IndexTemplateMetaData .builder (request .name );
132- templateBuilder .order (request .order );
133- templateBuilder .template (request .template );
134- templateBuilder .settings (request .settings );
135- for (Map .Entry <String , String > entry : request .mappings .entrySet ()) {
136- templateBuilder .putMapping (entry .getKey (), entry .getValue ());
137- }
138- for (Alias alias : request .aliases ) {
139- AliasMetaData aliasMetaData = AliasMetaData .builder (alias .name ()).filter (alias .filter ())
140- .indexRouting (alias .indexRouting ()).searchRouting (alias .searchRouting ()).build ();
141- templateBuilder .putAlias (aliasMetaData );
142- }
143- for (Map .Entry <String , IndexMetaData .Custom > entry : request .customs .entrySet ()) {
144- templateBuilder .putCustom (entry .getKey (), entry .getValue ());
145- }
146- } catch (Throwable e ) {
147- listener .onFailure (e );
148- return ;
149- }
150- final IndexTemplateMetaData template = templateBuilder .build ();
142+ final IndexTemplateMetaData .Builder templateBuilder = IndexTemplateMetaData .builder (request .name );
151143
152144 clusterService .submitStateUpdateTask ("create-index-template [" + request .name + "], cause [" + request .cause + "]" ,
153145 new ClusterStateUpdateTask (Priority .URGENT ) {
@@ -163,22 +155,77 @@ public void onFailure(String source, Throwable t) {
163155 }
164156
165157 @ Override
166- public ClusterState execute (ClusterState currentState ) {
158+ public ClusterState execute (ClusterState currentState ) throws Exception {
167159 if (request .create && currentState .metaData ().templates ().containsKey (request .name )) {
168160 throw new IndexTemplateAlreadyExistsException (request .name );
169161 }
162+
163+ validateAndAddTemplate (request , templateBuilder , indicesService , nodeServicesProvider , metaDataCreateIndexService );
164+
165+ for (Alias alias : request .aliases ) {
166+ AliasMetaData aliasMetaData = AliasMetaData .builder (alias .name ()).filter (alias .filter ())
167+ .indexRouting (alias .indexRouting ()).searchRouting (alias .searchRouting ()).build ();
168+ templateBuilder .putAlias (aliasMetaData );
169+ }
170+ for (Map .Entry <String , IndexMetaData .Custom > entry : request .customs .entrySet ()) {
171+ templateBuilder .putCustom (entry .getKey (), entry .getValue ());
172+ }
173+ IndexTemplateMetaData template = templateBuilder .build ();
174+
170175 MetaData .Builder builder = MetaData .builder (currentState .metaData ()).put (template );
171176
172177 return ClusterState .builder (currentState ).metaData (builder ).build ();
173178 }
174179
175180 @ Override
176181 public void clusterStateProcessed (String source , ClusterState oldState , ClusterState newState ) {
177- listener .onResponse (new PutResponse (true , template ));
182+ listener .onResponse (new PutResponse (true , templateBuilder . build () ));
178183 }
179184 });
180185 }
181186
187+ private static void validateAndAddTemplate (final PutRequest request , IndexTemplateMetaData .Builder templateBuilder , IndicesService indicesService ,
188+ NodeServicesProvider nodeServicesProvider , MetaDataCreateIndexService metaDataCreateIndexService ) throws Exception {
189+ Index createdIndex = null ;
190+ final String temporaryIndexName = UUIDs .randomBase64UUID ();
191+ try {
192+
193+ //create index service for parsing and validating "mappings"
194+ Settings dummySettings = Settings .builder ()
195+ .put (IndexMetaData .SETTING_VERSION_CREATED , Version .CURRENT )
196+ .put (request .settings )
197+ .put (IndexMetaData .SETTING_NUMBER_OF_SHARDS , 1 )
198+ .put (IndexMetaData .SETTING_NUMBER_OF_REPLICAS , 0 )
199+ .put (IndexMetaData .SETTING_INDEX_UUID , UUIDs .randomBase64UUID ())
200+ .build ();
201+
202+ final IndexMetaData tmpIndexMetadata = IndexMetaData .builder (temporaryIndexName ).settings (dummySettings ).build ();
203+ IndexService dummyIndexService = indicesService .createIndex (nodeServicesProvider , tmpIndexMetadata , Collections .emptyList ());
204+ createdIndex = dummyIndexService .index ();
205+
206+ templateBuilder .order (request .order );
207+ templateBuilder .template (request .template );
208+ templateBuilder .settings (request .settings );
209+
210+ Map <String , Map <String , Object >> mappingsForValidation = new HashMap <>();
211+ for (Map .Entry <String , String > entry : request .mappings .entrySet ()) {
212+ try {
213+ templateBuilder .putMapping (entry .getKey (), entry .getValue ());
214+ } catch (Exception e ) {
215+ throw new MapperParsingException ("Failed to parse mapping [{}]: {}" , e , entry .getKey (), e .getMessage ());
216+ }
217+ mappingsForValidation .put (entry .getKey (), MapperService .parseMapping (entry .getValue ()));
218+ }
219+
220+ dummyIndexService .mapperService ().merge (mappingsForValidation , false );
221+
222+ } finally {
223+ if (createdIndex != null ) {
224+ indicesService .removeIndex (createdIndex , " created for parsing template mapping" );
225+ }
226+ }
227+ }
228+
182229 private void validate (PutRequest request ) {
183230 List <String > validationErrors = new ArrayList <>();
184231 if (request .name .contains (" " )) {
0 commit comments