diff --git a/rest-api-spec/build.gradle b/rest-api-spec/build.gradle index 67a0a035c8253..8634b54dba8d8 100644 --- a/rest-api-spec/build.gradle +++ b/rest-api-spec/build.gradle @@ -146,11 +146,9 @@ tasks.named("yamlRestCompatTest").configure { 'explain/21_source_filtering_with_types/Source filtering', 'explain/31_query_string_with_types/explain with query_string parameters', 'explain/40_mix_typeless_typeful/Explain with typeless API on an index that has types', - 'field_caps/10_basic/Get date_nanos field caps', 'field_caps/30_filter/Field caps with index filter', - 'get/100_mix_typeless_typeful/GET with typeless API on an index that has types',// failing due to include_type_name #48632 - 'get/21_stored_fields_with_types/Stored fields', // failing due to include_type_name #48632 - 'get/71_source_filtering_with_types/Source filtering',// failing due to include_type_name #48632 + // WILL NOT BE FIXED - failing due to not recognising missing type (the type path param is ignored) + 'get/100_mix_typeless_typeful/GET with typeless API on an index that has types', 'get_source/11_basic_with_types/Basic with types', 'get_source/16_default_values_with_types/Default values', 'get_source/41_routing_with_types/Routing', @@ -160,43 +158,35 @@ tasks.named("yamlRestCompatTest").configure { 'get_source/81_missing_with_types/Missing document with ignore', 'get_source/86_source_missing_with_types/Missing document source with catch', 'get_source/86_source_missing_with_types/Missing document source with ignore', - 'index/70_mix_typeless_typeful/Index call that introduces new field mappings', // failing due to include_type_name #48632 - 'index/70_mix_typeless_typeful/Index with typeless API on an index that has types', // failing due to include_type_name #48632 'indices.clone/10_basic/Clone index via API', - 'indices.create/10_basic/Create index with explicit _doc type', 'indices.create/10_basic/Create index without soft deletes', - 'indices.create/11_basic_with_types/Create index', - 'indices.create/11_basic_with_types/Create index with aliases', + // 5 below await retrofitting Removes typed URLs from mapping APIs #41676 'indices.create/11_basic_with_types/Create index with mappings', - 'indices.create/11_basic_with_types/Create index with settings', - 'indices.create/11_basic_with_types/Create index with wait_for_active_shards set to all', - 'indices.create/11_basic_with_types/Create index with write aliases', 'indices.create/20_mix_typeless_typeful/Create a typed index while there is a typeless template', 'indices.create/20_mix_typeless_typeful/Create a typeless index while there is a typed template', 'indices.create/20_mix_typeless_typeful/Implicitly create a typed index while there is a typeless template', 'indices.create/20_mix_typeless_typeful/Implicitly create a typeless index while there is a typed template', + // 'indices.flush/10_basic/Flush stats', 'indices.flush/10_basic/Index synced flush rest test', 'indices.forcemerge/10_basic/Check deprecation warning when incompatible only_expunge_deletes and max_num_segments values are both set', - 'indices.get/11_basic_with_types/Test include_type_name', - 'indices.get/11_basic_with_types/Test include_type_name dafaults to false', - 'indices.get_field_mapping/10_basic/Get field mapping with local is deprecated', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping by index only', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping by type & field', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping by type & field, with another field that doesn\'t exist', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping should work without index specifying type and fields', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping with include_defaults', - 'indices.get_field_mapping/11_basic_with_types/Get field mapping with no index and type', - 'indices.get_field_mapping/21_missing_field_with_types/Return empty object if field doesn\'t exist, but type and index do', - 'indices.get_field_mapping/30_missing_type/Raise 404 when type doesn\'t exist', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using \'*\' for indices and types', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using \'_all\' for indices and types', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using comma_separated values for indices and types', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with * for fields', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with *t1 for fields', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with t* for fields', - 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with wildcarded relative names', - 'indices.get_field_mapping/60_mix_typeless_typeful/GET mapping with typeless API on an index that has types', + 'indices.get_field_mapping/10_basic/Get field mapping with local is deprecated',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping by index only',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping by type & field',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping by type & field, with another field that doesn\'t exist',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping should work without index specifying type and fields',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping with include_defaults',// awaits #41676 + 'indices.get_field_mapping/11_basic_with_types/Get field mapping with no index and type',// awaits #41676 + 'indices.get_field_mapping/21_missing_field_with_types/Return empty object if field doesn\'t exist, but type and index do',// awaits #41676 + 'indices.get_field_mapping/30_missing_type/Raise 404 when type doesn\'t exist',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using \'*\' for indices and types',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using \'_all\' for indices and types',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping should work using comma_separated values for indices and types',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with * for fields',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with *t1 for fields',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with t* for fields',// awaits #41676 + 'indices.get_field_mapping/51_field_wildcards_with_types/Get field mapping with wildcarded relative names',// awaits #41676 + 'indices.get_field_mapping/60_mix_typeless_typeful/GET mapping with typeless API on an index that has types',// awaits #41676 'indices.get_mapping/11_basic_with_types/Get /*/_mapping/{type}', 'indices.get_mapping/11_basic_with_types/Get /_all/_mapping/{type}', 'indices.get_mapping/11_basic_with_types/Get /_mapping', @@ -217,8 +207,6 @@ tasks.named("yamlRestCompatTest").configure { 'indices.get_mapping/40_aliases/Getting mapping for aliases should return the real index as key', 'indices.get_mapping/61_empty_with_types/Check empty mapping when getting all mappings via /_mapping', 'indices.get_mapping/70_mix_typeless_typeful/GET mapping with typeless API on an index that has types', - 'indices.get_template/11_basic_with_types/Get template', - 'indices.get_template/11_basic_with_types/Get template with no mappings', 'indices.open/10_basic/?wait_for_active_shards default is deprecated', 'indices.open/10_basic/?wait_for_active_shards=index-setting', 'indices.put_mapping/10_basic/Put mappings with explicit _doc type', @@ -233,15 +221,9 @@ tasks.named("yamlRestCompatTest").configure { 'indices.put_mapping/all_path_options_with_types/put mapping in prefix* index', 'indices.put_mapping/all_path_options_with_types/put mapping with blank index', 'indices.put_mapping/all_path_options_with_types/put one mapping per index', - 'indices.put_template/10_basic/Put template with explicit _doc type', - 'indices.put_template/11_basic_with_types/Put multiple template', - 'indices.put_template/11_basic_with_types/Put template', + // there is a small distinction between empty mappings and no mappings at all. The code to implement this test was refactored #54003 + // not fixing this in #70966 'indices.put_template/11_basic_with_types/Put template with empty mappings', - 'indices.rollover/10_basic/Rollover index via API', - 'indices.rollover/20_max_doc_condition/Max docs rollover conditions matches only primary shards', - 'indices.rollover/30_max_size_condition/Rollover with max_size condition', - 'indices.rollover/40_mapping/Mappings with explicit _doc type', - 'indices.rollover/41_mapping_with_types/Typeless mapping', 'indices.segments/10_basic/basic segments test', 'indices.segments/10_basic/closed segments test', 'indices.shard_stores/10_basic/basic index test', @@ -302,8 +284,6 @@ tasks.named("yamlRestCompatTest").configure { 'search.aggregation/10_histogram/Deprecated _time order', 'search.aggregation/200_top_hits_metric/top_hits aggregation with sequence numbers', 'search.aggregation/20_terms/Deprecated _term order', - 'search.aggregation/280_geohash_grid/Basic test', - 'search.aggregation/290_geotile_grid/Basic test', 'search.aggregation/51_filter_with_types/Filter aggs with terms lookup and ensure it\'s cached', 'search.inner_hits/10_basic/Nested doc version and seqIDs', 'search.inner_hits/10_basic/Nested inner hits', @@ -363,6 +343,9 @@ tasks.named("transformV7RestTests").configure({ task -> task.replaceMatch("nodes.\$node_id.roles.8", "ml", "node_info role test") task.replaceMatch("nodes.\$node_id.roles.9", "remote_cluster_client", "node_info role test") task.removeMatch("nodes.\$node_id.roles.10", "node_info role test") + task.replaceIsTrue("test_index.mappings.type_1", "test_index.mappings._doc") + task.replaceIsFalse("test_index.mappings.type_1", "test_index.mappings._doc") + task.replaceIsFalse("test-1.mappings.my_type", "test-1.mappings._doc") }) tasks.register('enforceYamlTestConvention').configure { diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java index cc9aaf74ef970..74fae9eaacfbd 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/get/GetIndexResponse.java @@ -12,6 +12,7 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.metadata.AliasMetadata; import org.elasticsearch.cluster.metadata.MappingMetadata; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.Strings; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.io.stream.StreamInput; @@ -26,6 +27,9 @@ import java.util.List; import java.util.Objects; +import static org.elasticsearch.rest.BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY; +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; + /** * A response for a get index action. */ @@ -192,7 +196,14 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws if (indexMappings == null) { builder.startObject("mappings").endObject(); } else { - builder.field("mappings", indexMappings.sourceAsMap()); + if (builder.getRestApiVersion() == RestApiVersion.V_7 && + params.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY)) { + builder.startObject("mappings"); + builder.field(MapperService.SINGLE_MAPPING_NAME, indexMappings.sourceAsMap()); + builder.endObject(); + } else { + builder.field("mappings", indexMappings.sourceAsMap()); + } } builder.startObject("settings"); diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java index e91492c1344e1..bb1443d9d76f3 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java @@ -11,6 +11,7 @@ import org.elasticsearch.Version; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; @@ -22,6 +23,7 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.rest.BaseRestHandler; import java.io.IOException; import java.io.InputStream; @@ -30,6 +32,7 @@ import java.util.Objects; import static java.util.Collections.unmodifiableMap; +import static org.elasticsearch.rest.BaseRestHandler.DEFAULT_INCLUDE_TYPE_NAME_POLICY; /** * Response object for {@link GetFieldMappingsRequest} API @@ -84,15 +87,23 @@ public FieldMappingMetadata fieldMappings(String index, String field) { @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); for (Map.Entry> indexEntry : mappings.entrySet()) { builder.startObject(indexEntry.getKey()); builder.startObject(MAPPINGS.getPreferredName()); - if (indexEntry.getValue() != null) { - addFieldMappingsToBuilder(builder, params, indexEntry.getValue()); + if (builder.getRestApiVersion() == RestApiVersion.V_7 && + params.paramAsBoolean(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY)) { + builder.startObject(MapperService.SINGLE_MAPPING_NAME); + addFieldMappingsToBuilder(builder, params, indexEntry.getValue()); + builder.endObject(); + } else { + addFieldMappingsToBuilder(builder, params, indexEntry.getValue()); + } } + builder.endObject(); builder.endObject(); } diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequest.java b/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequest.java index 248c8c162d16c..31a40b22a9e4c 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequest.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequest.java @@ -14,6 +14,7 @@ import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.common.ParseField; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.unit.ByteSizeValue; @@ -37,7 +38,7 @@ */ public class RolloverRequest extends AcknowledgedRequest implements IndicesRequest { - private static final ObjectParser PARSER = new ObjectParser<>("rollover"); + private static final ObjectParser PARSER = new ObjectParser<>("rollover"); private static final ObjectParser>, Void> CONDITION_PARSER = new ObjectParser<>("conditions"); private static final ParseField CONDITIONS = new ParseField("conditions"); @@ -67,14 +68,32 @@ public class RolloverRequest extends AcknowledgedRequest implem CONDITIONS, ObjectParser.ValueType.OBJECT); PARSER.declareField((parser, request, context) -> request.createIndexRequest.settings(parser.map()), CreateIndexRequest.SETTINGS, ObjectParser.ValueType.OBJECT); + PARSER.declareField((parser, request, includeTypeName) -> { + if (includeTypeName) { + //expecting one type only + for (Map.Entry mappingsEntry : parser.map().entrySet()) { + request.createIndexRequest.mapping((Map) mappingsEntry.getValue()); + } + } else { + // a type is not included, add a dummy _doc type + Map mappings = parser.map(); + if (MapperService.isMappingSourceTyped(MapperService.SINGLE_MAPPING_NAME, mappings)) { + throw new IllegalArgumentException("The mapping definition cannot be nested under a type " + + "[" + MapperService.SINGLE_MAPPING_NAME + "] unless include_type_name is set to true."); + } + request.createIndexRequest.mapping(mappings); + } + }, CreateIndexRequest.MAPPINGS.forRestApiVersion(RestApiVersion.equalTo(RestApiVersion.V_7)), ObjectParser.ValueType.OBJECT); PARSER.declareField((parser, request, context) -> { // a type is not included, add a dummy _doc type Map mappings = parser.map(); if (MapperService.isMappingSourceTyped(MapperService.SINGLE_MAPPING_NAME, mappings)) { + throw new IllegalArgumentException("The mapping definition cannot be nested under a type"); } request.createIndexRequest.mapping(mappings); - }, CreateIndexRequest.MAPPINGS, ObjectParser.ValueType.OBJECT); + }, CreateIndexRequest.MAPPINGS.forRestApiVersion(RestApiVersion.onOrAfter(RestApiVersion.V_8)), ObjectParser.ValueType.OBJECT); + PARSER.declareField((parser, request, context) -> request.createIndexRequest.aliases(parser.map()), CreateIndexRequest.ALIASES, ObjectParser.ValueType.OBJECT); } @@ -238,7 +257,7 @@ public CreateIndexRequest getCreateIndexRequest() { } // param isTypeIncluded decides how mappings should be parsed from XContent - public void fromXContent(XContentParser parser) throws IOException { - PARSER.parse(parser, this, null); + public void fromXContent(boolean isTypeIncluded, XContentParser parser) throws IOException { + PARSER.parse(parser, this, isTypeIncluded); } } 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 9b95c146b79a7..40ad35fd1eb5a 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 @@ -9,6 +9,7 @@ import org.elasticsearch.action.ActionResponse; import org.elasticsearch.cluster.metadata.IndexTemplateMetadata; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; @@ -20,6 +21,7 @@ import java.util.Objects; import static java.util.Collections.singletonMap; +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; public class GetIndexTemplatesResponse extends ActionResponse implements ToXContentObject { @@ -65,7 +67,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws builder.startObject(); for (IndexTemplateMetadata indexTemplateMetadata : getIndexTemplates()) { - IndexTemplateMetadata.Builder.toXContent(indexTemplateMetadata, builder, params); + if(builder.getRestApiVersion() == RestApiVersion.V_7 && + params.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, false)) { + IndexTemplateMetadata.Builder.toXContentWithTypes(indexTemplateMetadata, builder, params); + } else { + IndexTemplateMetadata.Builder.toXContent(indexTemplateMetadata, builder, params); + } } builder.endObject(); return builder; diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetadata.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetadata.java index 855e357bb6f93..fff997e4bc9ec 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetadata.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetadata.java @@ -37,6 +37,10 @@ import java.util.Objects; import java.util.Set; +import static org.elasticsearch.common.RestApiVersion.V_8; +import static org.elasticsearch.common.RestApiVersion.onOrAfter; + + public class IndexTemplateMetadata extends AbstractDiffable { private final String name; @@ -378,7 +382,9 @@ private static void toInnerXContent(IndexTemplateMetadata indexTemplateMetadata, indexTemplateMetadata.settings().toXContent(builder, params); builder.endObject(); - includeTypeName &= (params.paramAsBoolean("reduce_mappings", false) == false); + if(builder.getRestApiVersion().matches(onOrAfter(V_8))) { + includeTypeName &= (params.paramAsBoolean("reduce_mappings", false) == false); + } CompressedXContent m = indexTemplateMetadata.mappings(); if (m != null) { diff --git a/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java b/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java index 4bd7272b3c440..857e92bdbc18a 100644 --- a/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java +++ b/server/src/main/java/org/elasticsearch/rest/BaseRestHandler.java @@ -12,6 +12,7 @@ import org.apache.lucene.util.CollectionUtil; import org.elasticsearch.client.node.NodeClient; import org.elasticsearch.common.CheckedConsumer; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.collect.Tuple; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; @@ -40,6 +41,13 @@ */ public abstract class BaseRestHandler implements RestHandler { + /** + * Parameter that controls whether certain REST apis should include type names in their requests or responses. + * Note: This parameter is only available through compatible rest api for {@link RestApiVersion#V_7}. + */ + public static final String INCLUDE_TYPE_NAME_PARAMETER = "include_type_name"; + public static final boolean DEFAULT_INCLUDE_TYPE_NAME_POLICY = false; + public static final Setting MULTI_ALLOW_EXPLICIT_INDEX = Setting.boolSetting("rest.action.multi.allow_explicit_index", true, Property.NodeScope); @@ -72,14 +80,14 @@ public final void handleRequest(RestRequest request, RestChannel channel, NodeCl // use a sorted set so the unconsumed parameters appear in a reliable sorted order final SortedSet unconsumedParams = request.unconsumedParams() .stream() - .filter(p -> responseParams().contains(p) == false) + .filter(p -> responseParams(request.getRestApiVersion()).contains(p) == false) .collect(Collectors.toCollection(TreeSet::new)); // validate the non-response params if (unconsumedParams.isEmpty() == false) { final Set candidateParams = new HashSet<>(); candidateParams.addAll(request.consumedParams()); - candidateParams.addAll(responseParams()); + candidateParams.addAll(responseParams(request.getRestApiVersion())); throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter")); } @@ -174,6 +182,18 @@ protected Set responseParams() { return Collections.emptySet(); } + /** + * Parameters used for controlling the response and thus might not be consumed during + * preparation of the request execution. The value depends on the RestApiVersion provided + * by a user on a request. + * Used in RestHandlers with Compatible Rest Api + * @param restApiVersion - a version provided by a user on a request + * @return a set of parameters used to control the response, depending on a restApiVersion + */ + protected Set responseParams(RestApiVersion restApiVersion) { + return responseParams(); + } + public static class Wrapper extends BaseRestHandler { protected final BaseRestHandler delegate; @@ -202,6 +222,11 @@ protected Set responseParams() { return delegate.responseParams(); } + @Override + protected Set responseParams(RestApiVersion restApiVersion) { + return delegate.responseParams(restApiVersion); + } + @Override public boolean canTripCircuitBreaker() { return delegate.canTripCircuitBreaker(); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java index 78801211488f9..d5be27fca0d6d 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java @@ -11,6 +11,9 @@ import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.index.mapper.MapperService; @@ -19,6 +22,7 @@ import org.elasticsearch.rest.action.RestToXContentListener; import java.io.IOException; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -28,6 +32,10 @@ public class RestCreateIndexAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestCreateIndexAction.class); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in create " + + "index requests is deprecated. The parameter will be removed in the next major version."; + @Override public List routes() { return List.of(new Route(PUT, "/{index}")); @@ -40,7 +48,62 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + CreateIndexRequest createIndexRequest; + if (request.getRestApiVersion() == RestApiVersion.V_7) { + createIndexRequest = prepareRequestV7(request); + } else { + createIndexRequest = prepareRequest(request); + } + return channel -> client.admin().indices().create(createIndexRequest, new RestToXContentListener<>(channel)); + } + + // default scope for testing types in mapping + CreateIndexRequest prepareRequestV7(RestRequest request) { + CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index")); + if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + request.param(INCLUDE_TYPE_NAME_PARAMETER);// just consume, it is always replaced with _doc + deprecationLogger.compatibleApiWarning("create_index_with_types", TYPES_DEPRECATION_MESSAGE); + } + + if (request.hasContent()) { + Map sourceAsMap = XContentHelper.convertToMap(request.requiredContent(), false, request.getXContentType()).v2(); + + sourceAsMap = prepareMappingsV7(sourceAsMap, request); + + createIndexRequest.source(sourceAsMap, LoggingDeprecationHandler.INSTANCE); + } + + createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout())); + createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout())); + createIndexRequest.waitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); + return createIndexRequest; + } + + static Map prepareMappingsV7(Map source, RestRequest request) { + final boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, false); + + @SuppressWarnings("unchecked") + Map mappings = (Map) source.get("mappings"); + + if (includeTypeName && mappings != null && mappings.size() == 1) { + Map newSource = new HashMap<>(); + newSource.putAll(source); // mappings will be overridden. Aliases, settings stay the same + String typeName = mappings.keySet().iterator().next(); + if (Strings.hasText(typeName) == false) { + throw new IllegalArgumentException("name cannot be empty string"); + } + @SuppressWarnings("unchecked") + Map typedMappings = (Map) mappings.get(typeName); + + // no matter what the type was, replace it with _doc, because the internal representation still uses single type `_doc`. + newSource.put("mappings", Collections.singletonMap(MapperService.SINGLE_MAPPING_NAME, typedMappings)); + return newSource; + } else { + return prepareMappings(source); + } + } + CreateIndexRequest prepareRequest(RestRequest request) { CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index")); if (request.hasContent()) { @@ -53,9 +116,9 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout())); createIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", createIndexRequest.masterNodeTimeout())); createIndexRequest.waitForActiveShards(ActiveShardCount.parseString(request.param("wait_for_active_shards"))); - return channel -> client.admin().indices().create(createIndexRequest, new RestToXContentListener<>(channel)); - } + return createIndexRequest; + } static Map prepareMappings(Map source) { if (source.containsKey("mappings") == false @@ -68,7 +131,8 @@ static Map prepareMappings(Map source) { @SuppressWarnings("unchecked") Map mappings = (Map) source.get("mappings"); if (MapperService.isMappingSourceTyped(MapperService.SINGLE_MAPPING_NAME, mappings)) { - throw new IllegalArgumentException("The mapping definition cannot be nested under a type"); + throw new IllegalArgumentException("The mapping definition cannot be nested under a type " + + "[" + MapperService.SINGLE_MAPPING_NAME + "] unless include_type_name is set to true."); } newSource.put("mappings", singletonMap(MapperService.SINGLE_MAPPING_NAME, mappings)); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java index 4e192bb996ffa..3c1ae91d42123 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetFieldMappingAction.java @@ -8,12 +8,16 @@ package org.elasticsearch.rest.action.admin.indices; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetadata; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.BytesRestResponse; @@ -32,6 +36,11 @@ public class RestGetFieldMappingAction extends BaseRestHandler { + private static final Logger logger = LogManager.getLogger(RestGetFieldMappingAction.class); + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(logger.getName()); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get " + + "field mapping requests is deprecated. The parameter will be removed in the next major version."; + @Override public List routes() { return List.of( @@ -49,6 +58,12 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC final String[] indices = Strings.splitStringByCommaToArray(request.param("index")); final String[] fields = Strings.splitStringByCommaToArray(request.param("fields")); + if (request.getRestApiVersion() == RestApiVersion.V_7 && request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + request.param(INCLUDE_TYPE_NAME_PARAMETER); + deprecationLogger.compatibleApiWarning("get_field_mapping_with_types", TYPES_DEPRECATION_MESSAGE); + } + + GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest(); getMappingsRequest.indices(indices).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false)); getMappingsRequest.indicesOptions(IndicesOptions.fromRequest(request, getMappingsRequest.indicesOptions())); 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 10b97915f1e7e..4d42c371c591d 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 @@ -11,14 +11,18 @@ 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.RestApiVersion; 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; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.action.RestToXContentListener; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -31,6 +35,11 @@ * The REST handler for get template and head template APIs. */ public class RestGetIndexTemplateAction extends BaseRestHandler { + private static final Set COMPATIBLE_RESPONSE_PARAMS = Collections.unmodifiableSet(Sets.union( + Collections.singleton(INCLUDE_TYPE_NAME_PARAMETER), Settings.FORMAT_PARAMS)); + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestGetIndexTemplateAction.class); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get " + + "index template requests is deprecated. The parameter will be removed in the next major version."; @Override public List routes() { @@ -47,6 +56,9 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + if (request.getRestApiVersion() == RestApiVersion.V_7 && request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + deprecationLogger.compatibleApiWarning("get_index_template_include_type_name", TYPES_DEPRECATION_MESSAGE); + } final String[] names = Strings.splitStringByCommaToArray(request.param("name")); final GetIndexTemplatesRequest getIndexTemplatesRequest = new GetIndexTemplatesRequest(names); @@ -73,4 +85,12 @@ protected Set responseParams() { return Settings.FORMAT_PARAMS; } + @Override + protected Set responseParams(RestApiVersion restApiVersion) { + if(restApiVersion == RestApiVersion.V_7){ + return COMPATIBLE_RESPONSE_PARAMS; + } else { + return responseParams(); + } + } } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesAction.java index 6394666bd98e0..0b13c6620198c 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesAction.java @@ -12,15 +12,20 @@ import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; import java.io.IOException; +import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestRequest.Method.HEAD; @@ -29,6 +34,13 @@ * The REST handler for get index and head index APIs. */ public class RestGetIndicesAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestGetIndicesAction.class); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using `include_type_name` in get indices requests" + + " is deprecated. The parameter will be removed in the next major version."; + + private static final Set COMPATIBLE_RESPONSE_PARAMS = Collections + .unmodifiableSet(Stream.concat(Collections.singleton(INCLUDE_TYPE_NAME_PARAMETER).stream(), Settings.FORMAT_PARAMS.stream()) + .collect(Collectors.toSet())); @Override public List routes() { @@ -44,6 +56,12 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + // starting with 7.0 we don't include types by default in the response to GET requests + if (request.getRestApiVersion() == RestApiVersion.V_7 && + request.hasParam(INCLUDE_TYPE_NAME_PARAMETER) && request.method().equals(GET)) { + deprecationLogger.compatibleApiWarning("get_indices_with_types", TYPES_DEPRECATION_MESSAGE); + } + String[] indices = Strings.splitStringByCommaToArray(request.param("index")); final GetIndexRequest getIndexRequest = new GetIndexRequest(); getIndexRequest.indices(indices); @@ -63,4 +81,13 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC protected Set responseParams() { return Settings.FORMAT_PARAMS; } + + @Override + protected Set responseParams(RestApiVersion restApiVersion) { + if(restApiVersion == RestApiVersion.V_7){ + return COMPATIBLE_RESPONSE_PARAMS; + } else { + return responseParams(); + } + } } diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java index 53585818546f4..96bfb63d45abf 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestGetMappingAction.java @@ -14,7 +14,9 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.rest.BaseRestHandler; @@ -32,6 +34,9 @@ import static org.elasticsearch.rest.RestRequest.Method.GET; public class RestGetMappingAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestGetMappingAction.class); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in get" + + " mapping requests is deprecated. The parameter will be removed in the next major version."; private final ThreadPool threadPool; @@ -55,6 +60,11 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + if (request.getRestApiVersion() == RestApiVersion.V_7 && request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + request.param(INCLUDE_TYPE_NAME_PARAMETER); + deprecationLogger.compatibleApiWarning("get_mapping_with_types", TYPES_DEPRECATION_MESSAGE); + } + final String[] indices = Strings.splitStringByCommaToArray(request.param("index")); final GetMappingsRequest getMappingsRequest = new GetMappingsRequest(); 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 f330219c1b89f..3980f9d34054b 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 @@ -28,11 +28,13 @@ public class RestPutIndexTemplateAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestPutIndexTemplateAction.class); public static final String DEPRECATION_WARNING = "Legacy index templates are deprecated and will be removed completely in a " + "future version. Please use composable templates instead."; private static final RestApiVersion DEPRECATION_VERSION = RestApiVersion.V_8; - private static final DeprecationLogger deprecationLogger = DeprecationLogger.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."; @Override public List routes() { return List.of( @@ -67,7 +69,19 @@ public RestChannelConsumer prepareRequest(final RestRequest request, final NodeC Map sourceAsMap = XContentHelper.convertToMap(request.requiredContent(), false, request.getXContentType()).v2(); - sourceAsMap = RestCreateIndexAction.prepareMappings(sourceAsMap); + if(request.getRestApiVersion() == RestApiVersion.V_7) { + if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER) ) { + deprecationLogger.compatibleApiWarning("put_index_template_with_types", TYPES_DEPRECATION_MESSAGE); + } + boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY); + if(includeTypeName) { + sourceAsMap = RestCreateIndexAction.prepareMappingsV7(sourceAsMap, request); + } else { + sourceAsMap = RestCreateIndexAction.prepareMappings(sourceAsMap); + } + } else { + sourceAsMap = RestCreateIndexAction.prepareMappings(sourceAsMap); + } if (request.getRestApiVersion() == RestApiVersion.V_7 && sourceAsMap.containsKey("template")) { deprecationLogger.compatibleApiWarning("template_field_deprecation", "Deprecated field [template] used, replaced by [index_patterns]"); diff --git a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestRolloverIndexAction.java b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestRolloverIndexAction.java index 025e291176ef4..d8e0c329702f6 100644 --- a/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestRolloverIndexAction.java +++ b/server/src/main/java/org/elasticsearch/rest/action/admin/indices/RestRolloverIndexAction.java @@ -11,6 +11,8 @@ import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; import org.elasticsearch.action.support.ActiveShardCount; import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; +import org.elasticsearch.common.logging.DeprecationLogger; import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.rest.RestRequest; import org.elasticsearch.rest.action.RestToXContentListener; @@ -22,6 +24,10 @@ public class RestRolloverIndexAction extends BaseRestHandler { + private static final DeprecationLogger deprecationLogger = DeprecationLogger.getLogger(RestRolloverIndexAction.class); + public static final String TYPES_DEPRECATION_MESSAGE = "[types removal] Using include_type_name in rollover " + + "index requests is deprecated. The parameter will be removed in the next major version."; + @Override public List routes() { return List.of( @@ -36,13 +42,25 @@ public String getName() { @Override public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException { + final boolean includeTypeName = includeTypeName(request); RolloverRequest rolloverIndexRequest = new RolloverRequest(request.param("index"), request.param("new_index")); - request.applyContentParser(rolloverIndexRequest::fromXContent); + request.applyContentParser(parser -> rolloverIndexRequest.fromXContent(includeTypeName, parser)); rolloverIndexRequest.dryRun(request.paramAsBoolean("dry_run", false)); rolloverIndexRequest.timeout(request.paramAsTime("timeout", rolloverIndexRequest.timeout())); rolloverIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", rolloverIndexRequest.masterNodeTimeout())); rolloverIndexRequest.getCreateIndexRequest().waitForActiveShards( - ActiveShardCount.parseString(request.param("wait_for_active_shards"))); + ActiveShardCount.parseString(request.param("wait_for_active_shards"))); return channel -> client.admin().indices().rolloverIndex(rolloverIndexRequest, new RestToXContentListener<>(channel)); } + + private boolean includeTypeName(RestRequest request) { + boolean includeTypeName = false; + if (request.getRestApiVersion() == RestApiVersion.V_7) { + if (request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)) { + deprecationLogger.compatibleApiWarning("index_rollover_with_types", TYPES_DEPRECATION_MESSAGE); + } + includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, DEFAULT_INCLUDE_TYPE_NAME_POLICY); + } + return includeTypeName; + } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java index b967195eea83b..1b235c50e3a0a 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponseTests.java @@ -9,11 +9,19 @@ package org.elasticsearch.action.admin.indices.mapping.get; import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetadata; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.Strings; import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.Writeable; +import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.common.xcontent.json.JsonXContent; +import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.rest.BaseRestHandler; import org.elasticsearch.test.AbstractWireSerializingTestCase; import java.io.IOException; @@ -21,6 +29,8 @@ import java.util.HashMap; import java.util.Map; +import static org.hamcrest.Matchers.hasKey; + public class GetFieldMappingsResponseTests extends AbstractWireSerializingTestCase { public void testManualSerialization() throws IOException { @@ -47,6 +57,56 @@ public void testNullFieldMappingToXContent() { assertEquals("{\"index\":{\"mappings\":{}}}", Strings.toString(response)); } + public void testToXContentIncludesType() throws Exception { + Map> mappings = new HashMap<>(); + FieldMappingMetadata fieldMappingMetadata = new FieldMappingMetadata("my field", new BytesArray("{}")); + mappings.put("index", Collections.singletonMap("field", fieldMappingMetadata)); + GetFieldMappingsResponse response = new GetFieldMappingsResponse(mappings); + ToXContent.Params params = new ToXContent.MapParams(Collections.singletonMap(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, + "true")); + + // v7 with include_type_name attaches _doc + try (XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent, RestApiVersion.V_7)) { + response.toXContent(builder, params); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + Map>> index = + (Map>>) parser.map().get("index"); + assertThat(index.get("mappings"), hasKey(MapperService.SINGLE_MAPPING_NAME)); + assertThat(index.get("mappings").get(MapperService.SINGLE_MAPPING_NAME), hasKey("field")); + } + } + + // v7 with no include_type_name do not attach _doc + try (XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent, RestApiVersion.V_7)) { + response.toXContent(builder, ToXContent.EMPTY_PARAMS); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + Map> index = (Map>) parser.map().get("index"); + assertThat(index.get("mappings"), hasKey("field")); + } + } + //v8 does not have _doc, even when include_type_name is present + // (although this throws unconsumed parameter exception in RestGetFieldMappingsAction) + try (XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent, RestApiVersion.V_8)) { + response.toXContent(builder, params); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + Map> index = (Map>) parser.map().get("index"); + assertThat(index.get("mappings"), hasKey("field")); + } + } + + try (XContentBuilder builder = XContentBuilder.builder(JsonXContent.jsonXContent, RestApiVersion.V_8)) { + response.toXContent(builder, ToXContent.EMPTY_PARAMS); + + try (XContentParser parser = createParser(JsonXContent.jsonXContent, BytesReference.bytes(builder))) { + Map> index = (Map>) parser.map().get("index"); + assertThat(index.get("mappings"), hasKey("field")); + } + } + } + @Override protected GetFieldMappingsResponse createTestInstance() { return new GetFieldMappingsResponse(randomMapping()); @@ -61,7 +121,7 @@ private Map> randomMapping() { Map> mappings = new HashMap<>(); int indices = randomInt(10); - for(int i = 0; i < indices; i++) { + for (int i = 0; i < indices; i++) { Map fieldMappings = new HashMap<>(); int fields = randomInt(10); for (int k = 0; k < fields; k++) { diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequestTests.java index ced6901b6daaa..7269c68a3d3a8 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/RolloverRequestTests.java @@ -10,6 +10,7 @@ import org.elasticsearch.action.ActionRequestValidationException; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.common.RestApiVersion; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.io.stream.BytesStreamOutput; @@ -23,7 +24,9 @@ import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParseException; +import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.indices.IndicesModule; import org.elasticsearch.test.ESTestCase; @@ -60,7 +63,7 @@ public void testConditionsParsing() throws Exception { .field("max_primary_shard_size", "55gb") .endObject() .endObject(); - request.fromXContent(createParser(builder)); + request.fromXContent(false, createParser(builder)); Map> conditions = request.getConditions(); assertThat(conditions.size(), equalTo(4)); MaxAgeCondition maxAgeCondition = (MaxAgeCondition)conditions.get(MaxAgeCondition.NAME); @@ -97,7 +100,7 @@ public void testParsingWithIndexSettings() throws Exception { .startObject("alias1").endObject() .endObject() .endObject(); - request.fromXContent(createParser(builder)); + request.fromXContent(false, createParser(builder)); Map> conditions = request.getConditions(); assertThat(conditions.size(), equalTo(2)); assertThat(request.getCreateIndexRequest().mappings(), containsString("not_analyzed")); @@ -118,7 +121,7 @@ public void testTypelessMappingParsing() throws Exception { .endObject() .endObject(); - request.fromXContent(createParser(builder)); + request.fromXContent(false, createParser(builder)); CreateIndexRequest createIndexRequest = request.getCreateIndexRequest(); String mapping = createIndexRequest.mappings(); @@ -167,7 +170,7 @@ public void testUnknownFields() throws IOException { } builder.endObject(); BytesReference mutated = XContentTestUtils.insertRandomFields(xContentType, BytesReference.bytes(builder), null, random()); - expectThrows(XContentParseException.class, () -> request.fromXContent(createParser(xContentType.xContent(), mutated))); + expectThrows(XContentParseException.class, () -> request.fromXContent(false, createParser(xContentType.xContent(), mutated))); } public void testSameConditionCanOnlyBeAddedOnce() { @@ -186,6 +189,63 @@ public void testValidation() { assertEquals("rollover target is missing", validationException.validationErrors().get(0)); } + public void testParsingWithType() throws Exception { + final XContentBuilder builder = XContentFactory.jsonBuilder() + .startObject() + .startObject("conditions") + .field("max_age", "10d") + .field("max_docs", 100) + .endObject() + .startObject("mappings") + .startObject("type1") + .startObject("properties") + .startObject("field1") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + .endObject() + .endObject() + .endObject() + .startObject("settings") + .field("number_of_shards", 10) + .endObject() + .startObject("aliases") + .startObject("alias1").endObject() + .endObject() + .endObject(); + + try (XContentParser parser = createParserWithCompatibilityFor(JsonXContent.jsonXContent, + BytesReference.bytes(builder).utf8ToString(), RestApiVersion.V_7)) { + final RolloverRequest request = new RolloverRequest(randomAlphaOfLength(10), randomAlphaOfLength(10)); + request.fromXContent(true, parser); + Map> conditions = request.getConditions(); + assertThat(conditions.size(), equalTo(2)); + assertThat(request.getCreateIndexRequest().mappings(), + equalTo("{\"_doc\":{\"properties\":{\"field1\":{\"index\":\"not_analyzed\",\"type\":\"string\"}}}}")); + } + } + + public void testTypedRequestWithoutIncludeTypeName() throws IOException { + final XContentBuilder builder = XContentFactory.jsonBuilder() + .startObject() + .startObject("mappings") + .startObject("_doc") + .startObject("properties") + .startObject("field1") + .field("type", "string") + .field("index", "not_analyzed") + .endObject() + .endObject() + .endObject() + .endObject() + .endObject(); + try (XContentParser parser = createParserWithCompatibilityFor(JsonXContent.jsonXContent, + BytesReference.bytes(builder).utf8ToString(), RestApiVersion.V_7)) { + final RolloverRequest request = new RolloverRequest(randomAlphaOfLength(10), randomAlphaOfLength(10)); + expectThrows(IllegalArgumentException.class, () -> request.fromXContent(false, parser)); + } + } + private static List> conditionsGenerator = new ArrayList<>(); static { conditionsGenerator.add((request) -> request.addMaxIndexDocsCondition(randomNonNegativeLong())); diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java index fe89d90405777..b38c5d69b6fb8 100644 --- a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexActionTests.java @@ -8,15 +8,29 @@ package org.elasticsearch.rest.action.admin.indices; +import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.rest.RestRequest; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.Mockito.mock; + public class RestCreateIndexActionTests extends ESTestCase { public void testPrepareTypelessRequest() throws IOException { @@ -69,4 +83,59 @@ public void testMalformedMappings() throws IOException { Map source = RestCreateIndexAction.prepareMappings(contentAsMap); assertEquals(contentAsMap, source); } + + public void testIncludeTypeName() throws IOException { + RestCreateIndexAction action = new RestCreateIndexAction(); + List compatibleMediaType = Collections.singletonList(randomCompatibleMediaType(RestApiVersion.V_7)); + + Map params = new HashMap<>(); + params.put(INCLUDE_TYPE_NAME_PARAMETER, randomFrom("true", "false")); + RestRequest deprecatedRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Accept", compatibleMediaType)) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index") + .withParams(params) + .build(); + + action.prepareRequest(deprecatedRequest, mock(NodeClient.class)); + assertWarnings(RestCreateIndexAction.TYPES_DEPRECATION_MESSAGE); + + RestRequest validRequest = new FakeRestRequest.Builder(xContentRegistry()) + .withMethod(RestRequest.Method.PUT) + .withPath("/some_index") + .build(); + action.prepareRequest(validRequest, mock(NodeClient.class)); + } + + public void testTypeInMapping() throws IOException { + RestCreateIndexAction action = new RestCreateIndexAction(); + + List contentTypeHeader = Collections.singletonList(compatibleMediaType(XContentType.VND_JSON, RestApiVersion.V_7)); + + String content = "{\n" + + " \"mappings\": {\n" + + " \"some_type\": {\n" + + " \"properties\": {\n" + + " \"field1\": {\n" + + " \"type\": \"text\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + + Map params = new HashMap<>(); + params.put(RestCreateIndexAction.INCLUDE_TYPE_NAME_PARAMETER, "true"); + RestRequest request = new FakeRestRequest.Builder(xContentRegistry()).withMethod(RestRequest.Method.PUT) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withPath("/some_index") + .withParams(params) + .withContent(new BytesArray(content), null) + .build(); + + CreateIndexRequest createIndexRequest = action.prepareRequestV7(request); + // some_type is replaced with _doc + assertThat(createIndexRequest.mappings(), equalTo("{\"_doc\":{\"properties\":{\"field1\":{\"type\":\"text\"}}}}")); + assertWarnings(RestCreateIndexAction.TYPES_DEPRECATION_MESSAGE); + } } diff --git a/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesActionTests.java new file mode 100644 index 0000000000000..38e1c6d6cc13d --- /dev/null +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestGetIndicesActionTests.java @@ -0,0 +1,71 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.rest.action.admin.indices; + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; +import static org.mockito.Mockito.mock; + +public class RestGetIndicesActionTests extends ESTestCase { + final List contentTypeHeader = Collections.singletonList(randomCompatibleMediaType(RestApiVersion.V_7)); + + /** + * Test that setting the "include_type_name" parameter raises a warning for the GET request + */ + public void testIncludeTypeNamesWarning() throws IOException { + Map params = new HashMap<>(); + params.put(INCLUDE_TYPE_NAME_PARAMETER, randomFrom("true", "false")); + RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.GET) + .withPath("/some_index") + .withParams(params) + .build(); + + RestGetIndicesAction handler = new RestGetIndicesAction(); + handler.prepareRequest(request, mock(NodeClient.class)); + assertWarnings(RestGetIndicesAction.TYPES_DEPRECATION_MESSAGE); + + // the same request without the parameter should pass without warning + request = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.GET) + .withPath("/some_index") + .build(); + handler.prepareRequest(request, mock(NodeClient.class)); + } + + /** + * Test that setting the "include_type_name" parameter doesn't raises a warning if the HEAD method is used (indices.exists) + */ + public void testIncludeTypeNamesWarningExists() throws IOException { + Map params = new HashMap<>(); + params.put(INCLUDE_TYPE_NAME_PARAMETER, randomFrom("true", "false")); + RestRequest request = new FakeRestRequest.Builder(xContentRegistry()) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.HEAD) + .withPath("/some_index") + .withParams(params) + .build(); + + RestGetIndicesAction handler = new RestGetIndicesAction(); + handler.prepareRequest(request, mock(NodeClient.class)); + } +} 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 new file mode 100644 index 0000000000000..4fc39dde435b8 --- /dev/null +++ b/server/src/test/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateActionTests.java @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +package org.elasticsearch.rest.action.admin.indices; + + +import org.elasticsearch.client.node.NodeClient; +import org.elasticsearch.common.RestApiVersion; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.rest.RestRequest; +import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.test.rest.FakeRestRequest; +import org.junit.Before; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER; +import static org.mockito.Mockito.mock; + +public class RestPutIndexTemplateActionTests extends ESTestCase { + final List contentTypeHeader = Collections.singletonList(compatibleMediaType(XContentType.VND_JSON, RestApiVersion.V_7)); + + private RestPutIndexTemplateAction action; + + @Before + public void setUpAction() { + action = new RestPutIndexTemplateAction(); + } + + 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()) + .withHeaders(Map.of("Content-Type", contentTypeHeader, "Accept", contentTypeHeader)) + .withMethod(RestRequest.Method.PUT) + .withParams(params) + .withPath("/_template/_some_template") + .withContent(BytesReference.bytes(typedContent), null) + .build(); + action.prepareRequest(request, mock(NodeClient.class)); + assertWarnings(RestPutIndexTemplateAction.TYPES_DEPRECATION_MESSAGE); + } +} diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java index ab2a5f9b0cbe8..0994b015e2136 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java @@ -1145,6 +1145,10 @@ public static Class getTestTransportPlugin() { public String randomCompatibleMediaType(RestApiVersion version) { XContentType type = randomFrom(XContentType.VND_JSON, XContentType.VND_SMILE, XContentType.VND_CBOR, XContentType.VND_YAML); + return compatibleMediaType(type, version); + } + + public String compatibleMediaType(XContentType type, RestApiVersion version) { return type.toParsedMediaType() .responseContentTypeHeader(Map.of(MediaType.COMPATIBLE_WITH_PARAMETER_NAME, String.valueOf(version.major))); } diff --git a/x-pack/plugin/build.gradle b/x-pack/plugin/build.gradle index 4bdf449df6082..6372256ac9ab6 100644 --- a/x-pack/plugin/build.gradle +++ b/x-pack/plugin/build.gradle @@ -6,6 +6,7 @@ apply plugin: 'elasticsearch.yaml-rest-test' apply plugin: 'elasticsearch.yaml-rest-compat-test' apply plugin: 'elasticsearch.validate-rest-spec' apply plugin: 'elasticsearch.internal-test-artifact' +apply plugin: 'elasticsearch.yaml-rest-compat-test' archivesBaseName = 'x-pack' @@ -97,72 +98,61 @@ tasks.named("yamlRestCompatTest").configure { //TODO: blacklist specific to REST API compatibility restTestBlacklist.addAll([ - 'license/30_enterprise_license/Installing enterprise license', - 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header and column selection', - 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header', - 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics single job with header', - 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics single job', - 'ml/datafeed_cat_apis/Test cat datafeeds', - 'ml/datafeeds_crud/Test update datafeed to point to different job', - 'ml/datafeeds_crud/Test update datafeed to point to job already attached to another datafeed', - 'ml/datafeeds_crud/Test update datafeed to point to missing job', - 'ml/job_cat_apis/Test cat anomaly detector jobs', - 'ml/jobs_get_stats/Test get job stats after uploading data prompting the creation of some stats', - 'ml/jobs_get_stats/Test get job stats for closed job', - 'ml/jobs_get_stats/Test no exception on get job stats with missing index', - 'ml/post_data/Test flush with skip_time', - 'ml/post_data/Test POST data job api, flush, close and verify DataCounts doc', - 'ml/set_upgrade_mode/Setting upgrade mode to disabled from enabled', - 'ml/set_upgrade_mode/Setting upgrade_mode to enabled', - 'ml/set_upgrade_mode/Test setting upgrade_mode to false when it is already false', - 'ml/trained_model_cat_apis/Test cat trained models', - 'privileges/11_builtin/Test get builtin privileges', - 'roles/11_idx_arrays/Test put role api using as array of index names', - 'roles/30_prohibited_role_query/Test use prohibited query inside role query', - 'rollup/delete_job/Test basic delete_job', - 'rollup/delete_job/Test delete job twice', - 'rollup/delete_job/Test delete running job', - 'rollup/get_jobs/Test basic get_jobs', - 'rollup/put_job/Test basic put_job', - 'rollup/put_job/Test put_job in non-rollup index', - 'rollup/rollup_search/Obsolete BWC Timezone', - 'rollup/rollup_search/Obsolete Timezone', - 'rollup/start_job/Test start job twice', - 'security/authz/14_cat_indices/Test empty request while no-authorized index', - 'security/authz/14_cat_indices/Test empty request while single authorized index', - 'security/authz/14_cat_indices/Test explicit request while multiple authorized indices', - 'security/authz/14_cat_indices/Test explicit request while multiple opened/closed authorized indices', - 'security/authz/14_cat_indices/Test wildcard request with multiple authorized indices', - 'set_security_user/10_small_users_one_index/Test shared index separating user by using DLS', - 'sql/sql/Clean cursor', - 'sql/sql/Execute some SQL', - 'sql/sql/Getting textual representation', - 'sql/sql/Paging through results', - 'sql/translate/Translate SQL', - 'transform/transforms_cat_apis/Test cat transform stats hiding headers', - 'transform/transforms_cat_apis/Test cat transform stats with column selection', - 'transform/transforms_cat_apis/Test cat transform stats with continuous transform', - 'vectors/10_dense_vector_basic/Cosine Similarity', - 'vectors/10_dense_vector_basic/Deprecated function signature', - 'vectors/10_dense_vector_basic/Dot Product', - 'vectors/15_dense_vector_l1l2/L1 norm', - 'vectors/15_dense_vector_l1l2/L2 norm', - 'vectors/20_dense_vector_special_cases/Dense vectors should error with sparse vector functions', - 'vectors/20_dense_vector_special_cases/Documents missing a vector field', - 'vectors/20_dense_vector_special_cases/Functions with query vectors with dims different from docs vectors should error', - 'vectors/20_dense_vector_special_cases/Indexing of Dense vectors should error when dims don\'t match defined in the mapping', - 'vectors/20_dense_vector_special_cases/Vectors of mixed integers and floats', - 'vectors/30_sparse_vector_basic/Cosine Similarity', - 'vectors/30_sparse_vector_basic/Deprecated function signature', - 'vectors/30_sparse_vector_basic/Dot Product', - 'vectors/35_sparse_vector_l1l2/L1 norm', - 'vectors/35_sparse_vector_l1l2/L2 norm', - 'vectors/40_sparse_vector_special_cases/Dimensions can be sorted differently', - 'vectors/40_sparse_vector_special_cases/Documents missing a vector field', - 'vectors/40_sparse_vector_special_cases/Query vector has different dimensions from documents\' vectors', - 'vectors/40_sparse_vector_special_cases/Sparse vectors should error with dense vector functions', - 'vectors/40_sparse_vector_special_cases/Vectors of different dimensions and data types', - 'vectors/50_vector_stats/Usage stats on vector fields' + 'license/30_enterprise_license/Installing enterprise license', + 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header and column selection', + 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics all jobs with header', + 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics single job with header', + 'ml/data_frame_analytics_cat_apis/Test cat data frame analytics single job', + 'ml/datafeed_cat_apis/Test cat datafeeds', + 'ml/datafeeds_crud/Test update datafeed to point to different job', + 'ml/datafeeds_crud/Test update datafeed to point to job already attached to another datafeed', + 'ml/datafeeds_crud/Test update datafeed to point to missing job', + 'ml/job_cat_apis/Test cat anomaly detector jobs', + 'ml/jobs_get_stats/Test get job stats after uploading data prompting the creation of some stats', + 'ml/jobs_get_stats/Test get job stats for closed job', + 'ml/jobs_get_stats/Test no exception on get job stats with missing index', + 'ml/post_data/Test POST data job api, flush, close and verify DataCounts doc', + 'ml/post_data/Test flush with skip_time', + 'ml/set_upgrade_mode/Setting upgrade mode to disabled from enabled', + 'ml/set_upgrade_mode/Setting upgrade_mode to enabled', + 'ml/set_upgrade_mode/Test setting upgrade_mode to false when it is already false', + 'ml/trained_model_cat_apis/Test cat trained models', + 'roles/11_idx_arrays/Test put role api using as array of index names', + 'roles/30_prohibited_role_query/Test use prohibited query inside role query', + 'rollup/delete_job/Test basic delete_job', + 'rollup/delete_job/Test delete job twice', + 'rollup/delete_job/Test delete running job', + 'rollup/get_jobs/Test basic get_jobs', + 'rollup/put_job/Test basic put_job', + 'rollup/put_job/Test put_job in non-rollup index', + 'rollup/rollup_search/Obsolete BWC Timezone', + 'rollup/rollup_search/Obsolete Timezone', + 'rollup/start_job/Test start job twice', + 'security/authz/14_cat_indices/Test empty request while no-authorized index', + 'security/authz/14_cat_indices/Test empty request while single authorized index', + 'security/authz/14_cat_indices/Test explicit request while multiple authorized indices', + 'security/authz/14_cat_indices/Test explicit request while multiple opened/closed authorized indices', + 'security/authz/14_cat_indices/Test wildcard request with multiple authorized indices', + 'sql/sql/Clean cursor', + 'sql/sql/Execute some SQL', + 'sql/sql/Getting textual representation', + 'sql/sql/Paging through results', + 'sql/translate/Translate SQL', + 'transform/transforms_cat_apis/Test cat transform stats hiding headers', + 'transform/transforms_cat_apis/Test cat transform stats with column selection', + 'transform/transforms_cat_apis/Test cat transform stats with continuous transform', + 'vectors/10_dense_vector_basic/Deprecated function signature', + 'vectors/30_sparse_vector_basic/Cosine Similarity', + 'vectors/30_sparse_vector_basic/Deprecated function signature', + 'vectors/30_sparse_vector_basic/Dot Product', + 'vectors/35_sparse_vector_l1l2/L1 norm', + 'vectors/35_sparse_vector_l1l2/L2 norm', + 'vectors/40_sparse_vector_special_cases/Dimensions can be sorted differently', + 'vectors/40_sparse_vector_special_cases/Documents missing a vector field', + 'vectors/40_sparse_vector_special_cases/Query vector has different dimensions from documents\' vectors', + 'vectors/40_sparse_vector_special_cases/Sparse vectors should error with dense vector functions', + 'vectors/40_sparse_vector_special_cases/Vectors of different dimensions and data types', + 'vectors/50_vector_stats/Usage stats on vector fields' ]) systemProperty 'tests.rest.blacklist', restTestBlacklist.join(',') @@ -215,3 +205,8 @@ tasks.register('enforceYamlTestConvention').configure { tasks.named("precommit").configure { dependsOn 'enforceYamlTestConvention', 'enforceApiSpecsConvention' } + +tasks.named("transformV7RestTests").configure({ task -> + task.replaceMatch("_type", "_doc") + task.addAllowedWarningRegex("\\[types removal\\].*") +})