Skip to content

Commit b3e5098

Browse files
author
Christoph Büscher
committed
Add migration tool checks for _field_names disabling
This change adds a check to the migration tool that warns about the deprecated "enabled" setting for the "_field_names" field on 7.x indices and issues a critical error for templates containing this setting, since it has been removed with 8.0. Relates to elastic#42854, elastic#46681
1 parent ee4e6b1 commit b3e5098

File tree

5 files changed

+178
-4
lines changed

5 files changed

+178
-4
lines changed

x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/ClusterDeprecationChecks.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@
1212
import org.elasticsearch.cluster.metadata.MappingMetaData;
1313
import org.elasticsearch.common.Strings;
1414
import org.elasticsearch.common.unit.TimeValue;
15+
import org.elasticsearch.common.xcontent.XContentHelper;
16+
import org.elasticsearch.common.xcontent.XContentType;
1517
import org.elasticsearch.index.IndexSettings;
18+
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
1619
import org.elasticsearch.ingest.IngestService;
1720
import org.elasticsearch.ingest.PipelineConfiguration;
1821
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
1922

2023
import java.util.ArrayList;
24+
import java.util.HashSet;
2125
import java.util.List;
2226
import java.util.Map;
2327
import java.util.Objects;
28+
import java.util.Set;
2429
import java.util.concurrent.atomic.AtomicInteger;
2530
import java.util.stream.Collectors;
2631

@@ -91,6 +96,54 @@ static DeprecationIssue checkTemplatesWithTooManyFields(ClusterState state) {
9196
return null;
9297
}
9398

