Skip to content

Commit

Permalink
Prevent NullPointerException in TransportRolloverAction (elastic#43353)
Browse files Browse the repository at this point in the history
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 elastic#43296
  • Loading branch information
dakrone authored and jkakavas committed Jun 27, 2019
1 parent 6a1a80d commit 63c7824
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 5 deletions.
Expand Up @@ -44,6 +44,7 @@
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;
Expand All @@ -54,6 +55,7 @@
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;

Expand Down Expand Up @@ -233,7 +235,11 @@ static String generateRolloverIndexName(String sourceIndexName, IndexNameExpress
}

static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> 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));
Expand All @@ -242,9 +248,18 @@ static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> co
.collect(Collectors.toMap(result -> result.condition.toString(), result -> result.matched));
}

static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> conditions, final IndexMetaData metaData,
final IndicesStatsResponse statsResponse) {
return evaluateConditions(conditions, statsResponse.getIndex(metaData.getIndex().getName()).getPrimaries().getDocs(), metaData);
static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> 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) {
Expand Down
Expand Up @@ -51,6 +51,7 @@
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;
Expand Down Expand Up @@ -165,6 +166,35 @@ public void testEvaluateWithoutDocStats() {
}
}

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<Condition<?>> conditions = Sets.newHashSet(maxDocsCondition, maxAgeCondition, maxSizeCondition);
Map<String, Boolean> 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<String, Boolean> 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);
Expand Down
Expand Up @@ -151,7 +151,7 @@ public void testBuildTable() {
}
}

private IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) {
public static IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) {
List<ShardStats> shardStats = new ArrayList<>();
for (final IndexMetaData index : indices) {
int numShards = randomIntBetween(1, 3);
Expand Down

0 comments on commit 63c7824

Please sign in to comment.