Skip to content

Commit 8aeaf43

Browse files
committed
Add BootstrapContext to expose settings and recovered state to bootstrap checks (#26628)
This exposes the node settings and the persistent part of the cluster state to the bootstrap checks to allow plugins to enforce certain preconditions based on the recovered state.
1 parent 4e6bc14 commit 8aeaf43

File tree

11 files changed

+171
-107
lines changed

11 files changed

+171
-107
lines changed

core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@ public void run() {
212212
node = new Node(environment) {
213213
@Override
214214
protected void validateNodeBeforeAcceptingRequests(
215-
final Settings settings,
215+
final BootstrapContext context,
216216
final BoundTransportAddress boundTransportAddress, List<BootstrapCheck> checks) throws NodeValidationException {
217-
BootstrapChecks.check(settings, boundTransportAddress, checks);
217+
BootstrapChecks.check(context, boundTransportAddress, checks);
218218
}
219219
};
220220
}

core/src/main/java/org/elasticsearch/bootstrap/BootstrapCheck.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ public interface BootstrapCheck {
2727
/**
2828
* Test if the node fails the check.
2929
*
30+
* @param context the bootstrap context for more sophisticated checks
3031
* @return {@code true} if the node failed the check
3132
*/
32-
boolean check();
33+
boolean check(BootstrapContext context);
3334

3435
/**
3536
* The error message for a failed check.
@@ -41,5 +42,4 @@ public interface BootstrapCheck {
4142
default boolean alwaysEnforce() {
4243
return false;
4344
}
44-
4545
}

core/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java

Lines changed: 31 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.elasticsearch.common.SuppressForbidden;
2727
import org.elasticsearch.common.io.PathUtils;
2828
import org.elasticsearch.common.logging.Loggers;
29-
import org.elasticsearch.common.settings.Settings;
3029
import org.elasticsearch.common.transport.BoundTransportAddress;
3130
import org.elasticsearch.common.transport.TransportAddress;
3231
import org.elasticsearch.discovery.DiscoveryModule;
@@ -65,46 +64,50 @@ private BootstrapChecks() {
6564
* {@code es.enforce.bootstrap.checks} is set to {@code true} then the bootstrap checks will be enforced regardless of whether or not
6665
* the transport protocol is bound to a non-loopback interface.
6766
*
68-
* @param settings the current node settings
67+
* @param context the current node bootstrap context
6968
* @param boundTransportAddress the node network bindings
7069
*/
71-
static void check(final Settings settings, final BoundTransportAddress boundTransportAddress, List<BootstrapCheck> additionalChecks)
72-
throws NodeValidationException {
73-
final List<BootstrapCheck> builtInChecks = checks(settings);
70+
static void check(final BootstrapContext context, final BoundTransportAddress boundTransportAddress,
71+
List<BootstrapCheck> additionalChecks) throws NodeValidationException {
72+
final List<BootstrapCheck> builtInChecks = checks();
7473
final List<BootstrapCheck> combinedChecks = new ArrayList<>(builtInChecks);
7574
combinedChecks.addAll(additionalChecks);
76-
check(
77-
enforceLimits(boundTransportAddress, DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings)),
75+
check( context,
76+
enforceLimits(boundTransportAddress, DiscoveryModule.DISCOVERY_TYPE_SETTING.get(context.settings)),
7877
Collections.unmodifiableList(combinedChecks),
79-
Node.NODE_NAME_SETTING.get(settings));
78+
Node.NODE_NAME_SETTING.get(context.settings));
8079
}
8180

8281
/**
8382
* Executes the provided checks and fails the node if {@code enforceLimits} is {@code true}, otherwise logs warnings. If the system
8483
* property {@code es.enforce.bootstrap.checks} is set to {@code true} then the bootstrap checks will be enforced regardless of whether
8584
* or not the transport protocol is bound to a non-loopback interface.
8685
*
86+
* @param context the current node boostrap context
8787
* @param enforceLimits {@code true} if the checks should be enforced or otherwise warned
8888
* @param checks the checks to execute
8989
* @param nodeName the node name to be used as a logging prefix
9090
*/
9191
static void check(
92+
final BootstrapContext context,
9293
final boolean enforceLimits,
9394
final List<BootstrapCheck> checks,
9495
final String nodeName) throws NodeValidationException {
95-
check(enforceLimits, checks, Loggers.getLogger(BootstrapChecks.class, nodeName));
96+
check(context, enforceLimits, checks, Loggers.getLogger(BootstrapChecks.class, nodeName));
9697
}
9798

9899
/**
99100
* Executes the provided checks and fails the node if {@code enforceLimits} is {@code true}, otherwise logs warnings. If the system
100101
* property {@code es.enforce.bootstrap.checks }is set to {@code true} then the bootstrap checks will be enforced regardless of whether
101102
* or not the transport protocol is bound to a non-loopback interface.
102103
*
104+
* @param context the current node boostrap context
103105
* @param enforceLimits {@code true} if the checks should be enforced or otherwise warned
104106
* @param checks the checks to execute
105107
* @param logger the logger to
106108
*/
107109
static void check(
110+
final BootstrapContext context,
108111
final boolean enforceLimits,
109112
final List<BootstrapCheck> checks,
110113
final Logger logger) throws NodeValidationException {
@@ -134,7 +137,7 @@ static void check(
134137
}
135138

136139
for (final BootstrapCheck check : checks) {
137-
if (check.check()) {
140+
if (check.check(context)) {
138141
if (!(enforceLimits || enforceBootstrapChecks) && !check.alwaysEnforce()) {
139142
ignoredErrors.add(check.errorMessage());
140143
} else {
@@ -180,13 +183,13 @@ static boolean enforceLimits(final BoundTransportAddress boundTransportAddress,
180183
}
181184

182185
// the list of checks to execute
183-
static List<BootstrapCheck> checks(final Settings settings) {
186+
static List<BootstrapCheck> checks() {
184187
final List<BootstrapCheck> checks = new ArrayList<>();
185188
checks.add(new HeapSizeCheck());
186189
final FileDescriptorCheck fileDescriptorCheck
187190
= Constants.MAC_OS_X ? new OsXFileDescriptorCheck() : new FileDescriptorCheck();
188191
checks.add(fileDescriptorCheck);
189-
checks.add(new MlockallCheck(BootstrapSettings.MEMORY_LOCK_SETTING.get(settings)));
192+
checks.add(new MlockallCheck());
190193
if (Constants.LINUX) {
191194
checks.add(new MaxNumberOfThreadsCheck());
192195
}
@@ -201,7 +204,7 @@ static List<BootstrapCheck> checks(final Settings settings) {
201204
}
202205
checks.add(new ClientJvmCheck());
203206
checks.add(new UseSerialGCCheck());
204-
checks.add(new SystemCallFilterCheck(BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(settings)));
207+
checks.add(new SystemCallFilterCheck());
205208
checks.add(new OnErrorCheck());
206209
checks.add(new OnOutOfMemoryErrorCheck());
207210
checks.add(new EarlyAccessCheck());
@@ -212,7 +215,7 @@ static List<BootstrapCheck> checks(final Settings settings) {
212215
static class HeapSizeCheck implements BootstrapCheck {
213216

214217
@Override
215-
public boolean check() {
218+
public boolean check(BootstrapContext context) {
216219
final long initialHeapSize = getInitialHeapSize();
217220
final long maxHeapSize = getMaxHeapSize();
218221
return initialHeapSize != 0 && maxHeapSize != 0 && initialHeapSize != maxHeapSize;
@@ -268,7 +271,7 @@ protected FileDescriptorCheck(final int limit) {
268271
this.limit = limit;
269272
}
270273

271-
public final boolean check() {
274+
public final boolean check(BootstrapContext context) {
272275
final long maxFileDescriptorCount = getMaxFileDescriptorCount();
273276
return maxFileDescriptorCount != -1 && maxFileDescriptorCount < limit;
274277
}
@@ -292,15 +295,9 @@ long getMaxFileDescriptorCount() {
292295

293296
static class MlockallCheck implements BootstrapCheck {
294297

295-
private final boolean mlockallSet;
296-
297-
MlockallCheck(final boolean mlockAllSet) {
298-
this.mlockallSet = mlockAllSet;
299-
}
300-
301298
@Override
302-
public boolean check() {
303-
return mlockallSet && !isMemoryLocked();
299+
public boolean check(BootstrapContext context) {
300+
return BootstrapSettings.MEMORY_LOCK_SETTING.get(context.settings) && !isMemoryLocked();
304301
}
305302

306303
@Override
@@ -321,7 +318,7 @@ static class MaxNumberOfThreadsCheck implements BootstrapCheck {
321318
private static final long MAX_NUMBER_OF_THREADS_THRESHOLD = 1 << 12;
322319

323320
@Override
324-
public boolean check() {
321+
public boolean check(BootstrapContext context) {
325322
return getMaxNumberOfThreads() != -1 && getMaxNumberOfThreads() < MAX_NUMBER_OF_THREADS_THRESHOLD;
326323
}
327324

@@ -345,7 +342,7 @@ long getMaxNumberOfThreads() {
345342
static class MaxSizeVirtualMemoryCheck implements BootstrapCheck {
346343

347344
@Override
348-
public boolean check() {
345+
public boolean check(BootstrapContext context) {
349346
return getMaxSizeVirtualMemory() != Long.MIN_VALUE && getMaxSizeVirtualMemory() != getRlimInfinity();
350347
}
351348

@@ -376,7 +373,7 @@ long getMaxSizeVirtualMemory() {
376373
static class MaxFileSizeCheck implements BootstrapCheck {
377374

378375
@Override
379-
public boolean check() {
376+
public boolean check(BootstrapContext context) {
380377
final long maxFileSize = getMaxFileSize();
381378
return maxFileSize != Long.MIN_VALUE && maxFileSize != getRlimInfinity();
382379
}
@@ -405,7 +402,7 @@ static class MaxMapCountCheck implements BootstrapCheck {
405402
private static final long LIMIT = 1 << 18;
406403

407404
@Override
408-
public boolean check() {
405+
public boolean check(BootstrapContext context) {
409406
return getMaxMapCount() != -1 && getMaxMapCount() < LIMIT;
410407
}
411408

@@ -470,7 +467,7 @@ long parseProcSysVmMaxMapCount(final String procSysVmMaxMapCount) throws NumberF
470467
static class ClientJvmCheck implements BootstrapCheck {
471468

472469
@Override
473-
public boolean check() {
470+
public boolean check(BootstrapContext context) {
474471
return getVmName().toLowerCase(Locale.ROOT).contains("client");
475472
}
476473

@@ -496,7 +493,7 @@ public String errorMessage() {
496493
static class UseSerialGCCheck implements BootstrapCheck {
497494

498495
@Override
499-
public boolean check() {
496+
public boolean check(BootstrapContext context) {
500497
return getUseSerialGC().equals("true");
501498
}
502499

@@ -521,15 +518,9 @@ public String errorMessage() {
521518
*/
522519
static class SystemCallFilterCheck implements BootstrapCheck {
523520

524-
private final boolean areSystemCallFiltersEnabled;
525-
526-
SystemCallFilterCheck(final boolean areSystemCallFiltersEnabled) {
527-
this.areSystemCallFiltersEnabled = areSystemCallFiltersEnabled;
528-
}
529-
530521
@Override
531-
public boolean check() {
532-
return areSystemCallFiltersEnabled && !isSystemCallFilterInstalled();
522+
public boolean check(BootstrapContext context) {
523+
return BootstrapSettings.SYSTEM_CALL_FILTER_SETTING.get(context.settings) && !isSystemCallFilterInstalled();
533524
}
534525

535526
// visible for testing
@@ -548,7 +539,7 @@ public String errorMessage() {
548539
abstract static class MightForkCheck implements BootstrapCheck {
549540

550541
@Override
551-
public boolean check() {
542+
public boolean check(BootstrapContext context) {
552543
return isSystemCallFilterInstalled() && mightFork();
553544
}
554545

@@ -623,7 +614,7 @@ public String errorMessage() {
623614
static class EarlyAccessCheck implements BootstrapCheck {
624615

625616
@Override
626-
public boolean check() {
617+
public boolean check(BootstrapContext context) {
627618
return "Oracle Corporation".equals(jvmVendor()) && javaVersion().endsWith("-ea");
628619
}
629620

@@ -651,7 +642,7 @@ public String errorMessage() {
651642
static class G1GCCheck implements BootstrapCheck {
652643

653644
@Override
654-
public boolean check() {
645+
public boolean check(BootstrapContext context) {
655646
if ("Oracle Corporation".equals(jvmVendor()) && isJava8() && isG1GCEnabled()) {
656647
final String jvmVersion = jvmVersion();
657648
// HotSpot versions on Java 8 match this regular expression; note that this changes with Java 9 after JEP-223
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Licensed to Elasticsearch under one or more contributor
3+
* license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright
5+
* ownership. Elasticsearch licenses this file to you under
6+
* the Apache License, Version 2.0 (the "License"); you may
7+
* not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.elasticsearch.bootstrap;
20+
21+
import org.elasticsearch.cluster.metadata.MetaData;
22+
import org.elasticsearch.common.settings.Settings;
23+
24+
/**
25+
* Context that is passed to every bootstrap check to make decisions on.
26+
*/
27+
public class BootstrapContext {
28+
/**
29+
* The nodes settings
30+
*/
31+
public final Settings settings;
32+
/**
33+
* The nodes local state metadata loaded on startup
34+
*/
35+
public final MetaData metaData;
36+
37+
public BootstrapContext(Settings settings, MetaData metaData) {
38+
this.settings = settings;
39+
this.metaData = metaData;
40+
}
41+
}

core/src/main/java/org/elasticsearch/gateway/GatewayMetaState.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.elasticsearch.index.Index;
4242
import org.elasticsearch.plugins.MetaDataUpgrader;
4343

44+
import java.io.IOException;
4445
import java.nio.file.DirectoryStream;
4546
import java.nio.file.Files;
4647
import java.nio.file.Path;
@@ -114,7 +115,7 @@ public GatewayMetaState(Settings settings, NodeEnvironment nodeEnv, MetaStateSer
114115
}
115116
}
116117

117-
public MetaData loadMetaState() throws Exception {
118+
public MetaData loadMetaState() throws IOException {
118119
return metaStateService.loadFullState();
119120
}
120121

core/src/main/java/org/elasticsearch/gateway/MetaStateService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public MetaStateService(Settings settings, NodeEnvironment nodeEnv, NamedXConten
5353
* Loads the full state, which includes both the global state and all the indices
5454
* meta state.
5555
*/
56-
MetaData loadFullState() throws Exception {
56+
MetaData loadFullState() throws IOException {
5757
MetaData globalMetaData = loadGlobalState();
5858
MetaData.Builder metaDataBuilder;
5959
if (globalMetaData != null) {

core/src/main/java/org/elasticsearch/node/Node.java

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.elasticsearch.action.support.TransportAction;
3636
import org.elasticsearch.action.update.UpdateHelper;
3737
import org.elasticsearch.bootstrap.BootstrapCheck;
38+
import org.elasticsearch.bootstrap.BootstrapContext;
3839
import org.elasticsearch.client.Client;
3940
import org.elasticsearch.client.node.NodeClient;
4041
import org.elasticsearch.cluster.ClusterInfo;
@@ -86,6 +87,7 @@
8687
import org.elasticsearch.env.Environment;
8788
import org.elasticsearch.env.NodeEnvironment;
8889
import org.elasticsearch.gateway.GatewayAllocator;
90+
import org.elasticsearch.gateway.GatewayMetaState;
8991
import org.elasticsearch.gateway.GatewayModule;
9092
import org.elasticsearch.gateway.GatewayService;
9193
import org.elasticsearch.gateway.MetaStateService;
@@ -139,6 +141,7 @@
139141
import java.io.BufferedWriter;
140142
import java.io.Closeable;
141143
import java.io.IOException;
144+
import java.io.UncheckedIOException;
142145
import java.net.Inet6Address;
143146
import java.net.InetAddress;
144147
import java.net.InetSocketAddress;
@@ -604,7 +607,23 @@ public Node start() throws NodeValidationException {
604607
assert localNodeFactory.getNode() != null;
605608
assert transportService.getLocalNode().equals(localNodeFactory.getNode())
606609
: "transportService has a different local node than the factory provided";
607-
validateNodeBeforeAcceptingRequests(settings, transportService.boundAddress(), pluginsService.filterPlugins(Plugin.class).stream()
610+
final MetaData onDiskMetadata;
611+
try {
612+
// we load the global state here (the persistent part of the cluster state stored on disk) to
613+
// pass it to the bootstrap checks to allow plugins to enforce certain preconditions based on the recovered state.
614+
if (DiscoveryNode.isMasterNode(settings) || DiscoveryNode.isDataNode(settings)) {
615+
onDiskMetadata = injector.getInstance(GatewayMetaState.class).loadMetaState();
616+
} else {
617+
onDiskMetadata = MetaData.EMPTY_META_DATA;
618+
}
619+
assert onDiskMetadata != null : "metadata is null but shouldn't"; // this is never null
620+
} catch (IOException e) {
621+
throw new UncheckedIOException(e);
622+
}
623+
validateNodeBeforeAcceptingRequests(new BootstrapContext(settings, onDiskMetadata), transportService.boundAddress(), pluginsService
624+
.filterPlugins(Plugin
625+
.class)
626+
.stream()
608627
.flatMap(p -> p.getBootstrapChecks().stream()).collect(Collectors.toList()));
609628

610629
clusterService.addStateApplier(transportService.getTaskManager());
@@ -811,13 +830,13 @@ public Injector injector() {
811830
* and before the network service starts accepting incoming network
812831
* requests.
813832
*
814-
* @param settings the fully-resolved settings
833+
* @param context the bootstrap context for this node
815834
* @param boundTransportAddress the network addresses the node is
816835
* bound and publishing to
817836
*/
818837
@SuppressWarnings("unused")
819838
protected void validateNodeBeforeAcceptingRequests(
820-
final Settings settings,
839+
final BootstrapContext context,
821840
final BoundTransportAddress boundTransportAddress, List<BootstrapCheck> bootstrapChecks) throws NodeValidationException {
822841
}
823842

0 commit comments

Comments
 (0)