Skip to content

Commit 3585a6a

Browse files
authored
Don't download geoip databases if geoip system index is blocked. (#86842) (#86893)
For example in the case that the a cluster is running out of disk space and indices reject writes. This can otherwise load to unnecessary error logs being printed and just add to more instability. Instead, the GeoIpDownloader should just try to download the files the next it runs.
1 parent ad4d7bf commit 3585a6a

File tree

4 files changed

+70
-6
lines changed

4 files changed

+70
-6
lines changed

docs/changelog/86842.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 86842
2+
summary: Don't download geoip databases if geoip system index is blocked
3+
area: Ingest
4+
type: bug
5+
issues: []

modules/ingest-geoip/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloader.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
import org.apache.logging.log4j.Logger;
1313
import org.apache.logging.log4j.message.ParameterizedMessage;
1414
import org.apache.logging.log4j.util.Supplier;
15+
import org.elasticsearch.ElasticsearchException;
1516
import org.elasticsearch.action.ActionListener;
1617
import org.elasticsearch.action.admin.indices.flush.FlushRequest;
1718
import org.elasticsearch.action.admin.indices.refresh.RefreshRequest;
1819
import org.elasticsearch.action.index.IndexRequest;
1920
import org.elasticsearch.action.support.PlainActionFuture;
2021
import org.elasticsearch.client.internal.Client;
22+
import org.elasticsearch.cluster.block.ClusterBlockLevel;
2123
import org.elasticsearch.cluster.service.ClusterService;
2224
import org.elasticsearch.common.hash.MessageDigests;
2325
import org.elasticsearch.common.settings.Setting;
@@ -126,6 +128,18 @@ public void setPollInterval(TimeValue pollInterval) {
126128

127129
// visible for testing
128130
void updateDatabases() throws IOException {
131+
var clusterState = clusterService.state();
132+
var geoipIndex = clusterState.getMetadata().getIndicesLookup().get(GeoIpDownloader.DATABASES_INDEX);
133+
if (geoipIndex != null) {
134+
if (clusterState.getRoutingTable().index(geoipIndex.getWriteIndex()).allPrimaryShardsActive() == false) {
135+
throw new ElasticsearchException("not all primary shards of [" + DATABASES_INDEX + "] index are active");
136+
}
137+
var blockException = clusterState.blocks().indexBlockedException(ClusterBlockLevel.WRITE, geoipIndex.getWriteIndex().getName());
138+
if (blockException != null) {
139+
throw blockException;
140+
}
141+
}
142+
129143
logger.debug("updating geoip databases");
130144
List<Map<String, Object>> response = fetchDatabasesOverview();
131145
for (Map<String, Object> res : response) {

modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,11 @@ private String mockSearches(String databaseName, int firstChunk, int lastChunk)
352352
return MessageDigests.toHexString(md.digest());
353353
}
354354

355-
private static ClusterState createClusterState(PersistentTasksCustomMetadata tasksCustomMetadata) {
355+
static ClusterState createClusterState(PersistentTasksCustomMetadata tasksCustomMetadata) {
356+
return createClusterState(tasksCustomMetadata, false);
357+
}
358+
359+
static ClusterState createClusterState(PersistentTasksCustomMetadata tasksCustomMetadata, boolean noStartedShards) {
356360
boolean aliasGeoipDatabase = randomBoolean();
357361
String indexName = aliasGeoipDatabase
358362
? GeoIpDownloader.DATABASES_INDEX + "-" + randomAlphaOfLength(5)
@@ -376,9 +380,11 @@ private static ClusterState createClusterState(PersistentTasksCustomMetadata tas
376380
new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, "")
377381
);
378382
String nodeId = ESTestCase.randomAlphaOfLength(8);
379-
IndexShardRoutingTable table = new IndexShardRoutingTable.Builder(new ShardId(index, 0)).addShard(
380-
shardRouting.initialize(nodeId, null, shardRouting.getExpectedShardSize()).moveToStarted()
381-
).build();
383+
shardRouting = shardRouting.initialize(nodeId, null, shardRouting.getExpectedShardSize());
384+
if (noStartedShards == false) {
385+
shardRouting = shardRouting.moveToStarted();
386+
}
387+
IndexShardRoutingTable table = new IndexShardRoutingTable.Builder(new ShardId(index, 0)).addShard(shardRouting).build();
382388
return ClusterState.builder(new ClusterName("name"))
383389
.metadata(Metadata.builder().putCustom(TYPE, tasksCustomMetadata).put(idxMeta))
384390
.nodes(

modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/GeoIpDownloaderTests.java

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
package org.elasticsearch.ingest.geoip;
1010

11+
import org.elasticsearch.ElasticsearchException;
1112
import org.elasticsearch.action.ActionListener;
1213
import org.elasticsearch.action.ActionRequest;
1314
import org.elasticsearch.action.ActionResponse;
@@ -22,13 +23,16 @@
2223
import org.elasticsearch.action.index.IndexAction;
2324
import org.elasticsearch.action.index.IndexRequest;
2425
import org.elasticsearch.action.index.IndexResponse;
25-
import org.elasticsearch.cluster.ClusterName;
2626
import org.elasticsearch.cluster.ClusterState;
27+
import org.elasticsearch.cluster.block.ClusterBlockException;
28+
import org.elasticsearch.cluster.block.ClusterBlocks;
29+
import org.elasticsearch.cluster.metadata.IndexMetadata;
2730
import org.elasticsearch.cluster.service.ClusterService;
2831
import org.elasticsearch.common.settings.ClusterSettings;
2932
import org.elasticsearch.common.settings.Settings;
3033
import org.elasticsearch.node.Node;
3134
import org.elasticsearch.persistent.PersistentTaskState;
35+
import org.elasticsearch.persistent.PersistentTasksCustomMetadata;
3236
import org.elasticsearch.persistent.PersistentTasksCustomMetadata.PersistentTask;
3337
import org.elasticsearch.test.ESTestCase;
3438
import org.elasticsearch.test.client.NoOpClient;
@@ -52,10 +56,13 @@
5256
import java.util.concurrent.atomic.AtomicInteger;
5357
import java.util.function.BiConsumer;
5458

59+
import static org.elasticsearch.ingest.geoip.DatabaseNodeServiceTests.createClusterState;
5560
import static org.elasticsearch.ingest.geoip.GeoIpDownloader.ENDPOINT_SETTING;
5661
import static org.elasticsearch.ingest.geoip.GeoIpDownloader.MAX_CHUNK_SIZE;
5762
import static org.elasticsearch.tasks.TaskId.EMPTY_TASK_ID;
63+
import static org.hamcrest.Matchers.equalTo;
5864
import static org.mockito.Mockito.mock;
65+
import static org.mockito.Mockito.verifyNoInteractions;
5966
import static org.mockito.Mockito.when;
6067

6168
public class GeoIpDownloaderTests extends ESTestCase {
@@ -77,7 +84,7 @@ public void setup() {
7784
Set.of(GeoIpDownloader.ENDPOINT_SETTING, GeoIpDownloader.POLL_INTERVAL_SETTING, GeoIpDownloaderTaskExecutor.ENABLED_SETTING)
7885
)
7986
);
80-
ClusterState state = ClusterState.builder(ClusterName.DEFAULT).build();
87+
ClusterState state = createClusterState(new PersistentTasksCustomMetadata(1L, Map.of()));
8188
when(clusterService.state()).thenReturn(state);
8289
client = new MockClient(threadPool);
8390
geoIpDownloader = new GeoIpDownloader(
@@ -455,6 +462,38 @@ void processDatabase(Map<String, Object> databaseInfo) {
455462
assertFalse(it.hasNext());
456463
}
457464

465+
public void testUpdateDatabasesWriteBlock() {
466+
ClusterState state = createClusterState(new PersistentTasksCustomMetadata(1L, Map.of()));
467+
var geoIpIndex = state.getMetadata().getIndicesLookup().get(GeoIpDownloader.DATABASES_INDEX).getWriteIndex().getName();
468+
state = ClusterState.builder(state)
469+
.blocks(new ClusterBlocks.Builder().addIndexBlock(geoIpIndex, IndexMetadata.INDEX_READ_ONLY_ALLOW_DELETE_BLOCK))
470+
.build();
471+
when(clusterService.state()).thenReturn(state);
472+
var e = expectThrows(ClusterBlockException.class, () -> geoIpDownloader.updateDatabases());
473+
assertThat(
474+
e.getMessage(),
475+
equalTo(
476+
"index ["
477+
+ geoIpIndex
478+
+ "] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, "
479+
+ "index has read-only-allow-delete block];"
480+
)
481+
);
482+
verifyNoInteractions(httpClient);
483+
}
484+
485+
public void testUpdateDatabasesIndexNotReady() {
486+
ClusterState state = createClusterState(new PersistentTasksCustomMetadata(1L, Map.of()), true);
487+
var geoIpIndex = state.getMetadata().getIndicesLookup().get(GeoIpDownloader.DATABASES_INDEX).getWriteIndex().getName();
488+
state = ClusterState.builder(state)
489+
.blocks(new ClusterBlocks.Builder().addIndexBlock(geoIpIndex, IndexMetadata.INDEX_READ_ONLY_ALLOW_DELETE_BLOCK))
490+
.build();
491+
when(clusterService.state()).thenReturn(state);
492+
var e = expectThrows(ElasticsearchException.class, () -> geoIpDownloader.updateDatabases());
493+
assertThat(e.getMessage(), equalTo("not all primary shards of [.geoip_databases] index are active"));
494+
verifyNoInteractions(httpClient);
495+
}
496+
458497
private static class MockClient extends NoOpClient {
459498

460499
private final Map<ActionType<?>, BiConsumer<? extends ActionRequest, ? extends ActionListener<?>>> handlers = new HashMap<>();

0 commit comments

Comments
 (0)