diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java
index f484d7375ba6f..17d803a713a7b 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesClient.java
@@ -50,8 +50,6 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
-import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
-import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
@@ -62,7 +60,9 @@
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.GetMappingsResponse;
+import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
+import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
import org.elasticsearch.rest.RestStatus;
@@ -1341,6 +1341,7 @@ public void putSettingsAsync(UpdateSettingsRequest updateSettingsRequest, Reques
AcknowledgedResponse::fromXContent, listener, emptySet());
}
+
/**
* Asynchronously updates specific index level settings using the Update Indices Settings API.
*
@@ -1363,9 +1364,13 @@ public void putSettingsAsync(UpdateSettingsRequest updateSettingsRequest, Action
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
+ * @deprecated This old form of request allows types in mappings. Use {@link #putTemplate(PutIndexTemplateRequest, RequestOptions)}
+ * instead which introduces a new request object without types.
*/
- public AcknowledgedResponse putTemplate(PutIndexTemplateRequest putIndexTemplateRequest,
- RequestOptions options) throws IOException {
+ @Deprecated
+ public AcknowledgedResponse putTemplate(
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putIndexTemplateRequest,
+ RequestOptions options) throws IOException {
return restHighLevelClient.performRequestAndParseEntity(putIndexTemplateRequest, IndicesRequestConverters::putTemplate, options,
AcknowledgedResponse::fromXContent, emptySet());
}
@@ -1377,9 +1382,44 @@ public AcknowledgedResponse putTemplate(PutIndexTemplateRequest putIndexTemplate
* @param putIndexTemplateRequest the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
+ * @deprecated This old form of request allows types in mappings.
+ * Use {@link #putTemplateAsync(PutIndexTemplateRequest, RequestOptions, ActionListener)}
+ * instead which introduces a new request object without types.
*/
- public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest, RequestOptions options,
- ActionListener listener) {
+ @Deprecated
+ public void putTemplateAsync(org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putIndexTemplateRequest,
+ RequestOptions options, ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(putIndexTemplateRequest, IndicesRequestConverters::putTemplate, options,
+ AcknowledgedResponse::fromXContent, listener, emptySet());
+ }
+
+
+ /**
+ * Puts an index template using the Index Templates API.
+ * See Index Templates API
+ * on elastic.co
+ * @param putIndexTemplateRequest the request
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public AcknowledgedResponse putTemplate(
+ PutIndexTemplateRequest putIndexTemplateRequest,
+ RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(putIndexTemplateRequest, IndicesRequestConverters::putTemplate, options,
+ AcknowledgedResponse::fromXContent, emptySet());
+ }
+
+ /**
+ * Asynchronously puts an index template using the Index Templates API.
+ * See Index Templates API
+ * on elastic.co
+ * @param putIndexTemplateRequest the request
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ */
+ public void putTemplateAsync(PutIndexTemplateRequest putIndexTemplateRequest,
+ RequestOptions options, ActionListener listener) {
restHighLevelClient.performRequestAsyncAndParseEntity(putIndexTemplateRequest, IndicesRequestConverters::putTemplate, options,
AcknowledgedResponse::fromXContent, listener, emptySet());
}
@@ -1415,33 +1455,74 @@ public void validateQueryAsync(ValidateQueryRequest validateQueryRequest, Reques
}
/**
- * Gets index templates using the Index Templates API
+ * Gets index templates using the Index Templates API. The mappings will be returned in a legacy deprecated format, where the
+ * mapping definition is nested under the type name.
* See Index Templates API
* on elastic.co
* @param getIndexTemplatesRequest the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @return the response
* @throws IOException in case there is a problem sending the request or parsing back the response
+ * @deprecated This method uses an old response object which still refers to types, a deprecated feature. Use
+ * {@link #getIndexTemplate(GetIndexTemplatesRequest, RequestOptions)} instead which returns a new response object
*/
- public GetIndexTemplatesResponse getTemplate(GetIndexTemplatesRequest getIndexTemplatesRequest,
- RequestOptions options) throws IOException {
- return restHighLevelClient.performRequestAndParseEntity(getIndexTemplatesRequest, IndicesRequestConverters::getTemplates,
- options, GetIndexTemplatesResponse::fromXContent, emptySet());
+ @Deprecated
+ public org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse getTemplate(
+ GetIndexTemplatesRequest getIndexTemplatesRequest, RequestOptions options) throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(getIndexTemplatesRequest,
+ IndicesRequestConverters::getTemplatesWithDocumentTypes,
+ options, org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse::fromXContent, emptySet());
}
+
+ /**
+ * Gets index templates using the Index Templates API
+ * See Index Templates API
+ * on elastic.co
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param getIndexTemplatesRequest the request
+ * @return the response
+ * @throws IOException in case there is a problem sending the request or parsing back the response
+ */
+ public GetIndexTemplatesResponse getIndexTemplate(GetIndexTemplatesRequest getIndexTemplatesRequest, RequestOptions options)
+ throws IOException {
+ return restHighLevelClient.performRequestAndParseEntity(getIndexTemplatesRequest,
+ IndicesRequestConverters::getTemplates,
+ options, GetIndexTemplatesResponse::fromXContent, emptySet());
+ }
/**
- * Asynchronously gets index templates using the Index Templates API
+ * Asynchronously gets index templates using the Index Templates API. The mappings will be returned in a legacy deprecated format,
+ * where the mapping definition is nested under the type name.
* See Index Templates API
* on elastic.co
* @param getIndexTemplatesRequest the request
* @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
* @param listener the listener to be notified upon request completion
+ * @deprecated This method uses an old response object which still refers to types, a deprecated feature. Use
+ * {@link #getIndexTemplateAsync(GetIndexTemplatesRequest, RequestOptions, ActionListener)} instead which returns a new response object
*/
+ @Deprecated
public void getTemplateAsync(GetIndexTemplatesRequest getIndexTemplatesRequest, RequestOptions options,
+ ActionListener listener) {
+ restHighLevelClient.performRequestAsyncAndParseEntity(getIndexTemplatesRequest,
+ IndicesRequestConverters::getTemplatesWithDocumentTypes,
+ options, org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse::fromXContent, listener, emptySet());
+ }
+
+ /**
+ * Asynchronously gets index templates using the Index Templates API
+ * See Index Templates API
+ * on elastic.co
+ * @param getIndexTemplatesRequest the request
+ * @param options the request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+ * @param listener the listener to be notified upon request completion
+ */
+ public void getIndexTemplateAsync(GetIndexTemplatesRequest getIndexTemplatesRequest, RequestOptions options,
ActionListener listener) {
- restHighLevelClient.performRequestAsyncAndParseEntity(getIndexTemplatesRequest, IndicesRequestConverters::getTemplates,
+ restHighLevelClient.performRequestAsyncAndParseEntity(getIndexTemplatesRequest,
+ IndicesRequestConverters::getTemplates,
options, GetIndexTemplatesResponse::fromXContent, listener, emptySet());
- }
+ }
/**
* Uses the Index Templates API to determine if index templates exist
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java
index d26f9babed889..d8eb625c2ff4e 100644
--- a/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IndicesRequestConverters.java
@@ -43,7 +43,6 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
-import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.client.indices.CreateIndexRequest;
@@ -51,6 +50,7 @@
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
+import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
import org.elasticsearch.common.Strings;
@@ -423,6 +423,28 @@ static Request indexPutSettings(UpdateSettingsRequest updateSettingsRequest) thr
return request;
}
+ /**
+ * @deprecated This uses the old form of PutIndexTemplateRequest which uses types.
+ * Use (@link {@link #putTemplate(PutIndexTemplateRequest)} instead
+ */
+ @Deprecated
+ static Request putTemplate(org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putIndexTemplateRequest)
+ throws IOException {
+ String endpoint = new RequestConverters.EndpointBuilder().addPathPartAsIs("_template")
+ .addPathPart(putIndexTemplateRequest.name()).build();
+ Request request = new Request(HttpPut.METHOD_NAME, endpoint);
+ RequestConverters.Params params = new RequestConverters.Params(request);
+ params.withMasterTimeout(putIndexTemplateRequest.masterNodeTimeout());
+ if (putIndexTemplateRequest.create()) {
+ params.putParam("create", Boolean.TRUE.toString());
+ }
+ if (Strings.hasText(putIndexTemplateRequest.cause())) {
+ params.putParam("cause", putIndexTemplateRequest.cause());
+ }
+ request.setEntity(RequestConverters.createEntity(putIndexTemplateRequest, RequestConverters.REQUEST_BODY_CONTENT_TYPE));
+ return request;
+ }
+
static Request putTemplate(PutIndexTemplateRequest putIndexTemplateRequest) throws IOException {
String endpoint = new RequestConverters.EndpointBuilder().addPathPartAsIs("_template")
.addPathPart(putIndexTemplateRequest.name()).build();
@@ -464,7 +486,16 @@ static Request getAlias(GetAliasesRequest getAliasesRequest) {
return request;
}
+ @Deprecated
+ static Request getTemplatesWithDocumentTypes(GetIndexTemplatesRequest getIndexTemplatesRequest) {
+ return getTemplates(getIndexTemplatesRequest, true);
+ }
+
static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest) {
+ return getTemplates(getIndexTemplatesRequest, false);
+ }
+
+ private static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest, boolean includeTypeName) {
final String endpoint = new RequestConverters.EndpointBuilder()
.addPathPartAsIs("_template")
.addCommaSeparatedPathParts(getIndexTemplatesRequest.names())
@@ -473,8 +504,9 @@ static Request getTemplates(GetIndexTemplatesRequest getIndexTemplatesRequest) {
final RequestConverters.Params params = new RequestConverters.Params(request);
params.withLocal(getIndexTemplatesRequest.isLocal());
params.withMasterTimeout(getIndexTemplatesRequest.getMasterNodeTimeout());
+ params.withIncludeTypeName(includeTypeName);
return request;
- }
+ }
static Request templatesExist(IndexTemplatesExistRequest indexTemplatesExistRequest) {
final String endpoint = new RequestConverters.EndpointBuilder()
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetIndexTemplatesResponse.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetIndexTemplatesResponse.java
new file mode 100644
index 0000000000000..ef283b31c0634
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/GetIndexTemplatesResponse.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.elasticsearch.client.indices;
+
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+
+public class GetIndexTemplatesResponse {
+
+ @Override
+ public String toString() {
+ List thisList = new ArrayList<>(this.indexTemplates);
+ thisList.sort(Comparator.comparing(IndexTemplateMetaData::name));
+ return "GetIndexTemplatesResponse [indexTemplates=" + thisList + "]";
+ }
+
+ private final List indexTemplates;
+
+ GetIndexTemplatesResponse() {
+ indexTemplates = new ArrayList<>();
+ }
+
+ GetIndexTemplatesResponse(List indexTemplates) {
+ this.indexTemplates = indexTemplates;
+ }
+
+ public List getIndexTemplates() {
+ return indexTemplates;
+ }
+
+
+ public static GetIndexTemplatesResponse fromXContent(XContentParser parser) throws IOException {
+ final List templates = new ArrayList<>();
+ for (XContentParser.Token token = parser.nextToken(); token != XContentParser.Token.END_OBJECT; token = parser.nextToken()) {
+ if (token == XContentParser.Token.FIELD_NAME) {
+ final IndexTemplateMetaData templateMetaData = IndexTemplateMetaData.Builder.fromXContent(parser, parser.currentName());
+ templates.add(templateMetaData);
+ }
+ }
+ return new GetIndexTemplatesResponse(templates);
+ }
+
+ @Override
+ public int hashCode() {
+ List sortedList = new ArrayList<>(this.indexTemplates);
+ sortedList.sort(Comparator.comparing(IndexTemplateMetaData::name));
+ return Objects.hash(sortedList);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ // To compare results we need to make sure the templates are listed in the same order
+ GetIndexTemplatesResponse other = (GetIndexTemplatesResponse) obj;
+ List thisList = new ArrayList<>(this.indexTemplates);
+ List otherList = new ArrayList<>(other.indexTemplates);
+ thisList.sort(Comparator.comparing(IndexTemplateMetaData::name));
+ otherList.sort(Comparator.comparing(IndexTemplateMetaData::name));
+ return Objects.equals(thisList, otherList);
+ }
+
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/IndexTemplateMetaData.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/IndexTemplateMetaData.java
new file mode 100644
index 0000000000000..12fc747ab3473
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/IndexTemplateMetaData.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.elasticsearch.client.indices;
+
+import org.elasticsearch.ElasticsearchParseException;
+import org.elasticsearch.cluster.metadata.AliasMetaData;
+import org.elasticsearch.cluster.metadata.IndexMetaData;
+import org.elasticsearch.cluster.metadata.MappingMetaData;
+import org.elasticsearch.common.Nullable;
+import org.elasticsearch.common.collect.ImmutableOpenMap;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.util.set.Sets;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.index.mapper.MapperService;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+public class IndexTemplateMetaData {
+
+
+ private final String name;
+
+ private final int order;
+
+ /**
+ * The version is an arbitrary number managed by the user so that they can easily and quickly verify the existence of a given template.
+ * Expected usage:
+ *
+ * PUT /_template/my_template
+ * {
+ * "index_patterns": ["my_index-*"],
+ * "mappings": { ... },
+ * "version": 1
+ * }
+ *
+ * Then, some process from the user can occasionally verify that the template exists with the appropriate version without having to
+ * check the template's content:
+ *
+ * GET /_template/my_template?filter_path=*.version
+ *
+ */
+ @Nullable
+ private final Integer version;
+
+ private final List patterns;
+
+ private final Settings settings;
+
+ private final MappingMetaData mappings;
+
+ private final ImmutableOpenMap aliases;
+
+ public IndexTemplateMetaData(String name, int order, Integer version,
+ List patterns, Settings settings,
+ MappingMetaData mappings,
+ ImmutableOpenMap aliases) {
+ if (patterns == null || patterns.isEmpty()) {
+ throw new IllegalArgumentException("Index patterns must not be null or empty; got " + patterns);
+ }
+ this.name = name;
+ this.order = order;
+ this.version = version;
+ this.patterns= patterns;
+ this.settings = settings;
+ this.mappings = mappings;
+ this.aliases = aliases;
+ }
+
+ public String name() {
+ return this.name;
+ }
+
+ public int order() {
+ return this.order;
+ }
+
+ @Nullable
+ public Integer version() {
+ return version;
+ }
+
+ public List patterns() {
+ return this.patterns;
+ }
+
+ public Settings settings() {
+ return this.settings;
+ }
+
+ public MappingMetaData mappings() {
+ return this.mappings;
+ }
+
+ public ImmutableOpenMap aliases() {
+ return this.aliases;
+ }
+
+ public static Builder builder(String name) {
+ return new Builder(name);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ IndexTemplateMetaData that = (IndexTemplateMetaData) o;
+
+ if (order != that.order) return false;
+ if (!Objects.equals(mappings, that.mappings)) return false;
+ if (!name.equals(that.name)) return false;
+ if (!settings.equals(that.settings)) return false;
+ if (!patterns.equals(that.patterns)) return false;
+
+ return Objects.equals(version, that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(name, order, version, patterns, settings, mappings);
+ }
+
+ public static class Builder {
+
+ private static final Set VALID_FIELDS = Sets.newHashSet(
+ "template", "order", "mappings", "settings", "index_patterns", "aliases", "version");
+
+ private String name;
+
+ private int order;
+
+ private Integer version;
+
+ private List indexPatterns;
+
+ private Settings settings = Settings.Builder.EMPTY_SETTINGS;
+
+ private MappingMetaData mappings;
+
+ private final ImmutableOpenMap.Builder aliases;
+
+ public Builder(String name) {
+ this.name = name;
+ mappings = null;
+ aliases = ImmutableOpenMap.builder();
+ }
+
+ public Builder(IndexTemplateMetaData indexTemplateMetaData) {
+ this.name = indexTemplateMetaData.name();
+ order(indexTemplateMetaData.order());
+ version(indexTemplateMetaData.version());
+ patterns(indexTemplateMetaData.patterns());
+ settings(indexTemplateMetaData.settings());
+
+ mappings = indexTemplateMetaData.mappings();
+ aliases = ImmutableOpenMap.builder(indexTemplateMetaData.aliases());
+ }
+
+ public Builder order(int order) {
+ this.order = order;
+ return this;
+ }
+
+ public Builder version(Integer version) {
+ this.version = version;
+ return this;
+ }
+
+ public Builder patterns(List indexPatterns) {
+ this.indexPatterns = indexPatterns;
+ return this;
+ }
+
+
+ public Builder settings(Settings.Builder settings) {
+ this.settings = settings.build();
+ return this;
+ }
+
+ public Builder settings(Settings settings) {
+ this.settings = settings;
+ return this;
+ }
+
+ public Builder mapping(MappingMetaData mappings) {
+ this.mappings = mappings;
+ return this;
+ }
+
+ public Builder putAlias(AliasMetaData aliasMetaData) {
+ aliases.put(aliasMetaData.alias(), aliasMetaData);
+ return this;
+ }
+
+ public Builder putAlias(AliasMetaData.Builder aliasMetaData) {
+ aliases.put(aliasMetaData.alias(), aliasMetaData.build());
+ return this;
+ }
+
+ public IndexTemplateMetaData build() {
+ return new IndexTemplateMetaData(name, order, version, indexPatterns, settings, mappings, aliases.build());
+ }
+
+
+ public static IndexTemplateMetaData fromXContent(XContentParser parser, String templateName) throws IOException {
+ Builder builder = new Builder(templateName);
+
+ String currentFieldName = skipTemplateName(parser);
+ XContentParser.Token token;
+ while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ if (token == XContentParser.Token.FIELD_NAME) {
+ currentFieldName = parser.currentName();
+ } else if (token == XContentParser.Token.START_OBJECT) {
+ if ("settings".equals(currentFieldName)) {
+ Settings.Builder templateSettingsBuilder = Settings.builder();
+ templateSettingsBuilder.put(Settings.fromXContent(parser));
+ templateSettingsBuilder.normalizePrefix(IndexMetaData.INDEX_SETTING_PREFIX);
+ builder.settings(templateSettingsBuilder.build());
+ } else if ("mappings".equals(currentFieldName)) {
+ Map mapping = parser.map();
+ if (mapping.isEmpty() == false) {
+ MappingMetaData md = new MappingMetaData(MapperService.SINGLE_MAPPING_NAME, mapping);
+ builder.mapping(md);
+ }
+ } else if ("aliases".equals(currentFieldName)) {
+ while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ builder.putAlias(AliasMetaData.Builder.fromXContent(parser));
+ }
+ } else {
+ throw new ElasticsearchParseException("unknown key [{}] for index template", currentFieldName);
+ }
+ } else if (token == XContentParser.Token.START_ARRAY) {
+ if ("mappings".equals(currentFieldName)) {
+ // The server-side IndexTemplateMetaData has toXContent impl that can return mappings
+ // in an array but also a comment saying this never happens with typeless APIs.
+ throw new ElasticsearchParseException("Invalid response format - "
+ + "mappings are not expected to be returned in an array", currentFieldName);
+ } else if ("index_patterns".equals(currentFieldName)) {
+ List index_patterns = new ArrayList<>();
+ while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
+ index_patterns.add(parser.text());
+ }
+ builder.patterns(index_patterns);
+ }
+ } else if (token.isValue()) {
+ // Prior to 5.1.0, elasticsearch only supported a single index pattern called `template` (#21009)
+ if("template".equals(currentFieldName)) {
+ builder.patterns(Collections.singletonList(parser.text()));
+ } else if ("order".equals(currentFieldName)) {
+ builder.order(parser.intValue());
+ } else if ("version".equals(currentFieldName)) {
+ builder.version(parser.intValue());
+ }
+ }
+ }
+ return builder.build();
+ }
+
+ private static String skipTemplateName(XContentParser parser) throws IOException {
+ XContentParser.Token token = parser.nextToken();
+ if (token == XContentParser.Token.START_OBJECT) {
+ token = parser.nextToken();
+ if (token == XContentParser.Token.FIELD_NAME) {
+ String currentFieldName = parser.currentName();
+ if (VALID_FIELDS.contains(currentFieldName)) {
+ return currentFieldName;
+ } else {
+ // we just hit the template name, which should be ignored and we move on
+ parser.nextToken();
+ }
+ }
+ }
+
+ return null;
+ }
+ }
+
+}
diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutIndexTemplateRequest.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutIndexTemplateRequest.java
new file mode 100644
index 0000000000000..5f22691b046eb
--- /dev/null
+++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/indices/PutIndexTemplateRequest.java
@@ -0,0 +1,453 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.elasticsearch.client.indices;
+
+import org.elasticsearch.ElasticsearchGenerationException;
+import org.elasticsearch.ElasticsearchParseException;
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.IndicesRequest;
+import org.elasticsearch.action.admin.indices.alias.Alias;
+import org.elasticsearch.action.support.IndicesOptions;
+import org.elasticsearch.action.support.master.MasterNodeRequest;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.bytes.BytesReference;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.DeprecationHandler;
+import org.elasticsearch.common.xcontent.NamedXContentRegistry;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
+import org.elasticsearch.common.xcontent.support.XContentMapValues;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static org.elasticsearch.action.ValidateActions.addValidationError;
+import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;
+
+/**
+ * A request to create an index template.
+ */
+public class PutIndexTemplateRequest extends MasterNodeRequest implements IndicesRequest, ToXContent {
+
+ private String name;
+
+ private String cause = "";
+
+ private List indexPatterns;
+
+ private int order;
+
+ private boolean create;
+
+ private Settings settings = EMPTY_SETTINGS;
+
+ private BytesReference mappings = null;
+
+ private final Set aliases = new HashSet<>();
+
+ private Integer version;
+
+ /**
+ * Constructs a new put index template request with the provided name.
+ */
+ public PutIndexTemplateRequest(String name) {
+ this.name(name);
+ }
+
+ @Override
+ public ActionRequestValidationException validate() {
+ ActionRequestValidationException validationException = null;
+ if (indexPatterns == null || indexPatterns.size() == 0) {
+ validationException = addValidationError("index patterns are missing", validationException);
+ }
+ return validationException;
+ }
+
+ /**
+ * Sets the name of the index template.
+ */
+ public PutIndexTemplateRequest name(String name) {
+ if(name == null) {
+ throw new IllegalArgumentException("Name cannot be null");
+ }
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * The name of the index template.
+ */
+ public String name() {
+ return this.name;
+ }
+
+ public PutIndexTemplateRequest patterns(List indexPatterns) {
+ this.indexPatterns = indexPatterns;
+ return this;
+ }
+
+ public List patterns() {
+ return this.indexPatterns;
+ }
+
+ public PutIndexTemplateRequest order(int order) {
+ this.order = order;
+ return this;
+ }
+
+ public int order() {
+ return this.order;
+ }
+
+ public PutIndexTemplateRequest version(Integer version) {
+ this.version = version;
+ return this;
+ }
+
+ public Integer version() {
+ return this.version;
+ }
+
+ /**
+ * Set to {@code true} to force only creation, not an update of an index template. If it already
+ * exists, it will fail with an {@link IllegalArgumentException}.
+ */
+ public PutIndexTemplateRequest create(boolean create) {
+ this.create = create;
+ return this;
+ }
+
+ public boolean create() {
+ return create;
+ }
+
+ /**
+ * The settings to create the index template with.
+ */
+ public PutIndexTemplateRequest settings(Settings settings) {
+ this.settings = settings;
+ return this;
+ }
+
+ /**
+ * The settings to create the index template with.
+ */
+ public PutIndexTemplateRequest settings(Settings.Builder settings) {
+ this.settings = settings.build();
+ return this;
+ }
+
+ /**
+ * The settings to create the index template with (either json/yaml format).
+ */
+ public PutIndexTemplateRequest settings(String source, XContentType xContentType) {
+ this.settings = Settings.builder().loadFromSource(source, xContentType).build();
+ return this;
+ }
+
+ /**
+ * The settings to create the index template with (either json or yaml format).
+ */
+ public PutIndexTemplateRequest settings(Map source) {
+ try {
+ XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
+ builder.map(source);
+ settings(Strings.toString(builder), XContentType.JSON);
+ } catch (IOException e) {
+ throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
+ }
+ return this;
+ }
+
+ public Settings settings() {
+ return this.settings;
+ }
+
+ /**
+ * Adds mapping that will be added when the index gets created.
+ *
+ * @param source The mapping source
+ * @param xContentType The type of content contained within the source
+ */
+ public PutIndexTemplateRequest mapping(String source, XContentType xContentType) {
+ internalMapping(XContentHelper.convertToMap(new BytesArray(source), true, xContentType).v2());
+ return this;
+ }
+
+ /**
+ * The cause for this index template creation.
+ */
+ public PutIndexTemplateRequest cause(String cause) {
+ this.cause = cause;
+ return this;
+ }
+
+ public String cause() {
+ return this.cause;
+ }
+
+ /**
+ * Adds mapping that will be added when the index gets created.
+ *
+ * @param source The mapping source
+ */
+ public PutIndexTemplateRequest mapping(XContentBuilder source) {
+ internalMapping(XContentHelper.convertToMap(BytesReference.bytes(source),
+ true, source.contentType()).v2());
+ return this;
+ }
+
+ /**
+ * Adds mapping that will be added when the index gets created.
+ *
+ * @param source The mapping source
+ * @param xContentType the source content type
+ */
+ public PutIndexTemplateRequest mapping(BytesReference source, XContentType xContentType) {
+ internalMapping(XContentHelper.convertToMap(source, true, xContentType).v2());
+ return this;
+ }
+
+ /**
+ * Adds mapping that will be added when the index gets created.
+ *
+ * @param source The mapping source
+ */
+ public PutIndexTemplateRequest mapping(Map source) {
+ return internalMapping(source);
+ }
+
+ private PutIndexTemplateRequest internalMapping(Map source) {
+ try {
+ XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
+ builder.map(source);
+ Objects.requireNonNull(builder.contentType());
+ try {
+ mappings = new BytesArray(
+ XContentHelper.convertToJson(BytesReference.bytes(builder), false, false, builder.contentType()));
+ return this;
+ } catch (IOException e) {
+ throw new UncheckedIOException("failed to convert source to json", e);
+ }
+ } catch (IOException e) {
+ throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
+ }
+ }
+
+ public BytesReference mappings() {
+ return this.mappings;
+ }
+
+ /**
+ * The template source definition.
+ */
+ public PutIndexTemplateRequest source(XContentBuilder templateBuilder) {
+ try {
+ return source(BytesReference.bytes(templateBuilder), templateBuilder.contentType());
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Failed to build json for template request", e);
+ }
+ }
+
+ /**
+ * The template source definition.
+ */
+ @SuppressWarnings("unchecked")
+ public PutIndexTemplateRequest source(Map templateSource) {
+ Map source = templateSource;
+ for (Map.Entry entry : source.entrySet()) {
+ String name = entry.getKey();
+ if (name.equals("template")) {
+ if(entry.getValue() instanceof String) {
+ patterns(Collections.singletonList((String) entry.getValue()));
+ }
+ } else if (name.equals("index_patterns")) {
+ if(entry.getValue() instanceof String) {
+ patterns(Collections.singletonList((String) entry.getValue()));
+ } else if (entry.getValue() instanceof List) {
+ List elements = ((List>) entry.getValue()).stream().map(Object::toString).collect(Collectors.toList());
+ patterns(elements);
+ } else {
+ throw new IllegalArgumentException("Malformed [template] value, should be a string or a list of strings");
+ }
+ } else if (name.equals("order")) {
+ order(XContentMapValues.nodeIntegerValue(entry.getValue(), order()));
+ } else if ("version".equals(name)) {
+ if ((entry.getValue() instanceof Integer) == false) {
+ throw new IllegalArgumentException("Malformed [version] value, should be an integer");
+ }
+ version((Integer)entry.getValue());
+ } else if (name.equals("settings")) {
+ if ((entry.getValue() instanceof Map) == false) {
+ throw new IllegalArgumentException("Malformed [settings] section, should include an inner object");
+ }
+ settings((Map) entry.getValue());
+ } else if (name.equals("mappings")) {
+ Map mappings = (Map) entry.getValue();
+ mapping(mappings);
+ } else if (name.equals("aliases")) {
+ aliases((Map) entry.getValue());
+ } else {
+ throw new ElasticsearchParseException("unknown key [{}] in the template ", name);
+ }
+ }
+ return this;
+ }
+
+ /**
+ * The template source definition.
+ */
+ public PutIndexTemplateRequest source(String templateSource, XContentType xContentType) {
+ return source(XContentHelper.convertToMap(xContentType.xContent(), templateSource, true));
+ }
+
+ /**
+ * The template source definition.
+ */
+ public PutIndexTemplateRequest source(byte[] source, XContentType xContentType) {
+ return source(source, 0, source.length, xContentType);
+ }
+
+ /**
+ * The template source definition.
+ */
+ public PutIndexTemplateRequest source(byte[] source, int offset, int length, XContentType xContentType) {
+ return source(new BytesArray(source, offset, length), xContentType);
+ }
+
+ /**
+ * The template source definition.
+ */
+ public PutIndexTemplateRequest source(BytesReference source, XContentType xContentType) {
+ return source(XContentHelper.convertToMap(source, true, xContentType).v2());
+ }
+
+
+ public Set aliases() {
+ return this.aliases;
+ }
+
+ /**
+ * Sets the aliases that will be associated with the index when it gets created
+ */
+ public PutIndexTemplateRequest aliases(Map source) {
+ try {
+ XContentBuilder builder = XContentFactory.jsonBuilder();
+ builder.map(source);
+ return aliases(BytesReference.bytes(builder));
+ } catch (IOException e) {
+ throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
+ }
+ }
+
+ /**
+ * Sets the aliases that will be associated with the index when it gets created
+ */
+ public PutIndexTemplateRequest aliases(XContentBuilder source) {
+ return aliases(BytesReference.bytes(source));
+ }
+
+ /**
+ * Sets the aliases that will be associated with the index when it gets created
+ */
+ public PutIndexTemplateRequest aliases(String source) {
+ return aliases(new BytesArray(source));
+ }
+
+ /**
+ * Sets the aliases that will be associated with the index when it gets created
+ */
+ public PutIndexTemplateRequest aliases(BytesReference source) {
+ // EMPTY is safe here because we never call namedObject
+ try (XContentParser parser = XContentHelper
+ .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, source)) {
+ //move to the first alias
+ parser.nextToken();
+ while ((parser.nextToken()) != XContentParser.Token.END_OBJECT) {
+ alias(Alias.fromXContent(parser));
+ }
+ return this;
+ } catch(IOException e) {
+ throw new ElasticsearchParseException("Failed to parse aliases", e);
+ }
+ }
+
+ /**
+ * Adds an alias that will be added when the index gets created.
+ *
+ * @param alias The metadata for the new alias
+ * @return the index template creation request
+ */
+ public PutIndexTemplateRequest alias(Alias alias) {
+ aliases.add(alias);
+ return this;
+ }
+
+ @Override
+ public String[] indices() {
+ return indexPatterns.toArray(new String[indexPatterns.size()]);
+ }
+
+ @Override
+ public IndicesOptions indicesOptions() {
+ return IndicesOptions.strictExpand();
+ }
+
+ @Override
+ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+ builder.field("index_patterns", indexPatterns);
+ builder.field("order", order);
+ if (version != null) {
+ builder.field("version", version);
+ }
+
+ builder.startObject("settings");
+ settings.toXContent(builder, params);
+ builder.endObject();
+
+ if (mappings != null) {
+ builder.field("mappings");
+ try (XContentParser parser = JsonXContent.jsonXContent.createParser(NamedXContentRegistry.EMPTY,
+ DeprecationHandler.THROW_UNSUPPORTED_OPERATION, mappings.utf8ToString())) {
+ builder.copyCurrentStructure(parser);
+ }
+ }
+
+ builder.startObject("aliases");
+ for (Alias alias : aliases) {
+ alias.toXContent(builder, params);
+ }
+ builder.endObject();
+
+ return builder;
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
index c549399d193a4..9cb3c08afed45 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesClientIT.java
@@ -56,8 +56,6 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
-import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
-import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
import org.elasticsearch.action.index.IndexRequest;
@@ -73,12 +71,14 @@
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.GetMappingsResponse;
+import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
+import org.elasticsearch.client.indices.IndexTemplateMetaData;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
+import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.IndexMetaData;
-import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
import org.elasticsearch.common.ValidationException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.settings.Setting;
@@ -87,6 +87,7 @@
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.IndexSettings;
@@ -98,6 +99,8 @@
import org.elasticsearch.rest.action.admin.indices.RestGetFieldMappingAction;
import org.elasticsearch.rest.action.admin.indices.RestGetMappingAction;
import org.elasticsearch.rest.action.admin.indices.RestPutMappingAction;
+import org.elasticsearch.rest.action.admin.indices.RestGetIndexTemplateAction;
+import org.elasticsearch.rest.action.admin.indices.RestPutIndexTemplateAction;
import java.io.IOException;
import java.util.Arrays;
@@ -1445,8 +1448,9 @@ public void testIndexPutSettingNonExistent() throws IOException {
}
@SuppressWarnings("unchecked")
- public void testPutTemplate() throws Exception {
- PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest()
+ public void testPutTemplateWithTypes() throws Exception {
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putTemplateRequest =
+ new org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest()
.name("my-template")
.patterns(Arrays.asList("pattern-1", "name-*"))
.order(10)
@@ -1456,7 +1460,9 @@ public void testPutTemplate() throws Exception {
.alias(new Alias("alias-1").indexRouting("abc")).alias(new Alias("{index}-write").searchRouting("xyz"));
AcknowledgedResponse putTemplateResponse = execute(putTemplateRequest,
- highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync);
+ highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync,
+ expectWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE)
+ );
assertThat(putTemplateResponse.isAcknowledged(), equalTo(true));
Map templates = getAsMap("/_template/my-template");
@@ -1470,6 +1476,94 @@ public void testPutTemplate() throws Exception {
assertThat((Map) extractValue("my-template.aliases.alias-1", templates), hasEntry("index_routing", "abc"));
assertThat((Map) extractValue("my-template.aliases.{index}-write", templates), hasEntry("search_routing", "xyz"));
}
+
+ @SuppressWarnings("unchecked")
+ public void testPutTemplate() throws Exception {
+ PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest("my-template")
+ .patterns(Arrays.asList("pattern-1", "name-*"))
+ .order(10)
+ .create(randomBoolean())
+ .settings(Settings.builder().put("number_of_shards", "3").put("number_of_replicas", "0"))
+ .mapping("{ \"properties\":{"
+ + "\"host_name\": {\"type\":\"keyword\"}"
+ + "}"
+ + "}", XContentType.JSON)
+ .alias(new Alias("alias-1").indexRouting("abc")).alias(new Alias("{index}-write").searchRouting("xyz"));
+
+ AcknowledgedResponse putTemplateResponse = execute(putTemplateRequest,
+ highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync);
+ assertThat(putTemplateResponse.isAcknowledged(), equalTo(true));
+
+ Map templates = getAsMap("/_template/my-template");
+ assertThat(templates.keySet(), hasSize(1));
+ assertThat(extractValue("my-template.order", templates), equalTo(10));
+ assertThat(extractRawValues("my-template.index_patterns", templates), contains("pattern-1", "name-*"));
+ assertThat(extractValue("my-template.settings.index.number_of_shards", templates), equalTo("3"));
+ assertThat(extractValue("my-template.settings.index.number_of_replicas", templates), equalTo("0"));
+ assertThat(extractValue("my-template.mappings.properties.host_name.type", templates), equalTo("keyword"));
+ assertThat((Map) extractValue("my-template.aliases.alias-1", templates), hasEntry("index_routing", "abc"));
+ assertThat((Map) extractValue("my-template.aliases.{index}-write", templates), hasEntry("search_routing", "xyz"));
+ }
+
+ public void testPutTemplateWithTypesUsingUntypedAPI() throws Exception {
+ PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest("my-template")
+ .patterns(Arrays.asList("pattern-1", "name-*"))
+ .order(10)
+ .create(randomBoolean())
+ .settings(Settings.builder().put("number_of_shards", "3").put("number_of_replicas", "0"))
+ .mapping("{ "
+ + "\"my_doc_type\":{"
+ + "\"properties\":{"
+ + "\"host_name\": {\"type\":\"keyword\"}"
+ + "}"
+ + "}"
+ + "}", XContentType.JSON)
+ .alias(new Alias("alias-1").indexRouting("abc")).alias(new Alias("{index}-write").searchRouting("xyz"));
+
+
+ ElasticsearchStatusException badMappingError = expectThrows(ElasticsearchStatusException.class,
+ () -> execute(putTemplateRequest,
+ highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync));
+ assertThat(badMappingError.getDetailedMessage(),
+ containsString("Root mapping definition has unsupported parameters: [my_doc_type"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testPutTemplateWithNoTypesUsingTypedApi() throws Exception {
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putTemplateRequest =
+ new org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest()
+ .name("my-template")
+ .patterns(Arrays.asList("pattern-1", "name-*"))
+ .order(10)
+ .create(randomBoolean())
+ .settings(Settings.builder().put("number_of_shards", "3").put("number_of_replicas", "0"))
+ .mapping("my_doc_type",
+ // Note that the declared type is missing from the mapping
+ "{ "
+ + "\"properties\":{"
+ + "\"host_name\": {\"type\":\"keyword\"},"
+ + "\"description\": {\"type\":\"text\"}"
+ + "}"
+ + "}", XContentType.JSON)
+ .alias(new Alias("alias-1").indexRouting("abc")).alias(new Alias("{index}-write").searchRouting("xyz"));
+
+ AcknowledgedResponse putTemplateResponse = execute(putTemplateRequest,
+ highLevelClient().indices()::putTemplate, highLevelClient().indices()::putTemplateAsync,
+ expectWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE)
+ );
+ assertThat(putTemplateResponse.isAcknowledged(), equalTo(true));
+
+ Map templates = getAsMap("/_template/my-template");
+ assertThat(templates.keySet(), hasSize(1));
+ assertThat(extractValue("my-template.order", templates), equalTo(10));
+ assertThat(extractRawValues("my-template.index_patterns", templates), contains("pattern-1", "name-*"));
+ assertThat(extractValue("my-template.settings.index.number_of_shards", templates), equalTo("3"));
+ assertThat(extractValue("my-template.settings.index.number_of_replicas", templates), equalTo("0"));
+ assertThat(extractValue("my-template.mappings.properties.host_name.type", templates), equalTo("keyword"));
+ assertThat(extractValue("my-template.mappings.properties.description.type", templates), equalTo("text"));
+ assertThat((Map) extractValue("my-template.aliases.alias-1", templates), hasEntry("index_routing", "abc"));
+ assertThat((Map) extractValue("my-template.aliases.{index}-write", templates), hasEntry("search_routing", "xyz"));
+ }
public void testPutTemplateBadRequests() throws Exception {
RestHighLevelClient client = highLevelClient();
@@ -1534,68 +1628,168 @@ public void testInvalidValidateQuery() throws IOException{
assertFalse(response.isValid());
}
+ // Tests the deprecated form of the API that returns templates with doc types (using the server-side's GetIndexTemplateResponse)
+ public void testCRUDIndexTemplateWithTypes() throws Exception {
+ RestHighLevelClient client = highLevelClient();
+
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putTemplate1 =
+ new org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest().name("template-1")
+ .patterns(Arrays.asList("pattern-1", "name-1")).alias(new Alias("alias-1"));
+ assertThat(execute(putTemplate1, client.indices()::putTemplate, client.indices()::putTemplateAsync
+ , expectWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE))
+ .isAcknowledged(), equalTo(true));
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putTemplate2 =
+ new org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest().name("template-2")
+ .patterns(Arrays.asList("pattern-2", "name-2"))
+ .mapping("custom_doc_type", "name", "type=text")
+ .settings(Settings.builder().put("number_of_shards", "2").put("number_of_replicas", "0"));
+ assertThat(execute(putTemplate2, client.indices()::putTemplate, client.indices()::putTemplateAsync,
+ expectWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE))
+ .isAcknowledged(), equalTo(true));
+
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse getTemplate1 = execute(
+ new GetIndexTemplatesRequest("template-1"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE));
+ assertThat(getTemplate1.getIndexTemplates(), hasSize(1));
+ org.elasticsearch.cluster.metadata.IndexTemplateMetaData template1 = getTemplate1.getIndexTemplates().get(0);
+ assertThat(template1.name(), equalTo("template-1"));
+ assertThat(template1.patterns(), contains("pattern-1", "name-1"));
+ assertTrue(template1.aliases().containsKey("alias-1"));
+
+ //Check the typed version of the call
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse getTemplate2 =
+ execute(new GetIndexTemplatesRequest("template-2"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE));
+ assertThat(getTemplate2.getIndexTemplates(), hasSize(1));
+ org.elasticsearch.cluster.metadata.IndexTemplateMetaData template2 = getTemplate2.getIndexTemplates().get(0);
+ assertThat(template2.name(), equalTo("template-2"));
+ assertThat(template2.patterns(), contains("pattern-2", "name-2"));
+ assertTrue(template2.aliases().isEmpty());
+ assertThat(template2.settings().get("index.number_of_shards"), equalTo("2"));
+ assertThat(template2.settings().get("index.number_of_replicas"), equalTo("0"));
+ // Ugly deprecated form of API requires use of doc type to get at mapping object which is CompressedXContent
+ assertTrue(template2.mappings().containsKey("custom_doc_type"));
+
+ List names = randomBoolean()
+ ? Arrays.asList("*-1", "template-2")
+ : Arrays.asList("template-*");
+ GetIndexTemplatesRequest getBothRequest = new GetIndexTemplatesRequest(names);
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse getBoth = execute(
+ getBothRequest, client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE));
+ assertThat(getBoth.getIndexTemplates(), hasSize(2));
+ assertThat(getBoth.getIndexTemplates().stream().map(org.elasticsearch.cluster.metadata.IndexTemplateMetaData::getName).toArray(),
+ arrayContainingInAnyOrder("template-1", "template-2"));
+
+ GetIndexTemplatesRequest getAllRequest = new GetIndexTemplatesRequest();
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse getAll = execute(
+ getAllRequest, client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE));
+ assertThat(getAll.getIndexTemplates().size(), greaterThanOrEqualTo(2));
+ assertThat(getAll.getIndexTemplates().stream().map(org.elasticsearch.cluster.metadata.IndexTemplateMetaData::getName)
+ .collect(Collectors.toList()),
+ hasItems("template-1", "template-2"));
+
+ assertTrue(execute(new DeleteIndexTemplateRequest("template-1"),
+ client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync).isAcknowledged());
+ assertThat(expectThrows(ElasticsearchException.class, () -> execute(new GetIndexTemplatesRequest("template-1"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
+ assertThat(expectThrows(ElasticsearchException.class, () -> execute(new DeleteIndexTemplateRequest("template-1"),
+ client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
+
+ assertThat(execute(new GetIndexTemplatesRequest("template-*"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE)).getIndexTemplates(), hasSize(1));
+ assertThat(execute(new GetIndexTemplatesRequest("template-*"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE)).getIndexTemplates()
+ .get(0).name(), equalTo("template-2"));
+
+ assertTrue(execute(new DeleteIndexTemplateRequest("template-*"),
+ client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync).isAcknowledged());
+ assertThat(expectThrows(ElasticsearchException.class, () -> execute(new GetIndexTemplatesRequest("template-*"),
+ client.indices()::getTemplate, client.indices()::getTemplateAsync,
+ expectWarnings(RestGetIndexTemplateAction.TYPES_DEPRECATION_MESSAGE))).status(), equalTo(RestStatus.NOT_FOUND));
+ }
+
+
public void testCRUDIndexTemplate() throws Exception {
RestHighLevelClient client = highLevelClient();
- PutIndexTemplateRequest putTemplate1 = new PutIndexTemplateRequest().name("template-1")
+ PutIndexTemplateRequest putTemplate1 = new PutIndexTemplateRequest("template-1")
.patterns(Arrays.asList("pattern-1", "name-1")).alias(new Alias("alias-1"));
assertThat(execute(putTemplate1, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged(),
equalTo(true));
- PutIndexTemplateRequest putTemplate2 = new PutIndexTemplateRequest().name("template-2")
+ PutIndexTemplateRequest putTemplate2 = new PutIndexTemplateRequest("template-2")
.patterns(Arrays.asList("pattern-2", "name-2"))
+ .mapping("{\"properties\": { \"name\": { \"type\": \"text\" }}}", XContentType.JSON)
.settings(Settings.builder().put("number_of_shards", "2").put("number_of_replicas", "0"));
- assertThat(execute(putTemplate2, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged(),
- equalTo(true));
+ assertThat(execute(putTemplate2, client.indices()::putTemplate, client.indices()::putTemplateAsync)
+ .isAcknowledged(), equalTo(true));
- GetIndexTemplatesResponse getTemplate1 = execute(new GetIndexTemplatesRequest("template-1"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync);
+ GetIndexTemplatesResponse getTemplate1 = execute(
+ new GetIndexTemplatesRequest("template-1"),
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync);
assertThat(getTemplate1.getIndexTemplates(), hasSize(1));
IndexTemplateMetaData template1 = getTemplate1.getIndexTemplates().get(0);
assertThat(template1.name(), equalTo("template-1"));
assertThat(template1.patterns(), contains("pattern-1", "name-1"));
assertTrue(template1.aliases().containsKey("alias-1"));
-
+
GetIndexTemplatesResponse getTemplate2 = execute(new GetIndexTemplatesRequest("template-2"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync);
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync);
assertThat(getTemplate2.getIndexTemplates(), hasSize(1));
IndexTemplateMetaData template2 = getTemplate2.getIndexTemplates().get(0);
assertThat(template2.name(), equalTo("template-2"));
assertThat(template2.patterns(), contains("pattern-2", "name-2"));
assertTrue(template2.aliases().isEmpty());
assertThat(template2.settings().get("index.number_of_shards"), equalTo("2"));
- assertThat(template2.settings().get("index.number_of_replicas"), equalTo("0"));
+ assertThat(template2.settings().get("index.number_of_replicas"), equalTo("0"));
+ // New API returns a MappingMetaData class rather than CompressedXContent for the mapping
+ assertTrue(template2.mappings().sourceAsMap().containsKey("properties"));
+ @SuppressWarnings("unchecked")
+ Map props = (Map) template2.mappings().sourceAsMap().get("properties");
+ assertTrue(props.containsKey("name"));
+
+
List names = randomBoolean()
? Arrays.asList("*-1", "template-2")
: Arrays.asList("template-*");
GetIndexTemplatesRequest getBothRequest = new GetIndexTemplatesRequest(names);
- GetIndexTemplatesResponse getBoth = execute(getBothRequest, client.indices()::getTemplate, client.indices()::getTemplateAsync);
+ GetIndexTemplatesResponse getBoth = execute(
+ getBothRequest, client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync);
assertThat(getBoth.getIndexTemplates(), hasSize(2));
- assertThat(getBoth.getIndexTemplates().stream().map(IndexTemplateMetaData::getName).toArray(),
+ assertThat(getBoth.getIndexTemplates().stream().map(IndexTemplateMetaData::name).toArray(),
arrayContainingInAnyOrder("template-1", "template-2"));
GetIndexTemplatesRequest getAllRequest = new GetIndexTemplatesRequest();
- GetIndexTemplatesResponse getAll = execute(getAllRequest, client.indices()::getTemplate, client.indices()::getTemplateAsync);
+ GetIndexTemplatesResponse getAll = execute(
+ getAllRequest, client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync);
assertThat(getAll.getIndexTemplates().size(), greaterThanOrEqualTo(2));
- assertThat(getAll.getIndexTemplates().stream().map(IndexTemplateMetaData::getName).collect(Collectors.toList()),
+ assertThat(getAll.getIndexTemplates().stream().map(IndexTemplateMetaData::name)
+ .collect(Collectors.toList()),
hasItems("template-1", "template-2"));
assertTrue(execute(new DeleteIndexTemplateRequest("template-1"),
client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync).isAcknowledged());
assertThat(expectThrows(ElasticsearchException.class, () -> execute(new GetIndexTemplatesRequest("template-1"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
assertThat(expectThrows(ElasticsearchException.class, () -> execute(new DeleteIndexTemplateRequest("template-1"),
client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
assertThat(execute(new GetIndexTemplatesRequest("template-*"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync).getIndexTemplates(), hasSize(1));
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync).getIndexTemplates(), hasSize(1));
assertThat(execute(new GetIndexTemplatesRequest("template-*"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync).getIndexTemplates().get(0).name(), equalTo("template-2"));
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync).getIndexTemplates()
+ .get(0).name(), equalTo("template-2"));
assertTrue(execute(new DeleteIndexTemplateRequest("template-*"),
client.indices()::deleteTemplate, client.indices()::deleteTemplateAsync).isAcknowledged());
assertThat(expectThrows(ElasticsearchException.class, () -> execute(new GetIndexTemplatesRequest("template-*"),
- client.indices()::getTemplate, client.indices()::getTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
+ client.indices()::getIndexTemplate, client.indices()::getIndexTemplateAsync)).status(), equalTo(RestStatus.NOT_FOUND));
}
public void testIndexTemplatesExist() throws Exception {
@@ -1604,8 +1798,7 @@ public void testIndexTemplatesExist() throws Exception {
{
for (String suffix : Arrays.asList("1", "2")) {
- final PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest()
- .name("template-" + suffix)
+ final PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest("template-" + suffix)
.patterns(Arrays.asList("pattern-" + suffix, "name-" + suffix))
.alias(new Alias("alias-" + suffix));
assertTrue(execute(putRequest, client.indices()::putTemplate, client.indices()::putTemplateAsync).isAcknowledged());
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java
index 5ddaf873b9d65..289369398cf8b 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IndicesRequestConvertersTests.java
@@ -45,7 +45,6 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
-import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.support.ActiveShardCount;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
@@ -54,6 +53,7 @@
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
+import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.RandomCreateIndexGenerator;
import org.elasticsearch.common.CheckedFunction;
@@ -61,6 +61,7 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.CollectionUtils;
+import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import org.junit.Assert;
@@ -926,14 +927,16 @@ public void testIndexPutSettings() throws IOException {
Assert.assertEquals(expectedParams, request.getParameters());
}
- public void testPutTemplateRequest() throws Exception {
+ public void testPutTemplateRequestWithTypes() throws Exception {
Map names = new HashMap<>();
names.put("log", "log");
names.put("template#1", "template%231");
names.put("-#template", "-%23template");
names.put("foo^bar", "foo%5Ebar");
- PutIndexTemplateRequest putTemplateRequest = new PutIndexTemplateRequest().name(ESTestCase.randomFrom(names.keySet()))
+ org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest putTemplateRequest =
+ new org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest()
+ .name(ESTestCase.randomFrom(names.keySet()))
.patterns(Arrays.asList(ESTestCase.generateRandomStringArray(20, 100, false, false)));
if (ESTestCase.randomBoolean()) {
putTemplateRequest.order(ESTestCase.randomInt());
@@ -944,14 +947,15 @@ public void testPutTemplateRequest() throws Exception {
if (ESTestCase.randomBoolean()) {
putTemplateRequest.settings(Settings.builder().put("setting-" + ESTestCase.randomInt(), ESTestCase.randomTimeValue()));
}
+ Map expectedParams = new HashMap<>();
if (ESTestCase.randomBoolean()) {
putTemplateRequest.mapping("doc-" + ESTestCase.randomInt(),
"field-" + ESTestCase.randomInt(), "type=" + ESTestCase.randomFrom("text", "keyword"));
}
+ expectedParams.put(INCLUDE_TYPE_NAME_PARAMETER, "true");
if (ESTestCase.randomBoolean()) {
putTemplateRequest.alias(new Alias("alias-" + ESTestCase.randomInt()));
}
- Map expectedParams = new HashMap<>();
if (ESTestCase.randomBoolean()) {
expectedParams.put("create", Boolean.TRUE.toString());
putTemplateRequest.create(true);
@@ -960,7 +964,7 @@ public void testPutTemplateRequest() throws Exception {
String cause = ESTestCase.randomUnicodeOfCodepointLengthBetween(1, 50);
putTemplateRequest.cause(cause);
expectedParams.put("cause", cause);
- }
+ }
RequestConvertersTests.setRandomMasterTimeout(putTemplateRequest, expectedParams);
Request request = IndicesRequestConverters.putTemplate(putTemplateRequest);
Assert.assertThat(request.getEndpoint(), equalTo("/_template/" + names.get(putTemplateRequest.name())));
@@ -968,6 +972,49 @@ public void testPutTemplateRequest() throws Exception {
RequestConvertersTests.assertToXContentBody(putTemplateRequest, request.getEntity());
}
+ public void testPutTemplateRequest() throws Exception {
+ Map names = new HashMap<>();
+ names.put("log", "log");
+ names.put("template#1", "template%231");
+ names.put("-#template", "-%23template");
+ names.put("foo^bar", "foo%5Ebar");
+
+ PutIndexTemplateRequest putTemplateRequest =
+ new PutIndexTemplateRequest(ESTestCase.randomFrom(names.keySet()))
+ .patterns(Arrays.asList(ESTestCase.generateRandomStringArray(20, 100, false, false)));
+ if (ESTestCase.randomBoolean()) {
+ putTemplateRequest.order(ESTestCase.randomInt());
+ }
+ if (ESTestCase.randomBoolean()) {
+ putTemplateRequest.version(ESTestCase.randomInt());
+ }
+ if (ESTestCase.randomBoolean()) {
+ putTemplateRequest.settings(Settings.builder().put("setting-" + ESTestCase.randomInt(), ESTestCase.randomTimeValue()));
+ }
+ Map expectedParams = new HashMap<>();
+ if (ESTestCase.randomBoolean()) {
+ putTemplateRequest.mapping("{ \"properties\": { \"field-" + ESTestCase.randomInt() +
+ "\" : { \"type\" : \"" + ESTestCase.randomFrom("text", "keyword") + "\" }}}", XContentType.JSON);
+ }
+ if (ESTestCase.randomBoolean()) {
+ putTemplateRequest.alias(new Alias("alias-" + ESTestCase.randomInt()));
+ }
+ if (ESTestCase.randomBoolean()) {
+ expectedParams.put("create", Boolean.TRUE.toString());
+ putTemplateRequest.create(true);
+ }
+ if (ESTestCase.randomBoolean()) {
+ String cause = ESTestCase.randomUnicodeOfCodepointLengthBetween(1, 50);
+ putTemplateRequest.cause(cause);
+ expectedParams.put("cause", cause);
+ }
+ RequestConvertersTests.setRandomMasterTimeout(putTemplateRequest, expectedParams);
+
+ Request request = IndicesRequestConverters.putTemplate(putTemplateRequest);
+ Assert.assertThat(request.getEndpoint(), equalTo("/_template/" + names.get(putTemplateRequest.name())));
+ Assert.assertThat(request.getParameters(), equalTo(expectedParams));
+ RequestConvertersTests.assertToXContentBody(putTemplateRequest, request.getEntity());
+ }
public void testValidateQuery() throws Exception {
String[] indices = ESTestCase.randomBoolean() ? null : RequestConvertersTests.randomIndicesNames(0, 5);
String[] types = ESTestCase.randomBoolean() ? ESTestCase.generateRandomStringArray(5, 5, false, false) : null;
@@ -1015,7 +1062,8 @@ public void testGetTemplateRequest() throws Exception {
Map expectedParams = new HashMap<>();
RequestConvertersTests.setRandomMasterTimeout(getTemplatesRequest::setMasterNodeTimeout, expectedParams);
RequestConvertersTests.setRandomLocal(getTemplatesRequest::setLocal, expectedParams);
- Request request = IndicesRequestConverters.getTemplates(getTemplatesRequest);
+ Request request = IndicesRequestConverters.getTemplatesWithDocumentTypes(getTemplatesRequest);
+ expectedParams.put(INCLUDE_TYPE_NAME_PARAMETER, "true");
Assert.assertThat(request.getEndpoint(),
equalTo("/_template/" + names.stream().map(encodes::get).collect(Collectors.joining(","))));
Assert.assertThat(request.getParameters(), equalTo(expectedParams));
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
index 8064ba2f2b565..09ace08723a83 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/RestHighLevelClientTests.java
@@ -762,6 +762,14 @@ public void testApiNamingConventions() throws Exception {
.collect(Collectors.groupingBy(Tuple::v1,
Collectors.mapping(Tuple::v2, Collectors.toSet())));
+ // TODO remove in 8.0 - we will undeprecate indices.get_template because the current getIndexTemplate
+ // impl will replace the existing getTemplate method.
+ // The above general-purpose code ignores all deprecated methods which in this case leaves `getTemplate`
+ // looking like it doesn't have a valid implementatation when it does.
+ apiUnsupported.remove("indices.get_template");
+
+
+
for (Map.Entry> entry : methods.entrySet()) {
String apiName = entry.getKey();
@@ -794,7 +802,10 @@ public void testApiNamingConventions() throws Exception {
apiName.startsWith("security.") == false &&
apiName.startsWith("index_lifecycle.") == false &&
apiName.startsWith("ccr.") == false &&
- apiName.endsWith("freeze") == false) {
+ apiName.endsWith("freeze") == false &&
+ // IndicesClientIT.getIndexTemplate should be renamed "getTemplate" in version 8.0 when we
+ // can get rid of 7.0's deprecated "getTemplate"
+ apiName.equals("indices.get_index_template") == false) {
apiNotFound.add(apiName);
}
}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
index c20389c24b10a..5f80e6766056a 100644
--- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IndicesClientDocumentationIT.java
@@ -55,8 +55,6 @@
import org.elasticsearch.action.admin.indices.shrink.ResizeResponse;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest;
-import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
-import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequest;
import org.elasticsearch.action.admin.indices.validate.query.QueryExplanation;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryRequest;
import org.elasticsearch.action.admin.indices.validate.query.ValidateQueryResponse;
@@ -76,12 +74,13 @@
import org.elasticsearch.client.indices.GetIndexTemplatesRequest;
import org.elasticsearch.client.indices.GetMappingsRequest;
import org.elasticsearch.client.indices.GetMappingsResponse;
+import org.elasticsearch.client.indices.GetIndexTemplatesResponse;
+import org.elasticsearch.client.indices.IndexTemplateMetaData;
import org.elasticsearch.client.indices.IndexTemplatesExistRequest;
+import org.elasticsearch.client.indices.PutIndexTemplateRequest;
import org.elasticsearch.client.indices.PutMappingRequest;
import org.elasticsearch.client.indices.UnfreezeIndexRequest;
import org.elasticsearch.cluster.metadata.AliasMetaData;
-import org.elasticsearch.cluster.metadata.IndexTemplateMetaData;
-import org.elasticsearch.cluster.metadata.AliasMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
@@ -2085,13 +2084,11 @@ public void testPutTemplate() throws Exception {
{
// tag::put-template-request-mappings-json
- request.mapping("_doc", // <1>
+ request.mapping(// <1>
"{\n" +
- " \"_doc\": {\n" +
- " \"properties\": {\n" +
- " \"message\": {\n" +
- " \"type\": \"text\"\n" +
- " }\n" +
+ " \"properties\": {\n" +
+ " \"message\": {\n" +
+ " \"type\": \"text\"\n" +
" }\n" +
" }\n" +
"}", // <2>
@@ -2102,14 +2099,16 @@ public void testPutTemplate() throws Exception {
{
//tag::put-template-request-mappings-map
Map jsonMap = new HashMap<>();
- Map message = new HashMap<>();
- message.put("type", "text");
- Map properties = new HashMap<>();
- properties.put("message", message);
- Map mapping = new HashMap<>();
- mapping.put("properties", properties);
- jsonMap.put("_doc", mapping);
- request.mapping("_doc", jsonMap); // <1>
+ {
+ Map properties = new HashMap<>();
+ {
+ Map message = new HashMap<>();
+ message.put("type", "text");
+ properties.put("message", message);
+ }
+ jsonMap.put("properties", properties);
+ }
+ request.mapping(jsonMap); // <1>
//end::put-template-request-mappings-map
assertTrue(client.indices().putTemplate(request, RequestOptions.DEFAULT).isAcknowledged());
}
@@ -2118,31 +2117,21 @@ public void testPutTemplate() throws Exception {
XContentBuilder builder = XContentFactory.jsonBuilder();
builder.startObject();
{
- builder.startObject("_doc");
+ builder.startObject("properties");
{
- builder.startObject("properties");
+ builder.startObject("message");
{
- builder.startObject("message");
- {
- builder.field("type", "text");
- }
- builder.endObject();
+ builder.field("type", "text");
}
builder.endObject();
}
builder.endObject();
}
builder.endObject();
- request.mapping("_doc", builder); // <1>
+ request.mapping(builder); // <1>
//end::put-template-request-mappings-xcontent
assertTrue(client.indices().putTemplate(request, RequestOptions.DEFAULT).isAcknowledged());
}
- {
- //tag::put-template-request-mappings-shortcut
- request.mapping("_doc", "message", "type=text"); // <1>
- //end::put-template-request-mappings-shortcut
- assertTrue(client.indices().putTemplate(request, RequestOptions.DEFAULT).isAcknowledged());
- }
// tag::put-template-request-aliases
request.alias(new Alias("twitter_alias").filter(QueryBuilders.termQuery("user", "kimchy"))); // <1>
@@ -2168,11 +2157,9 @@ public void testPutTemplate() throws Exception {
" \"number_of_shards\": 1\n" +
" },\n" +
" \"mappings\": {\n" +
- " \"_doc\": {\n" +
- " \"properties\": {\n" +
- " \"message\": {\n" +
- " \"type\": \"text\"\n" +
- " }\n" +
+ " \"properties\": {\n" +
+ " \"message\": {\n" +
+ " \"type\": \"text\"\n" +
" }\n" +
" }\n" +
" },\n" +
@@ -2235,13 +2222,11 @@ public void testGetTemplates() throws Exception {
PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest("my-template");
putRequest.patterns(Arrays.asList("pattern-1", "log-*"));
putRequest.settings(Settings.builder().put("index.number_of_shards", 3).put("index.number_of_replicas", 1));
- putRequest.mapping("_doc",
+ putRequest.mapping(
"{\n" +
- " \"_doc\": {\n" +
- " \"properties\": {\n" +
- " \"message\": {\n" +
- " \"type\": \"text\"\n" +
- " }\n" +
+ " \"properties\": {\n" +
+ " \"message\": {\n" +
+ " \"type\": \"text\"\n" +
" }\n" +
" }\n" +
"}", XContentType.JSON);
@@ -2260,7 +2245,7 @@ public void testGetTemplates() throws Exception {
// end::get-templates-request-masterTimeout
// tag::get-templates-execute
- GetIndexTemplatesResponse getTemplatesResponse = client.indices().getTemplate(request, RequestOptions.DEFAULT);
+ GetIndexTemplatesResponse getTemplatesResponse = client.indices().getIndexTemplate(request, RequestOptions.DEFAULT);
// end::get-templates-execute
// tag::get-templates-response
@@ -2290,7 +2275,7 @@ public void onFailure(Exception e) {
listener = new LatchedActionListener<>(listener, latch);
// tag::get-templates-execute-async
- client.indices().getTemplateAsync(request, RequestOptions.DEFAULT, listener); // <1>
+ client.indices().getIndexTemplateAsync(request, RequestOptions.DEFAULT, listener); // <1>
// end::get-templates-execute-async
assertTrue(latch.await(30L, TimeUnit.SECONDS));
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetIndexTemplatesResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetIndexTemplatesResponseTests.java
new file mode 100644
index 0000000000000..d2f0c3d7eba88
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/GetIndexTemplatesResponseTests.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.indices;
+
+import org.elasticsearch.cluster.metadata.AliasMetaData;
+import org.elasticsearch.cluster.metadata.MappingMetaData;
+import org.elasticsearch.common.bytes.BytesArray;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.ToXContent;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.common.xcontent.XContentHelper;
+import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.index.mapper.MapperService;
+import org.elasticsearch.test.ESTestCase;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import static org.elasticsearch.test.AbstractXContentTestCase.xContentTester;
+
+public class GetIndexTemplatesResponseTests extends ESTestCase {
+
+ static final String mappingString = "{\"properties\":{"
+ + "\"f1\": {\"type\":\"text\"},"
+ + "\"f2\": {\"type\":\"keyword\"}"
+ + "}}";
+
+
+ public void testFromXContent() throws IOException {
+ xContentTester(this::createParser, GetIndexTemplatesResponseTests::createTestInstance, GetIndexTemplatesResponseTests::toXContent,
+ GetIndexTemplatesResponse::fromXContent).supportsUnknownFields(false)
+ .assertEqualsConsumer(GetIndexTemplatesResponseTests::assertEqualInstances)
+ .shuffleFieldsExceptions(new String[] {"aliases", "mappings", "patterns", "settings"})
+ .test();
+ }
+
+ private static void assertEqualInstances(GetIndexTemplatesResponse expectedInstance, GetIndexTemplatesResponse newInstance) {
+ assertEquals(expectedInstance, newInstance);
+ // Check there's no doc types at the root of the mapping
+ Map expectedMap = XContentHelper.convertToMap(
+ new BytesArray(mappingString), true, XContentType.JSON).v2();
+ for (IndexTemplateMetaData template : newInstance.getIndexTemplates()) {
+ MappingMetaData mappingMD = template.mappings();
+ if(mappingMD!=null) {
+ Map mappingAsMap = mappingMD.sourceAsMap();
+ assertEquals(expectedMap, mappingAsMap);
+ }
+ }
+ }
+
+ static GetIndexTemplatesResponse createTestInstance() {
+ List templates = new ArrayList<>();
+ int numTemplates = between(0, 10);
+ for (int t = 0; t < numTemplates; t++) {
+ IndexTemplateMetaData.Builder templateBuilder = IndexTemplateMetaData.builder("template-" + t);
+ templateBuilder.patterns(IntStream.range(0, between(1, 5)).mapToObj(i -> "pattern-" + i).collect(Collectors.toList()));
+ int numAlias = between(0, 5);
+ for (int i = 0; i < numAlias; i++) {
+ templateBuilder.putAlias(AliasMetaData.builder(randomAlphaOfLengthBetween(1, 10)));
+ }
+ if (randomBoolean()) {
+ templateBuilder.settings(Settings.builder().put("index.setting-1", randomLong()));
+ }
+ if (randomBoolean()) {
+ templateBuilder.order(randomInt());
+ }
+ if (randomBoolean()) {
+ templateBuilder.version(between(0, 100));
+ }
+ if (randomBoolean()) {
+ try {
+ Map map = XContentHelper.convertToMap(new BytesArray(mappingString), true, XContentType.JSON).v2();
+ MappingMetaData mapping = new MappingMetaData(MapperService.SINGLE_MAPPING_NAME, map);
+ templateBuilder.mapping(mapping);
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }
+ templates.add(templateBuilder.build());
+ }
+ return new GetIndexTemplatesResponse(templates);
+ }
+
+ // As the client class GetIndexTemplatesResponse doesn't have toXContent method, adding this method here only for the test
+ static void toXContent(GetIndexTemplatesResponse response, XContentBuilder builder) throws IOException {
+
+ //Create a server-side counterpart for the client-side class and call toXContent on it
+
+ List serverIndexTemplates = new ArrayList<>();
+ List clientIndexTemplates = response.getIndexTemplates();
+ for (IndexTemplateMetaData clientITMD : clientIndexTemplates) {
+ org.elasticsearch.cluster.metadata.IndexTemplateMetaData.Builder serverTemplateBuilder =
+ org.elasticsearch.cluster.metadata.IndexTemplateMetaData.builder(clientITMD.name());
+
+ serverTemplateBuilder.patterns(clientITMD.patterns());
+
+ Iterator aliases = clientITMD.aliases().valuesIt();
+ aliases.forEachRemaining((a)->serverTemplateBuilder.putAlias(a));
+
+ serverTemplateBuilder.settings(clientITMD.settings());
+ serverTemplateBuilder.order(clientITMD.order());
+ serverTemplateBuilder.version(clientITMD.version());
+ if (clientITMD.mappings() != null) {
+ serverTemplateBuilder.putMapping(MapperService.SINGLE_MAPPING_NAME, clientITMD.mappings().source());
+ }
+ serverIndexTemplates.add(serverTemplateBuilder.build());
+
+ }
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse serverResponse = new
+ org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse(serverIndexTemplates);
+ serverResponse.toXContent(builder, ToXContent.EMPTY_PARAMS);
+ }
+}
diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutIndexTemplateRequestTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutIndexTemplateRequestTests.java
new file mode 100644
index 0000000000000..8aab973982fc0
--- /dev/null
+++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/indices/PutIndexTemplateRequestTests.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.elasticsearch.client.indices;
+
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.admin.indices.alias.Alias;
+import org.elasticsearch.common.settings.Settings;
+import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.test.AbstractXContentTestCase;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.nullValue;
+import static org.hamcrest.core.Is.is;
+
+public class PutIndexTemplateRequestTests extends AbstractXContentTestCase {
+ public void testValidateErrorMessage() throws Exception {
+ expectThrows(IllegalArgumentException.class, () -> new PutIndexTemplateRequest(null));
+ expectThrows(IllegalArgumentException.class, () -> new PutIndexTemplateRequest("test").name(null));
+ PutIndexTemplateRequest request = new PutIndexTemplateRequest("test");
+ ActionRequestValidationException withoutPattern = request.validate();
+ assertThat(withoutPattern.getMessage(), containsString("index patterns are missing"));
+
+ request.name("foo");
+ ActionRequestValidationException withoutIndexPatterns = request.validate();
+ assertThat(withoutIndexPatterns.validationErrors(), hasSize(1));
+ assertThat(withoutIndexPatterns.getMessage(), containsString("index patterns are missing"));
+
+ request.patterns(Collections.singletonList("test-*"));
+ ActionRequestValidationException noError = request.validate();
+ assertThat(noError, is(nullValue()));
+ }
+
+ @Override
+ protected PutIndexTemplateRequest createTestInstance() {
+ PutIndexTemplateRequest request = new PutIndexTemplateRequest("test");
+ if (randomBoolean()) {
+ request.version(randomInt());
+ }
+ if (randomBoolean()) {
+ request.order(randomInt());
+ }
+ request.patterns(Arrays.asList(generateRandomStringArray(20, 100, false, false)));
+ int numAlias = between(0, 5);
+ for (int i = 0; i < numAlias; i++) {
+ // some ASCII or Latin-1 control characters, especially newline, can lead to
+ // problems with yaml parsers, that's why we filter them here (see #30911)
+ Alias alias = new Alias(randomRealisticUnicodeOfLengthBetween(1, 10).replaceAll("\\p{Cc}", ""));
+ if (randomBoolean()) {
+ alias.indexRouting(randomRealisticUnicodeOfLengthBetween(1, 10));
+ }
+ if (randomBoolean()) {
+ alias.searchRouting(randomRealisticUnicodeOfLengthBetween(1, 10));
+ }
+ request.alias(alias);
+ }
+ if (randomBoolean()) {
+ try {
+ request.mapping(XContentFactory.jsonBuilder().startObject()
+ .startObject("properties")
+ .startObject("field-" + randomInt()).field("type", randomFrom("keyword", "text")).endObject()
+ .endObject().endObject());
+ } catch (IOException ex) {
+ throw new UncheckedIOException(ex);
+ }
+ }
+ if (randomBoolean()) {
+ request.settings(Settings.builder().put("setting1", randomLong()).put("setting2", randomTimeValue()).build());
+ }
+ return request;
+ }
+
+ @Override
+ protected PutIndexTemplateRequest doParseInstance(XContentParser parser) throws IOException {
+ return new PutIndexTemplateRequest("test").source(parser.map());
+ }
+
+ @Override
+ protected void assertEqualInstances(PutIndexTemplateRequest expected, PutIndexTemplateRequest actual) {
+ assertNotSame(expected, actual);
+ assertThat(actual.version(), equalTo(expected.version()));
+ assertThat(actual.order(), equalTo(expected.order()));
+ assertThat(actual.patterns(), equalTo(expected.patterns()));
+ assertThat(actual.aliases(), equalTo(expected.aliases()));
+ assertThat(actual.mappings(), equalTo(expected.mappings()));
+ assertThat(actual.settings(), equalTo(expected.settings()));
+ }
+
+ @Override
+ protected boolean supportsUnknownFields() {
+ return false;
+ }
+}
diff --git a/docs/java-rest/high-level/indices/put_template.asciidoc b/docs/java-rest/high-level/indices/put_template.asciidoc
index 7618fc8ce7af5..3e3954308736d 100644
--- a/docs/java-rest/high-level/indices/put_template.asciidoc
+++ b/docs/java-rest/high-level/indices/put_template.asciidoc
@@ -39,8 +39,7 @@ template's patterns.
--------------------------------------------------
include-tagged::{doc-tests-file}[{api}-request-mappings-json]
--------------------------------------------------
-<1> The type to define
-<2> The mapping for this type, provided as a JSON string
+<1> The mapping, provided as a JSON string
The mapping source can be provided in different ways in addition to the
`String` example shown above:
@@ -59,13 +58,6 @@ include-tagged::{doc-tests-file}[{api}-request-mappings-xcontent]
<1> Mapping source provided as an `XContentBuilder` object, the Elasticsearch
built-in helpers to generate JSON content
-["source","java",subs="attributes,callouts,macros"]
---------------------------------------------------
-include-tagged::{doc-tests-file}[{api}-request-mappings-shortcut]
---------------------------------------------------
-<1> Mapping source provided as `Object` key-pairs, which gets converted to
-JSON format
-
==== Aliases
The aliases of the template will define aliasing to the index whose name matches the
template's patterns. A placeholder `{index}` can be used in an alias of a template.
diff --git a/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java b/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java
index 2cd0367a4d40a..48a1632a97477 100644
--- a/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java
+++ b/qa/full-cluster-restart/src/test/java/org/elasticsearch/upgrades/FullClusterRestartIT.java
@@ -891,6 +891,7 @@ public void testSnapshotRestore() throws IOException {
templateBuilder.endObject().endObject();
Request createTemplateRequest = new Request("PUT", "/_template/test_template");
createTemplateRequest.setJsonEntity(Strings.toString(templateBuilder));
+
client().performRequest(createTemplateRequest);
if (isRunningAgainstOldCluster()) {
diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/template/get/GetIndexTemplatesResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/template/get/GetIndexTemplatesResponse.java
index 2bdc966c74e59..9ddea863d48f4 100644
--- a/server/src/main/java/org/elasticsearch/action/admin/indices/template/get/GetIndexTemplatesResponse.java
+++ b/server/src/main/java/org/elasticsearch/action/admin/indices/template/get/GetIndexTemplatesResponse.java
@@ -41,7 +41,7 @@ public class GetIndexTemplatesResponse extends ActionResponse implements ToXCont
indexTemplates = new ArrayList<>();
}
- GetIndexTemplatesResponse(List indexTemplates) {
+ public GetIndexTemplatesResponse(List indexTemplates) {
this.indexTemplates = indexTemplates;
}
diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndexTemplateAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndexTemplateAction.java
index 50370797aa6f2..707378eec4cf6 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndexTemplateAction.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndexTemplateAction.java
@@ -19,10 +19,12 @@
package org.elasticsearch.rest.action.admin.indices;
+import org.apache.logging.log4j.LogManager;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesRequest;
import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.rest.BaseRestHandler;
@@ -47,6 +49,10 @@ public class RestGetIndexTemplateAction extends BaseRestHandler {
private static final Set RESPONSE_PARAMETERS = Collections.unmodifiableSet(Sets.union(
Collections.singleton(INCLUDE_TYPE_NAME_PARAMETER), Settings.FORMAT_PARAMS));
+ private static final DeprecationLogger deprecationLogger = new DeprecationLogger(
+ LogManager.getLogger(RestGetIndexTemplateAction.class));
+ public static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
+ " Specifying include_type_name in get index template requests is deprecated.";
public RestGetIndexTemplateAction(final Settings settings, final RestController controller) {
super(settings);
@@ -65,6 +71,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC
final String[] names = Strings.splitStringByCommaToArray(request.param("name"));
final GetIndexTemplatesRequest getIndexTemplatesRequest = new GetIndexTemplatesRequest(names);
+ if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) {
+ deprecationLogger.deprecatedAndMaybeLog("get_index_template_include_type_name", TYPES_DEPRECATION_MESSAGE);
+ }
getIndexTemplatesRequest.local(request.paramAsBoolean("local", getIndexTemplatesRequest.local()));
getIndexTemplatesRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexTemplatesRequest.masterNodeTimeout()));
diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
index 8a292859d6031..f460bb3969211 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
@@ -42,6 +42,9 @@ public class RestPutIndexTemplateAction extends BaseRestHandler {
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(
LogManager.getLogger(RestPutIndexTemplateAction.class));
+ public static final String TYPES_DEPRECATION_MESSAGE = "[types removal]" +
+ " Specifying include_type_name in put index template requests is deprecated."+
+ " The parameter will be removed in the next major version.";
public RestPutIndexTemplateAction(Settings settings, RestController controller) {
super(settings);
@@ -57,6 +60,9 @@ public String getName() {
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest(request.param("name"));
+ if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) {
+ deprecationLogger.deprecatedAndMaybeLog("put_index_template_with_types", TYPES_DEPRECATION_MESSAGE);
+ }
if (request.hasParam("template")) {
DEPRECATION_LOGGER.deprecated("Deprecated parameter[template] used, replaced by [index_patterns]");
putRequest.patterns(Collections.singletonList(request.param("template")));
diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateActionTests.java
index ac0eb8f0d81a6..d1900aaee84d5 100644
--- a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateActionTests.java
+++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateActionTests.java
@@ -19,6 +19,7 @@
package org.elasticsearch.rest.action.admin.indices;
+import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
@@ -31,8 +32,12 @@
import org.junit.Before;
import java.io.IOException;
+import java.util.HashMap;
import java.util.Map;
+import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER;
+import static org.mockito.Mockito.mock;
+
public class RestPutIndexTemplateActionTests extends RestActionTestCase {
private RestPutIndexTemplateAction action;
@@ -45,7 +50,8 @@ public void testPrepareTypelessRequest() throws IOException {
XContentBuilder content = XContentFactory.jsonBuilder().startObject()
.startObject("mappings")
.startObject("properties")
- .startObject("field").field("type", "keyword").endObject()
+ .startObject("field1").field("type", "keyword").endObject()
+ .startObject("field2").field("type", "text").endObject()
.endObject()
.endObject()
.startObject("aliases")
@@ -58,6 +64,11 @@ public void testPrepareTypelessRequest() throws IOException {
.withPath("/_template/_some_template")
.withContent(BytesReference.bytes(content), XContentType.JSON)
.build();
+ action.prepareRequest(request, mock(NodeClient.class));
+
+ // Internally the above prepareRequest method calls prepareRequestSource to inject a
+ // default type into the mapping. Here we test that this does what is expected by
+ // explicitly calling that same helper function
boolean includeTypeName = false;
Map source = action.prepareRequestSource(request, includeTypeName);
@@ -65,7 +76,8 @@ public void testPrepareTypelessRequest() throws IOException {
.startObject("mappings")
.startObject("_doc")
.startObject("properties")
- .startObject("field").field("type", "keyword").endObject()
+ .startObject("field1").field("type", "keyword").endObject()
+ .startObject("field2").field("type", "text").endObject()
.endObject()
.endObject()
.endObject()
@@ -78,4 +90,51 @@ public void testPrepareTypelessRequest() throws IOException {
assertEquals(expectedContentAsMap, source);
}
+
+ public void testIncludeTypeName() throws IOException {
+ XContentBuilder typedContent = XContentFactory.jsonBuilder().startObject()
+ .startObject("mappings")
+ .startObject("my_doc")
+ .startObject("properties")
+ .startObject("field1").field("type", "keyword").endObject()
+ .startObject("field2").field("type", "text").endObject()
+ .endObject()
+ .endObject()
+ .endObject()
+ .startObject("aliases")
+ .startObject("read_alias").endObject()
+ .endObject()
+ .endObject();
+
+ Map params = new HashMap<>();
+ params.put(INCLUDE_TYPE_NAME_PARAMETER, "true");
+ RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
+ .withMethod(RestRequest.Method.PUT)
+ .withParams(params)
+ .withPath("/_template/_some_template")
+ .withContent(BytesReference.bytes(typedContent), XContentType.JSON)
+ .build();
+ action.prepareRequest(request, mock(NodeClient.class));
+ assertWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE);
+ boolean includeTypeName = true;
+ Map source = action.prepareRequestSource(request, includeTypeName);
+
+ XContentBuilder expectedContent = XContentFactory.jsonBuilder().startObject()
+ .startObject("mappings")
+ .startObject("my_doc")
+ .startObject("properties")
+ .startObject("field1").field("type", "keyword").endObject()
+ .startObject("field2").field("type", "text").endObject()
+ .endObject()
+ .endObject()
+ .endObject()
+ .startObject("aliases")
+ .startObject("read_alias").endObject()
+ .endObject()
+ .endObject();
+ Map expectedContentAsMap = XContentHelper.convertToMap(
+ BytesReference.bytes(expectedContent), true, expectedContent.contentType()).v2();
+
+ assertEquals(expectedContentAsMap, source);
+ }
}