Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup bootstrap package. #13053

Merged
merged 1 commit into from Aug 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 7 additions & 21 deletions core/src/main/java/org/elasticsearch/bootstrap/Bootstrap.java
Expand Up @@ -21,15 +21,12 @@

import org.apache.lucene.util.Constants;
import org.apache.lucene.util.StringHelper;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version;
import org.elasticsearch.common.PidFile;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.inject.CreationException;
import org.elasticsearch.common.inject.spi.Message;
import org.elasticsearch.common.lease.Releasables;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;
Expand All @@ -44,16 +41,14 @@
import org.elasticsearch.node.internal.InternalSettingsPreparer;

import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CountDownLatch;

import static com.google.common.collect.Sets.newHashSet;
import static org.elasticsearch.common.settings.Settings.Builder.EMPTY_SETTINGS;

/**
* A main entry point when starting from the command line.
* Internal startup code.
*/
public class Bootstrap {
final class Bootstrap {

private static volatile Bootstrap INSTANCE;

Expand Down Expand Up @@ -137,10 +132,6 @@ static void initializeProbes() {
OsProbe.getInstance();
}

public static boolean isMemoryLocked() {
return Natives.isMemoryLocked();
}

private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception {
initializeNatives(settings.getAsBoolean("bootstrap.mlockall", false),
settings.getAsBoolean("bootstrap.ctrlhandler", true));
Expand Down Expand Up @@ -221,17 +212,12 @@ private void stop() {
keepAliveLatch.countDown();
}
}

/** Calls doMain(), but with special formatting of errors */
public static void main(String[] args) throws StartupError {
try {
doMain(args);
} catch (Throwable t) {
throw new StartupError(t);
}
}

public static void doMain(String[] args) throws Throwable {
/**
* This method is invoked by {@link Elasticsearch#main(String[])}
* to startup elasticsearch.
*/
static void init(String[] args) throws Throwable {
BootstrapCLIParser bootstrapCLIParser = new BootstrapCLIParser();
CliTool.ExitStatus status = bootstrapCLIParser.execute(args);

Expand Down
Expand Up @@ -38,7 +38,7 @@
import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
import static org.elasticsearch.common.cli.CliToolConfig.Builder.optionBuilder;

public class BootstrapCLIParser extends CliTool {
final class BootstrapCLIParser extends CliTool {

private static final CliToolConfig CONFIG = CliToolConfig.config("elasticsearch", BootstrapCLIParser.class)
.cmds(Start.CMD, Version.CMD)
Expand Down
46 changes: 46 additions & 0 deletions core/src/main/java/org/elasticsearch/bootstrap/BootstrapInfo.java
@@ -0,0 +1,46 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.elasticsearch.bootstrap;

/**
* Exposes system startup information
*/
public final class BootstrapInfo {

/** no instantiation */
private BootstrapInfo() {}

/**
* Returns true if we successfully loaded native libraries.
* <p>
* If this returns false, then native operations such as locking
* memory did not work.
*/
public static boolean isNativesAvailable() {
return Natives.JNA_AVAILABLE;
}

/**
* Returns true if we were able to lock the process's address space.
*/
public static boolean isMemoryLocked() {
return Natives.isMemoryLocked();
}
}
18 changes: 15 additions & 3 deletions core/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java
Expand Up @@ -20,11 +20,23 @@
package org.elasticsearch.bootstrap;

/**
* A wrapper around {@link Bootstrap} just so the process will look nicely on things like jps.
* This class starts elasticsearch.
*/
public class Elasticsearch extends Bootstrap {
public final class Elasticsearch {

/** no instantiation */
private Elasticsearch() {}

/**
* Main entry point for starting elasticsearch
*/
public static void main(String[] args) throws StartupError {
Bootstrap.main(args);
try {
Bootstrap.init(args);
} catch (Throwable t) {
// format exceptions to the console in a special way
// to avoid 2MB stacktraces from guice, etc.
throw new StartupError(t);
}
}
}
Expand Up @@ -59,7 +59,7 @@ public static final class Rlimit extends Structure implements Structure.ByRefere
public long rlim_max = 0;

@Override
protected List getFieldOrder() {
protected List<String> getFieldOrder() {
return Arrays.asList(new String[] { "rlim_cur", "rlim_max" });
}
}
Expand Down
Expand Up @@ -35,7 +35,7 @@
/**
* Library for Windows/Kernel32
*/
class JNAKernel32Library {
final class JNAKernel32Library {

private static final ESLogger logger = Loggers.getLogger(JNAKernel32Library.class);

Expand Down Expand Up @@ -148,7 +148,7 @@ public static class MemoryBasicInformation extends Structure {
public NativeLong Type;

@Override
protected List getFieldOrder() {
protected List<String> getFieldOrder() {
return Arrays.asList(new String[]{"BaseAddress", "AllocationBase", "AllocationProtect", "RegionSize", "State", "Protect", "Type"});
}
}
Expand Down
Expand Up @@ -34,10 +34,13 @@
*/
class JNANatives {

/** no instantiation */
private JNANatives() {}

private static final ESLogger logger = Loggers.getLogger(JNANatives.class);

// Set to true, in case native mlockall call was successful
public static boolean LOCAL_MLOCKALL = false;
static boolean LOCAL_MLOCKALL = false;

static void tryMlockall() {
int errno = Integer.MIN_VALUE;
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/elasticsearch/bootstrap/JVMCheck.java
Expand Up @@ -29,6 +29,8 @@

/** Checks that the JVM is ok and won't cause index corruption */
final class JVMCheck {
/** no instantiation */
private JVMCheck() {}

/**
* URL with latest JVM recommendations
Expand Down
25 changes: 22 additions & 3 deletions core/src/main/java/org/elasticsearch/bootstrap/JarHell.java
Expand Up @@ -25,7 +25,6 @@
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.Loggers;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
Expand All @@ -34,14 +33,34 @@
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;

/** Simple check for duplicate class files across the classpath */
/**
* Simple check for duplicate class files across the classpath.
* <p>
* This class checks for incompatibilities in the following ways:
* <ul>
* <li>Checks that class files are not duplicated across jars.</li>
* <li>Checks any {@code X-Compile-Target-JDK} value in the jar
* manifest is compatible with current JRE</li>
* <li>Checks any {@code X-Compile-Elasticsearch-Version} value in
* the jar manifest is compatible with the current ES</li>
* </ul>
*/
public class JarHell {

/** no instantiation */
private JarHell() {}

/** Simple driver class, can be used eg. from builds. Returns non-zero on jar-hell */
@SuppressForbidden(reason = "command line tool")
public static void main(String args[]) throws Exception {
Expand Down
21 changes: 13 additions & 8 deletions core/src/main/java/org/elasticsearch/bootstrap/Natives.java
Expand Up @@ -26,59 +26,64 @@
* The Natives class is a wrapper class that checks if the classes necessary for calling native methods are available on
* startup. If they are not available, this class will avoid calling code that loads these classes.
*/
class Natives {
final class Natives {
/** no instantiation */
private Natives() {}

private static final ESLogger logger = Loggers.getLogger(Natives.class);

// marker to determine if the JNA class files are available to the JVM
private static boolean jnaAvailable = false;
static final boolean JNA_AVAILABLE;

static {
boolean v = false;
try {
// load one of the main JNA classes to see if the classes are available. this does not ensure that all native
// libraries are available, only the ones necessary by JNA to function
Class.forName("com.sun.jna.Native");
jnaAvailable = true;
v = true;
} catch (ClassNotFoundException e) {
logger.warn("JNA not found. native methods will be disabled.", e);
} catch (UnsatisfiedLinkError e) {
logger.warn("unable to load JNA native support library, native methods will be disabled.", e);
}
JNA_AVAILABLE = v;
}

static void tryMlockall() {
if (!jnaAvailable) {
if (!JNA_AVAILABLE) {
logger.warn("cannot mlockall because JNA is not available");
return;
}
JNANatives.tryMlockall();
}

static boolean definitelyRunningAsRoot() {
if (!jnaAvailable) {
if (!JNA_AVAILABLE) {
logger.warn("cannot check if running as root because JNA is not available");
return false;
}
return JNANatives.definitelyRunningAsRoot();
}

static void tryVirtualLock() {
if (!jnaAvailable) {
if (!JNA_AVAILABLE) {
logger.warn("cannot mlockall because JNA is not available");
return;
}
JNANatives.tryVirtualLock();
}

static void addConsoleCtrlHandler(ConsoleCtrlHandler handler) {
if (!jnaAvailable) {
if (!JNA_AVAILABLE) {
logger.warn("cannot register console handler because JNA is not available");
return;
}
JNANatives.addConsoleCtrlHandler(handler);
}

static boolean isMemoryLocked() {
if (!jnaAvailable) {
if (!JNA_AVAILABLE) {
return false;
}
return JNANatives.LOCAL_MLOCKALL;
Expand Down
52 changes: 48 additions & 4 deletions core/src/main/java/org/elasticsearch/bootstrap/Security.java
Expand Up @@ -38,15 +38,59 @@
import java.util.regex.Pattern;

/**
* Initializes securitymanager with necessary permissions.
* Initializes SecurityManager with necessary permissions.
* <p>
* We use a template file (the one we test with), and add additional
* permissions based on the environment (data paths, etc)
* <h1>Initialization</h1>
* The JVM is not initially started with security manager enabled,
* instead we turn it on early in the startup process. This is a tradeoff
* between security and ease of use:
* <ul>
* <li>Assigns file permissions to user-configurable paths that can
* be specified from the command-line or {@code elasticsearch.yml}.</li>
* <li>Allows for some contained usage of native code that would not
* otherwise be permitted.</li>
* </ul>
* <p>
* <h1>Permissions</h1>
* Permissions use a policy file packaged as a resource, this file is
* also used in tests. File permissions are generated dynamically and
* combined with this policy file.
* <p>
* For each configured path, we ensure it exists and is accessible before
* granting permissions, otherwise directory creation would require
* permissions to parent directories.
* <p>
* In some exceptional cases, permissions are assigned to specific jars only,
* when they are so dangerous that general code should not be granted the
* permission, but there are extenuating circumstances.
* <p>
* Groovy scripts are assigned no permissions. This does not provide adequate
* sandboxing, as these scripts still have access to ES classes, and could
* modify members, etc that would cause bad things to happen later on their
* behalf (no package protections are yet in place, this would need some
* cleanups to the scripting apis). But still it can provide some defense for users
* that enable dynamic scripting without being fully aware of the consequences.
* <p>
* <h1>Disabling Security</h1>
* SecurityManager can be disabled completely with this setting:
* <pre>
* es.security.manager.enabled = false
* </pre>
* <p>
* <h1>Debugging Security</h1>
* A good place to start when there is a problem is to turn on security debugging:
* <pre>
* JAVA_OPTS="-Djava.security.debug=access:failure" bin/elasticsearch
* </pre>
* See <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/troubleshooting-security.html">
* Troubleshooting Security</a> for information.
*/
final class Security {
/** no instantiation */
private Security() {}

/**
* Initializes securitymanager for the environment
* Initializes SecurityManager for the environment
* Can only happen once!
*/
static void configure(Environment environment) throws Exception {
Expand Down
Expand Up @@ -32,7 +32,7 @@
*/
//TODO: remove this when guice is removed, and exceptions are cleaned up
//this is horrible, but its what we must do
class StartupError extends RuntimeException {
final class StartupError extends RuntimeException {

/** maximum length of a stacktrace, before we truncate it */
static final int STACKTRACE_LIMIT = 30;
Expand Down