From 6b084e55c57c9ab8d7ab1725228b68d5db0f015b Mon Sep 17 00:00:00 2001 From: Lee Hinman Date: Wed, 19 Jun 2019 16:07:28 -0600 Subject: [PATCH] [7.x] Prevent NullPointerException in TransportRolloverAction (#43353) (#43397) It's possible for the passed in `IndexMetaData` to be null (for instance, cluster state passed in does not have the index in its metadata) which in turn can cause a `NullPointerException` when evaluating the conditions for an index. This commit adds null protection and unit tests for this case. Resolves #43296 --- .../rollover/TransportRolloverAction.java | 23 +++++++++++--- .../TransportRolloverActionTests.java | 30 +++++++++++++++++++ .../action/cat/RestIndicesActionTests.java | 2 +- 3 files changed, 50 insertions(+), 5 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverAction.java b/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverAction.java index edd59f8b18c..1e71dc589af 100644 --- a/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverAction.java +++ b/server/src/main/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverAction.java @@ -44,6 +44,7 @@ import org.elasticsearch.cluster.metadata.MetaDataCreateIndexService; import org.elasticsearch.cluster.metadata.MetaDataIndexAliasesService; import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService; import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.Nullable; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.index.shard.DocsStats; @@ -55,6 +56,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -238,7 +240,11 @@ public class TransportRolloverAction extends TransportMasterNodeAction evaluateConditions(final Collection> conditions, - final DocsStats docsStats, final IndexMetaData metaData) { + @Nullable final DocsStats docsStats, + @Nullable final IndexMetaData metaData) { + if (metaData == null) { + return conditions.stream().collect(Collectors.toMap(Condition::toString, cond -> false)); + } final long numDocs = docsStats == null ? 0 : docsStats.getCount(); final long indexSize = docsStats == null ? 0 : docsStats.getTotalSizeInBytes(); final Condition.Stats stats = new Condition.Stats(numDocs, metaData.getCreationDate(), new ByteSizeValue(indexSize)); @@ -247,9 +253,18 @@ public class TransportRolloverAction extends TransportMasterNodeAction result.condition.toString(), result -> result.matched)); } - static Map evaluateConditions(final Collection> conditions, final IndexMetaData metaData, - final IndicesStatsResponse statsResponse) { - return evaluateConditions(conditions, statsResponse.getIndex(metaData.getIndex().getName()).getPrimaries().getDocs(), metaData); + static Map evaluateConditions(final Collection> conditions, + @Nullable final IndexMetaData metaData, + @Nullable final IndicesStatsResponse statsResponse) { + if (metaData == null) { + return conditions.stream().collect(Collectors.toMap(Condition::toString, cond -> false)); + } else { + final DocsStats docsStats = Optional.ofNullable(statsResponse) + .map(stats -> stats.getIndex(metaData.getIndex().getName())) + .map(indexStats -> indexStats.getPrimaries().getDocs()) + .orElse(null); + return evaluateConditions(conditions, docsStats, metaData); + } } static void validate(MetaData metaData, RolloverRequest request) { diff --git a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverActionTests.java b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverActionTests.java index 058dcc72430..ba6622ec2d1 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverActionTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/indices/rollover/TransportRolloverActionTests.java @@ -51,6 +51,7 @@ import org.elasticsearch.common.unit.ByteSizeValue; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.util.set.Sets; import org.elasticsearch.index.shard.DocsStats; +import org.elasticsearch.rest.action.cat.RestIndicesActionTests; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; @@ -165,6 +166,35 @@ public class TransportRolloverActionTests extends ESTestCase { } } + public void testEvaluateWithoutMetaData() { + MaxDocsCondition maxDocsCondition = new MaxDocsCondition(100L); + MaxAgeCondition maxAgeCondition = new MaxAgeCondition(TimeValue.timeValueHours(2)); + MaxSizeCondition maxSizeCondition = new MaxSizeCondition(new ByteSizeValue(randomIntBetween(10, 100), ByteSizeUnit.MB)); + + long matchMaxDocs = randomIntBetween(100, 1000); + final Set> conditions = Sets.newHashSet(maxDocsCondition, maxAgeCondition, maxSizeCondition); + Map results = evaluateConditions(conditions, + new DocsStats(matchMaxDocs, 0L, ByteSizeUnit.MB.toBytes(120)), null); + assertThat(results.size(), equalTo(3)); + results.forEach((k, v) -> assertFalse(v)); + + final Settings settings = Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .put(IndexMetaData.SETTING_INDEX_UUID, UUIDs.randomBase64UUID()) + .put(IndexMetaData.SETTING_NUMBER_OF_SHARDS, randomIntBetween(1, 1000)) + .put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, randomInt(10)) + .build(); + + final IndexMetaData metaData = IndexMetaData.builder(randomAlphaOfLength(10)) + .creationDate(System.currentTimeMillis() - TimeValue.timeValueHours(randomIntBetween(5, 10)).getMillis()) + .settings(settings) + .build(); + IndicesStatsResponse indicesStats = RestIndicesActionTests.randomIndicesStatsResponse(new IndexMetaData[]{metaData}); + Map results2 = evaluateConditions(conditions, null, indicesStats); + assertThat(results2.size(), equalTo(3)); + results2.forEach((k, v) -> assertFalse(v)); + } + public void testCreateUpdateAliasRequest() { String sourceAlias = randomAlphaOfLength(10); String sourceIndex = randomAlphaOfLength(10); diff --git a/server/src/test/java/org/elasticsearch/rest/action/cat/RestIndicesActionTests.java b/server/src/test/java/org/elasticsearch/rest/action/cat/RestIndicesActionTests.java index ae387806796..b9a42b5cc1c 100644 --- a/server/src/test/java/org/elasticsearch/rest/action/cat/RestIndicesActionTests.java +++ b/server/src/test/java/org/elasticsearch/rest/action/cat/RestIndicesActionTests.java @@ -151,7 +151,7 @@ public class RestIndicesActionTests extends ESTestCase { } } - private IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) { + public static IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) { List shardStats = new ArrayList<>(); for (final IndexMetaData index : indices) { int numShards = randomIntBetween(1, 3);