99+
/**
100+
* Check templates that use `_field_names` explicitly, which was deprecated in https://github.com/elastic/elasticsearch/pull/42854
101+
* and will throw an error on new indices in 8.0
102+
*/
103+
static DeprecationIssue checkTemplatesWithFieldNamesDisabled(ClusterState state) {
104+
Set<String> templatesContainingFieldNamed = new HashSet<>();
105+
state.getMetaData().getTemplates().forEach((templateCursor) -> {
106+
String templateName = templateCursor.key;
107+
templateCursor.value.getMappings().forEach((mappingCursor) -> {
108+
Map<String, Object> map = XContentHelper.convertToMap(mappingCursor.value.compressedReference(), false, XContentType.JSON)
109+
.v2();
110+
if (mapContainsFieldNamesDisabled(map)) {
111+
templatesContainingFieldNamed.add(templateName);
112+
}
113+
});
114+
});
115+
116+
if (templatesContainingFieldNamed.isEmpty() == false) {
117+
return new DeprecationIssue(DeprecationIssue.Level.CRITICAL, "Index templates contain _field_names settings.",
118+
"https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html#fieldnames-enabling",
119+
"Index templates " + templatesContainingFieldNamed + " use the deprecated `enable` setting for the `"
120+
+ FieldNamesFieldMapper.NAME + "` field. Using this setting in new index mappings will throw an error "
121+
+ "in the next major version and needs to be removed from existing mappings and templates.");
122+
}
123+
return null;
124+
}
125+
126+
/**
127+
* check for "_field_names" entries in the map that contain another property "enabled" in the sub-map
128+
*/
129+
static boolean mapContainsFieldNamesDisabled(Map<?, ?> map) {
130+
if (map != null) {
131+
Object fieldNamesMapping = map.get(FieldNamesFieldMapper.NAME);
132+
if (fieldNamesMapping != null && fieldNamesMapping instanceof Map) {
133+
if (((Map<?, ?>) fieldNamesMapping).keySet().contains("enabled")) {
134+
return true;
135+
}
136+
} else {
137+
for (Object value : map.values()) {
138+
if (value instanceof Map) {
139+
return mapContainsFieldNamesDisabled((Map<?, ?>) value);
140+
}
141+
}
142+
}
143+
}
144+
return false;
145+
}
146+
94147
static DeprecationIssue checkPollIntervalTooLow(ClusterState state) {
95148
String pollIntervalString = state.metaData().settings().get(LIFECYCLE_POLL_INTERVAL_SETTING.getKey());
96149
if (Strings.isNullOrEmpty(pollIntervalString)) {

x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/DeprecationChecks.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ private DeprecationChecks() {
3535
Collections.unmodifiableList(Arrays.asList(
3636
ClusterDeprecationChecks::checkUserAgentPipelines,
3737
ClusterDeprecationChecks::checkTemplatesWithTooManyFields,
38-
ClusterDeprecationChecks::checkPollIntervalTooLow
38+
ClusterDeprecationChecks::checkPollIntervalTooLow,
39+
ClusterDeprecationChecks::checkTemplatesWithFieldNamesDisabled
3940
));
4041

4142

@@ -51,7 +52,8 @@ private DeprecationChecks() {
5152
IndexDeprecationChecks::tooManyFieldsCheck,
5253
IndexDeprecationChecks::chainedMultiFieldsCheck,
5354
IndexDeprecationChecks::deprecatedDateTimeFormat,
54-
IndexDeprecationChecks::translogRetentionSettingCheck
55+
IndexDeprecationChecks::translogRetentionSettingCheck,
56+
IndexDeprecationChecks::fieldNamesEnabling
5557
));
5658

5759
static List<BiFunction<DatafeedConfig, NamedXContentRegistry, DeprecationIssue>> ML_SETTINGS_CHECKS =

x-pack/plugin/deprecation/src/main/java/org/elasticsearch/xpack/deprecation/IndexDeprecationChecks.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88

99
import com.carrotsearch.hppc.cursors.ObjectCursor;
10+
1011
import org.elasticsearch.Version;
1112
import org.elasticsearch.cluster.metadata.IndexMetaData;
1213
import org.elasticsearch.cluster.metadata.MappingMetaData;
@@ -185,6 +186,21 @@ private static boolean containsChainedMultiFields(Map<?, ?> property) {
185186
return false;
186187
}
187188

189+
/**
190+
* warn about existing explicit "_field_names" enabled settings in existing mappings
191+
*/
192+
static DeprecationIssue fieldNamesEnabling(IndexMetaData indexMetaData) {
193+
MappingMetaData mapping = indexMetaData.mapping();
194+
if ((mapping != null) && ClusterDeprecationChecks.mapContainsFieldNamesDisabled(mapping.getSourceAsMap())) {
195+
return new DeprecationIssue(DeprecationIssue.Level.WARNING,
196+
"Index mapping contain explicit _field_names enabling settings.",
197+
"https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html" +
198+
"#fieldnames-enabling",
199+
"The index mapping contains a deprecated `enabled` setting for `_field_names` that should be removed moving foward.");
200+
}
201+
return null;
202+
}
203+
188204
private static final Set<String> TYPES_THAT_DONT_COUNT;
189205
static {
190206
HashSet<String> typesThatDontCount = new HashSet<>();

x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/ClusterDeprecationChecksTests.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.elasticsearch.common.xcontent.XContentBuilder;
1717
import org.elasticsearch.common.xcontent.XContentType;
1818
import org.elasticsearch.index.IndexSettings;
19+
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
1920
import org.elasticsearch.ingest.IngestService;
2021
import org.elasticsearch.test.ESTestCase;
2122
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
@@ -158,6 +159,80 @@ public void testTemplateWithTooManyFields() throws IOException {
158159
assertEquals(singletonList(expected), issues);
159160
}
160161

162+
public void testTemplatesWithFieldNamesDisabled() throws IOException {
163+
XContentBuilder goodMappingBuilder = jsonBuilder();
164+
goodMappingBuilder.startObject();
165+
{
166+
goodMappingBuilder.startObject("_doc");
167+
{
168+
goodMappingBuilder.startObject("properties");
169+
{
170+
addRandomFields(10, goodMappingBuilder);
171+
}
172+
goodMappingBuilder.endObject();
173+
}
174+
goodMappingBuilder.endObject();
175+
}
176+
goodMappingBuilder.endObject();
177+
assertFieldNamesEnabledTemplate(goodMappingBuilder, false);
178+
179+
XContentBuilder badMappingWithTypeBuilder = jsonBuilder();
180+
badMappingWithTypeBuilder.startObject();
181+
{
182+
badMappingWithTypeBuilder.startObject("_doc");
183+
{
184+
badMappingWithTypeBuilder.startObject(FieldNamesFieldMapper.NAME);
185+
{
186+
badMappingWithTypeBuilder.field("enabled", randomBoolean());
187+
}
188+
badMappingWithTypeBuilder.endObject();
189+
}
190+
badMappingWithTypeBuilder.endObject();
191+
}
192+
badMappingWithTypeBuilder.endObject();
193+
assertFieldNamesEnabledTemplate(badMappingWithTypeBuilder, true);
194+
195+
XContentBuilder badMappingWithoutTypeBuilder = jsonBuilder();
196+
badMappingWithoutTypeBuilder.startObject();
197+
{
198+
badMappingWithoutTypeBuilder.startObject(FieldNamesFieldMapper.NAME);
199+
{
200+
badMappingWithoutTypeBuilder.field("enabled", randomBoolean());
201+
}
202+
badMappingWithoutTypeBuilder.endObject();
203+
}
204+
badMappingWithoutTypeBuilder.endObject();
205+
assertFieldNamesEnabledTemplate(badMappingWithoutTypeBuilder, true);
206+
}
207+
208+
private void assertFieldNamesEnabledTemplate(XContentBuilder templateBuilder, boolean expectIssue) throws IOException {
209+
String badTemplateName = randomAlphaOfLength(5);
210+
final ClusterState state = ClusterState.builder(new ClusterName(randomAlphaOfLength(5)))
211+
.metaData(MetaData.builder()
212+
.put(IndexTemplateMetaData.builder(badTemplateName)
213+
.patterns(Collections.singletonList(randomAlphaOfLength(5)))
214+
.putMapping("_doc", Strings.toString(templateBuilder))
215+
.build())
216+
.build())
217+
.build();
218+
219+
List<DeprecationIssue> issues = DeprecationChecks.filterChecks(CLUSTER_SETTINGS_CHECKS, c -> c.apply(state));
220+
if (expectIssue) {
221+
assertEquals(1, issues.size());
222+
DeprecationIssue issue = issues.get(0);
223+
assertEquals(DeprecationIssue.Level.CRITICAL, issue.getLevel());
224+
assertEquals("https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html#fieldnames-enabling"
225+
, issue.getUrl());
226+
assertEquals("Index templates contain _field_names settings.", issue.getMessage());
227+
assertEquals("Index templates [" + badTemplateName + "] "
228+
+ "use the deprecated `enable` setting for the `" + FieldNamesFieldMapper.NAME +
229+
"` field. Using this setting in new index mappings will throw an error in the next major version and " +
230+
"needs to be removed from existing mappings and templates.", issue.getDetails());
231+
} else {
232+
assertTrue(issues.isEmpty());
233+
}
234+
}
235+
161236
public void testPollIntervalTooLow() {
162237
{
163238
final String tooLowInterval = randomTimeValue(1, 999, "ms", "micros", "nanos");

x-pack/plugin/deprecation/src/test/java/org/elasticsearch/xpack/deprecation/IndexDeprecationChecksTests.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
import org.elasticsearch.common.Strings;
1212
import org.elasticsearch.common.bytes.BytesReference;
1313
import org.elasticsearch.common.joda.JodaDeprecationPatterns;
14+
import org.elasticsearch.common.settings.Settings;
1415
import org.elasticsearch.common.xcontent.XContentBuilder;
1516
import org.elasticsearch.common.xcontent.XContentFactory;
1617
import org.elasticsearch.index.IndexSettings;
17-
import org.elasticsearch.common.settings.Settings;
18+
import org.elasticsearch.index.mapper.FieldNamesFieldMapper;
1819
import org.elasticsearch.test.ESTestCase;
1920
import org.elasticsearch.test.VersionUtils;
2021
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
@@ -27,8 +28,8 @@
2728
import static java.util.Collections.singletonList;
2829
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
2930
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.INDEX_SETTINGS_CHECKS;
30-
import static org.hamcrest.Matchers.hasItem;
3131
import static org.hamcrest.Matchers.empty;
32+
import static org.hamcrest.Matchers.hasItem;
3233
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
3334

3435
public class IndexDeprecationChecksTests extends ESTestCase {
@@ -161,6 +162,7 @@ public void testChainedMultiFields() throws IOException {
161162
"The names of fields that contain chained multi-fields: [[type: _doc, field: invalid-field]]");
162163
assertEquals(singletonList(expected), issues);
163164
}
165+
164166
public void testDefinedPatternsDoNotWarn() throws IOException {
165167
String simpleMapping = "{\n" +
166168
"\"properties\" : {\n" +
@@ -412,4 +414,30 @@ public void testDefaultTranslogRetentionSettings() {
412414
List<DeprecationIssue> issues = DeprecationChecks.filterChecks(INDEX_SETTINGS_CHECKS, c -> c.apply(indexMetaData));
413415
assertThat(issues, empty());
414416
}
417+
418+
public void testFieldNamesEnabling() throws IOException {
419+
XContentBuilder xContent = XContentFactory.jsonBuilder().startObject()
420+
.startObject(FieldNamesFieldMapper.NAME)
421+
.field("enabled", randomBoolean())
422+
.endObject()
423+
.endObject();
424+
String mapping = BytesReference.bytes(xContent).utf8ToString();
425+
426+
IndexMetaData simpleIndex = IndexMetaData.builder(randomAlphaOfLengthBetween(5, 10))
427+
.settings(settings(
428+
VersionUtils.randomVersionBetween(random(), Version.V_7_0_0, Version.CURRENT)))
429+
.numberOfShards(1)
430+
.numberOfReplicas(0)
431+
.putMapping("_doc", mapping).build();
432+
List<DeprecationIssue> issues = DeprecationChecks.filterChecks(INDEX_SETTINGS_CHECKS, c -> c.apply(simpleIndex));
433+
assertEquals(1, issues.size());
434+
435+
DeprecationIssue issue = issues.get(0);
436+
assertEquals(DeprecationIssue.Level.WARNING, issue.getLevel());
437+
assertEquals("https://www.elastic.co/guide/en/elasticsearch/reference/master/breaking-changes-8.0.html#fieldnames-enabling"
438+
, issue.getUrl());
439+
assertEquals("Index mapping contain explicit _field_names enabling settings.", issue.getMessage());
440+
assertEquals("The index mapping contains a deprecated `enabled` setting for `_field_names` that should be removed moving foward.",
441+
issue.getDetails());
442+
}
415443
}

0 commit comments

Comments
 (0)