diff --git a/docs/changelog/144040.yaml b/docs/changelog/144040.yaml new file mode 100644 index 0000000000000..e0d2dd322f775 --- /dev/null +++ b/docs/changelog/144040.yaml @@ -0,0 +1,10 @@ +area: Mapping +issues: + - 142544 + - 142964 + - 142410 + - 143884 + - 142477 +pr: 144040 +summary: Drop deprecation warnings when updating a mapping in the cluster state applier +type: bug diff --git a/muted-tests.yml b/muted-tests.yml index 70a239844d732..c0db6b02a8914 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -408,9 +408,6 @@ tests: - class: org.elasticsearch.xpack.esql.qa.single_node.EsqlSpecIT method: test {csv-spec:approximation.Approximate stats with sample} issue: https://github.com/elastic/elasticsearch/issues/144022 -- class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlClientYamlIT - method: test {p0=esql/40_tsdb/to_aggregate_metric_double with multi_values} - issue: https://github.com/elastic/elasticsearch/issues/142964 - class: org.elasticsearch.repositories.azure.AzureBlobContainerRetriesTests method: testWriteBlobWithRetries issue: https://github.com/elastic/elasticsearch/issues/144025 diff --git a/server/src/main/java/org/elasticsearch/index/IndexService.java b/server/src/main/java/org/elasticsearch/index/IndexService.java index f47b8fe1cc61c..28155a1ae6026 100644 --- a/server/src/main/java/org/elasticsearch/index/IndexService.java +++ b/server/src/main/java/org/elasticsearch/index/IndexService.java @@ -884,7 +884,12 @@ List getSearchOperationListener() { // pkg private for public void updateMapping(final IndexMetadata currentIndexMetadata, final IndexMetadata newIndexMetadata) { if (mapperService != null) { - mapperService.updateMapping(currentIndexMetadata, newIndexMetadata); + // Mapper service re-parses the mapping here, potentially adding deprecation warning response headers, but we're in the process + // of applying the cluster state and have no way to send these warnings back to the client so we just drop them. We will have + // generated, and sent back, the same headers while handling the request that created this mapping in the first place. + try (var ignored = threadPool.getThreadContext().newStoredContext()) { + mapperService.updateMapping(currentIndexMetadata, newIndexMetadata); + } } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index 4d72f2de453da..0144aaee78f42 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -12,7 +12,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.lucene.index.LeafReaderContext; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.common.Explicit; import org.elasticsearch.common.TriFunction; @@ -1940,13 +1939,6 @@ public final void parse(String name, MappingParserContext parserContext, Map getEngineFactory(final IndexSettings indexSetting } + static class DeprecatedParameterMapper extends FieldMapper { + + static final String CONTENT_TYPE = "deprecated-param-mapper"; + + private DeprecatedParameterMapper(String simpleName, MappedFieldType mappedFieldType, BuilderParams builderParams) { + super(simpleName, mappedFieldType, builderParams); + } + + @Override + protected void parseCreateField(DocumentParserContext context) {} + + @Override + public Builder getMergeBuilder() { + return new DeprecatedParameterMapper.TypeBuilder(leafName()).init(this); + } + + @Override + protected String contentType() { + return CONTENT_TYPE; + } + + static class TypeBuilder extends FieldMapper.Builder { + + private final Parameter deprecatedParam = Parameter.stringParam( + "deprecated_field", + true, + m -> ((DeprecatedParameterFieldType) m.fieldType()).deprecatedField, + null + ).acceptsNull().deprecated(); + + TypeBuilder(String name) { + super(name); + } + + @Override + protected Parameter[] getParameters() { + return new Parameter[] { deprecatedParam }; + } + + @Override + public String contentType() { + return CONTENT_TYPE; + } + + @Override + public FieldMapper build(MapperBuilderContext context) { + return new DeprecatedParameterMapper( + leafName(), + new DeprecatedParameterFieldType(context.buildFullName(leafName()), deprecatedParam.getValue()), + builderParams(this, context) + ); + } + } + + static class DeprecatedParameterFieldType extends MappedFieldType { + + private final String deprecatedField; + + DeprecatedParameterFieldType(String name, String deprecatedField) { + super(name, IndexType.NONE, false, Map.of()); + this.deprecatedField = deprecatedField; + } + + @Override + public ValueFetcher valueFetcher(SearchExecutionContext context, String format) { + return ValueFetcher.EMPTY; + } + + @Override + public String typeName() { + return CONTENT_TYPE; + } + + @Override + public Query termQuery(Object value, SearchExecutionContext context) { + throw new UnsupportedOperationException(); + } + } + } + public static class TestPlugin extends Plugin implements MapperPlugin { public TestPlugin() {} @Override public Map getMappers() { - return Collections.singletonMap("fake-mapper", KeywordFieldMapper.PARSER); + return Map.of( + "fake-mapper", + KeywordFieldMapper.PARSER, + DeprecatedParameterMapper.CONTENT_TYPE, + new FieldMapper.TypeParser((name, parserContext) -> new DeprecatedParameterMapper.TypeBuilder(name)) + ); } @Override @@ -940,6 +1034,45 @@ public void testMapperServiceForValidationChecksMapping() throws IOException { assertNull(temporaryDocumentMapper); } + /** + * Tests that deprecations warnings do not leak when the mapping is updated + */ + public void testDeprecationsWarningsDoNotEscape() throws IOException { + IndicesService indicesService = getIndicesService(); + IndexMetadata initialIndexMetadata = IndexMetadata.builder("test") + .settings(indexSettings(IndexVersion.current(), randomUUID(), 1, 0)) + .build(); + IndexService indexService = indicesService.createIndex(initialIndexMetadata, List.of(), randomBoolean()); + + IndexMetadata newIndexMetadata = IndexMetadata.builder(initialIndexMetadata) + .mappingVersion(initialIndexMetadata.getMappingVersion() + 1) + .putMapping(""" + { + "_doc":{ + "properties": { + "my-field": { + "type": "deprecated-param-mapper", + "deprecated_field": "someValue" + } + } + } + }""") + .build(); + indexService.updateMapping(initialIndexMetadata, newIndexMetadata); + // This test sets two thread contexts to the HeaderWarning class, the thread context of the ESTestCase and the + // thread pool one, consequently the deprecation warning is added to both. The production code will only have + // the thread pool context, so we test the isolation of this context only. + final List warnings = indexService.getThreadPool().getThreadContext().getResponseHeaders().get("Warning"); + if (warnings != null) { + assertThat( + warnings, + not(contains(containsString("Parameter [deprecated_field] is deprecated and will be removed in a future version"))) + ); + } + // For the test's thread context we just handle the expected warning. + assertWarnings("Parameter [deprecated_field] is deprecated and will be removed in a future version"); + } + private Set resolvedExpressions(String... expressions) { return Arrays.stream(expressions).map(ResolvedExpression::new).collect(Collectors.toSet()); } diff --git a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/Clusters.java b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/Clusters.java index add63db533eeb..c68561b3b3594 100644 --- a/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/Clusters.java +++ b/x-pack/plugin/esql/qa/server/mixed-cluster/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/mixed/Clusters.java @@ -23,9 +23,7 @@ public static ElasticsearchCluster mixedVersionCluster() { .withNode(node -> node.version(oldVersionString, isDetachedVersion)) .withNode(node -> node.version(Version.CURRENT)) .setting("xpack.security.enabled", "false") - .setting("xpack.license.self_generated.type", "trial") - // Remove after https://github.com/elastic/elasticsearch/issues/143884 (only the current version will log the stack trace) - .setting("logger.org.elasticsearch.index.mapper.FieldMapper", "DEBUG"); + .setting("xpack.license.self_generated.type", "trial"); if (supportRetryOnShardFailures(oldVersion) == false) { cluster.setting("cluster.routing.rebalance.enable", "none"); } diff --git a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/FieldExtractorIT.java b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/FieldExtractorIT.java index d7e9773b1fbb6..7f41a5ee0a666 100644 --- a/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/FieldExtractorIT.java +++ b/x-pack/plugin/esql/qa/server/multi-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/multi_node/FieldExtractorIT.java @@ -18,10 +18,7 @@ @ThreadLeakFilters(filters = TestClustersThreadFilter.class) public class FieldExtractorIT extends FieldExtractorTestCase { @ClassRule - public static ElasticsearchCluster cluster = Clusters.testCluster( - // Remove after https://github.com/elastic/elasticsearch/issues/143884 - spec -> spec.setting("logger.org.elasticsearch.index.mapper.FieldMapper", "DEBUG") - ); + public static ElasticsearchCluster cluster = Clusters.testCluster(spec -> {}); public FieldExtractorIT(MappedFieldType.FieldExtractPreference preference) { super(preference); diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java index 053f65c12355b..2a527a8c25e21 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java @@ -14,7 +14,6 @@ import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; import org.elasticsearch.client.ResponseException; -import org.elasticsearch.client.WarningFailureException; import org.elasticsearch.common.Strings; import org.elasticsearch.common.network.NetworkAddress; import org.elasticsearch.common.settings.Settings; @@ -1412,30 +1411,19 @@ public void testTsIndexConflictingTypes() throws IOException { } } """, null, DEPRECATED_DEFAULT_METRIC_WARNING_HANDLER); - // Remove try-catch after https://github.com/elastic/elasticsearch/issues/143884 - try { - ESRestTestCase.createIndex("metrics-long", settings, """ - "properties": { - "@timestamp": { "type": "date" }, - "metric.name": { - "type": "keyword", - "time_series_dimension": true - }, - "metric.value": { - "type": "long", - "time_series_metric": "gauge" - } - } - """); - } catch (WarningFailureException warningException) { - List warnings = warningException.getResponse().getWarnings(); - if (warnings.stream() - .anyMatch(warning -> warning.equals("Parameter [default_metric] is deprecated and will be removed in a future version"))) { - Map indexMapping = ESRestTestCase.getIndexMapping("metrics-long"); - logger.error("Received warning when creating index [metrics-long] with mapping [{}]", indexMapping); + ESRestTestCase.createIndex("metrics-long", settings, """ + "properties": { + "@timestamp": { "type": "date" }, + "metric.name": { + "type": "keyword", + "time_series_dimension": true + }, + "metric.value": { + "type": "long", + "time_series_metric": "gauge" + } } - throw warningException; - } + """); ESRestTestCase.createIndex("metrics-long_dimension", settings, """ "properties": { "@timestamp": { "type": "date" }, diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml index 41bc84b9df3c1..62ed5865a9117 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/esql/40_tsdb.yml @@ -1,15 +1,6 @@ setup: - requires: test_runner_features: [allowed_warnings_regex, allowed_warnings] - # Remove enabling debug logging after https://github.com/elastic/elasticsearch/issues/143884 - - do: - cluster.put_settings: - body: > - { - "persistent": { - "logger.org.elasticsearch.index.mapper.FieldMapper": "DEBUG" - } - } - do: indices.create: index: test