Browse Source

Consolidate early startup into phase1 (#87509)

This commit introduces a new method in startup of Elasticsearch that
consolidates all the steps up to and including initialization of
logging. Some ordering is changed as some steps were not actually
necessary to run before logging, for example loading secure settings
since they are not actually used by logging.
Ryan Ernst 3 years ago
parent
commit
65b1a799e4

+ 2 - 23
server/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java

@@ -280,31 +280,14 @@ final class Bootstrap {
     /**
      * This method is invoked by {@link Elasticsearch#main(String[])} to startup elasticsearch.
      */
-    static void init(
-        final boolean foreground,
-        final boolean quiet,
-        final Environment initialEnv,
-        SecureString keystorePassword,
-        Path pidFile
-    ) throws BootstrapException, NodeValidationException, UserException {
-        // force the class initializer for BootstrapInfo to run before
-        // the security manager is installed
-        BootstrapInfo.init();
+    static void init(final boolean foreground, final Environment initialEnv, SecureString keystorePassword, Path pidFile)
+        throws BootstrapException, NodeValidationException, UserException {
 
         INSTANCE = new Bootstrap();
 
         final SecureSettings keystore = BootstrapUtil.loadSecureSettings(initialEnv, keystorePassword);
         final Environment environment = createEnvironment(keystore, initialEnv.settings(), initialEnv.configFile());
 
-        BootstrapInfo.setConsole(getConsole(environment));
-
-        LogConfigurator.setNodeName(Node.NODE_NAME_SETTING.get(environment.settings()));
-        try {
-            LogConfigurator.configure(environment, quiet == false);
-        } catch (IOException e) {
-            throw new BootstrapException(e);
-        }
-
         try {
             // fail if somebody replaced the lucene jars
             checkLucene();
@@ -352,10 +335,6 @@ final class Bootstrap {
         }
     }
 
-    private static ConsoleLoader.Console getConsole(Environment environment) {
-        return ConsoleLoader.loadConsole(environment);
-    }
-
     private static void checkLucene() {
         if (Version.CURRENT.luceneVersion.equals(org.apache.lucene.util.Version.LATEST) == false) {
             throw new AssertionError(

+ 45 - 21
server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

@@ -17,6 +17,7 @@ import org.elasticsearch.common.io.stream.InputStreamStreamInput;
 import org.elasticsearch.common.logging.LogConfigurator;
 import org.elasticsearch.core.SuppressForbidden;
 import org.elasticsearch.env.Environment;
+import org.elasticsearch.node.Node;
 import org.elasticsearch.node.NodeValidationException;
 
 import java.io.IOException;
@@ -38,33 +39,14 @@ class Elasticsearch {
      * Main entry point for starting elasticsearch
      */
     public static void main(final String[] args) {
-        bootstrapSecurityProperties();
-        org.elasticsearch.bootstrap.Security.prepopulateSecurityCaller();
-
-        /*
-         * We want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
-         * presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy). This
-         * forces such policies to take effect immediately.
-         */
-        org.elasticsearch.bootstrap.Security.setSecurityManager(new SecurityManager() {
-
-            @Override
-            public void checkPermission(Permission perm) {
-                // grant all permissions so that we can later set the security manager to the one that we want
-            }
-
-        });
-        LogConfigurator.registerErrorListener();
 
         PrintStream out = getStdout();
         PrintStream err = getStderr();
         try {
-            final var in = new InputStreamStreamInput(System.in);
-            final ServerArgs serverArgs = new ServerArgs(in);
+            final ServerArgs serverArgs = initPhase1();
             initPidFile(serverArgs.pidFile());
             Bootstrap.init(
                 serverArgs.daemonize() == false,
-                serverArgs.quiet(),
                 new Environment(serverArgs.nodeSettings(), serverArgs.configDir()),
                 serverArgs.keystorePassword(),
                 serverArgs.pidFile()
@@ -127,6 +109,48 @@ class Elasticsearch {
         System.exit(exitCode);
     }
 
+    /**
+     * First phase of process initialization.
+     *
+     * <p> Phase 1 consists of some static initialization, reading args from the CLI process, and
+     * finally initializing logging. As little as possible should be done in this phase because
+     * initializing logging is the last step.
+     */
+    private static ServerArgs initPhase1() throws IOException, UserException {
+        initSecurityProperties();
+
+        /*
+         * We want the JVM to think there is a security manager installed so that if internal policy decisions that would be based on the
+         * presence of a security manager or lack thereof act as if there is a security manager present (e.g., DNS cache policy). This
+         * forces such policies to take effect immediately.
+         */
+        org.elasticsearch.bootstrap.Security.setSecurityManager(new SecurityManager() {
+            @Override
+            public void checkPermission(Permission perm) {
+                // grant all permissions so that we can later set the security manager to the one that we want
+            }
+        });
+        LogConfigurator.registerErrorListener();
+
+        BootstrapInfo.init();
+
+        // note that reading server args does *not* close System.in, as it will be read from later for shutdown notification
+        var in = new InputStreamStreamInput(System.in);
+        var args = new ServerArgs(in);
+
+        // mostly just paths are used in phase 1, so secure settings are not needed
+        Environment nodeEnv = new Environment(args.nodeSettings(), args.configDir());
+
+        BootstrapInfo.setConsole(ConsoleLoader.loadConsole(nodeEnv));
+
+        // DO NOT MOVE THIS
+        // Logging must remain the last step of phase 1. Anything init steps needing logging should be in phase 2.
+        LogConfigurator.setNodeName(Node.NODE_NAME_SETTING.get(args.nodeSettings()));
+        LogConfigurator.configure(nodeEnv, args.quiet() == false);
+
+        return args;
+    }
+
     /**
      * Prints a message directing the user to look at the logs. A message is only printed if
      * logging has been configured.
@@ -199,7 +223,7 @@ class Elasticsearch {
         Files.writeString(pidFile, Long.toString(ProcessHandle.current().pid()));
     }
 
-    private static void bootstrapSecurityProperties() {
+    private static void initSecurityProperties() {
         for (final String property : new String[] { "networkaddress.cache.ttl", "networkaddress.cache.negative.ttl" }) {
             final String overrideProperty = "es." + property;
             final String overrideValue = System.getProperty(overrideProperty);

+ 5 - 0
server/src/main/java/org/elasticsearch/bootstrap/Security.java

@@ -96,6 +96,11 @@ import static org.elasticsearch.bootstrap.FilePermissionUtils.addSingleFilePath;
  * Troubleshooting Security</a> for information.
  */
 final class Security {
+
+    static {
+        prepopulateSecurityCaller();
+    }
+
     /** no instantiation */
     private Security() {}