From 51b5dbffb7de37f19c0bffb9f84126f34490bcbe Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Tue, 4 Apr 2017 09:39:04 -0400 Subject: [PATCH] Disable bootstrap checks for single-node discovery While there are use-cases where a single-node is in production, there are also use-cases for starting a single-node that binds transport to an external interface where the node is not in production (for example, for testing the transport client against a node started in a Docker container). It's tricky to balance the desire to always enforce the bootstrap checks when a node might be in production with the need for the community to perform testing in situations that would trip the bootstrap checks. This commit enables some flexibility for these users. By setting the discovery type to "single-node", we disable the bootstrap checks independently of how transport is bound. While this sounds like a hole in the bootstrap checks, the bootstrap checks can already be avoided in the single-node use-case by binding only HTTP but not transport. For users that are genuinely in production on a single-node use-case with transport bound to an external use-case, they can set the system property "es.enable.bootstrap.checks" to force running the bootstrap checks. It would be a mistake for them not to do this. Relates #23598 --- .../bootstrap/BootstrapChecks.java | 11 +- .../bootstrap/BootstrapChecksTests.java | 9 +- .../reference/setup/bootstrap-checks.asciidoc | 108 ++++++++++-------- 3 files changed, 76 insertions(+), 52 deletions(-) diff --git a/core/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java b/core/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java index a9758267ff3..1adf4ac7c76 100644 --- a/core/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java +++ b/core/src/main/java/org/elasticsearch/bootstrap/BootstrapChecks.java @@ -29,6 +29,7 @@ import org.elasticsearch.common.logging.Loggers; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.BoundTransportAddress; import org.elasticsearch.common.transport.TransportAddress; +import org.elasticsearch.discovery.DiscoveryModule; import org.elasticsearch.monitor.jvm.JvmInfo; import org.elasticsearch.monitor.process.ProcessProbe; import org.elasticsearch.node.Node; @@ -73,7 +74,7 @@ final class BootstrapChecks { final List combinedChecks = new ArrayList<>(builtInChecks); combinedChecks.addAll(additionalChecks); check( - enforceLimits(boundTransportAddress), + enforceLimits(boundTransportAddress, DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings)), Collections.unmodifiableList(combinedChecks), Node.NODE_NAME_SETTING.get(settings)); } @@ -166,11 +167,13 @@ final class BootstrapChecks { * @param boundTransportAddress the node network bindings * @return {@code true} if the checks should be enforced */ - static boolean enforceLimits(final BoundTransportAddress boundTransportAddress) { - Predicate isLoopbackOrLinkLocalAddress = + static boolean enforceLimits(final BoundTransportAddress boundTransportAddress, final String discoveryType) { + final Predicate isLoopbackOrLinkLocalAddress = t -> t.address().getAddress().isLinkLocalAddress() || t.address().getAddress().isLoopbackAddress(); - return !(Arrays.stream(boundTransportAddress.boundAddresses()).allMatch(isLoopbackOrLinkLocalAddress) && + final boolean bound = + !(Arrays.stream(boundTransportAddress.boundAddresses()).allMatch(isLoopbackOrLinkLocalAddress) && isLoopbackOrLinkLocalAddress.test(boundTransportAddress.publishAddress())); + return bound && !"single-node".equals(discoveryType); } // the list of checks to execute diff --git a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapChecksTests.java b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapChecksTests.java index c3e08b81d6c..677309531c9 100644 --- a/core/src/test/java/org/elasticsearch/bootstrap/BootstrapChecksTests.java +++ b/core/src/test/java/org/elasticsearch/bootstrap/BootstrapChecksTests.java @@ -44,6 +44,7 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.Matchers.hasToString; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -98,7 +99,9 @@ public class BootstrapChecksTests extends ESTestCase { when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0])); when(boundTransportAddress.publishAddress()).thenReturn(publishAddress); - assertTrue(BootstrapChecks.enforceLimits(boundTransportAddress)); + final String discoveryType = randomFrom("zen", "single-node"); + + assertEquals(BootstrapChecks.enforceLimits(boundTransportAddress, discoveryType), !"single-node".equals(discoveryType)); } public void testEnforceLimitsWhenPublishingToNonLocalAddress() { @@ -114,7 +117,9 @@ public class BootstrapChecksTests extends ESTestCase { when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0])); when(boundTransportAddress.publishAddress()).thenReturn(publishAddress); - assertTrue(BootstrapChecks.enforceLimits(boundTransportAddress)); + final String discoveryType = randomFrom("zen", "single-node"); + + assertEquals(BootstrapChecks.enforceLimits(boundTransportAddress, discoveryType), !"single-node".equals(discoveryType)); } public void testExceptionAggregation() { diff --git a/docs/reference/setup/bootstrap-checks.asciidoc b/docs/reference/setup/bootstrap-checks.asciidoc index 2d18911beb6..6f32d5054fb 100644 --- a/docs/reference/setup/bootstrap-checks.asciidoc +++ b/docs/reference/setup/bootstrap-checks.asciidoc @@ -31,16 +31,31 @@ Elasticsearch instances must be reachable via transport communication so they must bind transport to an external interface. Thus, we consider an Elasticsearch instance to be in development mode if it does not bind transport to an external interface (the default), and is otherwise in -production mode if it does bind transport to an external interface. Note -that HTTP can be configured independently of transport via +production mode if it does bind transport to an external interface. + +Note that HTTP can be configured independently of transport via <> and <>; this can be useful for configuring a single instance to be reachable via -HTTP for testing purposes without triggering production mode. If you do -want to force enforcement of the bootstrap checks independent of the -binding of the transport protocal, you can set the system property -`es.enforce.bootstrap.checks` to `true` (this can be useful on a -single-node production system that does not bind transport to an external -interface). +HTTP for testing purposes without triggering production mode. + +We recognize that some users need to bind transport to an external +interface for testing their usage of the transport client. For this +situation, we provide the discovery type `single-node` (configure it by +setting `discovery.type` to `single-node`); in this situation, a node +will elect itself master and will not form a cluster with any other +node. + +If you are running a single node in production, it is possible to evade +the bootstrap checks (either by not binding transport to an external +interface, or by binding transport to an external interface and setting +the discovery type to `single-node`). For this situation, you can force +execution of the bootstrap checks by setting the system property +`es.enforce.bootstrap.checks` to `true` (set this in <>, or +by adding `-Des.enforce.bootstrap.checks=true` to the environment +variable `ES_JAVA_OPTS`). We strongly encourage you to do this if you +are in this specific situation. This system property can be used to +force execution of the bootstrap checks independent of the node +configuration. === Heap size check @@ -48,11 +63,11 @@ If a JVM is started with unequal initial and max heap size, it can be prone to pauses as the JVM heap is resized during system usage. To avoid these resize pauses, it's best to start the JVM with the initial heap size equal to the maximum heap size. Additionally, if -<> is enabled, the JVM will -lock the initial size of the heap on startup. If the initial heap size -is not equal to the maximum heap size, after a resize it will not be the -case that all of the JVM heap is locked in memory. To pass the heap size -check, you must configure the <>. +<> is enabled, the JVM +will lock the initial size of the heap on startup. If the initial heap +size is not equal to the maximum heap size, after a resize it will not +be the case that all of the JVM heap is locked in memory. To pass the +heap size check, you must configure the <>. === File descriptor check @@ -76,13 +91,13 @@ Elasticsearch would much rather use to service requests. There are several ways to configure a system to disallow swapping. One way is by requesting the JVM to lock the heap in memory through `mlockall` (Unix) or virtual lock (Windows). This is done via the Elasticsearch setting -<>. However, there are cases -where this setting can be passed to Elasticsearch but Elasticsearch is -not able to lock the heap (e.g., if the `elasticsearch` user does not -have `memlock unlimited`). The memory lock check verifies that *if* the -`bootstrap.memory_lock` setting is enabled, that the JVM was successfully -able to lock the heap. To pass the memory lock check, you might have to -configure <>. +<>. However, there are +cases where this setting can be passed to Elasticsearch but +Elasticsearch is not able to lock the heap (e.g., if the `elasticsearch` +user does not have `memlock unlimited`). The memory lock check verifies +that *if* the `bootstrap.memory_lock` setting is enabled, that the JVM +was successfully able to lock the heap. To pass the memory lock check, +you might have to configure <>. === Maximum number of threads check @@ -139,29 +154,30 @@ the server VM. === Use serial collector check -There are various garbage collectors for the OpenJDK-derived JVMs targeting -different workloads. The serial collector in particular is best suited for -single logical CPU machines or extremely small heaps, neither of which are -suitable for running Elasticsearch. Using the serial collector with -Elasticsearch can be devastating for performance. The serial collector check -ensures that Elasticsearch is not configured to run with the serial -collector. To pass the serial collector check, you must not start Elasticsearch -with the serial collector (whether it's from the defaults for the JVM that -you're using, or you've explicitly specified it with `-XX:+UseSerialGC`). Note -that the default JVM configuration that ship with Elasticsearch configures -Elasticsearch to use the CMS collector. +There are various garbage collectors for the OpenJDK-derived JVMs +targeting different workloads. The serial collector in particular is +best suited for single logical CPU machines or extremely small heaps, +neither of which are suitable for running Elasticsearch. Using the +serial collector with Elasticsearch can be devastating for performance. +The serial collector check ensures that Elasticsearch is not configured +to run with the serial collector. To pass the serial collector check, +you must not start Elasticsearch with the serial collector (whether it's +from the defaults for the JVM that you're using, or you've explicitly +specified it with `-XX:+UseSerialGC`). Note that the default JVM +configuration that ship with Elasticsearch configures Elasticsearch to +use the CMS collector. === System call filter check - -Elasticsearch installs system call filters of various flavors depending on the -operating system (e.g., seccomp on Linux). These system call filters are -installed to prevent the ability to execute system calls related to forking as -a defense mechanism against arbitrary code execution attacks on Elasticsearch -The system call filter check ensures that if system call filters are enabled, -then they were successfully installed. To pass the system call filter check you -must either fix any configuration errors on your system that prevented system -call filters from installing (check your logs), or *at your own risk* disable -system call filters by setting `bootstrap.system_call_filter` to `false`. +Elasticsearch installs system call filters of various flavors depending +on the operating system (e.g., seccomp on Linux). These system call +filters are installed to prevent the ability to execute system calls +related to forking as a defense mechanism against arbitrary code +execution attacks on Elasticsearch The system call filter check ensures +that if system call filters are enabled, then they were successfully +installed. To pass the system call filter check you must either fix any +configuration errors on your system that prevented system call filters +from installing (check your logs), or *at your own risk* disable system +call filters by setting `bootstrap.system_call_filter` to `false`. === OnError and OnOutOfMemoryError checks @@ -188,8 +204,8 @@ release build of the JVM. === G1GC check -Early versions of the HotSpot JVM that shipped with JDK 8 are known to have -issues that can lead to index corruption when the G1GC collector is enabled. -The versions impacted are those earlier than the version of HotSpot that -shipped with JDK 8u40. The G1GC check detects these early versions of the -HotSpot JVM. +Early versions of the HotSpot JVM that shipped with JDK 8 are known to +have issues that can lead to index corruption when the G1GC collector is +enabled. The versions impacted are those earlier than the version of +HotSpot that shipped with JDK 8u40. The G1GC check detects these early +versions of the HotSpot JVM.