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
This commit is contained in:
parent
77ce3260dd
commit
6b084e55c5
|
@ -44,6 +44,7 @@ import org.elasticsearch.cluster.metadata.MetaDataCreateIndexService;
|
||||||
import org.elasticsearch.cluster.metadata.MetaDataIndexAliasesService;
|
import org.elasticsearch.cluster.metadata.MetaDataIndexAliasesService;
|
||||||
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService;
|
import org.elasticsearch.cluster.metadata.MetaDataIndexTemplateService;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
import org.elasticsearch.cluster.service.ClusterService;
|
||||||
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.unit.ByteSizeValue;
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
import org.elasticsearch.index.shard.DocsStats;
|
import org.elasticsearch.index.shard.DocsStats;
|
||||||
|
@ -55,6 +56,7 @@ import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -238,7 +240,11 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> conditions,
|
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 numDocs = docsStats == null ? 0 : docsStats.getCount();
|
||||||
final long indexSize = docsStats == null ? 0 : docsStats.getTotalSizeInBytes();
|
final long indexSize = docsStats == null ? 0 : docsStats.getTotalSizeInBytes();
|
||||||
final Condition.Stats stats = new Condition.Stats(numDocs, metaData.getCreationDate(), new ByteSizeValue(indexSize));
|
final Condition.Stats stats = new Condition.Stats(numDocs, metaData.getCreationDate(), new ByteSizeValue(indexSize));
|
||||||
|
@ -247,9 +253,18 @@ public class TransportRolloverAction extends TransportMasterNodeAction<RolloverR
|
||||||
.collect(Collectors.toMap(result -> result.condition.toString(), result -> result.matched));
|
.collect(Collectors.toMap(result -> result.condition.toString(), result -> result.matched));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> conditions, final IndexMetaData metaData,
|
static Map<String, Boolean> evaluateConditions(final Collection<Condition<?>> conditions,
|
||||||
final IndicesStatsResponse statsResponse) {
|
@Nullable final IndexMetaData metaData,
|
||||||
return evaluateConditions(conditions, statsResponse.getIndex(metaData.getIndex().getName()).getPrimaries().getDocs(), 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) {
|
static void validate(MetaData metaData, RolloverRequest request) {
|
||||||
|
|
|
@ -51,6 +51,7 @@ import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
import org.elasticsearch.index.shard.DocsStats;
|
import org.elasticsearch.index.shard.DocsStats;
|
||||||
|
import org.elasticsearch.rest.action.cat.RestIndicesActionTests;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
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<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() {
|
public void testCreateUpdateAliasRequest() {
|
||||||
String sourceAlias = randomAlphaOfLength(10);
|
String sourceAlias = randomAlphaOfLength(10);
|
||||||
String sourceIndex = randomAlphaOfLength(10);
|
String sourceIndex = randomAlphaOfLength(10);
|
||||||
|
|
|
@ -151,7 +151,7 @@ public class RestIndicesActionTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) {
|
public static IndicesStatsResponse randomIndicesStatsResponse(final IndexMetaData[] indices) {
|
||||||
List<ShardStats> shardStats = new ArrayList<>();
|
List<ShardStats> shardStats = new ArrayList<>();
|
||||||
for (final IndexMetaData index : indices) {
|
for (final IndexMetaData index : indices) {
|
||||||
int numShards = randomIntBetween(1, 3);
|
int numShards = randomIntBetween(1, 3);
|
||||||
|
|
Loading…
Reference in New Issue