From aece89d6a1168fb15bccf53fa4c750c73a4b21c5 Mon Sep 17 00:00:00 2001 From: Daniel Mitterdorfer Date: Thu, 19 Jan 2017 07:59:18 +0100 Subject: [PATCH] Make boolean conversion strict (#22200) This PR removes all leniency in the conversion of Strings to booleans: "true" is converted to the boolean value `true`, "false" is converted to the boolean value `false`. Everything else raises an error. --- .../resources/checkstyle_suppressions.xml | 4 - .../create/CreateSnapshotRequest.java | 6 +- .../restore/RestoreSnapshotRequest.java | 8 +- .../flush/TransportShardFlushAction.java | 4 +- .../refresh/TransportShardRefreshAction.java | 4 +- .../action/get/MultiGetRequest.java | 3 +- .../action/get/TransportGetAction.java | 2 +- .../action/support/AutoCreateIndex.java | 2 +- .../action/support/IndicesOptions.java | 8 +- .../TransportReplicationAction.java | 6 +- .../cluster/InternalClusterInfoService.java | 3 +- .../cluster/metadata/AutoExpandReplicas.java | 2 +- .../cluster/metadata/IndexMetaData.java | 13 +- .../cluster/metadata/MappingMetaData.java | 13 +- .../metadata/MetaDataCreateIndexService.java | 2 +- .../cluster/routing/IndexRoutingTable.java | 2 +- .../cluster/routing/RoutingNodes.java | 4 +- .../org/elasticsearch/common/Booleans.java | 189 ++++++++++++------ .../org/elasticsearch/common/TriFunction.java | 42 ++++ .../common/settings/Setting.java | 6 +- .../common/settings/Settings.java | 29 +++ .../common/xcontent/XContent.java | 2 +- .../common/xcontent/XContentParser.java | 20 +- .../support/AbstractXContentParser.java | 31 ++- .../xcontent/support/XContentMapValues.java | 43 ++-- .../gateway/PrimaryShardAllocator.java | 8 +- .../org/elasticsearch/index/IndexModule.java | 7 +- .../org/elasticsearch/index/IndexService.java | 10 +- .../elasticsearch/index/IndexSettings.java | 13 +- .../index/MergePolicyConfig.java | 3 +- .../ASCIIFoldingTokenFilterFactory.java | 3 +- .../index/analysis/Analysis.java | 17 +- .../analysis/ArabicAnalyzerProvider.java | 6 +- .../analysis/ArmenianAnalyzerProvider.java | 6 +- .../analysis/BasqueAnalyzerProvider.java | 6 +- .../analysis/BrazilianAnalyzerProvider.java | 6 +- .../analysis/BulgarianAnalyzerProvider.java | 6 +- .../analysis/CJKBigramFilterFactory.java | 2 +- .../analysis/CatalanAnalyzerProvider.java | 6 +- .../index/analysis/CjkAnalyzerProvider.java | 3 +- .../CommonGramsTokenFilterFactory.java | 4 +- .../index/analysis/CzechAnalyzerProvider.java | 6 +- .../analysis/DanishAnalyzerProvider.java | 6 +- .../index/analysis/DutchAnalyzerProvider.java | 6 +- .../analysis/ElisionTokenFilterFactory.java | 2 +- .../analysis/EnglishAnalyzerProvider.java | 6 +- .../analysis/FingerprintAnalyzerProvider.java | 2 +- .../analysis/FinnishAnalyzerProvider.java | 6 +- .../analysis/FrenchAnalyzerProvider.java | 6 +- .../analysis/GalicianAnalyzerProvider.java | 6 +- .../analysis/GermanAnalyzerProvider.java | 6 +- .../index/analysis/GreekAnalyzerProvider.java | 5 +- .../index/analysis/HindiAnalyzerProvider.java | 6 +- .../analysis/HungarianAnalyzerProvider.java | 6 +- .../analysis/HunspellTokenFilterFactory.java | 6 +- .../analysis/IndonesianAnalyzerProvider.java | 6 +- .../index/analysis/IrishAnalyzerProvider.java | 6 +- .../analysis/ItalianAnalyzerProvider.java | 6 +- .../index/analysis/KeepWordFilterFactory.java | 4 +- .../KeywordMarkerTokenFilterFactory.java | 4 +- .../analysis/LatvianAnalyzerProvider.java | 6 +- .../LimitTokenCountFilterFactory.java | 5 +- .../analysis/LithuanianAnalyzerProvider.java | 6 +- .../analysis/NorwegianAnalyzerProvider.java | 6 +- .../PathHierarchyTokenizerFactory.java | 2 +- .../analysis/PatternAnalyzerProvider.java | 6 +- ...PatternCaptureGroupTokenFilterFactory.java | 2 +- .../PatternReplaceTokenFilterFactory.java | 2 +- .../analysis/PersianAnalyzerProvider.java | 5 +- .../analysis/PortugueseAnalyzerProvider.java | 6 +- .../analysis/RomanianAnalyzerProvider.java | 6 +- .../analysis/RussianAnalyzerProvider.java | 6 +- .../analysis/ShingleTokenFilterFactory.java | 4 +- .../analysis/SnowballAnalyzerProvider.java | 2 +- .../analysis/SoraniAnalyzerProvider.java | 6 +- .../analysis/SpanishAnalyzerProvider.java | 6 +- .../analysis/StandardAnalyzerProvider.java | 2 +- .../StandardHtmlStripAnalyzerProvider.java | 2 +- .../index/analysis/StopAnalyzerProvider.java | 3 +- .../analysis/StopTokenFilterFactory.java | 5 +- .../analysis/SwedishAnalyzerProvider.java | 6 +- .../analysis/SynonymTokenFilterFactory.java | 4 +- .../index/analysis/ThaiAnalyzerProvider.java | 5 +- .../analysis/TurkishAnalyzerProvider.java | 6 +- .../analysis/UniqueTokenFilterFactory.java | 3 +- .../WordDelimiterTokenFilterFactory.java | 4 +- ...bstractCompoundWordTokenFilterFactory.java | 5 +- .../index/mapper/AllFieldMapper.java | 7 +- .../index/mapper/BaseGeoPointFieldMapper.java | 2 +- .../index/mapper/BooleanFieldMapper.java | 18 +- .../index/mapper/DateFieldMapper.java | 2 +- .../index/mapper/FieldMapper.java | 2 +- .../index/mapper/FieldNamesFieldMapper.java | 4 +- .../index/mapper/GeoShapeFieldMapper.java | 9 +- .../index/mapper/IpFieldMapper.java | 2 +- .../index/mapper/KeywordFieldMapper.java | 4 +- .../index/mapper/NumberFieldMapper.java | 4 +- .../index/mapper/ObjectMapper.java | 18 +- .../index/mapper/ParentFieldMapper.java | 2 +- .../index/mapper/RangeFieldMapper.java | 2 +- .../index/mapper/RootObjectMapper.java | 4 +- .../index/mapper/RoutingFieldMapper.java | 4 +- .../index/mapper/ScaledFloatFieldMapper.java | 4 +- .../index/mapper/SourceFieldMapper.java | 4 +- .../index/mapper/TextFieldMapper.java | 4 +- .../index/mapper/TypeParsers.java | 131 ++++++------ .../elasticsearch/index/shard/IndexShard.java | 2 +- .../similarity/BM25SimilarityProvider.java | 6 +- .../similarity/ClassicSimilarityProvider.java | 6 +- .../similarity/DFISimilarityProvider.java | 6 +- .../similarity/DFRSimilarityProvider.java | 2 +- .../similarity/IBSimilarityProvider.java | 2 +- .../LMDirichletSimilarityProvider.java | 2 +- .../LMJelinekMercerSimilarityProvider.java | 2 +- .../index/similarity/SimilarityService.java | 45 +++-- .../index/store/FsDirectoryService.java | 3 +- .../org/elasticsearch/rest/RestRequest.java | 8 +- .../rest/action/cat/RestShardsAction.java | 2 +- .../action/search/RestMultiSearchAction.java | 4 +- .../fetch/subphase/FetchSourceContext.java | 4 +- .../action/get/MultiGetRequestTests.java | 67 +++++++ .../action/support/IndicesOptionsTests.java | 3 +- .../bwcompat/RestoreBackwardsCompatIT.java | 11 +- .../cluster/SimpleClusterStateIT.java | 33 ++- .../elasticsearch/common/BooleansTests.java | 126 ++++++++---- .../common/settings/SettingTests.java | 2 +- .../common/settings/SettingsModuleTests.java | 2 +- .../common/settings/SettingsTests.java | 64 +++++- .../common/xcontent/XContentParserTests.java | 91 +++++++++ .../elasticsearch/index/IndexModuleTests.java | 4 +- .../index/IndexServiceTests.java | 38 ++-- .../index/IndexingSlowLogTests.java | 2 +- .../index/mapper/BooleanFieldMapperTests.java | 82 +++++++- .../index/mapper/FieldTypeTestCase.java | 10 +- .../index/mapper/UpdateMappingTests.java | 30 ++- .../query/HasChildQueryBuilderTests.java | 6 +- .../indices/analysis/AnalysisModuleTests.java | 4 +- .../template/SimpleIndexTemplateIT.java | 33 ++- .../rest/BaseRestHandlerTests.java | 4 +- .../rest/action/cat/RestTableTests.java | 2 +- .../script/ScriptContextTests.java | 2 +- .../SharedClusterSnapshotRestoreIT.java | 46 ++++- .../resources/indices/bwc/index-5.1.1.zip | Bin 421094 -> 232549 bytes .../test/resources/indices/bwc/repo-5.1.1.zip | Bin 204156 -> 204921 bytes dev-tools/create_bwc_index.py | 78 ++++++-- .../pattern-capture-tokenfilter.asciidoc | 4 +- docs/reference/api-conventions.asciidoc | 5 +- docs/reference/cat/health.asciidoc | 2 +- docs/reference/mapping/types/boolean.asciidoc | 10 +- .../migration/migrate_6_0/mappings.asciidoc | 8 + .../migration/migrate_6_0/rest.asciidoc | 7 +- .../migration/migrate_6_0/settings.asciidoc | 7 + .../IcuCollationTokenFilterFactory.java | 7 +- .../JapaneseStopTokenFilterFactory.java | 5 +- .../analysis/KuromojiAnalyzerProvider.java | 3 +- ...uromojiIterationMarkCharFilterFactory.java | 6 +- .../KuromojiReadingFormFilterFactory.java | 2 +- .../analysis/KuromojiTokenizerFactory.java | 3 +- .../analysis/PhoneticTokenFilterFactory.java | 2 +- .../analysis/UkrainianAnalyzerProvider.java | 8 +- .../index/mapper/size/SizeFieldMapper.java | 7 +- .../test/cat.health/10_basic.yaml | 2 +- .../test/exists/60_realtime_refresh.yaml | 8 +- .../test/get/60_realtime_refresh.yaml | 8 +- .../test/get_source/60_realtime_refresh.yaml | 8 +- .../test/mget/60_realtime_refresh.yaml | 8 +- .../test/termvectors/20_issue7121.yaml | 2 +- .../test/termvectors/30_realtime.yaml | 4 +- .../test/update/22_doc_as_upsert.yaml | 4 +- 169 files changed, 1356 insertions(+), 611 deletions(-) create mode 100644 core/src/main/java/org/elasticsearch/common/TriFunction.java create mode 100644 core/src/test/java/org/elasticsearch/action/get/MultiGetRequestTests.java diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 6fc4a8275a21..61e9a205d3d2 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -255,7 +255,6 @@ - @@ -562,8 +561,6 @@ - - @@ -652,7 +649,6 @@ - diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java index 9cbc1b656324..ae715050e80b 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java @@ -42,7 +42,7 @@ import static org.elasticsearch.common.Strings.EMPTY_ARRAY; import static org.elasticsearch.common.settings.Settings.readSettingsFromStream; import static org.elasticsearch.common.settings.Settings.writeSettingsToStream; import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Create snapshot request @@ -366,14 +366,14 @@ public class CreateSnapshotRequest extends MasterNodeRequest) entry.getValue()); } else if (name.equals("include_global_state")) { - includeGlobalState = lenientNodeBooleanValue(entry.getValue()); + includeGlobalState = nodeBooleanValue(entry.getValue(), "include_global_state"); } } indicesOptions(IndicesOptions.fromMap((Map) source, IndicesOptions.lenientExpandOpen())); diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java index 641525f00e8b..a7bbd02ee54e 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java +++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java @@ -40,7 +40,7 @@ import static org.elasticsearch.action.ValidateActions.addValidationError; import static org.elasticsearch.common.settings.Settings.readSettingsFromStream; import static org.elasticsearch.common.settings.Settings.writeSettingsToStream; import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Restore snapshot request @@ -481,16 +481,16 @@ public class RestoreSnapshotRequest extends MasterNodeRequest) entry.getValue()); } else if (name.equals("include_global_state")) { - includeGlobalState = lenientNodeBooleanValue(entry.getValue()); + includeGlobalState = nodeBooleanValue(entry.getValue(), "include_global_state"); } else if (name.equals("include_aliases")) { - includeAliases = lenientNodeBooleanValue(entry.getValue()); + includeAliases = nodeBooleanValue(entry.getValue(), "include_aliases"); } else if (name.equals("rename_pattern")) { if (entry.getValue() instanceof String) { renamePattern((String) entry.getValue()); diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java index b04bb86a63c2..026946334ac6 100644 --- a/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java +++ b/core/src/main/java/org/elasticsearch/action/admin/indices/flush/TransportShardFlushAction.java @@ -23,7 +23,7 @@ import org.elasticsearch.action.support.ActionFilters; import org.elasticsearch.action.support.replication.ReplicationResponse; import org.elasticsearch.action.support.replication.TransportReplicationAction; import org.elasticsearch.cluster.action.shard.ShardStateAction; -import org.elasticsearch.cluster.block.ClusterBlockLevel; +import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.inject.Inject; @@ -65,7 +65,7 @@ public class TransportShardFlushAction extends TransportReplicationAction> expressions = new ArrayList<>(); try { - autoCreateIndex = Booleans.parseBooleanExact(value); + autoCreateIndex = Booleans.parseBoolean(value); } catch (IllegalArgumentException ex) { try { String[] patterns = Strings.commaDelimitedListToStringArray(value); diff --git a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java index 2bc49f7e9f86..b82bfcc7170d 100644 --- a/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java +++ b/core/src/main/java/org/elasticsearch/action/support/IndicesOptions.java @@ -26,7 +26,7 @@ import org.elasticsearch.rest.RestRequest; import java.io.IOException; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeStringArrayValue; /** @@ -195,8 +195,8 @@ public class IndicesOptions { //note that allowAliasesToMultipleIndices is not exposed, always true (only for internal use) return fromOptions( - lenientNodeBooleanValue(ignoreUnavailableString, defaultSettings.ignoreUnavailable()), - lenientNodeBooleanValue(allowNoIndicesString, defaultSettings.allowNoIndices()), + nodeBooleanValue(ignoreUnavailableString, "ignore_unavailable", defaultSettings.ignoreUnavailable()), + nodeBooleanValue(allowNoIndicesString, "allow_no_indices", defaultSettings.allowNoIndices()), expandWildcardsOpen, expandWildcardsClosed, defaultSettings.allowAliasesToMultipleIndices(), @@ -279,7 +279,7 @@ public class IndicesOptions { ", allow_no_indices=" + allowNoIndices() + ", expand_wildcards_open=" + expandWildcardsOpen() + ", expand_wildcards_closed=" + expandWildcardsClosed() + - ", allow_alisases_to_multiple_indices=" + allowAliasesToMultipleIndices() + + ", allow_aliases_to_multiple_indices=" + allowAliasesToMultipleIndices() + ", forbid_closed_indices=" + forbidClosedIndices() + ']'; } diff --git a/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java b/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java index ee97612d93b1..c616107203e9 100644 --- a/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java +++ b/core/src/main/java/org/elasticsearch/action/support/replication/TransportReplicationAction.java @@ -315,7 +315,7 @@ public abstract class TransportReplicationAction< } else { setPhase(replicationTask, "primary"); final IndexMetaData indexMetaData = clusterService.state().getMetaData().index(request.shardId().getIndex()); - final boolean executeOnReplicas = (indexMetaData == null) || shouldExecuteReplication(indexMetaData.getSettings()); + final boolean executeOnReplicas = (indexMetaData == null) || shouldExecuteReplication(indexMetaData); final ActionListener listener = createResponseListener(primaryShardReference); createReplicatedOperation(request, ActionListener.wrap(result -> result.respond(listener), listener::onFailure), @@ -910,8 +910,8 @@ public abstract class TransportReplicationAction< * Indicated whether this operation should be replicated to shadow replicas or not. If this method returns true the replication phase * will be skipped. For example writes such as index and delete don't need to be replicated on shadow replicas but refresh and flush do. */ - protected boolean shouldExecuteReplication(Settings settings) { - return IndexMetaData.isIndexUsingShadowReplicas(settings) == false; + protected boolean shouldExecuteReplication(IndexMetaData indexMetaData) { + return indexMetaData.isIndexUsingShadowReplicas() == false; } class ShardReference implements Releasable { diff --git a/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java b/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java index b8ac2a5eb50c..a9392d3c017d 100644 --- a/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java +++ b/core/src/main/java/org/elasticsearch/cluster/InternalClusterInfoService.java @@ -377,14 +377,13 @@ public class InternalClusterInfoService extends AbstractComponent MetaData meta = state.getMetaData(); for (ShardStats s : stats) { IndexMetaData indexMeta = meta.index(s.getShardRouting().index()); - Settings indexSettings = indexMeta == null ? null : indexMeta.getSettings(); newShardRoutingToDataPath.put(s.getShardRouting(), s.getDataPath()); long size = s.getStats().getStore().sizeInBytes(); String sid = ClusterInfo.shardIdentifierFromRouting(s.getShardRouting()); if (logger.isTraceEnabled()) { logger.trace("shard: {} size: {}", sid, size); } - if (indexSettings != null && IndexMetaData.isIndexUsingShadowReplicas(indexSettings)) { + if (indexMeta != null && indexMeta.isIndexUsingShadowReplicas()) { // Shards on a shared filesystem should be considered of size 0 if (logger.isTraceEnabled()) { logger.trace("shard: {} is using shadow replicas and will be treated as size 0", sid); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java b/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java index 4b4a8e54d7c6..fa30abe5a736 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/AutoExpandReplicas.java @@ -33,7 +33,7 @@ final class AutoExpandReplicas { public static final Setting SETTING = new Setting<>(IndexMetaData.SETTING_AUTO_EXPAND_REPLICAS, "false", (value) -> { final int min; final int max; - if (Booleans.parseBoolean(value, true) == false) { + if (Booleans.isFalse(value)) { return new AutoExpandReplicas(0, 0, false); } final int dash = value.indexOf('-'); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java index ba5ce1067b3b..6865983e180c 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexMetaData.java @@ -1263,9 +1263,10 @@ public class IndexMetaData implements Diffable, ToXContent { * is the returned value from * {@link #isIndexUsingShadowReplicas(org.elasticsearch.common.settings.Settings)}. */ - public static boolean isOnSharedFilesystem(Settings settings) { + public boolean isOnSharedFilesystem(Settings settings) { // don't use the setting directly, not to trigger verbose deprecation logging - return settings.getAsBoolean(SETTING_SHARED_FILESYSTEM, isIndexUsingShadowReplicas(settings)); + return settings.getAsBooleanLenientForPreEs6Indices( + this.indexCreatedVersion, SETTING_SHARED_FILESYSTEM, isIndexUsingShadowReplicas(settings)); } /** @@ -1273,9 +1274,13 @@ public class IndexMetaData implements Diffable, ToXContent { * with these settings uses shadow replicas. Otherwise false. The default * setting for this is false. */ - public static boolean isIndexUsingShadowReplicas(Settings settings) { + public boolean isIndexUsingShadowReplicas() { + return isIndexUsingShadowReplicas(this.settings); + } + + public boolean isIndexUsingShadowReplicas(Settings settings) { // don't use the setting directly, not to trigger verbose deprecation logging - return settings.getAsBoolean(SETTING_SHADOW_REPLICAS, false); + return settings.getAsBooleanLenientForPreEs6Indices(this.indexCreatedVersion, SETTING_SHADOW_REPLICAS, false); } /** diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java index c9a0c6175532..08d5211e12d7 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MappingMetaData.java @@ -34,7 +34,7 @@ import org.elasticsearch.index.mapper.DocumentMapper; import java.io.IOException; import java.util.Map; -import static org.elasticsearch.common.xcontent.support.XContentMapValues.lenientNodeBooleanValue; +import static org.elasticsearch.common.xcontent.support.XContentMapValues.nodeBooleanValue; /** * Mapping configuration for a type. @@ -95,10 +95,6 @@ public class MappingMetaData extends AbstractDiffable { initMappers((Map) mappingMap.get(this.type)); } - public MappingMetaData(Map mapping) throws IOException { - this(mapping.keySet().iterator().next(), mapping); - } - public MappingMetaData(String type, Map mapping) throws IOException { this.type = type; XContentBuilder mappingBuilder = XContentFactory.jsonBuilder().map(mapping); @@ -127,7 +123,12 @@ public class MappingMetaData extends AbstractDiffable { String fieldName = entry.getKey(); Object fieldNode = entry.getValue(); if (fieldName.equals("required")) { - required = lenientNodeBooleanValue(fieldNode); + try { + required = nodeBooleanValue(fieldNode); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Failed to create mapping for type [" + this.type() + "]. " + + "Illegal value in field [_routing.required].", ex); + } } } this.routing = new Routing(required); diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java index 64f96c8e263b..701569594893 100644 --- a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java +++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java @@ -428,7 +428,7 @@ public class MetaDataCreateIndexService extends AbstractComponent { .put(indexMetaData, false) .build(); - String maybeShadowIndicator = IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) ? "s" : ""; + String maybeShadowIndicator = indexMetaData.isIndexUsingShadowReplicas() ? "s" : ""; logger.info("[{}] creating index, cause [{}], templates {}, shards [{}]/[{}{}], mappings {}", request.index(), request.cause(), templateNames, indexMetaData.getNumberOfShards(), indexMetaData.getNumberOfReplicas(), maybeShadowIndicator, mappings.keySet()); diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java b/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java index 1d137d30dba3..53590550d84d 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/IndexRoutingTable.java @@ -140,7 +140,7 @@ public class IndexRoutingTable extends AbstractDiffable imple } if (indexMetaData.getCreationVersion().onOrAfter(Version.V_5_0_0_alpha1) && - IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) == false && // see #20650 + indexMetaData.isIndexUsingShadowReplicas() == false && // see #20650 shardRouting.primary() && shardRouting.initializing() && shardRouting.relocating() == false && RecoverySource.isInitialRecovery(shardRouting.recoverySource().getType()) == false && inSyncAllocationIds.contains(shardRouting.allocationId().getId()) == false) diff --git a/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java b/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java index 6b0b13247170..45d567b657e9 100644 --- a/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java +++ b/core/src/main/java/org/elasticsearch/cluster/routing/RoutingNodes.java @@ -540,7 +540,7 @@ public class RoutingNodes implements Iterable { if (failedShard.primary()) { // promote active replica to primary if active replica exists (only the case for shadow replicas) ShardRouting activeReplica = activeReplica(failedShard.shardId()); - assert activeReplica == null || IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings()) : + assert activeReplica == null || indexMetaData.isIndexUsingShadowReplicas() : "initializing primary [" + failedShard + "] with active replicas [" + activeReplica + "] only expected when " + "using shadow replicas"; if (activeReplica == null) { @@ -599,7 +599,7 @@ public class RoutingNodes implements Iterable { assert activeReplica.started() : "replica relocation should have been cancelled: " + activeReplica; ShardRouting primarySwappedCandidate = promoteActiveReplicaShardToPrimary(activeReplica); routingChangesObserver.replicaPromoted(activeReplica); - if (IndexMetaData.isIndexUsingShadowReplicas(indexMetaData.getSettings())) { + if (indexMetaData.isIndexUsingShadowReplicas()) { ShardRouting initializedShard = reinitShadowPrimary(primarySwappedCandidate); routingChangesObserver.startedPrimaryReinitialized(primarySwappedCandidate, initializedShard); } diff --git a/core/src/main/java/org/elasticsearch/common/Booleans.java b/core/src/main/java/org/elasticsearch/common/Booleans.java index 9ec1ac968aca..025174c477d6 100644 --- a/core/src/main/java/org/elasticsearch/common/Booleans.java +++ b/core/src/main/java/org/elasticsearch/common/Booleans.java @@ -19,14 +19,128 @@ package org.elasticsearch.common; -public class Booleans { +public final class Booleans { + private Booleans() { + throw new AssertionError("No instances intended"); + } + + /** + * Parses a char[] representation of a boolean value to boolean. + * + * @return true iff the sequence of chars is "true", false iff the sequence of chars is "false" or the + * provided default value iff either text is null or length == 0. + * @throws IllegalArgumentException if the string cannot be parsed to boolean. + */ + public static boolean parseBoolean(char[] text, int offset, int length, boolean defaultValue) { + if (text == null || length == 0) { + return defaultValue; + } else { + return parseBoolean(new String(text, offset, length)); + } + } + + /** + * returns true iff the sequence of chars is one of "true","false". + * + * @param text sequence to check + * @param offset offset to start + * @param length length to check + */ + public static boolean isBoolean(char[] text, int offset, int length) { + if (text == null || length == 0) { + return false; + } + return isBoolean(new String(text, offset, length)); + } + + public static boolean isBoolean(String value) { + return isFalse(value) || isTrue(value); + } + + /** + * Parses a string representation of a boolean value to boolean. + * + * @return true iff the provided value is "true". false iff the provided value is "false". + * @throws IllegalArgumentException if the string cannot be parsed to boolean. + */ + public static boolean parseBoolean(String value) { + if (isFalse(value)) { + return false; + } + if (isTrue(value)) { + return true; + } + throw new IllegalArgumentException("Failed to parse value [" + value + "] as only [true] or [false] are allowed."); + } + + /** + * + * @param value text to parse. + * @param defaultValue The default value to return if the provided value is null. + * @return see {@link #parseBoolean(String)} + */ + public static boolean parseBoolean(String value, boolean defaultValue) { + if (Strings.hasText(value)) { + return parseBoolean(value); + } + return defaultValue; + } + + public static Boolean parseBoolean(String value, Boolean defaultValue) { + if (Strings.hasText(value)) { + return parseBoolean(value); + } + return defaultValue; + } /** * Returns false if text is in false, 0, off, no; else, true + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(String, Boolean)} instead. */ - public static boolean parseBoolean(char[] text, int offset, int length, boolean defaultValue) { - // TODO: the leniency here is very dangerous: a simple typo will be misinterpreted and the user won't know. - // We should remove it and cutover to https://github.com/rmuir/booleanparser + @Deprecated + public static Boolean parseBooleanLenient(String value, Boolean defaultValue) { + if (value == null) { // only for the null case we do that here! + return defaultValue; + } + return parseBooleanLenient(value, false); + } + /** + * Returns true iff the value is neither of the following: + * false, 0, off, no + * otherwise false + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(String, boolean)} instead. + */ + @Deprecated + public static boolean parseBooleanLenient(String value, boolean defaultValue) { + if (value == null) { + return defaultValue; + } + return !(value.equals("false") || value.equals("0") || value.equals("off") || value.equals("no")); + } + + /** + * @return true iff the value is false, otherwise false. + */ + public static boolean isFalse(String value) { + return "false".equals(value); + } + + /** + * @return true iff the value is true, otherwise false + */ + public static boolean isTrue(String value) { + return "true".equals(value); + } + + /** + * Returns false if text is in false, 0, off, no; else, true + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #parseBoolean(char[], int, int, boolean)} instead + */ + @Deprecated + public static boolean parseBooleanLenient(char[] text, int offset, int length, boolean defaultValue) { if (text == null || length == 0) { return defaultValue; } @@ -40,7 +154,8 @@ public class Booleans { return !(text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f'); } if (length == 5) { - return !(text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && text[offset + 4] == 'e'); + return !(text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && + text[offset + 4] == 'e'); } return true; } @@ -51,8 +166,11 @@ public class Booleans { * @param text sequence to check * @param offset offset to start * @param length length to check + * + * @deprecated Only kept to provide automatic upgrades for pre 6.0 indices. Use {@link #isBoolean(char[], int, int)} instead. */ - public static boolean isBoolean(char[] text, int offset, int length) { + @Deprecated + public static boolean isBooleanLenient(char[] text, int offset, int length) { if (text == null || length == 0) { return false; } @@ -64,69 +182,16 @@ public class Booleans { } if (length == 3) { return (text[offset] == 'o' && text[offset + 1] == 'f' && text[offset + 2] == 'f') || - (text[offset] == 'y' && text[offset + 1] == 'e' && text[offset + 2] == 's'); + (text[offset] == 'y' && text[offset + 1] == 'e' && text[offset + 2] == 's'); } if (length == 4) { return (text[offset] == 't' && text[offset + 1] == 'r' && text[offset + 2] == 'u' && text[offset + 3] == 'e'); } if (length == 5) { - return (text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && text[offset + 4] == 'e'); + return (text[offset] == 'f' && text[offset + 1] == 'a' && text[offset + 2] == 'l' && text[offset + 3] == 's' && + text[offset + 4] == 'e'); } return false; } - /*** - * - * @return true/false - * throws exception if string cannot be parsed to boolean - */ - public static Boolean parseBooleanExact(String value) { - boolean isFalse = isExplicitFalse(value); - if (isFalse) { - return false; - } - boolean isTrue = isExplicitTrue(value); - if (isTrue) { - return true; - } - - throw new IllegalArgumentException("Failed to parse value [" + value + "] cannot be parsed to boolean [ true/1/on/yes OR false/0/off/no ]"); - } - - public static Boolean parseBoolean(String value, Boolean defaultValue) { - if (value == null) { // only for the null case we do that here! - return defaultValue; - } - return parseBoolean(value, false); - } - /** - * Returns true iff the value is neither of the following: - * false, 0, off, no - * otherwise false - */ - public static boolean parseBoolean(String value, boolean defaultValue) { - if (value == null) { - return defaultValue; - } - return !(value.equals("false") || value.equals("0") || value.equals("off") || value.equals("no")); - } - - /** - * Returns true iff the value is either of the following: - * false, 0, off, no - * otherwise false - */ - public static boolean isExplicitFalse(String value) { - return value != null && (value.equals("false") || value.equals("0") || value.equals("off") || value.equals("no")); - } - - /** - * Returns true iff the value is either of the following: - * true, 1, on, yes - * otherwise false - */ - public static boolean isExplicitTrue(String value) { - return value != null && (value.equals("true") || value.equals("1") || value.equals("on") || value.equals("yes")); - } - } diff --git a/core/src/main/java/org/elasticsearch/common/TriFunction.java b/core/src/main/java/org/elasticsearch/common/TriFunction.java new file mode 100644 index 000000000000..85655863a4f9 --- /dev/null +++ b/core/src/main/java/org/elasticsearch/common/TriFunction.java @@ -0,0 +1,42 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.elasticsearch.common; + +/** + * Represents a function that accepts three arguments and produces a result. + * + * @param the type of the first argument + * @param the type of the second argument + * @param the type of the third argument + * @param the return type + */ +@FunctionalInterface +public interface TriFunction { + /** + * Applies this function to the given arguments. + * + * @param s the first function argument + * @param t the second function argument + * @param u the third function argument + * @return the result + */ + R apply(S s, T t, U u); +} diff --git a/core/src/main/java/org/elasticsearch/common/settings/Setting.java b/core/src/main/java/org/elasticsearch/common/settings/Setting.java index 45ebe1b061c6..74e10bd6e11b 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Setting.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Setting.java @@ -668,15 +668,15 @@ public class Setting extends ToXContentToBytes { } public static Setting boolSetting(String key, boolean defaultValue, Property... properties) { - return new Setting<>(key, (s) -> Boolean.toString(defaultValue), Booleans::parseBooleanExact, properties); + return new Setting<>(key, (s) -> Boolean.toString(defaultValue), Booleans::parseBoolean, properties); } public static Setting boolSetting(String key, Setting fallbackSetting, Property... properties) { - return new Setting<>(key, fallbackSetting, Booleans::parseBooleanExact, properties); + return new Setting<>(key, fallbackSetting, Booleans::parseBoolean, properties); } public static Setting boolSetting(String key, Function defaultValueFn, Property... properties) { - return new Setting<>(key, defaultValueFn, Booleans::parseBooleanExact, properties); + return new Setting<>(key, defaultValueFn, Booleans::parseBoolean, properties); } public static Setting byteSizeSetting(String key, ByteSizeValue value, Property... properties) { diff --git a/core/src/main/java/org/elasticsearch/common/settings/Settings.java b/core/src/main/java/org/elasticsearch/common/settings/Settings.java index ef9ff00a1f02..e588b28b6354 100644 --- a/core/src/main/java/org/elasticsearch/common/settings/Settings.java +++ b/core/src/main/java/org/elasticsearch/common/settings/Settings.java @@ -26,6 +26,8 @@ import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.logging.DeprecationLogger; +import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.loader.SettingsLoader; import org.elasticsearch.common.settings.loader.SettingsLoaderFactory; import org.elasticsearch.common.unit.ByteSizeUnit; @@ -74,6 +76,7 @@ import static org.elasticsearch.common.unit.TimeValue.parseTimeValue; * An immutable settings implementation. */ public final class Settings implements ToXContent { + private static final DeprecationLogger deprecationLogger = new DeprecationLogger(Loggers.getLogger(Settings.class)); public static final Settings EMPTY = new Builder().build(); private static final Pattern ARRAY_PATTERN = Pattern.compile("(.*)\\.\\d+$"); @@ -313,6 +316,32 @@ public final class Settings implements ToXContent { return Booleans.parseBoolean(get(setting), defaultValue); } + // TODO #22298: Delete this method and update call sites to #getAsBoolean(String, Boolean). + /** + * Returns the setting value (as boolean) associated with the setting key. If it does not exist, returns the default value provided. + * If the index was created on Elasticsearch below 6.0, booleans will be parsed leniently otherwise they are parsed strictly. + * + * See {@link Booleans#isBooleanLenient(char[], int, int)} for the definition of a "lenient boolean" + * and {@link Booleans#isBoolean(char[], int, int)} for the definition of a "strict boolean". + * + * @deprecated Only used to provide automatic upgrades for pre 6.0 indices. + */ + @Deprecated + public Boolean getAsBooleanLenientForPreEs6Indices(Version indexVersion, String setting, Boolean defaultValue) { + if (indexVersion.before(Version.V_6_0_0_alpha1_UNRELEASED)) { + //Only emit a warning if the setting's value is not a proper boolean + final String value = get(setting, "false"); + if (Booleans.isBoolean(value) == false) { + @SuppressWarnings("deprecation") + boolean convertedValue = Booleans.parseBooleanLenient(get(setting), defaultValue); + deprecationLogger.deprecated("The value [{}] of setting [{}] is not coerced into boolean anymore. Please change " + + "this value to [{}].", value, setting, String.valueOf(convertedValue)); + return convertedValue; + } + } + return getAsBoolean(setting, defaultValue); + } + /** * Returns the setting value (as time) associated with the setting key. If it does not exists, * returns the default value provided. diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java index e7dbeafe5d0d..879b9e9d723f 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContent.java @@ -52,7 +52,7 @@ public interface XContent { */ static boolean isStrictDuplicateDetectionEnabled() { // Don't allow duplicate keys in JSON content by default but let the user opt out - return Booleans.parseBooleanExact(System.getProperty("es.xcontent.strict_duplicate_detection", "true")); + return Booleans.parseBoolean(System.getProperty("es.xcontent.strict_duplicate_detection", "true")); } /** diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java index 7ca77442268c..e1f1c4b3f8a1 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java @@ -201,16 +201,32 @@ public interface XContentParser extends Releasable { double doubleValue() throws IOException; + /** + * @return true iff the current value is either boolean (true or false) or one of "false", "true". + */ + boolean isBooleanValue() throws IOException; + + boolean booleanValue() throws IOException; + + // TODO #22298: Remove this method and replace all call sites with #isBooleanValue() /** * returns true if the current value is boolean in nature. * values that are considered booleans: * - boolean value (true/false) * - numeric integers (=0 is considered as false, !=0 is true) * - one of the following strings: "true","false","on","off","yes","no","1","0" + * + * @deprecated Just present for providing backwards compatibility. Use {@link #isBooleanValue()} instead. */ - boolean isBooleanValue() throws IOException; + @Deprecated + boolean isBooleanValueLenient() throws IOException; - boolean booleanValue() throws IOException; + // TODO #22298: Remove this method and replace all call sites with #booleanValue() + /** + * @deprecated Just present for providing backwards compatibility. Use {@link #booleanValue()} instead. + */ + @Deprecated + boolean booleanValueLenient() throws IOException; /** * Reads a plain binary value that was written via one of the following methods: diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java index 162e5f7fb7d8..95fe08d96c35 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/AbstractXContentParser.java @@ -77,9 +77,6 @@ public abstract class AbstractXContentParser implements XContentParser { switch (currentToken()) { case VALUE_BOOLEAN: return true; - case VALUE_NUMBER: - NumberType numberType = numberType(); - return numberType == NumberType.LONG || numberType == NumberType.INT; case VALUE_STRING: return Booleans.isBoolean(textCharacters(), textOffset(), textLength()); default: @@ -89,11 +86,37 @@ public abstract class AbstractXContentParser implements XContentParser { @Override public boolean booleanValue() throws IOException { + Token token = currentToken(); + if (token == Token.VALUE_STRING) { + return Booleans.parseBoolean(textCharacters(), textOffset(), textLength(), false /* irrelevant */); + } + return doBooleanValue(); + } + + @Override + @Deprecated + public boolean isBooleanValueLenient() throws IOException { + switch (currentToken()) { + case VALUE_BOOLEAN: + return true; + case VALUE_NUMBER: + NumberType numberType = numberType(); + return numberType == NumberType.LONG || numberType == NumberType.INT; + case VALUE_STRING: + return Booleans.isBooleanLenient(textCharacters(), textOffset(), textLength()); + default: + return false; + } + } + + @Override + @Deprecated + public boolean booleanValueLenient() throws IOException { Token token = currentToken(); if (token == Token.VALUE_NUMBER) { return intValue() != 0; } else if (token == Token.VALUE_STRING) { - return Booleans.parseBoolean(textCharacters(), textOffset(), textLength(), false /* irrelevant */); + return Booleans.parseBooleanLenient(textCharacters(), textOffset(), textLength(), false /* irrelevant */); } return doBooleanValue(); } diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java index 09d9dabac754..36eacb81f830 100644 --- a/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java +++ b/core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java @@ -24,6 +24,7 @@ import org.apache.lucene.util.automaton.Automaton; import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.apache.lucene.util.automaton.Operations; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.common.Booleans; import org.elasticsearch.common.Numbers; import org.elasticsearch.common.Strings; import org.elasticsearch.common.regex.Regex; @@ -412,39 +413,29 @@ public class XContentMapValues { return Long.parseLong(node.toString()); } - /** - * This method is very lenient, use {@link #nodeBooleanValue} instead. - */ - public static boolean lenientNodeBooleanValue(Object node, boolean defaultValue) { - if (node == null) { - return defaultValue; + public static boolean nodeBooleanValue(Object node, String name, boolean defaultValue) { + try { + return nodeBooleanValue(node, defaultValue); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Could not convert [" + name + "] to boolean", ex); } - return lenientNodeBooleanValue(node); } - /** - * This method is very lenient, use {@link #nodeBooleanValue} instead. - */ - public static boolean lenientNodeBooleanValue(Object node) { - if (node instanceof Boolean) { - return (Boolean) node; + public static boolean nodeBooleanValue(Object node, boolean defaultValue) { + String nodeValue = node == null ? null : node.toString(); + return Booleans.parseBoolean(nodeValue, defaultValue); + } + + public static boolean nodeBooleanValue(Object node, String name) { + try { + return nodeBooleanValue(node); + } catch (IllegalArgumentException ex) { + throw new IllegalArgumentException("Could not convert [" + name + "] to boolean", ex); } - if (node instanceof Number) { - return ((Number) node).intValue() != 0; - } - String value = node.toString(); - return !(value.equals("false") || value.equals("0") || value.equals("off")); } public static boolean nodeBooleanValue(Object node) { - switch (node.toString()) { - case "true": - return true; - case "false": - return false; - default: - throw new IllegalArgumentException("Can't parse boolean value [" + node + "], expected [true] or [false]"); - } + return Booleans.parseBoolean(node.toString()); } public static TimeValue nodeTimeValue(Object node, TimeValue defaultValue) { diff --git a/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java b/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java index e930f327f0d3..927397725be0 100644 --- a/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java +++ b/core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java @@ -477,9 +477,11 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator { */ private boolean recoverOnAnyNode(IndexMetaData metaData) { // don't use the setting directly, not to trigger verbose deprecation logging - return (IndexMetaData.isOnSharedFilesystem(metaData.getSettings()) || IndexMetaData.isOnSharedFilesystem(this.settings)) - && (metaData.getSettings().getAsBoolean(IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false) || - this.settings.getAsBoolean(IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false)); + return (metaData.isOnSharedFilesystem(metaData.getSettings()) || metaData.isOnSharedFilesystem(this.settings)) + && (metaData.getSettings().getAsBooleanLenientForPreEs6Indices( + metaData.getCreationVersion(), IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false) || + this.settings.getAsBooleanLenientForPreEs6Indices + (metaData.getCreationVersion(), IndexMetaData.SETTING_SHARED_FS_ALLOW_RECOVERY_ON_ANY_NODE, false)); } protected abstract FetchResult fetchData(ShardRouting shard, RoutingAllocation allocation); diff --git a/core/src/main/java/org/elasticsearch/index/IndexModule.java b/core/src/main/java/org/elasticsearch/index/IndexModule.java index 97edd2fd468f..25e32dc0dee9 100644 --- a/core/src/main/java/org/elasticsearch/index/IndexModule.java +++ b/core/src/main/java/org/elasticsearch/index/IndexModule.java @@ -23,6 +23,7 @@ import org.apache.lucene.util.SetOnce; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.TriFunction; import org.elasticsearch.common.settings.Setting; import org.elasticsearch.common.settings.Setting.Property; import org.elasticsearch.common.settings.Settings; @@ -69,7 +70,7 @@ import java.util.function.Function; * IndexModule represents the central extension point for index level custom implementations like: *