Remove settings and system properties entanglement
Today when parsing settings during bootstrap, we add a system property for every Elasticsearch setting. Additionally, settings can be set via system properties. This commit simplifies this situation. - settings are no longer propogated to system properties - system properties can not be used to set settings - the "es." prefix on settings is no longer required (nor permitted) - test logging has a dedicated system property (tests.logger.level) Relates #18198
This commit is contained in:
parent
5da9e5dcbc
commit
c257e2c51f
|
@ -201,7 +201,7 @@ gradle test -Dtests.timeoutSuite=5000! ...
|
||||||
Change the logging level of ES (not gradle)
|
Change the logging level of ES (not gradle)
|
||||||
|
|
||||||
--------------------------------
|
--------------------------------
|
||||||
gradle test -Des.logger.level=DEBUG
|
gradle test -Dtests.logger.level=DEBUG
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
Print all the logging output from the test runs to the commandline
|
Print all the logging output from the test runs to the commandline
|
||||||
|
|
|
@ -456,7 +456,7 @@ class BuildPlugin implements Plugin<Project> {
|
||||||
// default test sysprop values
|
// default test sysprop values
|
||||||
systemProperty 'tests.ifNoTests', 'fail'
|
systemProperty 'tests.ifNoTests', 'fail'
|
||||||
// TODO: remove setting logging level via system property
|
// TODO: remove setting logging level via system property
|
||||||
systemProperty 'es.logger.level', 'WARN'
|
systemProperty 'tests.logger.level', 'WARN'
|
||||||
for (Map.Entry<String, String> property : System.properties.entrySet()) {
|
for (Map.Entry<String, String> property : System.properties.entrySet()) {
|
||||||
if (property.getKey().startsWith('tests.') ||
|
if (property.getKey().startsWith('tests.') ||
|
||||||
property.getKey().startsWith('es.')) {
|
property.getKey().startsWith('es.')) {
|
||||||
|
|
|
@ -129,7 +129,7 @@ class NodeInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
env = [ 'JAVA_HOME' : project.javaHome ]
|
env = [ 'JAVA_HOME' : project.javaHome ]
|
||||||
args.addAll("-E", "es.node.portsfile=true")
|
args.addAll("-E", "node.portsfile=true")
|
||||||
String collectedSystemProperties = config.systemProperties.collect { key, value -> "-D${key}=${value}" }.join(" ")
|
String collectedSystemProperties = config.systemProperties.collect { key, value -> "-D${key}=${value}" }.join(" ")
|
||||||
String esJavaOpts = config.jvmArgs.isEmpty() ? collectedSystemProperties : collectedSystemProperties + " " + config.jvmArgs
|
String esJavaOpts = config.jvmArgs.isEmpty() ? collectedSystemProperties : collectedSystemProperties + " " + config.jvmArgs
|
||||||
env.put('ES_JAVA_OPTS', esJavaOpts)
|
env.put('ES_JAVA_OPTS', esJavaOpts)
|
||||||
|
@ -140,7 +140,7 @@ class NodeInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
env.put('ES_JVM_OPTIONS', new File(confDir, 'jvm.options'))
|
env.put('ES_JVM_OPTIONS', new File(confDir, 'jvm.options'))
|
||||||
args.addAll("-E", "es.path.conf=${confDir}")
|
args.addAll("-E", "path.conf=${confDir}")
|
||||||
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
|
||||||
args.add('"') // end the entire command, quoted
|
args.add('"') // end the entire command, quoted
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,15 +177,7 @@ final class Bootstrap {
|
||||||
// install SM after natives, shutdown hooks, etc.
|
// install SM after natives, shutdown hooks, etc.
|
||||||
Security.configure(environment, BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(settings));
|
Security.configure(environment, BootstrapSettings.SECURITY_FILTER_BAD_DEFAULTS_SETTING.get(settings));
|
||||||
|
|
||||||
// We do not need to reload system properties here as we have already applied them in building the settings and
|
node = new Node(settings) {
|
||||||
// reloading could cause multiple prompts to the user for values if a system property was specified with a prompt
|
|
||||||
// placeholder
|
|
||||||
Settings nodeSettings = Settings.builder()
|
|
||||||
.put(settings)
|
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
node = new Node(nodeSettings) {
|
|
||||||
@Override
|
@Override
|
||||||
protected void validateNodeBeforeAcceptingRequests(Settings settings, BoundTransportAddress boundTransportAddress) {
|
protected void validateNodeBeforeAcceptingRequests(Settings settings, BoundTransportAddress boundTransportAddress) {
|
||||||
BootstrapCheck.check(settings, boundTransportAddress);
|
BootstrapCheck.check(settings, boundTransportAddress);
|
||||||
|
@ -193,13 +185,13 @@ final class Bootstrap {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Environment initialSettings(boolean foreground, String pidFile) {
|
private static Environment initialSettings(boolean foreground, String pidFile, Map<String, String> esSettings) {
|
||||||
Terminal terminal = foreground ? Terminal.DEFAULT : null;
|
Terminal terminal = foreground ? Terminal.DEFAULT : null;
|
||||||
Settings.Builder builder = Settings.builder();
|
Settings.Builder builder = Settings.builder();
|
||||||
if (Strings.hasLength(pidFile)) {
|
if (Strings.hasLength(pidFile)) {
|
||||||
builder.put(Environment.PIDFILE_SETTING.getKey(), pidFile);
|
builder.put(Environment.PIDFILE_SETTING.getKey(), pidFile);
|
||||||
}
|
}
|
||||||
return InternalSettingsPreparer.prepareEnvironment(builder.build(), terminal);
|
return InternalSettingsPreparer.prepareEnvironment(builder.build(), terminal, esSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start() {
|
private void start() {
|
||||||
|
@ -233,11 +225,13 @@ final class Bootstrap {
|
||||||
// Set the system property before anything has a chance to trigger its use
|
// Set the system property before anything has a chance to trigger its use
|
||||||
initLoggerPrefix();
|
initLoggerPrefix();
|
||||||
|
|
||||||
elasticsearchSettings(esSettings);
|
// force the class initializer for BootstrapInfo to run before
|
||||||
|
// the security manager is installed
|
||||||
|
BootstrapInfo.init();
|
||||||
|
|
||||||
INSTANCE = new Bootstrap();
|
INSTANCE = new Bootstrap();
|
||||||
|
|
||||||
Environment environment = initialSettings(foreground, pidFile);
|
Environment environment = initialSettings(foreground, pidFile, esSettings);
|
||||||
Settings settings = environment.settings();
|
Settings settings = environment.settings();
|
||||||
LogConfigurator.configure(settings, true);
|
LogConfigurator.configure(settings, true);
|
||||||
checkForCustomConfFile();
|
checkForCustomConfFile();
|
||||||
|
@ -295,13 +289,6 @@ final class Bootstrap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressForbidden(reason = "Sets system properties passed as CLI parameters")
|
|
||||||
private static void elasticsearchSettings(Map<String, String> esSettings) {
|
|
||||||
for (Map.Entry<String, String> esSetting : esSettings.entrySet()) {
|
|
||||||
System.setProperty(esSetting.getKey(), esSetting.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressForbidden(reason = "System#out")
|
@SuppressForbidden(reason = "System#out")
|
||||||
private static void closeSystOut() {
|
private static void closeSystOut() {
|
||||||
System.out.close();
|
System.out.close();
|
||||||
|
|
|
@ -120,4 +120,8 @@ public final class BootstrapInfo {
|
||||||
}
|
}
|
||||||
return SYSTEM_PROPERTIES;
|
return SYSTEM_PROPERTIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,28 +21,25 @@ package org.elasticsearch.bootstrap;
|
||||||
|
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpec;
|
import joptsimple.OptionSpec;
|
||||||
import joptsimple.util.KeyValuePair;
|
|
||||||
import org.elasticsearch.Build;
|
import org.elasticsearch.Build;
|
||||||
import org.elasticsearch.cli.Command;
|
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
|
import org.elasticsearch.cli.SettingCommand;
|
||||||
import org.elasticsearch.cli.Terminal;
|
import org.elasticsearch.cli.Terminal;
|
||||||
import org.elasticsearch.cli.UserError;
|
import org.elasticsearch.cli.UserError;
|
||||||
import org.elasticsearch.monitor.jvm.JvmInfo;
|
import org.elasticsearch.monitor.jvm.JvmInfo;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class starts elasticsearch.
|
* This class starts elasticsearch.
|
||||||
*/
|
*/
|
||||||
class Elasticsearch extends Command {
|
class Elasticsearch extends SettingCommand {
|
||||||
|
|
||||||
private final OptionSpec<Void> versionOption;
|
private final OptionSpec<Void> versionOption;
|
||||||
private final OptionSpec<Void> daemonizeOption;
|
private final OptionSpec<Void> daemonizeOption;
|
||||||
private final OptionSpec<String> pidfileOption;
|
private final OptionSpec<String> pidfileOption;
|
||||||
private final OptionSpec<KeyValuePair> propertyOption;
|
|
||||||
|
|
||||||
// visible for testing
|
// visible for testing
|
||||||
Elasticsearch() {
|
Elasticsearch() {
|
||||||
|
@ -56,7 +53,6 @@ class Elasticsearch extends Command {
|
||||||
pidfileOption = parser.acceptsAll(Arrays.asList("p", "pidfile"),
|
pidfileOption = parser.acceptsAll(Arrays.asList("p", "pidfile"),
|
||||||
"Creates a pid file in the specified path on start")
|
"Creates a pid file in the specified path on start")
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
propertyOption = parser.accepts("E", "Configure an Elasticsearch setting").withRequiredArg().ofType(KeyValuePair.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -75,7 +71,7 @@ class Elasticsearch extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options) throws Exception {
|
protected void execute(Terminal terminal, OptionSet options, Map<String, String> settings) throws Exception {
|
||||||
if (options.nonOptionArguments().isEmpty() == false) {
|
if (options.nonOptionArguments().isEmpty() == false) {
|
||||||
throw new UserError(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments());
|
throw new UserError(ExitCodes.USAGE, "Positional arguments not allowed, found " + options.nonOptionArguments());
|
||||||
}
|
}
|
||||||
|
@ -84,26 +80,15 @@ class Elasticsearch extends Command {
|
||||||
throw new UserError(ExitCodes.USAGE, "Elasticsearch version option is mutually exclusive with any other option");
|
throw new UserError(ExitCodes.USAGE, "Elasticsearch version option is mutually exclusive with any other option");
|
||||||
}
|
}
|
||||||
terminal.println("Version: " + org.elasticsearch.Version.CURRENT
|
terminal.println("Version: " + org.elasticsearch.Version.CURRENT
|
||||||
+ ", Build: " + Build.CURRENT.shortHash() + "/" + Build.CURRENT.date()
|
+ ", Build: " + Build.CURRENT.shortHash() + "/" + Build.CURRENT.date()
|
||||||
+ ", JVM: " + JvmInfo.jvmInfo().version());
|
+ ", JVM: " + JvmInfo.jvmInfo().version());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean daemonize = options.has(daemonizeOption);
|
final boolean daemonize = options.has(daemonizeOption);
|
||||||
final String pidFile = pidfileOption.value(options);
|
final String pidFile = pidfileOption.value(options);
|
||||||
|
|
||||||
final Map<String, String> esSettings = new HashMap<>();
|
init(daemonize, pidFile, settings);
|
||||||
for (final KeyValuePair kvp : propertyOption.values(options)) {
|
|
||||||
if (!kvp.key.startsWith("es.")) {
|
|
||||||
throw new UserError(ExitCodes.USAGE, "Elasticsearch settings must be prefixed with [es.] but was [" + kvp.key + "]");
|
|
||||||
}
|
|
||||||
if (kvp.value.isEmpty()) {
|
|
||||||
throw new UserError(ExitCodes.USAGE, "Elasticsearch setting [" + kvp.key + "] must not be empty");
|
|
||||||
}
|
|
||||||
esSettings.put(kvp.key, kvp.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
init(daemonize, pidFile, esSettings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init(final boolean daemonize, final String pidFile, final Map<String, String> esSettings) {
|
void init(final boolean daemonize, final String pidFile, final Map<String, String> esSettings) {
|
||||||
|
|
|
@ -19,15 +19,15 @@
|
||||||
|
|
||||||
package org.elasticsearch.cli;
|
package org.elasticsearch.cli;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import joptsimple.OptionException;
|
import joptsimple.OptionException;
|
||||||
import joptsimple.OptionParser;
|
import joptsimple.OptionParser;
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpec;
|
import joptsimple.OptionSpec;
|
||||||
import org.elasticsearch.common.SuppressForbidden;
|
import org.elasticsearch.common.SuppressForbidden;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action to execute within a cli.
|
* An action to execute within a cli.
|
||||||
*/
|
*/
|
||||||
|
@ -112,4 +112,5 @@ public abstract class Command {
|
||||||
*
|
*
|
||||||
* Any runtime user errors (like an input file that does not exist), should throw a {@link UserError}. */
|
* Any runtime user errors (like an input file that does not exist), should throw a {@link UserError}. */
|
||||||
protected abstract void execute(Terminal terminal, OptionSet options) throws Exception;
|
protected abstract void execute(Terminal terminal, OptionSet options) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* 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.cli;
|
||||||
|
|
||||||
|
import joptsimple.OptionSet;
|
||||||
|
import joptsimple.OptionSpec;
|
||||||
|
import joptsimple.util.KeyValuePair;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public abstract class SettingCommand extends Command {
|
||||||
|
|
||||||
|
private final OptionSpec<KeyValuePair> settingOption;
|
||||||
|
|
||||||
|
public SettingCommand(String description) {
|
||||||
|
super(description);
|
||||||
|
this.settingOption = parser.accepts("E", "Configure a setting").withRequiredArg().ofType(KeyValuePair.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void execute(Terminal terminal, OptionSet options) throws Exception {
|
||||||
|
final Map<String, String> settings = new HashMap<>();
|
||||||
|
for (final KeyValuePair kvp : settingOption.values(options)) {
|
||||||
|
if (kvp.value.isEmpty()) {
|
||||||
|
throw new UserError(ExitCodes.USAGE, "Setting [" + kvp.key + "] must not be empty");
|
||||||
|
}
|
||||||
|
settings.put(kvp.key, kvp.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
putSystemPropertyIfSettingIsMissing(settings, "path.conf", "es.path.conf");
|
||||||
|
putSystemPropertyIfSettingIsMissing(settings, "path.data", "es.path.data");
|
||||||
|
putSystemPropertyIfSettingIsMissing(settings, "path.home", "es.path.home");
|
||||||
|
putSystemPropertyIfSettingIsMissing(settings, "path.logs", "es.path.logs");
|
||||||
|
|
||||||
|
execute(terminal, options, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static void putSystemPropertyIfSettingIsMissing(final Map<String, String> settings, final String setting, final String key) {
|
||||||
|
final String value = System.getProperty(key);
|
||||||
|
if (value != null) {
|
||||||
|
if (settings.containsKey(setting)) {
|
||||||
|
final String message =
|
||||||
|
String.format(
|
||||||
|
Locale.ROOT,
|
||||||
|
"duplicate setting [%s] found via command-line [%s] and system property [%s]",
|
||||||
|
setting,
|
||||||
|
settings.get(setting),
|
||||||
|
value);
|
||||||
|
throw new IllegalArgumentException(message);
|
||||||
|
} else {
|
||||||
|
settings.put(setting, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void execute(Terminal terminal, OptionSet options, Map<String, String> settings) throws Exception;
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,6 @@ package org.elasticsearch.common.logging;
|
||||||
|
|
||||||
import org.apache.log4j.PropertyConfigurator;
|
import org.apache.log4j.PropertyConfigurator;
|
||||||
import org.elasticsearch.ElasticsearchException;
|
import org.elasticsearch.ElasticsearchException;
|
||||||
import org.elasticsearch.bootstrap.BootstrapInfo;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsException;
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
@ -93,8 +92,7 @@ public class LogConfigurator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consolidates settings and converts them into actual log4j settings, then initializes loggers and appenders.
|
* Consolidates settings and converts them into actual log4j settings, then initializes loggers and appenders.
|
||||||
*
|
* @param settings custom settings that should be applied
|
||||||
* @param settings custom settings that should be applied
|
|
||||||
* @param resolveConfig controls whether the logging conf file should be read too or not.
|
* @param resolveConfig controls whether the logging conf file should be read too or not.
|
||||||
*/
|
*/
|
||||||
public static void configure(Settings settings, boolean resolveConfig) {
|
public static void configure(Settings settings, boolean resolveConfig) {
|
||||||
|
@ -109,7 +107,7 @@ public class LogConfigurator {
|
||||||
if (resolveConfig) {
|
if (resolveConfig) {
|
||||||
resolveConfig(environment, settingsBuilder);
|
resolveConfig(environment, settingsBuilder);
|
||||||
}
|
}
|
||||||
settingsBuilder.putProperties("es.", BootstrapInfo.getSystemProperties());
|
|
||||||
// add custom settings after config was added so that they are not overwritten by config
|
// add custom settings after config was added so that they are not overwritten by config
|
||||||
settingsBuilder.put(settings);
|
settingsBuilder.put(settings);
|
||||||
settingsBuilder.replacePropertyPlaceholders();
|
settingsBuilder.replacePropertyPlaceholders();
|
||||||
|
|
|
@ -375,7 +375,6 @@ public final class ClusterSettings extends AbstractScopedSettings {
|
||||||
BaseRestHandler.MULTI_ALLOW_EXPLICIT_INDEX,
|
BaseRestHandler.MULTI_ALLOW_EXPLICIT_INDEX,
|
||||||
ClusterName.CLUSTER_NAME_SETTING,
|
ClusterName.CLUSTER_NAME_SETTING,
|
||||||
Client.CLIENT_TYPE_SETTING_S,
|
Client.CLIENT_TYPE_SETTING_S,
|
||||||
InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING,
|
|
||||||
ClusterModule.SHARDS_ALLOCATOR_TYPE_SETTING,
|
ClusterModule.SHARDS_ALLOCATOR_TYPE_SETTING,
|
||||||
EsExecutors.PROCESSORS_SETTING,
|
EsExecutors.PROCESSORS_SETTING,
|
||||||
ThreadContext.DEFAULT_HEADERS_SETTING,
|
ThreadContext.DEFAULT_HEADERS_SETTING,
|
||||||
|
|
|
@ -58,9 +58,11 @@ import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.common.unit.ByteSizeValue.parseBytesSizeValue;
|
import static org.elasticsearch.common.unit.ByteSizeValue.parseBytesSizeValue;
|
||||||
import static org.elasticsearch.common.unit.SizeValue.parseSizeValue;
|
import static org.elasticsearch.common.unit.SizeValue.parseSizeValue;
|
||||||
|
@ -942,66 +944,27 @@ public final class Settings implements ToXContent {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Builder putProperties(Map<String, String> esSettings, Predicate<String> keyPredicate, Function<String, String> keyFunction) {
|
||||||
* Puts all the properties with keys starting with the provided <tt>prefix</tt>.
|
for (final Map.Entry<String, String> esSetting : esSettings.entrySet()) {
|
||||||
*
|
final String key = esSetting.getKey();
|
||||||
* @param prefix The prefix to filter property key by
|
if (keyPredicate.test(key)) {
|
||||||
* @param properties The properties to put
|
map.put(keyFunction.apply(key), esSetting.getValue());
|
||||||
* @return The builder
|
|
||||||
*/
|
|
||||||
public Builder putProperties(String prefix, Dictionary<Object, Object> properties) {
|
|
||||||
for (Object property : Collections.list(properties.keys())) {
|
|
||||||
String key = Objects.toString(property);
|
|
||||||
String value = Objects.toString(properties.get(property));
|
|
||||||
if (key.startsWith(prefix)) {
|
|
||||||
map.put(key.substring(prefix.length()), value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Puts all the properties with keys starting with the provided <tt>prefix</tt>.
|
* Runs across all the settings set on this builder and
|
||||||
*
|
* replaces <tt>${...}</tt> elements in each setting with
|
||||||
* @param prefix The prefix to filter property key by
|
* another setting already set on this builder.
|
||||||
* @param properties The properties to put
|
|
||||||
* @return The builder
|
|
||||||
*/
|
|
||||||
public Builder putProperties(String prefix, Dictionary<Object, Object> properties, String ignorePrefix) {
|
|
||||||
for (Object property : Collections.list(properties.keys())) {
|
|
||||||
String key = Objects.toString(property);
|
|
||||||
String value = Objects.toString(properties.get(property));
|
|
||||||
if (key.startsWith(prefix)) {
|
|
||||||
if (!key.startsWith(ignorePrefix)) {
|
|
||||||
map.put(key.substring(prefix.length()), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs across all the settings set on this builder and replaces <tt>${...}</tt> elements in the
|
|
||||||
* each setting value according to the following logic:
|
|
||||||
* <p>
|
|
||||||
* First, tries to resolve it against a System property ({@link System#getProperty(String)}), next,
|
|
||||||
* tries and resolve it against an environment variable ({@link System#getenv(String)}), and last, tries
|
|
||||||
* and replace it with another setting already set on this builder.
|
|
||||||
*/
|
*/
|
||||||
public Builder replacePropertyPlaceholders() {
|
public Builder replacePropertyPlaceholders() {
|
||||||
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
|
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
|
||||||
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() {
|
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() {
|
||||||
@Override
|
@Override
|
||||||
public String resolvePlaceholder(String placeholderName) {
|
public String resolvePlaceholder(String placeholderName) {
|
||||||
if (placeholderName.startsWith("env.")) {
|
final String value = System.getenv(placeholderName);
|
||||||
// explicit env var prefix
|
|
||||||
return System.getenv(placeholderName.substring("env.".length()));
|
|
||||||
}
|
|
||||||
String value = System.getProperty(placeholderName);
|
|
||||||
if (value != null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
value = System.getenv(placeholderName);
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -1010,8 +973,7 @@ public final class Settings implements ToXContent {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldIgnoreMissing(String placeholderName) {
|
public boolean shouldIgnoreMissing(String placeholderName) {
|
||||||
// if its an explicit env var, we are ok with not having a value for it and treat it as optional
|
if (placeholderName.startsWith("prompt.")) {
|
||||||
if (placeholderName.startsWith("env.") || placeholderName.startsWith("prompt.")) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -19,14 +19,11 @@
|
||||||
|
|
||||||
package org.elasticsearch.node.internal;
|
package org.elasticsearch.node.internal;
|
||||||
|
|
||||||
import org.elasticsearch.bootstrap.BootstrapInfo;
|
import org.elasticsearch.cli.Terminal;
|
||||||
import org.elasticsearch.cluster.ClusterName;
|
import org.elasticsearch.cluster.ClusterName;
|
||||||
import org.elasticsearch.common.Randomness;
|
import org.elasticsearch.common.Randomness;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.cli.Terminal;
|
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
|
||||||
import org.elasticsearch.common.settings.Setting.Property;
|
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.settings.SettingsException;
|
import org.elasticsearch.common.settings.SettingsException;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
@ -39,10 +36,13 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import static org.elasticsearch.common.Strings.cleanPath;
|
import static org.elasticsearch.common.Strings.cleanPath;
|
||||||
|
|
||||||
|
@ -52,20 +52,18 @@ import static org.elasticsearch.common.Strings.cleanPath;
|
||||||
public class InternalSettingsPreparer {
|
public class InternalSettingsPreparer {
|
||||||
|
|
||||||
private static final String[] ALLOWED_SUFFIXES = {".yml", ".yaml", ".json", ".properties"};
|
private static final String[] ALLOWED_SUFFIXES = {".yml", ".yaml", ".json", ".properties"};
|
||||||
static final String PROPERTY_PREFIX = "es.";
|
static final String PROPERTY_DEFAULTS_PREFIX = "default.";
|
||||||
static final String PROPERTY_DEFAULTS_PREFIX = "es.default.";
|
static final Predicate<String> PROPERTY_DEFAULTS_PREDICATE = key -> key.startsWith(PROPERTY_DEFAULTS_PREFIX);
|
||||||
|
|
||||||
public static final String SECRET_PROMPT_VALUE = "${prompt.secret}";
|
public static final String SECRET_PROMPT_VALUE = "${prompt.secret}";
|
||||||
public static final String TEXT_PROMPT_VALUE = "${prompt.text}";
|
public static final String TEXT_PROMPT_VALUE = "${prompt.text}";
|
||||||
public static final Setting<Boolean> IGNORE_SYSTEM_PROPERTIES_SETTING =
|
|
||||||
Setting.boolSetting("config.ignore_system_properties", false, Property.NodeScope);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the settings by gathering all elasticsearch system properties and setting defaults.
|
* Prepares the settings by gathering all elasticsearch system properties and setting defaults.
|
||||||
*/
|
*/
|
||||||
public static Settings prepareSettings(Settings input) {
|
public static Settings prepareSettings(Settings input) {
|
||||||
Settings.Builder output = Settings.builder();
|
Settings.Builder output = Settings.builder();
|
||||||
initializeSettings(output, input, true);
|
initializeSettings(output, input, true, Collections.emptyMap());
|
||||||
finalizeSettings(output, null, null);
|
finalizeSettings(output, null, null);
|
||||||
return output.build();
|
return output.build();
|
||||||
}
|
}
|
||||||
|
@ -80,9 +78,23 @@ public class InternalSettingsPreparer {
|
||||||
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
||||||
*/
|
*/
|
||||||
public static Environment prepareEnvironment(Settings input, Terminal terminal) {
|
public static Environment prepareEnvironment(Settings input, Terminal terminal) {
|
||||||
|
return prepareEnvironment(input, terminal, Collections.emptyMap());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares the settings by gathering all elasticsearch system properties, optionally loading the configuration settings,
|
||||||
|
* and then replacing all property placeholders. If a {@link Terminal} is provided and configuration settings are loaded,
|
||||||
|
* settings with a value of <code>${prompt.text}</code> or <code>${prompt.secret}</code> will result in a prompt for
|
||||||
|
* the setting to the user.
|
||||||
|
* @param input The custom settings to use. These are not overwritten by settings in the configuration file.
|
||||||
|
* @param terminal the Terminal to use for input/output
|
||||||
|
* @param properties Map of properties key/value pairs (usually from the command-line)
|
||||||
|
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
||||||
|
*/
|
||||||
|
public static Environment prepareEnvironment(Settings input, Terminal terminal, Map<String, String> properties) {
|
||||||
// just create enough settings to build the environment, to get the config dir
|
// just create enough settings to build the environment, to get the config dir
|
||||||
Settings.Builder output = Settings.builder();
|
Settings.Builder output = Settings.builder();
|
||||||
initializeSettings(output, input, true);
|
initializeSettings(output, input, true, properties);
|
||||||
Environment environment = new Environment(output.build());
|
Environment environment = new Environment(output.build());
|
||||||
|
|
||||||
boolean settingsFileFound = false;
|
boolean settingsFileFound = false;
|
||||||
|
@ -103,7 +115,7 @@ public class InternalSettingsPreparer {
|
||||||
|
|
||||||
// re-initialize settings now that the config file has been loaded
|
// re-initialize settings now that the config file has been loaded
|
||||||
// TODO: only re-initialize if a config file was actually loaded
|
// TODO: only re-initialize if a config file was actually loaded
|
||||||
initializeSettings(output, input, false);
|
initializeSettings(output, input, false, properties);
|
||||||
finalizeSettings(output, terminal, environment.configFile());
|
finalizeSettings(output, terminal, environment.configFile());
|
||||||
|
|
||||||
environment = new Environment(output.build());
|
environment = new Environment(output.build());
|
||||||
|
@ -113,22 +125,16 @@ public class InternalSettingsPreparer {
|
||||||
return new Environment(output.build());
|
return new Environment(output.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean useSystemProperties(Settings input) {
|
|
||||||
return !IGNORE_SYSTEM_PROPERTIES_SETTING.get(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the builder with the given input settings, and loads system properties settings if allowed.
|
* Initializes the builder with the given input settings, and loads system properties settings if allowed.
|
||||||
* If loadDefaults is true, system property default settings are loaded.
|
* If loadDefaults is true, system property default settings are loaded.
|
||||||
*/
|
*/
|
||||||
private static void initializeSettings(Settings.Builder output, Settings input, boolean loadDefaults) {
|
private static void initializeSettings(Settings.Builder output, Settings input, boolean loadDefaults, Map<String, String> esSettings) {
|
||||||
output.put(input);
|
output.put(input);
|
||||||
if (useSystemProperties(input)) {
|
if (loadDefaults) {
|
||||||
if (loadDefaults) {
|
output.putProperties(esSettings, PROPERTY_DEFAULTS_PREDICATE, key -> key.substring(PROPERTY_DEFAULTS_PREFIX.length()));
|
||||||
output.putProperties(PROPERTY_DEFAULTS_PREFIX, BootstrapInfo.getSystemProperties());
|
|
||||||
}
|
|
||||||
output.putProperties(PROPERTY_PREFIX, BootstrapInfo.getSystemProperties(), PROPERTY_DEFAULTS_PREFIX);
|
|
||||||
}
|
}
|
||||||
|
output.putProperties(esSettings, PROPERTY_DEFAULTS_PREDICATE.negate(), Function.identity());
|
||||||
output.replacePropertyPlaceholders();
|
output.replacePropertyPlaceholders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,11 +27,14 @@ import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.bootstrap.JarHell;
|
import org.elasticsearch.bootstrap.JarHell;
|
||||||
import org.elasticsearch.cli.Command;
|
import org.elasticsearch.cli.Command;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
|
import org.elasticsearch.cli.SettingCommand;
|
||||||
import org.elasticsearch.cli.Terminal;
|
import org.elasticsearch.cli.Terminal;
|
||||||
import org.elasticsearch.cli.UserError;
|
import org.elasticsearch.cli.UserError;
|
||||||
import org.elasticsearch.common.hash.MessageDigests;
|
import org.elasticsearch.common.hash.MessageDigests;
|
||||||
import org.elasticsearch.common.io.FileSystemUtils;
|
import org.elasticsearch.common.io.FileSystemUtils;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -56,6 +59,7 @@ import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
|
@ -95,7 +99,7 @@ import static org.elasticsearch.common.util.set.Sets.newHashSet;
|
||||||
* elasticsearch config directory, using the name of the plugin. If any files to be installed
|
* elasticsearch config directory, using the name of the plugin. If any files to be installed
|
||||||
* already exist, they will be skipped.
|
* already exist, they will be skipped.
|
||||||
*/
|
*/
|
||||||
class InstallPluginCommand extends Command {
|
class InstallPluginCommand extends SettingCommand {
|
||||||
|
|
||||||
private static final String PROPERTY_SUPPORT_STAGING_URLS = "es.plugins.staging";
|
private static final String PROPERTY_SUPPORT_STAGING_URLS = "es.plugins.staging";
|
||||||
|
|
||||||
|
@ -132,7 +136,6 @@ class InstallPluginCommand extends Command {
|
||||||
"store-smb",
|
"store-smb",
|
||||||
"x-pack")));
|
"x-pack")));
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
private final OptionSpec<Void> batchOption;
|
private final OptionSpec<Void> batchOption;
|
||||||
private final OptionSpec<String> arguments;
|
private final OptionSpec<String> arguments;
|
||||||
|
|
||||||
|
@ -160,9 +163,8 @@ class InstallPluginCommand extends Command {
|
||||||
FILE_PERMS = Collections.unmodifiableSet(filePerms);
|
FILE_PERMS = Collections.unmodifiableSet(filePerms);
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallPluginCommand(Environment env) {
|
InstallPluginCommand() {
|
||||||
super("Install a plugin");
|
super("Install a plugin");
|
||||||
this.env = env;
|
|
||||||
this.batchOption = parser.acceptsAll(Arrays.asList("b", "batch"),
|
this.batchOption = parser.acceptsAll(Arrays.asList("b", "batch"),
|
||||||
"Enable batch mode explicitly, automatic confirmation of security permission");
|
"Enable batch mode explicitly, automatic confirmation of security permission");
|
||||||
this.arguments = parser.nonOptions("plugin id");
|
this.arguments = parser.nonOptions("plugin id");
|
||||||
|
@ -178,7 +180,7 @@ class InstallPluginCommand extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options) throws Exception {
|
protected void execute(Terminal terminal, OptionSet options, Map<String, String> settings) throws Exception {
|
||||||
// TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args
|
// TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args
|
||||||
List<String> args = arguments.values(options);
|
List<String> args = arguments.values(options);
|
||||||
if (args.size() != 1) {
|
if (args.size() != 1) {
|
||||||
|
@ -186,12 +188,12 @@ class InstallPluginCommand extends Command {
|
||||||
}
|
}
|
||||||
String pluginId = args.get(0);
|
String pluginId = args.get(0);
|
||||||
boolean isBatch = options.has(batchOption) || System.console() == null;
|
boolean isBatch = options.has(batchOption) || System.console() == null;
|
||||||
execute(terminal, pluginId, isBatch);
|
execute(terminal, pluginId, isBatch, settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pkg private for testing
|
// pkg private for testing
|
||||||
void execute(Terminal terminal, String pluginId, boolean isBatch) throws Exception {
|
void execute(Terminal terminal, String pluginId, boolean isBatch, Map<String, String> settings) throws Exception {
|
||||||
|
final Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings);
|
||||||
// TODO: remove this leniency!! is it needed anymore?
|
// TODO: remove this leniency!! is it needed anymore?
|
||||||
if (Files.exists(env.pluginsFile()) == false) {
|
if (Files.exists(env.pluginsFile()) == false) {
|
||||||
terminal.println("Plugins directory [" + env.pluginsFile() + "] does not exist. Creating...");
|
terminal.println("Plugins directory [" + env.pluginsFile() + "] does not exist. Creating...");
|
||||||
|
@ -200,7 +202,7 @@ class InstallPluginCommand extends Command {
|
||||||
|
|
||||||
Path pluginZip = download(terminal, pluginId, env.tmpFile());
|
Path pluginZip = download(terminal, pluginId, env.tmpFile());
|
||||||
Path extractedZip = unzip(pluginZip, env.pluginsFile());
|
Path extractedZip = unzip(pluginZip, env.pluginsFile());
|
||||||
install(terminal, isBatch, extractedZip);
|
install(terminal, isBatch, extractedZip, env);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Downloads the plugin and returns the file it was downloaded to. */
|
/** Downloads the plugin and returns the file it was downloaded to. */
|
||||||
|
@ -349,7 +351,7 @@ class InstallPluginCommand extends Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load information about the plugin, and verify it can be installed with no errors. */
|
/** Load information about the plugin, and verify it can be installed with no errors. */
|
||||||
private PluginInfo verify(Terminal terminal, Path pluginRoot, boolean isBatch) throws Exception {
|
private PluginInfo verify(Terminal terminal, Path pluginRoot, boolean isBatch, Environment env) throws Exception {
|
||||||
// read and validate the plugin descriptor
|
// read and validate the plugin descriptor
|
||||||
PluginInfo info = PluginInfo.readFromProperties(pluginRoot);
|
PluginInfo info = PluginInfo.readFromProperties(pluginRoot);
|
||||||
terminal.println(VERBOSE, info.toString());
|
terminal.println(VERBOSE, info.toString());
|
||||||
|
@ -398,12 +400,12 @@ class InstallPluginCommand extends Command {
|
||||||
* Installs the plugin from {@code tmpRoot} into the plugins dir.
|
* Installs the plugin from {@code tmpRoot} into the plugins dir.
|
||||||
* If the plugin has a bin dir and/or a config dir, those are copied.
|
* If the plugin has a bin dir and/or a config dir, those are copied.
|
||||||
*/
|
*/
|
||||||
private void install(Terminal terminal, boolean isBatch, Path tmpRoot) throws Exception {
|
private void install(Terminal terminal, boolean isBatch, Path tmpRoot, Environment env) throws Exception {
|
||||||
List<Path> deleteOnFailure = new ArrayList<>();
|
List<Path> deleteOnFailure = new ArrayList<>();
|
||||||
deleteOnFailure.add(tmpRoot);
|
deleteOnFailure.add(tmpRoot);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PluginInfo info = verify(terminal, tmpRoot, isBatch);
|
PluginInfo info = verify(terminal, tmpRoot, isBatch, env);
|
||||||
|
|
||||||
final Path destination = env.pluginsFile().resolve(info.getName());
|
final Path destination = env.pluginsFile().resolve(info.getName());
|
||||||
if (Files.exists(destination)) {
|
if (Files.exists(destination)) {
|
||||||
|
|
|
@ -19,6 +19,13 @@
|
||||||
|
|
||||||
package org.elasticsearch.plugins;
|
package org.elasticsearch.plugins;
|
||||||
|
|
||||||
|
import joptsimple.OptionSet;
|
||||||
|
import org.elasticsearch.cli.SettingCommand;
|
||||||
|
import org.elasticsearch.cli.Terminal;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.DirectoryStream;
|
import java.nio.file.DirectoryStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -26,26 +33,20 @@ import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import joptsimple.OptionSet;
|
|
||||||
import org.elasticsearch.cli.Command;
|
|
||||||
import org.elasticsearch.cli.Terminal;
|
|
||||||
import org.elasticsearch.env.Environment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command for the plugin cli to list plugins installed in elasticsearch.
|
* A command for the plugin cli to list plugins installed in elasticsearch.
|
||||||
*/
|
*/
|
||||||
class ListPluginsCommand extends Command {
|
class ListPluginsCommand extends SettingCommand {
|
||||||
|
|
||||||
private final Environment env;
|
ListPluginsCommand() {
|
||||||
|
|
||||||
ListPluginsCommand(Environment env) {
|
|
||||||
super("Lists installed elasticsearch plugins");
|
super("Lists installed elasticsearch plugins");
|
||||||
this.env = env;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options) throws Exception {
|
protected void execute(Terminal terminal, OptionSet options, Map<String, String> settings) throws Exception {
|
||||||
|
final Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings);
|
||||||
if (Files.exists(env.pluginsFile()) == false) {
|
if (Files.exists(env.pluginsFile()) == false) {
|
||||||
throw new IOException("Plugins directory missing: " + env.pluginsFile());
|
throw new IOException("Plugins directory missing: " + env.pluginsFile());
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,21 +26,24 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cli tool for adding, removing and listing plugins for elasticsearch.
|
* A cli tool for adding, removing and listing plugins for elasticsearch.
|
||||||
*/
|
*/
|
||||||
public class PluginCli extends MultiCommand {
|
public class PluginCli extends MultiCommand {
|
||||||
|
|
||||||
public PluginCli(Environment env) {
|
public PluginCli() {
|
||||||
super("A tool for managing installed elasticsearch plugins");
|
super("A tool for managing installed elasticsearch plugins");
|
||||||
subcommands.put("list", new ListPluginsCommand(env));
|
subcommands.put("list", new ListPluginsCommand());
|
||||||
subcommands.put("install", new InstallPluginCommand(env));
|
subcommands.put("install", new InstallPluginCommand());
|
||||||
subcommands.put("remove", new RemovePluginCommand(env));
|
subcommands.put("remove", new RemovePluginCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// initialize default for es.logger.level because we will not read the logging.yml
|
// initialize default for es.logger.level because we will not read the logging.yml
|
||||||
String loggerLevel = System.getProperty("es.logger.level", "INFO");
|
String loggerLevel = System.getProperty("es.logger.level", "INFO");
|
||||||
|
String pathHome = System.getProperty("es.path.home");
|
||||||
// Set the appender for all potential log files to terminal so that other components that use the logger print out the
|
// Set the appender for all potential log files to terminal so that other components that use the logger print out the
|
||||||
// same terminal.
|
// same terminal.
|
||||||
// The reason for this is that the plugin cli cannot be configured with a file appender because when the plugin command is
|
// The reason for this is that the plugin cli cannot be configured with a file appender because when the plugin command is
|
||||||
|
@ -48,12 +51,14 @@ public class PluginCli extends MultiCommand {
|
||||||
// is run as service then the logs should be at /var/log/elasticsearch but when started from the tar they should be at es.home/logs.
|
// is run as service then the logs should be at /var/log/elasticsearch but when started from the tar they should be at es.home/logs.
|
||||||
// Therefore we print to Terminal.
|
// Therefore we print to Terminal.
|
||||||
Environment loggingEnvironment = InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
Environment loggingEnvironment = InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
||||||
|
.put("path.home", pathHome)
|
||||||
.put("appender.terminal.type", "terminal")
|
.put("appender.terminal.type", "terminal")
|
||||||
.put("rootLogger", "${es.logger.level}, terminal")
|
.put("rootLogger", "${logger.level}, terminal")
|
||||||
.put("es.logger.level", loggerLevel)
|
.put("logger.level", loggerLevel)
|
||||||
.build(), Terminal.DEFAULT);
|
.build(), Terminal.DEFAULT);
|
||||||
LogConfigurator.configure(loggingEnvironment.settings(), false);
|
LogConfigurator.configure(loggingEnvironment.settings(), false);
|
||||||
Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, Terminal.DEFAULT);
|
|
||||||
exit(new PluginCli(env).main(args, Terminal.DEFAULT));
|
exit(new PluginCli().main(args, Terminal.DEFAULT));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,45 +24,49 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpec;
|
import joptsimple.OptionSpec;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
import org.elasticsearch.cli.Command;
|
import org.elasticsearch.cli.Command;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
|
import org.elasticsearch.cli.SettingCommand;
|
||||||
import org.elasticsearch.cli.UserError;
|
import org.elasticsearch.cli.UserError;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.cli.Terminal;
|
import org.elasticsearch.cli.Terminal;
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
|
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||||
|
|
||||||
import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE;
|
import static org.elasticsearch.cli.Terminal.Verbosity.VERBOSE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A command for the plugin cli to remove a plugin from elasticsearch.
|
* A command for the plugin cli to remove a plugin from elasticsearch.
|
||||||
*/
|
*/
|
||||||
class RemovePluginCommand extends Command {
|
class RemovePluginCommand extends SettingCommand {
|
||||||
|
|
||||||
private final Environment env;
|
|
||||||
private final OptionSpec<String> arguments;
|
private final OptionSpec<String> arguments;
|
||||||
|
|
||||||
RemovePluginCommand(Environment env) {
|
RemovePluginCommand() {
|
||||||
super("Removes a plugin from elasticsearch");
|
super("Removes a plugin from elasticsearch");
|
||||||
this.env = env;
|
|
||||||
this.arguments = parser.nonOptions("plugin name");
|
this.arguments = parser.nonOptions("plugin name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void execute(Terminal terminal, OptionSet options) throws Exception {
|
protected void execute(Terminal terminal, OptionSet options, Map<String, String> settings) throws Exception {
|
||||||
// TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args
|
// TODO: in jopt-simple 5.0 we can enforce a min/max number of positional args
|
||||||
List<String> args = arguments.values(options);
|
List<String> args = arguments.values(options);
|
||||||
if (args.size() != 1) {
|
if (args.size() != 1) {
|
||||||
throw new UserError(ExitCodes.USAGE, "Must supply a single plugin id argument");
|
throw new UserError(ExitCodes.USAGE, "Must supply a single plugin id argument");
|
||||||
}
|
}
|
||||||
execute(terminal, args.get(0));
|
execute(terminal, args.get(0), settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
// pkg private for testing
|
// pkg private for testing
|
||||||
void execute(Terminal terminal, String pluginName) throws Exception {
|
void execute(Terminal terminal, String pluginName, Map<String, String> settings) throws Exception {
|
||||||
|
final Environment env = InternalSettingsPreparer.prepareEnvironment(Settings.EMPTY, terminal, settings);
|
||||||
|
|
||||||
terminal.println("-> Removing " + Strings.coalesceToEmpty(pluginName) + "...");
|
terminal.println("-> Removing " + Strings.coalesceToEmpty(pluginName) + "...");
|
||||||
|
|
||||||
Path pluginDir = env.pluginsFile().resolve(pluginName);
|
Path pluginDir = env.pluginsFile().resolve(pluginName);
|
||||||
|
|
|
@ -71,7 +71,7 @@ grant {
|
||||||
|
|
||||||
// set by ESTestCase to improve test reproducibility
|
// set by ESTestCase to improve test reproducibility
|
||||||
// TODO: set this with gradle or some other way that repros with seed?
|
// TODO: set this with gradle or some other way that repros with seed?
|
||||||
permission java.util.PropertyPermission "es.processors.override", "write";
|
permission java.util.PropertyPermission "processors.override", "write";
|
||||||
|
|
||||||
// TODO: these simply trigger a noisy warning if its unable to clear the properties
|
// TODO: these simply trigger a noisy warning if its unable to clear the properties
|
||||||
// fix that in randomizedtesting
|
// fix that in randomizedtesting
|
||||||
|
|
|
@ -22,25 +22,15 @@ package org.elasticsearch.bootstrap;
|
||||||
import org.elasticsearch.Build;
|
import org.elasticsearch.Build;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
import org.elasticsearch.cli.MockTerminal;
|
|
||||||
import org.elasticsearch.common.SuppressForbidden;
|
|
||||||
import org.elasticsearch.monitor.jvm.JvmInfo;
|
import org.elasticsearch.monitor.jvm.JvmInfo;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Before;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.Matchers.hasEntry;
|
import static org.hamcrest.Matchers.hasEntry;
|
||||||
|
|
||||||
public class ElasticsearchCliTests extends ESTestCase {
|
public class ElasticsearchCliTests extends ESElasticsearchCliTestCase {
|
||||||
|
|
||||||
public void testVersion() throws Exception {
|
public void testVersion() throws Exception {
|
||||||
runTestThatVersionIsMutuallyExclusiveToOtherOptions("-V", "-d");
|
runTestThatVersionIsMutuallyExclusiveToOtherOptions("-V", "-d");
|
||||||
|
@ -96,7 +86,7 @@ public class ElasticsearchCliTests extends ESTestCase {
|
||||||
false,
|
false,
|
||||||
output -> assertThat(output, containsString("Positional arguments not allowed, found [foo]")),
|
output -> assertThat(output, containsString("Positional arguments not allowed, found [foo]")),
|
||||||
(foreground, pidFile, esSettings) -> {},
|
(foreground, pidFile, esSettings) -> {},
|
||||||
"-E", "something", "foo", "-E", "somethingelse"
|
"-E", "foo=bar", "foo", "-E", "baz=qux"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,26 +128,10 @@ public class ElasticsearchCliTests extends ESTestCase {
|
||||||
output -> {},
|
output -> {},
|
||||||
(foreground, pidFile, esSettings) -> {
|
(foreground, pidFile, esSettings) -> {
|
||||||
assertThat(esSettings.size(), equalTo(2));
|
assertThat(esSettings.size(), equalTo(2));
|
||||||
assertThat(esSettings, hasEntry("es.foo", "bar"));
|
assertThat(esSettings, hasEntry("foo", "bar"));
|
||||||
assertThat(esSettings, hasEntry("es.baz", "qux"));
|
assertThat(esSettings, hasEntry("baz", "qux"));
|
||||||
},
|
},
|
||||||
"-Ees.foo=bar", "-E", "es.baz=qux"
|
"-Efoo=bar", "-E", "baz=qux"
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testElasticsearchSettingPrefix() throws Exception {
|
|
||||||
runElasticsearchSettingPrefixTest("-E", "foo");
|
|
||||||
runElasticsearchSettingPrefixTest("-E", "foo=bar");
|
|
||||||
runElasticsearchSettingPrefixTest("-E", "=bar");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runElasticsearchSettingPrefixTest(String... args) throws Exception {
|
|
||||||
runTest(
|
|
||||||
ExitCodes.USAGE,
|
|
||||||
false,
|
|
||||||
output -> assertThat(output, containsString("Elasticsearch settings must be prefixed with [es.] but was [")),
|
|
||||||
(foreground, pidFile, esSettings) -> {},
|
|
||||||
args
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +139,9 @@ public class ElasticsearchCliTests extends ESTestCase {
|
||||||
runTest(
|
runTest(
|
||||||
ExitCodes.USAGE,
|
ExitCodes.USAGE,
|
||||||
false,
|
false,
|
||||||
output -> assertThat(output, containsString("Elasticsearch setting [es.foo] must not be empty")),
|
output -> assertThat(output, containsString("Setting [foo] must not be empty")),
|
||||||
(foreground, pidFile, esSettings) -> {},
|
(foreground, pidFile, esSettings) -> {},
|
||||||
"-E", "es.foo="
|
"-E", "foo="
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,36 +154,4 @@ public class ElasticsearchCliTests extends ESTestCase {
|
||||||
"--network.host");
|
"--network.host");
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface InitConsumer {
|
|
||||||
void accept(final boolean foreground, final String pidFile, final Map<String, String> esSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runTest(
|
|
||||||
final int expectedStatus,
|
|
||||||
final boolean expectedInit,
|
|
||||||
final Consumer<String> outputConsumer,
|
|
||||||
final InitConsumer initConsumer,
|
|
||||||
String... args) throws Exception {
|
|
||||||
final MockTerminal terminal = new MockTerminal();
|
|
||||||
try {
|
|
||||||
final AtomicBoolean init = new AtomicBoolean();
|
|
||||||
final int status = Elasticsearch.main(args, new Elasticsearch() {
|
|
||||||
@Override
|
|
||||||
void init(final boolean daemonize, final String pidFile, final Map<String, String> esSettings) {
|
|
||||||
init.set(true);
|
|
||||||
initConsumer.accept(!daemonize, pidFile, esSettings);
|
|
||||||
}
|
|
||||||
}, terminal);
|
|
||||||
assertThat(status, equalTo(expectedStatus));
|
|
||||||
assertThat(init.get(), equalTo(expectedInit));
|
|
||||||
outputConsumer.accept(terminal.getOutput());
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// if an unexpected exception is thrown, we log
|
|
||||||
// terminal output to aid debugging
|
|
||||||
logger.info(terminal.getOutput());
|
|
||||||
// rethrow so the test fails
|
|
||||||
throw t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ public class TransportClientIT extends ESIntegTestCase {
|
||||||
.put("http.enabled", false)
|
.put("http.enabled", false)
|
||||||
.put(Node.NODE_DATA_SETTING.getKey(), false)
|
.put(Node.NODE_DATA_SETTING.getKey(), false)
|
||||||
.put("cluster.name", "foobar")
|
.put("cluster.name", "foobar")
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true) // make sure we get what we set :)
|
|
||||||
.build());
|
.build());
|
||||||
node.start();
|
node.start();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -55,7 +55,6 @@ public class TransportClientRetryIT extends ESIntegTestCase {
|
||||||
.put("node.name", "transport_client_retry_test")
|
.put("node.name", "transport_client_retry_test")
|
||||||
.put(Node.NODE_MODE_SETTING.getKey(), internalCluster().getNodeMode())
|
.put(Node.NODE_MODE_SETTING.getKey(), internalCluster().getNodeMode())
|
||||||
.put(ClusterName.CLUSTER_NAME_SETTING.getKey(), internalCluster().getClusterName())
|
.put(ClusterName.CLUSTER_NAME_SETTING.getKey(), internalCluster().getClusterName())
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true)
|
|
||||||
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir());
|
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir());
|
||||||
|
|
||||||
try (TransportClient client = TransportClient.builder().settings(builder.build()).build()) {
|
try (TransportClient client = TransportClient.builder().settings(builder.build()).build()) {
|
||||||
|
|
|
@ -302,11 +302,8 @@ public class ScopedSettingsTests extends ESTestCase {
|
||||||
public void testLoggingUpdates() {
|
public void testLoggingUpdates() {
|
||||||
final String level = ESLoggerFactory.getRootLogger().getLevel();
|
final String level = ESLoggerFactory.getRootLogger().getLevel();
|
||||||
final String testLevel = ESLoggerFactory.getLogger("test").getLevel();
|
final String testLevel = ESLoggerFactory.getLogger("test").getLevel();
|
||||||
String property = System.getProperty("es.logger.level");
|
String property = randomFrom(ESLoggerFactory.LogLevel.values()).toString();
|
||||||
Settings.Builder builder = Settings.builder();
|
Settings.Builder builder = Settings.builder().put("logger.level", property);
|
||||||
if (property != null) {
|
|
||||||
builder.put("logger.level", property);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
ClusterSettings settings = new ClusterSettings(builder.build(), ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
ClusterSettings settings = new ClusterSettings(builder.build(), ClusterSettings.BUILT_IN_CLUSTER_SETTINGS);
|
||||||
try {
|
try {
|
||||||
|
@ -319,7 +316,7 @@ public class ScopedSettingsTests extends ESTestCase {
|
||||||
settings.applySettings(Settings.builder().put("logger._root", "TRACE").build());
|
settings.applySettings(Settings.builder().put("logger._root", "TRACE").build());
|
||||||
assertEquals("TRACE", ESLoggerFactory.getRootLogger().getLevel());
|
assertEquals("TRACE", ESLoggerFactory.getRootLogger().getLevel());
|
||||||
settings.applySettings(Settings.builder().build());
|
settings.applySettings(Settings.builder().build());
|
||||||
assertEquals(level, ESLoggerFactory.getRootLogger().getLevel());
|
assertEquals(property, ESLoggerFactory.getRootLogger().getLevel());
|
||||||
settings.applySettings(Settings.builder().put("logger.test", "TRACE").build());
|
settings.applySettings(Settings.builder().put("logger.test", "TRACE").build());
|
||||||
assertEquals("TRACE", ESLoggerFactory.getLogger("test").getLevel());
|
assertEquals("TRACE", ESLoggerFactory.getLogger("test").getLevel());
|
||||||
settings.applySettings(Settings.builder().build());
|
settings.applySettings(Settings.builder().build());
|
||||||
|
|
|
@ -31,7 +31,9 @@ import java.util.Set;
|
||||||
import static org.hamcrest.Matchers.allOf;
|
import static org.hamcrest.Matchers.allOf;
|
||||||
import static org.hamcrest.Matchers.arrayContaining;
|
import static org.hamcrest.Matchers.arrayContaining;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasToString;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
@ -42,31 +44,32 @@ public class SettingsTests extends ESTestCase {
|
||||||
String value = System.getProperty("java.home");
|
String value = System.getProperty("java.home");
|
||||||
assertFalse(value.isEmpty());
|
assertFalse(value.isEmpty());
|
||||||
Settings settings = Settings.builder()
|
Settings settings = Settings.builder()
|
||||||
.put("setting1", "${java.home}")
|
.put("property.placeholder", value)
|
||||||
|
.put("setting1", "${property.placeholder}")
|
||||||
.replacePropertyPlaceholders()
|
.replacePropertyPlaceholders()
|
||||||
.build();
|
.build();
|
||||||
assertThat(settings.get("setting1"), equalTo(value));
|
assertThat(settings.get("setting1"), equalTo(value));
|
||||||
|
|
||||||
assertNull(System.getProperty("_test_property_should_not_exist"));
|
|
||||||
settings = Settings.builder()
|
|
||||||
.put("setting1", "${_test_property_should_not_exist:defaultVal1}")
|
|
||||||
.replacePropertyPlaceholders()
|
|
||||||
.build();
|
|
||||||
assertThat(settings.get("setting1"), equalTo("defaultVal1"));
|
|
||||||
|
|
||||||
settings = Settings.builder()
|
|
||||||
.put("setting1", "${_test_property_should_not_exist:}")
|
|
||||||
.replacePropertyPlaceholders()
|
|
||||||
.build();
|
|
||||||
assertThat(settings.get("setting1"), is(nullValue()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReplacePropertiesPlaceholderIgnoreEnvUnset() {
|
public void testReplacePropertiesPlaceholderSystemVariablesHaveNoEffect() {
|
||||||
Settings settings = Settings.builder()
|
final String value = System.getProperty("java.home");
|
||||||
.put("setting1", "${env.UNSET_ENV_VAR}")
|
assertNotNull(value);
|
||||||
|
final IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> Settings.builder()
|
||||||
|
.put("setting1", "${java.home}")
|
||||||
.replacePropertyPlaceholders()
|
.replacePropertyPlaceholders()
|
||||||
.build();
|
.build());
|
||||||
assertThat(settings.get("setting1"), is(nullValue()));
|
assertThat(e, hasToString(containsString("Could not resolve placeholder 'java.home'")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReplacePropertiesPlaceholderByEnvironmentVariables() {
|
||||||
|
final Map.Entry<String, String> entry = randomSubsetOf(1, System.getenv().entrySet()).get(0);
|
||||||
|
assertNotNull(entry.getValue());
|
||||||
|
|
||||||
|
final Settings implicitEnvSettings = Settings.builder()
|
||||||
|
.put("setting1", "${" + entry.getKey() + "}")
|
||||||
|
.replacePropertyPlaceholders()
|
||||||
|
.build();
|
||||||
|
assertThat(implicitEnvSettings.get("setting1"), equalTo(entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testReplacePropertiesPlaceholderIgnoresPrompt() {
|
public void testReplacePropertiesPlaceholderIgnoresPrompt() {
|
||||||
|
|
|
@ -19,11 +19,6 @@
|
||||||
|
|
||||||
package org.elasticsearch.node.internal;
|
package org.elasticsearch.node.internal;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
|
|
||||||
import org.elasticsearch.cli.MockTerminal;
|
import org.elasticsearch.cli.MockTerminal;
|
||||||
import org.elasticsearch.cluster.ClusterName;
|
import org.elasticsearch.cluster.ClusterName;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
@ -33,6 +28,11 @@ import org.elasticsearch.test.ESTestCase;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
|
||||||
|
@ -134,7 +134,6 @@ public class InternalSettingsPreparerTests extends ESTestCase {
|
||||||
Files.createDirectory(config);
|
Files.createDirectory(config);
|
||||||
Files.copy(garbage, config.resolve("elasticsearch.yml"));
|
Files.copy(garbage, config.resolve("elasticsearch.yml"));
|
||||||
InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
||||||
.put("config.ignore_system_properties", true)
|
|
||||||
.put(baseEnvSettings)
|
.put(baseEnvSettings)
|
||||||
.build(), null);
|
.build(), null);
|
||||||
} catch (SettingsException e) {
|
} catch (SettingsException e) {
|
||||||
|
@ -153,7 +152,6 @@ public class InternalSettingsPreparerTests extends ESTestCase {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
InternalSettingsPreparer.prepareEnvironment(Settings.builder()
|
||||||
.put("config.ignore_system_properties", true)
|
|
||||||
.put(baseEnvSettings)
|
.put(baseEnvSettings)
|
||||||
.build(), null);
|
.build(), null);
|
||||||
} catch (SettingsException e) {
|
} catch (SettingsException e) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# you can override this using by setting a system property, for example -Ees.logger.level=DEBUG
|
# you can override using a command-line parameter
|
||||||
es.logger.level: INFO
|
# -E logger.level=(ERROR|WARN|INFO|DEBUG|TRACE)
|
||||||
rootLogger: ${es.logger.level}, console
|
logger.level: INFO
|
||||||
|
rootLogger: ${logger.level}, console
|
||||||
logger:
|
logger:
|
||||||
test: TRACE, console
|
test: TRACE, console
|
||||||
|
|
||||||
|
|
|
@ -203,7 +203,7 @@ def smoke_test_release(release, files, expected_hash, plugins):
|
||||||
headers = {}
|
headers = {}
|
||||||
print(' Starting elasticsearch deamon from [%s]' % es_dir)
|
print(' Starting elasticsearch deamon from [%s]' % es_dir)
|
||||||
try:
|
try:
|
||||||
run('%s; %s -Ees.node.name=smoke_tester -Ees.cluster.name=prepare_release -Ees.script.inline=true -Ees.script.stored=true -Ees.repositories.url.allowed_urls=http://snapshot.test* %s -Ees.pidfile=%s -Ees.node.portsfile=true'
|
run('%s; %s -Enode.name=smoke_tester -Ecluster.name=prepare_release -Escript.inline=true -Escript.stored=true -Erepositories.url.allowed_urls=http://snapshot.test* %s -Epidfile=%s -Enode.portsfile=true'
|
||||||
% (java_exe(), es_run_path, '-d', os.path.join(es_dir, 'es-smoke.pid')))
|
% (java_exe(), es_run_path, '-d', os.path.join(es_dir, 'es-smoke.pid')))
|
||||||
if not wait_for_node_startup(es_dir, header=headers):
|
if not wait_for_node_startup(es_dir, header=headers):
|
||||||
print("elasticsearch logs:")
|
print("elasticsearch logs:")
|
||||||
|
|
|
@ -79,7 +79,7 @@ fi
|
||||||
# Define other required variables
|
# Define other required variables
|
||||||
PID_FILE="$PID_DIR/$NAME.pid"
|
PID_FILE="$PID_DIR/$NAME.pid"
|
||||||
DAEMON=$ES_HOME/bin/elasticsearch
|
DAEMON=$ES_HOME/bin/elasticsearch
|
||||||
DAEMON_OPTS="-d -p $PID_FILE -Ees.default.path.logs=$LOG_DIR -Ees.default.path.data=$DATA_DIR -Ees.default.path.conf=$CONF_DIR"
|
DAEMON_OPTS="-d -p $PID_FILE -Edefault.path.logs=$LOG_DIR -Edefault.path.data=$DATA_DIR -Edefault.path.conf=$CONF_DIR"
|
||||||
|
|
||||||
export ES_JAVA_OPTS
|
export ES_JAVA_OPTS
|
||||||
export JAVA_HOME
|
export JAVA_HOME
|
||||||
|
|
|
@ -114,7 +114,7 @@ start() {
|
||||||
cd $ES_HOME
|
cd $ES_HOME
|
||||||
echo -n $"Starting $prog: "
|
echo -n $"Starting $prog: "
|
||||||
# if not running, start it up here, usually something like "daemon $exec"
|
# if not running, start it up here, usually something like "daemon $exec"
|
||||||
daemon --user $ES_USER --pidfile $pidfile $exec -p $pidfile -d -Ees.default.path.home=$ES_HOME -Ees.default.path.logs=$LOG_DIR -Ees.default.path.data=$DATA_DIR -Ees.default.path.conf=$CONF_DIR
|
daemon --user $ES_USER --pidfile $pidfile $exec -p $pidfile -d -Edefault.path.logs=$LOG_DIR -Edefault.path.data=$DATA_DIR -Edefault.path.conf=$CONF_DIR
|
||||||
retval=$?
|
retval=$?
|
||||||
echo
|
echo
|
||||||
[ $retval -eq 0 ] && touch $lockfile
|
[ $retval -eq 0 ] && touch $lockfile
|
||||||
|
|
|
@ -21,9 +21,9 @@ ExecStartPre=/usr/share/elasticsearch/bin/elasticsearch-systemd-pre-exec
|
||||||
|
|
||||||
ExecStart=/usr/share/elasticsearch/bin/elasticsearch \
|
ExecStart=/usr/share/elasticsearch/bin/elasticsearch \
|
||||||
-p ${PID_DIR}/elasticsearch.pid \
|
-p ${PID_DIR}/elasticsearch.pid \
|
||||||
-Ees.default.path.logs=${LOG_DIR} \
|
-Edefault.path.logs=${LOG_DIR} \
|
||||||
-Ees.default.path.data=${DATA_DIR} \
|
-Edefault.path.data=${DATA_DIR} \
|
||||||
-Ees.default.path.conf=${CONF_DIR}
|
-Edefault.path.conf=${CONF_DIR}
|
||||||
|
|
||||||
StandardOutput=journal
|
StandardOutput=journal
|
||||||
StandardError=inherit
|
StandardError=inherit
|
||||||
|
|
|
@ -81,10 +81,10 @@ fi
|
||||||
HOSTNAME=`hostname | cut -d. -f1`
|
HOSTNAME=`hostname | cut -d. -f1`
|
||||||
export HOSTNAME
|
export HOSTNAME
|
||||||
|
|
||||||
declare -a properties=(-Delasticsearch -Des.path.home="$ES_HOME")
|
declare -a args=("$@")
|
||||||
|
|
||||||
if [ -e "$CONF_DIR" ]; then
|
if [ -e "$CONF_DIR" ]; then
|
||||||
properties=("${properties[@]}" -Des.default.path.conf="$CONF_DIR")
|
args=("${args[@]}" -Edefault.path.conf="$CONF_DIR")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exec "$JAVA" $ES_JAVA_OPTS "${properties[@]}" -cp "$ES_HOME/lib/*" org.elasticsearch.plugins.PluginCli "$@"
|
exec "$JAVA" $ES_JAVA_OPTS -Delasticsearch -Des.path.home="$ES_HOME" -cp "$ES_HOME/lib/*" org.elasticsearch.plugins.PluginCli "${args[@]}"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# you can override this using by setting a system property, for example -Ees.logger.level=DEBUG
|
# you can override using a command-line parameter
|
||||||
es.logger.level: INFO
|
# -E logger.level=(ERROR|WARN|INFO|DEBUG|TRACE)
|
||||||
rootLogger: ${es.logger.level}, console, file
|
logger.level: INFO
|
||||||
|
rootLogger: ${logger.level}, console, file
|
||||||
logger:
|
logger:
|
||||||
# log action execution errors for easier debugging
|
# log action execution errors for easier debugging
|
||||||
action: DEBUG
|
action: DEBUG
|
||||||
|
|
|
@ -135,7 +135,7 @@ can do this as follows:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
---------------------
|
---------------------
|
||||||
sudo bin/elasticsearch-plugin -Ees.path.conf=/path/to/custom/config/dir install <plugin name>
|
sudo bin/elasticsearch-plugin -Epath.conf=/path/to/custom/config/dir install <plugin name>
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
You can also set the `CONF_DIR` environment variable to the custom config
|
You can also set the `CONF_DIR` environment variable to the custom config
|
||||||
|
|
|
@ -163,7 +163,7 @@ As mentioned previously, we can override either the cluster or node name. This c
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
./elasticsearch -Ees.cluster.name=my_cluster_name -Ees.node.name=my_node_name
|
./elasticsearch -Ecluster.name=my_cluster_name -Enode.name=my_node_name
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
||||||
Also note the line marked http with information about the HTTP address (`192.168.8.112`) and port (`9200`) that our node is reachable from. By default, Elasticsearch uses port `9200` to provide access to its REST API. This port is configurable if necessary.
|
Also note the line marked http with information about the HTTP address (`192.168.8.112`) and port (`9200`) that our node is reachable from. By default, Elasticsearch uses port `9200` to provide access to its REST API. This port is configurable if necessary.
|
||||||
|
|
|
@ -14,7 +14,7 @@ attribute as follows:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
------------------------
|
------------------------
|
||||||
bin/elasticsearch -Ees.node.attr.rack=rack1 -Ees.node.attr.size=big <1>
|
bin/elasticsearch -Enode.attr.rack=rack1 -Enode.attr.size=big <1>
|
||||||
------------------------
|
------------------------
|
||||||
<1> These attribute settings can also be specified in the `elasticsearch.yml` config file.
|
<1> These attribute settings can also be specified in the `elasticsearch.yml` config file.
|
||||||
|
|
||||||
|
|
|
@ -43,3 +43,15 @@ Previously, the scripts used to start Elasticsearch and run plugin
|
||||||
commands only required a Bourne-compatible shell. Starting in
|
commands only required a Bourne-compatible shell. Starting in
|
||||||
Elasticsearch 5.0.0, the bash shell is now required and `/bin/bash` is a
|
Elasticsearch 5.0.0, the bash shell is now required and `/bin/bash` is a
|
||||||
hard-dependency for the RPM and Debian packages.
|
hard-dependency for the RPM and Debian packages.
|
||||||
|
|
||||||
|
==== Environmental Settings
|
||||||
|
|
||||||
|
Previously, Elasticsearch could be configured via environment variables
|
||||||
|
in two ways: first by using the placeholder syntax
|
||||||
|
`${env.ENV_VAR_NAME}` and the second by using the same syntax without
|
||||||
|
the `env` prefix: `${ENV_VAR_NAME}`. The first method has been removed
|
||||||
|
from Elasticsearch.
|
||||||
|
|
||||||
|
Additionally, it was previously possible to set any setting in
|
||||||
|
Elasticsearch via JVM system properties. This has been removed from
|
||||||
|
Elasticsearch.
|
||||||
|
|
|
@ -202,19 +202,14 @@ the cache implementation used for the request cache and the field data cache.
|
||||||
|
|
||||||
==== Using system properties to configure Elasticsearch
|
==== Using system properties to configure Elasticsearch
|
||||||
|
|
||||||
Elasticsearch can be configured by setting system properties on the
|
Elasticsearch can no longer be configured by setting system properties.
|
||||||
command line via `-Des.name.of.property=value.of.property`. This will be
|
Instead, use `-Ename.of.setting=value.of.setting`.
|
||||||
removed in a future version of Elasticsearch. Instead, use
|
|
||||||
`-E es.name.of.setting=value.of.setting`. Note that in all cases the
|
|
||||||
name of the setting must be prefixed with `es.`.
|
|
||||||
|
|
||||||
==== Removed using double-dashes to configure Elasticsearch
|
==== Removed using double-dashes to configure Elasticsearch
|
||||||
|
|
||||||
Elasticsearch could previously be configured on the command line by
|
Elasticsearch could previously be configured on the command line by
|
||||||
setting settings via `--name.of.setting value.of.setting`. This feature
|
setting settings via `--name.of.setting value.of.setting`. This feature
|
||||||
has been removed. Instead, use
|
has been removed. Instead, use `-Ename.of.setting=value.of.setting`.
|
||||||
`-Ees.name.of.setting=value.of.setting`. Note that in all cases the
|
|
||||||
name of the setting must be prefixed with `es.`.
|
|
||||||
|
|
||||||
==== Discovery Settings
|
==== Discovery Settings
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ attribute called `rack_id` -- we could use any attribute name. For example:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
----------------------
|
----------------------
|
||||||
./bin/elasticsearch -Ees.node.attr.rack_id=rack_one <1>
|
./bin/elasticsearch -Enode.attr.rack_id=rack_one <1>
|
||||||
----------------------
|
----------------------
|
||||||
<1> This setting could also be specified in the `elasticsearch.yml` config file.
|
<1> This setting could also be specified in the `elasticsearch.yml` config file.
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ Like all node settings, it can also be specified on the command line as:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
-----------------------
|
-----------------------
|
||||||
./bin/elasticsearch -Ees.path.data=/var/elasticsearch/data
|
./bin/elasticsearch -Epath.data=/var/elasticsearch/data
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
TIP: When using the `.zip` or `.tar.gz` distributions, the `path.data` setting
|
TIP: When using the `.zip` or `.tar.gz` distributions, the `path.data` setting
|
||||||
|
|
|
@ -26,7 +26,7 @@ setting, as follows:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
-------------------------------
|
-------------------------------
|
||||||
./bin/elasticsearch -E es.path.conf=/path/to/my/config/
|
./bin/elasticsearch -Epath.conf=/path/to/my/config/
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
|
@ -93,15 +93,14 @@ is used in the settings and the process is run as a service or in the background
|
||||||
=== Setting default settings
|
=== Setting default settings
|
||||||
|
|
||||||
New default settings may be specified on the command line using the
|
New default settings may be specified on the command line using the
|
||||||
`es.default.` prefix instead of the `es.` prefix. This will specify a value
|
`default.` prefix. This will specify a value that will be used by
|
||||||
that will be used by default unless another value is specified in the config
|
default unless another value is specified in the config file.
|
||||||
file.
|
|
||||||
|
|
||||||
For instance, if Elasticsearch is started as follows:
|
For instance, if Elasticsearch is started as follows:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
---------------------------
|
---------------------------
|
||||||
./bin/elasticsearch -E es.default.node.name=My_Node
|
./bin/elasticsearch -Edefault.node.name=My_Node
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
the value for `node.name` will be `My_Node`, unless it is overwritten on the
|
the value for `node.name` will be `My_Node`, unless it is overwritten on the
|
||||||
|
|
|
@ -45,15 +45,14 @@ file by default. The format of this config file is explained in
|
||||||
<<settings>>.
|
<<settings>>.
|
||||||
|
|
||||||
Any settings that can be specified in the config file can also be specified on
|
Any settings that can be specified in the config file can also be specified on
|
||||||
the command line, using the `-E` syntax, and prepending `es.` to the setting
|
the command line, using the `-E` syntax as follows:
|
||||||
name, as follows:
|
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
./bin/elasticsearch -E es.cluster.name=my_cluster -E es.node.name=node_1
|
./bin/elasticsearch -Ecluster.name=my_cluster -Enode.name=node_1
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
NOTE: Values that contain spaces must be surrounded with quotes. For instance `-E es.path.logs="C:\My Logs\logs"`.
|
NOTE: Values that contain spaces must be surrounded with quotes. For instance `-Epath.logs="C:\My Logs\logs"`.
|
||||||
|
|
||||||
TIP: Typically, any cluster-wide settings (like `cluster.name`) should be
|
TIP: Typically, any cluster-wide settings (like `cluster.name`) should be
|
||||||
added to the `elasticsearch.yml` config file, while any node-specific settings
|
added to the `elasticsearch.yml` config file, while any node-specific settings
|
||||||
|
|
|
@ -93,7 +93,7 @@ name, as follows:
|
||||||
|
|
||||||
[source,sh]
|
[source,sh]
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
./bin/elasticsearch -d -E es.cluster.name=my_cluster -E es.node.name=node_1
|
./bin/elasticsearch -d -Ecluster.name=my_cluster -Enode.name=node_1
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
|
||||||
TIP: Typically, any cluster-wide settings (like `cluster.name`) should be
|
TIP: Typically, any cluster-wide settings (like `cluster.name`) should be
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
|
import org.elasticsearch.common.SuppressForbidden;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasEntry;
|
||||||
|
|
||||||
|
public class EvilElasticsearchCliTests extends ESElasticsearchCliTestCase {
|
||||||
|
|
||||||
|
@SuppressForbidden(reason = "manipulates system properties for testing")
|
||||||
|
public void testPathHome() throws Exception {
|
||||||
|
final String pathHome = System.getProperty("es.path.home");
|
||||||
|
final String value = randomAsciiOfLength(16);
|
||||||
|
System.setProperty("es.path.home", value);
|
||||||
|
|
||||||
|
runTest(
|
||||||
|
ExitCodes.OK,
|
||||||
|
true,
|
||||||
|
output -> {},
|
||||||
|
(foreground, pidFile, esSettings) -> {
|
||||||
|
assertThat(esSettings.size(), equalTo(1));
|
||||||
|
assertThat(esSettings, hasEntry("path.home", value));
|
||||||
|
});
|
||||||
|
|
||||||
|
System.clearProperty("es.path.home");
|
||||||
|
final String commandLineValue = randomAsciiOfLength(16);
|
||||||
|
runTest(
|
||||||
|
ExitCodes.OK,
|
||||||
|
true,
|
||||||
|
output -> {},
|
||||||
|
(foreground, pidFile, esSettings) -> {
|
||||||
|
assertThat(esSettings.size(), equalTo(1));
|
||||||
|
assertThat(esSettings, hasEntry("path.home", commandLineValue));
|
||||||
|
},
|
||||||
|
"-Epath.home=" + commandLineValue);
|
||||||
|
|
||||||
|
if (pathHome != null) System.setProperty("es.path.home", pathHome);
|
||||||
|
else System.clearProperty("es.path.home");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ import org.apache.lucene.util.SuppressForbidden;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.cli.MockTerminal;
|
import org.elasticsearch.cli.MockTerminal;
|
||||||
import org.elasticsearch.cli.UserError;
|
import org.elasticsearch.cli.UserError;
|
||||||
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
import org.elasticsearch.common.io.PathUtils;
|
import org.elasticsearch.common.io.PathUtils;
|
||||||
import org.elasticsearch.common.io.PathUtilsForTesting;
|
import org.elasticsearch.common.io.PathUtilsForTesting;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
@ -54,8 +55,10 @@ import java.nio.file.attribute.PosixFileAttributeView;
|
||||||
import java.nio.file.attribute.PosixFileAttributes;
|
import java.nio.file.attribute.PosixFileAttributes;
|
||||||
import java.nio.file.attribute.PosixFilePermission;
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
@ -129,7 +132,7 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a test environment with bin, config and plugins directories. */
|
/** Creates a test environment with bin, config and plugins directories. */
|
||||||
static Environment createEnv(FileSystem fs, Function<String, Path> temp) throws IOException {
|
static Tuple<Path, Environment> createEnv(FileSystem fs, Function<String, Path> temp) throws IOException {
|
||||||
Path home = temp.apply("install-plugin-command-tests");
|
Path home = temp.apply("install-plugin-command-tests");
|
||||||
Files.createDirectories(home.resolve("bin"));
|
Files.createDirectories(home.resolve("bin"));
|
||||||
Files.createFile(home.resolve("bin").resolve("elasticsearch"));
|
Files.createFile(home.resolve("bin").resolve("elasticsearch"));
|
||||||
|
@ -140,7 +143,7 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
Settings settings = Settings.builder()
|
Settings settings = Settings.builder()
|
||||||
.put("path.home", home)
|
.put("path.home", home)
|
||||||
.build();
|
.build();
|
||||||
return new Environment(settings);
|
return Tuple.tuple(home, new Environment(settings));
|
||||||
}
|
}
|
||||||
|
|
||||||
static Path createPluginDir(Function<String, Path> temp) throws IOException {
|
static Path createPluginDir(Function<String, Path> temp) throws IOException {
|
||||||
|
@ -185,20 +188,22 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
return writeZip(structure, "elasticsearch");
|
return writeZip(structure, "elasticsearch");
|
||||||
}
|
}
|
||||||
|
|
||||||
static MockTerminal installPlugin(String pluginUrl, Environment env) throws Exception {
|
static MockTerminal installPlugin(String pluginUrl, Path home) throws Exception {
|
||||||
return installPlugin(pluginUrl, env, false);
|
return installPlugin(pluginUrl, home, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MockTerminal installPlugin(String pluginUrl, Environment env, boolean jarHellCheck) throws Exception {
|
static MockTerminal installPlugin(String pluginUrl, Path home, boolean jarHellCheck) throws Exception {
|
||||||
|
Map<String, String> settings = new HashMap<>();
|
||||||
|
settings.put("path.home", home.toString());
|
||||||
MockTerminal terminal = new MockTerminal();
|
MockTerminal terminal = new MockTerminal();
|
||||||
new InstallPluginCommand(env) {
|
new InstallPluginCommand() {
|
||||||
@Override
|
@Override
|
||||||
void jarHellCheck(Path candidate, Path pluginsDir) throws Exception {
|
void jarHellCheck(Path candidate, Path pluginsDir) throws Exception {
|
||||||
if (jarHellCheck) {
|
if (jarHellCheck) {
|
||||||
super.jarHellCheck(candidate, pluginsDir);
|
super.jarHellCheck(candidate, pluginsDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.execute(terminal, pluginUrl, true);
|
}.execute(terminal, pluginUrl, true, settings);
|
||||||
return terminal;
|
return terminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,192 +280,176 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSomethingWorks() throws Exception {
|
public void testSomethingWorks() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSpaceInUrl() throws Exception {
|
public void testSpaceInUrl() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
Path pluginZipWithSpaces = createTempFile("foo bar", ".zip");
|
Path pluginZipWithSpaces = createTempFile("foo bar", ".zip");
|
||||||
try (InputStream in = new URL(pluginZip).openStream()) {
|
try (InputStream in = new URL(pluginZip).openStream()) {
|
||||||
Files.copy(in, pluginZipWithSpaces, StandardCopyOption.REPLACE_EXISTING);
|
Files.copy(in, pluginZipWithSpaces, StandardCopyOption.REPLACE_EXISTING);
|
||||||
}
|
}
|
||||||
installPlugin(pluginZipWithSpaces.toUri().toURL().toString(), env);
|
installPlugin(pluginZipWithSpaces.toUri().toURL().toString(), env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMalformedUrlNotMaven() throws Exception {
|
public void testMalformedUrlNotMaven() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
// has two colons, so it appears similar to maven coordinates
|
// has two colons, so it appears similar to maven coordinates
|
||||||
MalformedURLException e = expectThrows(MalformedURLException.class, () -> {
|
MalformedURLException e = expectThrows(MalformedURLException.class, () -> installPlugin("://host:1234", env.v1()));
|
||||||
installPlugin("://host:1234", env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("no protocol"));
|
assertTrue(e.getMessage(), e.getMessage().contains("no protocol"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginsDirMissing() throws Exception {
|
public void testPluginsDirMissing() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Files.delete(env.pluginsFile());
|
Files.delete(env.v2().pluginsFile());
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginsDirReadOnly() throws Exception {
|
public void testPluginsDirReadOnly() throws Exception {
|
||||||
assumeTrue("posix and filesystem", isPosix && isReal);
|
assumeTrue("posix and filesystem", isPosix && isReal);
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
try (PosixPermissionsResetter pluginsAttrs = new PosixPermissionsResetter(env.pluginsFile())) {
|
try (PosixPermissionsResetter pluginsAttrs = new PosixPermissionsResetter(env.v2().pluginsFile())) {
|
||||||
pluginsAttrs.setPermissions(new HashSet<>());
|
pluginsAttrs.setPermissions(new HashSet<>());
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
IOException e = expectThrows(IOException.class, () -> {
|
IOException e = expectThrows(IOException.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
assertTrue(e.getMessage(), e.getMessage().contains(env.v2().pluginsFile().toString()));
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains(env.pluginsFile().toString()));
|
|
||||||
}
|
}
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBuiltinModule() throws Exception {
|
public void testBuiltinModule() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
String pluginZip = createPlugin("lang-groovy", pluginDir);
|
String pluginZip = createPlugin("lang-groovy", pluginDir);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("is a system module"));
|
assertTrue(e.getMessage(), e.getMessage().contains("is a system module"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testJarHell() throws Exception {
|
public void testJarHell() throws Exception {
|
||||||
// jar hell test needs a real filesystem
|
// jar hell test needs a real filesystem
|
||||||
assumeTrue("real filesystem", isReal);
|
assumeTrue("real filesystem", isReal);
|
||||||
Environment environment = createEnv(fs, temp);
|
Tuple<Path, Environment> environment = createEnv(fs, temp);
|
||||||
Path pluginDirectory = createPluginDir(temp);
|
Path pluginDirectory = createPluginDir(temp);
|
||||||
writeJar(pluginDirectory.resolve("other.jar"), "FakePlugin");
|
writeJar(pluginDirectory.resolve("other.jar"), "FakePlugin");
|
||||||
String pluginZip = createPlugin("fake", pluginDirectory); // adds plugin.jar with FakePlugin
|
String pluginZip = createPlugin("fake", pluginDirectory); // adds plugin.jar with FakePlugin
|
||||||
IllegalStateException e = expectThrows(IllegalStateException.class, () -> {
|
IllegalStateException e = expectThrows(IllegalStateException.class, () -> installPlugin(pluginZip, environment.v1(), true));
|
||||||
installPlugin(pluginZip, environment, true);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
|
assertTrue(e.getMessage(), e.getMessage().contains("jar hell"));
|
||||||
assertInstallCleaned(environment);
|
assertInstallCleaned(environment.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testIsolatedPlugins() throws Exception {
|
public void testIsolatedPlugins() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
// these both share the same FakePlugin class
|
// these both share the same FakePlugin class
|
||||||
Path pluginDir1 = createPluginDir(temp);
|
Path pluginDir1 = createPluginDir(temp);
|
||||||
String pluginZip1 = createPlugin("fake1", pluginDir1);
|
String pluginZip1 = createPlugin("fake1", pluginDir1);
|
||||||
installPlugin(pluginZip1, env);
|
installPlugin(pluginZip1, env.v1());
|
||||||
Path pluginDir2 = createPluginDir(temp);
|
Path pluginDir2 = createPluginDir(temp);
|
||||||
String pluginZip2 = createPlugin("fake2", pluginDir2);
|
String pluginZip2 = createPlugin("fake2", pluginDir2);
|
||||||
installPlugin(pluginZip2, env);
|
installPlugin(pluginZip2, env.v1());
|
||||||
assertPlugin("fake1", pluginDir1, env);
|
assertPlugin("fake1", pluginDir1, env.v2());
|
||||||
assertPlugin("fake2", pluginDir2, env);
|
assertPlugin("fake2", pluginDir2, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExistingPlugin() throws Exception {
|
public void testExistingPlugin() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("already exists"));
|
assertTrue(e.getMessage(), e.getMessage().contains("already exists"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBin() throws Exception {
|
public void testBin() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path binDir = pluginDir.resolve("bin");
|
Path binDir = pluginDir.resolve("bin");
|
||||||
Files.createDirectory(binDir);
|
Files.createDirectory(binDir);
|
||||||
Files.createFile(binDir.resolve("somescript"));
|
Files.createFile(binDir.resolve("somescript"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBinNotDir() throws Exception {
|
public void testBinNotDir() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path binDir = pluginDir.resolve("bin");
|
Path binDir = pluginDir.resolve("bin");
|
||||||
Files.createFile(binDir);
|
Files.createFile(binDir);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBinContainsDir() throws Exception {
|
public void testBinContainsDir() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path dirInBinDir = pluginDir.resolve("bin").resolve("foo");
|
Path dirInBinDir = pluginDir.resolve("bin").resolve("foo");
|
||||||
Files.createDirectories(dirInBinDir);
|
Files.createDirectories(dirInBinDir);
|
||||||
Files.createFile(dirInBinDir.resolve("somescript"));
|
Files.createFile(dirInBinDir.resolve("somescript"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("Directories not allowed in bin dir for plugin"));
|
assertTrue(e.getMessage(), e.getMessage().contains("Directories not allowed in bin dir for plugin"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBinConflict() throws Exception {
|
public void testBinConflict() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path binDir = pluginDir.resolve("bin");
|
Path binDir = pluginDir.resolve("bin");
|
||||||
Files.createDirectory(binDir);
|
Files.createDirectory(binDir);
|
||||||
Files.createFile(binDir.resolve("somescript"));
|
Files.createFile(binDir.resolve("somescript"));
|
||||||
String pluginZip = createPlugin("elasticsearch", pluginDir);
|
String pluginZip = createPlugin("elasticsearch", pluginDir);
|
||||||
FileAlreadyExistsException e = expectThrows(FileAlreadyExistsException.class, () -> {
|
FileAlreadyExistsException e = expectThrows(FileAlreadyExistsException.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
assertTrue(e.getMessage(), e.getMessage().contains(env.v2().binFile().resolve("elasticsearch").toString()));
|
||||||
});
|
assertInstallCleaned(env.v2());
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains(env.binFile().resolve("elasticsearch").toString()));
|
|
||||||
assertInstallCleaned(env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBinPermissions() throws Exception {
|
public void testBinPermissions() throws Exception {
|
||||||
assumeTrue("posix filesystem", isPosix);
|
assumeTrue("posix filesystem", isPosix);
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path binDir = pluginDir.resolve("bin");
|
Path binDir = pluginDir.resolve("bin");
|
||||||
Files.createDirectory(binDir);
|
Files.createDirectory(binDir);
|
||||||
Files.createFile(binDir.resolve("somescript"));
|
Files.createFile(binDir.resolve("somescript"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
try (PosixPermissionsResetter binAttrs = new PosixPermissionsResetter(env.binFile())) {
|
try (PosixPermissionsResetter binAttrs = new PosixPermissionsResetter(env.v2().binFile())) {
|
||||||
Set<PosixFilePermission> perms = binAttrs.getCopyPermissions();
|
Set<PosixFilePermission> perms = binAttrs.getCopyPermissions();
|
||||||
// make sure at least one execute perm is missing, so we know we forced it during installation
|
// make sure at least one execute perm is missing, so we know we forced it during installation
|
||||||
perms.remove(PosixFilePermission.GROUP_EXECUTE);
|
perms.remove(PosixFilePermission.GROUP_EXECUTE);
|
||||||
binAttrs.setPermissions(perms);
|
binAttrs.setPermissions(perms);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConfig() throws Exception {
|
public void testConfig() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path configDir = pluginDir.resolve("config");
|
Path configDir = pluginDir.resolve("config");
|
||||||
Files.createDirectory(configDir);
|
Files.createDirectory(configDir);
|
||||||
Files.createFile(configDir.resolve("custom.yaml"));
|
Files.createFile(configDir.resolve("custom.yaml"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExistingConfig() throws Exception {
|
public void testExistingConfig() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path envConfigDir = env.configFile().resolve("fake");
|
Path envConfigDir = env.v2().configFile().resolve("fake");
|
||||||
Files.createDirectories(envConfigDir);
|
Files.createDirectories(envConfigDir);
|
||||||
Files.write(envConfigDir.resolve("custom.yaml"), "existing config".getBytes(StandardCharsets.UTF_8));
|
Files.write(envConfigDir.resolve("custom.yaml"), "existing config".getBytes(StandardCharsets.UTF_8));
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
|
@ -469,8 +458,8 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
Files.write(configDir.resolve("custom.yaml"), "new config".getBytes(StandardCharsets.UTF_8));
|
Files.write(configDir.resolve("custom.yaml"), "new config".getBytes(StandardCharsets.UTF_8));
|
||||||
Files.createFile(configDir.resolve("other.yaml"));
|
Files.createFile(configDir.resolve("other.yaml"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
installPlugin(pluginZip, env);
|
installPlugin(pluginZip, env.v1());
|
||||||
assertPlugin("fake", pluginDir, env);
|
assertPlugin("fake", pluginDir, env.v2());
|
||||||
List<String> configLines = Files.readAllLines(envConfigDir.resolve("custom.yaml"), StandardCharsets.UTF_8);
|
List<String> configLines = Files.readAllLines(envConfigDir.resolve("custom.yaml"), StandardCharsets.UTF_8);
|
||||||
assertEquals(1, configLines.size());
|
assertEquals(1, configLines.size());
|
||||||
assertEquals("existing config", configLines.get(0));
|
assertEquals("existing config", configLines.get(0));
|
||||||
|
@ -478,80 +467,68 @@ public class InstallPluginCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConfigNotDir() throws Exception {
|
public void testConfigNotDir() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path configDir = pluginDir.resolve("config");
|
Path configDir = pluginDir.resolve("config");
|
||||||
Files.createFile(configDir);
|
Files.createFile(configDir);
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConfigContainsDir() throws Exception {
|
public void testConfigContainsDir() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path dirInConfigDir = pluginDir.resolve("config").resolve("foo");
|
Path dirInConfigDir = pluginDir.resolve("config").resolve("foo");
|
||||||
Files.createDirectories(dirInConfigDir);
|
Files.createDirectories(dirInConfigDir);
|
||||||
Files.createFile(dirInConfigDir.resolve("myconfig.yml"));
|
Files.createFile(dirInConfigDir.resolve("myconfig.yml"));
|
||||||
String pluginZip = createPlugin("fake", pluginDir);
|
String pluginZip = createPlugin("fake", pluginDir);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("Directories not allowed in config dir for plugin"));
|
assertTrue(e.getMessage(), e.getMessage().contains("Directories not allowed in config dir for plugin"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testConfigConflict() throws Exception {
|
public void testConfigConflict() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Path configDir = pluginDir.resolve("config");
|
Path configDir = pluginDir.resolve("config");
|
||||||
Files.createDirectory(configDir);
|
Files.createDirectory(configDir);
|
||||||
Files.createFile(configDir.resolve("myconfig.yml"));
|
Files.createFile(configDir.resolve("myconfig.yml"));
|
||||||
String pluginZip = createPlugin("elasticsearch.yml", pluginDir);
|
String pluginZip = createPlugin("elasticsearch.yml", pluginDir);
|
||||||
FileAlreadyExistsException e = expectThrows(FileAlreadyExistsException.class, () -> {
|
FileAlreadyExistsException e = expectThrows(FileAlreadyExistsException.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
assertTrue(e.getMessage(), e.getMessage().contains(env.v2().configFile().resolve("elasticsearch.yml").toString()));
|
||||||
});
|
assertInstallCleaned(env.v2());
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains(env.configFile().resolve("elasticsearch.yml").toString()));
|
|
||||||
assertInstallCleaned(env);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMissingDescriptor() throws Exception {
|
public void testMissingDescriptor() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Files.createFile(pluginDir.resolve("fake.yml"));
|
Files.createFile(pluginDir.resolve("fake.yml"));
|
||||||
String pluginZip = writeZip(pluginDir, "elasticsearch");
|
String pluginZip = writeZip(pluginDir, "elasticsearch");
|
||||||
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> {
|
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("plugin-descriptor.properties"));
|
assertTrue(e.getMessage(), e.getMessage().contains("plugin-descriptor.properties"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMissingDirectory() throws Exception {
|
public void testMissingDirectory() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path pluginDir = createPluginDir(temp);
|
Path pluginDir = createPluginDir(temp);
|
||||||
Files.createFile(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES));
|
Files.createFile(pluginDir.resolve(PluginInfo.ES_PLUGIN_PROPERTIES));
|
||||||
String pluginZip = writeZip(pluginDir, null);
|
String pluginZip = writeZip(pluginDir, null);
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("`elasticsearch` directory is missing in the plugin zip"));
|
assertTrue(e.getMessage(), e.getMessage().contains("`elasticsearch` directory is missing in the plugin zip"));
|
||||||
assertInstallCleaned(env);
|
assertInstallCleaned(env.v2());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testZipRelativeOutsideEntryName() throws Exception {
|
public void testZipRelativeOutsideEntryName() throws Exception {
|
||||||
Environment env = createEnv(fs, temp);
|
Tuple<Path, Environment> env = createEnv(fs, temp);
|
||||||
Path zip = createTempDir().resolve("broken.zip");
|
Path zip = createTempDir().resolve("broken.zip");
|
||||||
try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zip))) {
|
try (ZipOutputStream stream = new ZipOutputStream(Files.newOutputStream(zip))) {
|
||||||
stream.putNextEntry(new ZipEntry("elasticsearch/../blah"));
|
stream.putNextEntry(new ZipEntry("elasticsearch/../blah"));
|
||||||
}
|
}
|
||||||
String pluginZip = zip.toUri().toURL().toString();
|
String pluginZip = zip.toUri().toURL().toString();
|
||||||
IOException e = expectThrows(IOException.class, () -> {
|
IOException e = expectThrows(IOException.class, () -> installPlugin(pluginZip, env.v1()));
|
||||||
installPlugin(pluginZip, env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("resolving outside of plugin directory"));
|
assertTrue(e.getMessage(), e.getMessage().contains("resolving outside of plugin directory"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,35 +25,47 @@ import java.nio.file.Files;
|
||||||
import java.nio.file.NoSuchFileException;
|
import java.nio.file.NoSuchFileException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.elasticsearch.cli.ExitCodes;
|
import org.elasticsearch.cli.ExitCodes;
|
||||||
import org.elasticsearch.cli.MockTerminal;
|
import org.elasticsearch.cli.MockTerminal;
|
||||||
|
import org.elasticsearch.common.inject.spi.HasDependencies;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
@LuceneTestCase.SuppressFileSystems("*")
|
@LuceneTestCase.SuppressFileSystems("*")
|
||||||
public class ListPluginsCommandTests extends ESTestCase {
|
public class ListPluginsCommandTests extends ESTestCase {
|
||||||
|
|
||||||
Environment createEnv() throws IOException {
|
private Path home;
|
||||||
Path home = createTempDir();
|
private Environment env;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
home = createTempDir();
|
||||||
Files.createDirectories(home.resolve("plugins"));
|
Files.createDirectories(home.resolve("plugins"));
|
||||||
Settings settings = Settings.builder()
|
Settings settings = Settings.builder()
|
||||||
.put("path.home", home)
|
.put("path.home", home)
|
||||||
.build();
|
.build();
|
||||||
return new Environment(settings);
|
env = new Environment(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MockTerminal listPlugins(Environment env) throws Exception {
|
static MockTerminal listPlugins(Path home) throws Exception {
|
||||||
return listPlugins(env, new String[0]);
|
return listPlugins(home, new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MockTerminal listPlugins(Environment env, String[] args) throws Exception {
|
static MockTerminal listPlugins(Path home, String[] args) throws Exception {
|
||||||
|
String[] argsAndHome = new String[args.length + 1];
|
||||||
|
System.arraycopy(args, 0, argsAndHome, 0, args.length);
|
||||||
|
argsAndHome[args.length] = "-Epath.home=" + home;
|
||||||
MockTerminal terminal = new MockTerminal();
|
MockTerminal terminal = new MockTerminal();
|
||||||
int status = new ListPluginsCommand(env).main(args, terminal);
|
int status = new ListPluginsCommand().main(argsAndHome, terminal);
|
||||||
assertEquals(ExitCodes.OK, status);
|
assertEquals(ExitCodes.OK, status);
|
||||||
return terminal;
|
return terminal;
|
||||||
}
|
}
|
||||||
|
@ -74,49 +86,42 @@ public class ListPluginsCommandTests extends ESTestCase {
|
||||||
|
|
||||||
|
|
||||||
public void testPluginsDirMissing() throws Exception {
|
public void testPluginsDirMissing() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
Files.delete(env.pluginsFile());
|
Files.delete(env.pluginsFile());
|
||||||
IOException e = expectThrows(IOException.class, () -> {
|
IOException e = expectThrows(IOException.class, () -> listPlugins(home));
|
||||||
listPlugins(env);
|
|
||||||
});
|
|
||||||
assertEquals(e.getMessage(), "Plugins directory missing: " + env.pluginsFile());
|
assertEquals(e.getMessage(), "Plugins directory missing: " + env.pluginsFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testNoPlugins() throws Exception {
|
public void testNoPlugins() throws Exception {
|
||||||
MockTerminal terminal = listPlugins(createEnv());
|
MockTerminal terminal = listPlugins(home);
|
||||||
assertTrue(terminal.getOutput(), terminal.getOutput().isEmpty());
|
assertTrue(terminal.getOutput(), terminal.getOutput().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testOnePlugin() throws Exception {
|
public void testOnePlugin() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
buildFakePlugin(env, "fake desc", "fake", "org.fake");
|
buildFakePlugin(env, "fake desc", "fake", "org.fake");
|
||||||
MockTerminal terminal = listPlugins(env);
|
MockTerminal terminal = listPlugins(home);
|
||||||
assertEquals(terminal.getOutput(), buildMultiline("fake"));
|
assertEquals(terminal.getOutput(), buildMultiline("fake"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testTwoPlugins() throws Exception {
|
public void testTwoPlugins() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
buildFakePlugin(env, "fake desc", "fake1", "org.fake");
|
buildFakePlugin(env, "fake desc", "fake1", "org.fake");
|
||||||
buildFakePlugin(env, "fake desc 2", "fake2", "org.fake");
|
buildFakePlugin(env, "fake desc 2", "fake2", "org.fake");
|
||||||
MockTerminal terminal = listPlugins(env);
|
MockTerminal terminal = listPlugins(home);
|
||||||
assertEquals(terminal.getOutput(), buildMultiline("fake1", "fake2"));
|
assertEquals(terminal.getOutput(), buildMultiline("fake1", "fake2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginWithVerbose() throws Exception {
|
public void testPluginWithVerbose() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
buildFakePlugin(env, "fake desc", "fake_plugin", "org.fake");
|
buildFakePlugin(env, "fake desc", "fake_plugin", "org.fake");
|
||||||
String[] params = { "-v" };
|
String[] params = { "-v" };
|
||||||
MockTerminal terminal = listPlugins(env, params);
|
MockTerminal terminal = listPlugins(home, params);
|
||||||
assertEquals(terminal.getOutput(), buildMultiline("Plugins directory: " + env.pluginsFile(), "fake_plugin",
|
assertEquals(terminal.getOutput(), buildMultiline("Plugins directory: " + env.pluginsFile(), "fake_plugin",
|
||||||
"- Plugin information:", "Name: fake_plugin", "Description: fake desc", "Version: 1.0", " * Classname: org.fake"));
|
"- Plugin information:", "Name: fake_plugin", "Description: fake desc", "Version: 1.0", " * Classname: org.fake"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginWithVerboseMultiplePlugins() throws Exception {
|
public void testPluginWithVerboseMultiplePlugins() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
buildFakePlugin(env, "fake desc 1", "fake_plugin1", "org.fake");
|
buildFakePlugin(env, "fake desc 1", "fake_plugin1", "org.fake");
|
||||||
buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2");
|
buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2");
|
||||||
String[] params = { "-v" };
|
String[] params = { "-v" };
|
||||||
MockTerminal terminal = listPlugins(env, params);
|
MockTerminal terminal = listPlugins(home, params);
|
||||||
assertEquals(terminal.getOutput(), buildMultiline("Plugins directory: " + env.pluginsFile(),
|
assertEquals(terminal.getOutput(), buildMultiline("Plugins directory: " + env.pluginsFile(),
|
||||||
"fake_plugin1", "- Plugin information:", "Name: fake_plugin1", "Description: fake desc 1", "Version: 1.0",
|
"fake_plugin1", "- Plugin information:", "Name: fake_plugin1", "Description: fake desc 1", "Version: 1.0",
|
||||||
" * Classname: org.fake", "fake_plugin2", "- Plugin information:", "Name: fake_plugin2",
|
" * Classname: org.fake", "fake_plugin2", "- Plugin information:", "Name: fake_plugin2",
|
||||||
|
@ -124,26 +129,23 @@ public class ListPluginsCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginWithoutVerboseMultiplePlugins() throws Exception {
|
public void testPluginWithoutVerboseMultiplePlugins() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
buildFakePlugin(env, "fake desc 1", "fake_plugin1", "org.fake");
|
buildFakePlugin(env, "fake desc 1", "fake_plugin1", "org.fake");
|
||||||
buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2");
|
buildFakePlugin(env, "fake desc 2", "fake_plugin2", "org.fake2");
|
||||||
MockTerminal terminal = listPlugins(env, new String[0]);
|
MockTerminal terminal = listPlugins(home, new String[0]);
|
||||||
String output = terminal.getOutput();
|
String output = terminal.getOutput();
|
||||||
assertEquals(output, buildMultiline("fake_plugin1", "fake_plugin2"));
|
assertEquals(output, buildMultiline("fake_plugin1", "fake_plugin2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginWithoutDescriptorFile() throws Exception{
|
public void testPluginWithoutDescriptorFile() throws Exception{
|
||||||
Environment env = createEnv();
|
|
||||||
Files.createDirectories(env.pluginsFile().resolve("fake1"));
|
Files.createDirectories(env.pluginsFile().resolve("fake1"));
|
||||||
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> listPlugins(env));
|
NoSuchFileException e = expectThrows(NoSuchFileException.class, () -> listPlugins(home));
|
||||||
assertEquals(e.getFile(), env.pluginsFile().resolve("fake1").resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString());
|
assertEquals(e.getFile(), env.pluginsFile().resolve("fake1").resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testPluginWithWrongDescriptorFile() throws Exception{
|
public void testPluginWithWrongDescriptorFile() throws Exception{
|
||||||
Environment env = createEnv();
|
|
||||||
PluginTestUtil.writeProperties(env.pluginsFile().resolve("fake1"),
|
PluginTestUtil.writeProperties(env.pluginsFile().resolve("fake1"),
|
||||||
"description", "fake desc");
|
"description", "fake desc");
|
||||||
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> listPlugins(env));
|
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> listPlugins(home));
|
||||||
assertEquals(e.getMessage(), "Property [name] is missing in [" +
|
assertEquals(e.getMessage(), "Property [name] is missing in [" +
|
||||||
env.pluginsFile().resolve("fake1").resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString() + "]");
|
env.pluginsFile().resolve("fake1").resolve(PluginInfo.ES_PLUGIN_PROPERTIES).toString() + "]");
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,8 @@ import java.io.IOException;
|
||||||
import java.nio.file.DirectoryStream;
|
import java.nio.file.DirectoryStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.lucene.util.LuceneTestCase;
|
import org.apache.lucene.util.LuceneTestCase;
|
||||||
import org.elasticsearch.cli.UserError;
|
import org.elasticsearch.cli.UserError;
|
||||||
|
@ -30,25 +32,32 @@ import org.elasticsearch.cli.MockTerminal;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.env.Environment;
|
import org.elasticsearch.env.Environment;
|
||||||
import org.elasticsearch.test.ESTestCase;
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
@LuceneTestCase.SuppressFileSystems("*")
|
@LuceneTestCase.SuppressFileSystems("*")
|
||||||
public class RemovePluginCommandTests extends ESTestCase {
|
public class RemovePluginCommandTests extends ESTestCase {
|
||||||
|
|
||||||
/** Creates a test environment with bin, config and plugins directories. */
|
private Path home;
|
||||||
static Environment createEnv() throws IOException {
|
private Environment env;
|
||||||
Path home = createTempDir();
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
home = createTempDir();
|
||||||
Files.createDirectories(home.resolve("bin"));
|
Files.createDirectories(home.resolve("bin"));
|
||||||
Files.createFile(home.resolve("bin").resolve("elasticsearch"));
|
Files.createFile(home.resolve("bin").resolve("elasticsearch"));
|
||||||
Files.createDirectories(home.resolve("plugins"));
|
Files.createDirectories(home.resolve("plugins"));
|
||||||
Settings settings = Settings.builder()
|
Settings settings = Settings.builder()
|
||||||
.put("path.home", home)
|
.put("path.home", home)
|
||||||
.build();
|
.build();
|
||||||
return new Environment(settings);
|
env = new Environment(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
static MockTerminal removePlugin(String name, Environment env) throws Exception {
|
static MockTerminal removePlugin(String name, Path home) throws Exception {
|
||||||
|
Map<String, String> settings = new HashMap<>();
|
||||||
|
settings.put("path.home", home.toString());
|
||||||
MockTerminal terminal = new MockTerminal();
|
MockTerminal terminal = new MockTerminal();
|
||||||
new RemovePluginCommand(env).execute(terminal, name);
|
new RemovePluginCommand().execute(terminal, name, settings);
|
||||||
return terminal;
|
return terminal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,33 +72,28 @@ public class RemovePluginCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testMissing() throws Exception {
|
public void testMissing() throws Exception {
|
||||||
Environment env = createEnv();
|
UserError e = expectThrows(UserError.class, () -> removePlugin("dne", home));
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
|
||||||
removePlugin("dne", env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("Plugin dne not found"));
|
assertTrue(e.getMessage(), e.getMessage().contains("Plugin dne not found"));
|
||||||
assertRemoveCleaned(env);
|
assertRemoveCleaned(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBasic() throws Exception {
|
public void testBasic() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
Files.createDirectory(env.pluginsFile().resolve("fake"));
|
Files.createDirectory(env.pluginsFile().resolve("fake"));
|
||||||
Files.createFile(env.pluginsFile().resolve("fake").resolve("plugin.jar"));
|
Files.createFile(env.pluginsFile().resolve("fake").resolve("plugin.jar"));
|
||||||
Files.createDirectory(env.pluginsFile().resolve("fake").resolve("subdir"));
|
Files.createDirectory(env.pluginsFile().resolve("fake").resolve("subdir"));
|
||||||
Files.createDirectory(env.pluginsFile().resolve("other"));
|
Files.createDirectory(env.pluginsFile().resolve("other"));
|
||||||
removePlugin("fake", env);
|
removePlugin("fake", home);
|
||||||
assertFalse(Files.exists(env.pluginsFile().resolve("fake")));
|
assertFalse(Files.exists(env.pluginsFile().resolve("fake")));
|
||||||
assertTrue(Files.exists(env.pluginsFile().resolve("other")));
|
assertTrue(Files.exists(env.pluginsFile().resolve("other")));
|
||||||
assertRemoveCleaned(env);
|
assertRemoveCleaned(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBin() throws Exception {
|
public void testBin() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
Files.createDirectories(env.pluginsFile().resolve("fake"));
|
Files.createDirectories(env.pluginsFile().resolve("fake"));
|
||||||
Path binDir = env.binFile().resolve("fake");
|
Path binDir = env.binFile().resolve("fake");
|
||||||
Files.createDirectories(binDir);
|
Files.createDirectories(binDir);
|
||||||
Files.createFile(binDir.resolve("somescript"));
|
Files.createFile(binDir.resolve("somescript"));
|
||||||
removePlugin("fake", env);
|
removePlugin("fake", home);
|
||||||
assertFalse(Files.exists(env.pluginsFile().resolve("fake")));
|
assertFalse(Files.exists(env.pluginsFile().resolve("fake")));
|
||||||
assertTrue(Files.exists(env.binFile().resolve("elasticsearch")));
|
assertTrue(Files.exists(env.binFile().resolve("elasticsearch")));
|
||||||
assertFalse(Files.exists(binDir));
|
assertFalse(Files.exists(binDir));
|
||||||
|
@ -97,14 +101,12 @@ public class RemovePluginCommandTests extends ESTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testBinNotDir() throws Exception {
|
public void testBinNotDir() throws Exception {
|
||||||
Environment env = createEnv();
|
|
||||||
Files.createDirectories(env.pluginsFile().resolve("elasticsearch"));
|
Files.createDirectories(env.pluginsFile().resolve("elasticsearch"));
|
||||||
UserError e = expectThrows(UserError.class, () -> {
|
UserError e = expectThrows(UserError.class, () -> removePlugin("elasticsearch", home));
|
||||||
removePlugin("elasticsearch", env);
|
|
||||||
});
|
|
||||||
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
assertTrue(e.getMessage(), e.getMessage().contains("not a directory"));
|
||||||
assertTrue(Files.exists(env.pluginsFile().resolve("elasticsearch"))); // did not remove
|
assertTrue(Files.exists(env.pluginsFile().resolve("elasticsearch"))); // did not remove
|
||||||
assertTrue(Files.exists(env.binFile().resolve("elasticsearch")));
|
assertTrue(Files.exists(env.binFile().resolve("elasticsearch")));
|
||||||
assertRemoveCleaned(env);
|
assertRemoveCleaned(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,29 +84,10 @@ public class TribeUnitTests extends ESTestCase {
|
||||||
tribe2 = null;
|
tribe2 = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testThatTribeClientsIgnoreGlobalSysProps() throws Exception {
|
|
||||||
System.setProperty("es.cluster.name", "tribe_node_cluster");
|
|
||||||
System.setProperty("es.tribe.t1.cluster.name", "tribe1");
|
|
||||||
System.setProperty("es.tribe.t2.cluster.name", "tribe2");
|
|
||||||
System.setProperty("es.tribe.t1.node_id.seed", Long.toString(random().nextLong()));
|
|
||||||
System.setProperty("es.tribe.t2.node_id.seed", Long.toString(random().nextLong()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
assertTribeNodeSuccessfullyCreated(Settings.EMPTY);
|
|
||||||
} finally {
|
|
||||||
System.clearProperty("es.cluster.name");
|
|
||||||
System.clearProperty("es.tribe.t1.cluster.name");
|
|
||||||
System.clearProperty("es.tribe.t2.cluster.name");
|
|
||||||
System.clearProperty("es.tribe.t1.node_id.seed");
|
|
||||||
System.clearProperty("es.tribe.t2.node_id.seed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testThatTribeClientsIgnoreGlobalConfig() throws Exception {
|
public void testThatTribeClientsIgnoreGlobalConfig() throws Exception {
|
||||||
Path pathConf = getDataPath("elasticsearch.yml").getParent();
|
Path pathConf = getDataPath("elasticsearch.yml").getParent();
|
||||||
Settings settings = Settings
|
Settings settings = Settings
|
||||||
.builder()
|
.builder()
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true)
|
|
||||||
.put(Environment.PATH_CONF_SETTING.getKey(), pathConf)
|
.put(Environment.PATH_CONF_SETTING.getKey(), pathConf)
|
||||||
.build();
|
.build();
|
||||||
assertTribeNodeSuccessfullyCreated(settings);
|
assertTribeNodeSuccessfullyCreated(settings);
|
||||||
|
|
|
@ -75,7 +75,6 @@ public abstract class ESSmokeClientTestCase extends LuceneTestCase {
|
||||||
private static Client startClient(Path tempDir, TransportAddress... transportAddresses) {
|
private static Client startClient(Path tempDir, TransportAddress... transportAddresses) {
|
||||||
Settings clientSettings = Settings.builder()
|
Settings clientSettings = Settings.builder()
|
||||||
.put("node.name", "qa_smoke_client_" + counter.getAndIncrement())
|
.put("node.name", "qa_smoke_client_" + counter.getAndIncrement())
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true) // prevents any settings to be replaced by system properties.
|
|
||||||
.put("client.transport.ignore_cluster_name", true)
|
.put("client.transport.ignore_cluster_name", true)
|
||||||
.put(Environment.PATH_HOME_SETTING.getKey(), tempDir)
|
.put(Environment.PATH_HOME_SETTING.getKey(), tempDir)
|
||||||
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we require network here!
|
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we require network here!
|
||||||
|
|
|
@ -103,7 +103,7 @@ fi
|
||||||
echo "CONF_FILE=$CONF_FILE" >> /etc/sysconfig/elasticsearch;
|
echo "CONF_FILE=$CONF_FILE" >> /etc/sysconfig/elasticsearch;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
run_elasticsearch_service 1 -Ees.default.config="$CONF_FILE"
|
run_elasticsearch_service 1 -Edefault.config="$CONF_FILE"
|
||||||
|
|
||||||
# remove settings again otherwise cleaning up before next testrun will fail
|
# remove settings again otherwise cleaning up before next testrun will fail
|
||||||
if is_dpkg ; then
|
if is_dpkg ; then
|
||||||
|
|
|
@ -340,7 +340,7 @@ run_elasticsearch_service() {
|
||||||
local CONF_DIR=""
|
local CONF_DIR=""
|
||||||
local ES_PATH_CONF=""
|
local ES_PATH_CONF=""
|
||||||
else
|
else
|
||||||
local ES_PATH_CONF="-Ees.path.conf=$CONF_DIR"
|
local ES_PATH_CONF="-Epath.conf=$CONF_DIR"
|
||||||
fi
|
fi
|
||||||
# we must capture the exit code to compare so we don't want to start as background process in case we expect something other than 0
|
# we must capture the exit code to compare so we don't want to start as background process in case we expect something other than 0
|
||||||
local background=""
|
local background=""
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.cli.MockTerminal;
|
||||||
|
import org.elasticsearch.test.ESTestCase;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
|
|
||||||
|
abstract class ESElasticsearchCliTestCase extends ESTestCase {
|
||||||
|
|
||||||
|
interface InitConsumer {
|
||||||
|
void accept(final boolean foreground, final String pidFile, final Map<String, String> esSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void runTest(
|
||||||
|
final int expectedStatus,
|
||||||
|
final boolean expectedInit,
|
||||||
|
final Consumer<String> outputConsumer,
|
||||||
|
final InitConsumer initConsumer,
|
||||||
|
String... args) throws Exception {
|
||||||
|
final MockTerminal terminal = new MockTerminal();
|
||||||
|
try {
|
||||||
|
final AtomicBoolean init = new AtomicBoolean();
|
||||||
|
final int status = Elasticsearch.main(args, new Elasticsearch() {
|
||||||
|
@Override
|
||||||
|
void init(final boolean daemonize, final String pidFile, final Map<String, String> esSettings) {
|
||||||
|
init.set(true);
|
||||||
|
initConsumer.accept(!daemonize, pidFile, esSettings);
|
||||||
|
}
|
||||||
|
}, terminal);
|
||||||
|
assertThat(status, equalTo(expectedStatus));
|
||||||
|
assertThat(init.get(), equalTo(expectedInit));
|
||||||
|
outputConsumer.accept(terminal.getOutput());
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// if an unexpected exception is thrown, we log
|
||||||
|
// terminal output to aid debugging
|
||||||
|
logger.info(terminal.getOutput());
|
||||||
|
// rethrow so the test fails
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -185,7 +185,6 @@ public abstract class ESSingleNodeTestCase extends ESTestCase {
|
||||||
.put("http.enabled", false)
|
.put("http.enabled", false)
|
||||||
.put(Node.NODE_LOCAL_SETTING.getKey(), true)
|
.put(Node.NODE_LOCAL_SETTING.getKey(), true)
|
||||||
.put(Node.NODE_DATA_SETTING.getKey(), true)
|
.put(Node.NODE_DATA_SETTING.getKey(), true)
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true) // make sure we get what we set :)
|
|
||||||
.put(nodeSettings()) // allow test cases to provide their own settings or override these
|
.put(nodeSettings()) // allow test cases to provide their own settings or override these
|
||||||
.build();
|
.build();
|
||||||
Node build = new MockNode(settings, getVersion(), getPlugins());
|
Node build = new MockNode(settings, getVersion(), getPlugins());
|
||||||
|
|
|
@ -51,7 +51,6 @@ import java.util.concurrent.TimeUnit;
|
||||||
final class ExternalNode implements Closeable {
|
final class ExternalNode implements Closeable {
|
||||||
|
|
||||||
public static final Settings REQUIRED_SETTINGS = Settings.builder()
|
public static final Settings REQUIRED_SETTINGS = Settings.builder()
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true)
|
|
||||||
.put(DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey(), "zen")
|
.put(DiscoveryModule.DISCOVERY_TYPE_SETTING.getKey(), "zen")
|
||||||
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we need network mode for this
|
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we need network mode for this
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,6 @@ public final class ExternalTestCluster extends TestCluster {
|
||||||
Settings clientSettings = Settings.builder()
|
Settings clientSettings = Settings.builder()
|
||||||
.put(additionalSettings)
|
.put(additionalSettings)
|
||||||
.put("node.name", InternalTestCluster.TRANSPORT_CLIENT_PREFIX + EXTERNAL_CLUSTER_PREFIX + counter.getAndIncrement())
|
.put("node.name", InternalTestCluster.TRANSPORT_CLIENT_PREFIX + EXTERNAL_CLUSTER_PREFIX + counter.getAndIncrement())
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true) // prevents any settings to be replaced by system properties.
|
|
||||||
.put("client.transport.ignore_cluster_name", true)
|
.put("client.transport.ignore_cluster_name", true)
|
||||||
.put(Environment.PATH_HOME_SETTING.getKey(), tempDir)
|
.put(Environment.PATH_HOME_SETTING.getKey(), tempDir)
|
||||||
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we require network here!
|
.put(Node.NODE_MODE_SETTING.getKey(), "network").build(); // we require network here!
|
||||||
|
|
|
@ -291,11 +291,10 @@ public final class InternalTestCluster extends TestCluster {
|
||||||
builder.put(Environment.PATH_REPO_SETTING.getKey(), baseDir.resolve("repos"));
|
builder.put(Environment.PATH_REPO_SETTING.getKey(), baseDir.resolve("repos"));
|
||||||
builder.put(TransportSettings.PORT.getKey(), TRANSPORT_BASE_PORT + "-" + (TRANSPORT_BASE_PORT + PORTS_PER_CLUSTER));
|
builder.put(TransportSettings.PORT.getKey(), TRANSPORT_BASE_PORT + "-" + (TRANSPORT_BASE_PORT + PORTS_PER_CLUSTER));
|
||||||
builder.put("http.port", HTTP_BASE_PORT + "-" + (HTTP_BASE_PORT + PORTS_PER_CLUSTER));
|
builder.put("http.port", HTTP_BASE_PORT + "-" + (HTTP_BASE_PORT + PORTS_PER_CLUSTER));
|
||||||
builder.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true);
|
|
||||||
builder.put(Node.NODE_MODE_SETTING.getKey(), nodeMode);
|
builder.put(Node.NODE_MODE_SETTING.getKey(), nodeMode);
|
||||||
builder.put("http.pipelining", enableHttpPipelining);
|
builder.put("http.pipelining", enableHttpPipelining);
|
||||||
if (Strings.hasLength(System.getProperty("es.logger.level"))) {
|
if (Strings.hasLength(System.getProperty("tests.logger.level"))) {
|
||||||
builder.put("logger.level", System.getProperty("es.logger.level"));
|
builder.put("logger.level", System.getProperty("tests.logger.level"));
|
||||||
}
|
}
|
||||||
if (Strings.hasLength(System.getProperty("es.logger.prefix"))) {
|
if (Strings.hasLength(System.getProperty("es.logger.prefix"))) {
|
||||||
builder.put("logger.prefix", System.getProperty("es.logger.prefix"));
|
builder.put("logger.prefix", System.getProperty("es.logger.prefix"));
|
||||||
|
@ -319,14 +318,14 @@ public final class InternalTestCluster extends TestCluster {
|
||||||
|
|
||||||
public static String configuredNodeMode() {
|
public static String configuredNodeMode() {
|
||||||
Builder builder = Settings.builder();
|
Builder builder = Settings.builder();
|
||||||
if (Strings.isEmpty(System.getProperty("es.node.mode")) && Strings.isEmpty(System.getProperty("es.node.local"))) {
|
if (Strings.isEmpty(System.getProperty("node.mode")) && Strings.isEmpty(System.getProperty("node.local"))) {
|
||||||
return "local"; // default if nothing is specified
|
return "local"; // default if nothing is specified
|
||||||
}
|
}
|
||||||
if (Strings.hasLength(System.getProperty("es.node.mode"))) {
|
if (Strings.hasLength(System.getProperty("node.mode"))) {
|
||||||
builder.put(Node.NODE_MODE_SETTING.getKey(), System.getProperty("es.node.mode"));
|
builder.put(Node.NODE_MODE_SETTING.getKey(), System.getProperty("node.mode"));
|
||||||
}
|
}
|
||||||
if (Strings.hasLength(System.getProperty("es.node.local"))) {
|
if (Strings.hasLength(System.getProperty("node.local"))) {
|
||||||
builder.put(Node.NODE_LOCAL_SETTING.getKey(), System.getProperty("es.node.local"));
|
builder.put(Node.NODE_LOCAL_SETTING.getKey(), System.getProperty("node.local"));
|
||||||
}
|
}
|
||||||
if (DiscoveryNode.isLocalNode(builder.build())) {
|
if (DiscoveryNode.isLocalNode(builder.build())) {
|
||||||
return "local";
|
return "local";
|
||||||
|
@ -882,7 +881,6 @@ public final class InternalTestCluster extends TestCluster {
|
||||||
.put(Node.NODE_MODE_SETTING.getKey(), Node.NODE_MODE_SETTING.exists(nodeSettings) ? Node.NODE_MODE_SETTING.get(nodeSettings) : nodeMode)
|
.put(Node.NODE_MODE_SETTING.getKey(), Node.NODE_MODE_SETTING.exists(nodeSettings) ? Node.NODE_MODE_SETTING.get(nodeSettings) : nodeMode)
|
||||||
.put("logger.prefix", nodeSettings.get("logger.prefix", ""))
|
.put("logger.prefix", nodeSettings.get("logger.prefix", ""))
|
||||||
.put("logger.level", nodeSettings.get("logger.level", "INFO"))
|
.put("logger.level", nodeSettings.get("logger.level", "INFO"))
|
||||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING.getKey(), true)
|
|
||||||
.put(settings);
|
.put(settings);
|
||||||
|
|
||||||
if (Node.NODE_LOCAL_SETTING.exists(nodeSettings)) {
|
if (Node.NODE_LOCAL_SETTING.exists(nodeSettings)) {
|
||||||
|
|
|
@ -137,10 +137,10 @@ public class ReproduceInfoPrinter extends RunListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReproduceErrorMessageBuilder appendESProperties() {
|
public ReproduceErrorMessageBuilder appendESProperties() {
|
||||||
appendProperties("es.logger.level");
|
appendProperties("tests.logger.level");
|
||||||
if (inVerifyPhase()) {
|
if (inVerifyPhase()) {
|
||||||
// these properties only make sense for integration tests
|
// these properties only make sense for integration tests
|
||||||
appendProperties("es.node.mode", "es.node.local", TESTS_CLUSTER,
|
appendProperties("node.mode", "node.local", TESTS_CLUSTER,
|
||||||
ESIntegTestCase.TESTS_ENABLE_MOCK_MODULES);
|
ESIntegTestCase.TESTS_ENABLE_MOCK_MODULES);
|
||||||
}
|
}
|
||||||
appendProperties("tests.assertion.disabled", "tests.security.manager", "tests.nightly", "tests.jvms",
|
appendProperties("tests.assertion.disabled", "tests.security.manager", "tests.nightly", "tests.jvms",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
es.logger.level=INFO
|
tests.logger.level=INFO
|
||||||
log4j.rootLogger=${es.logger.level}, out
|
log4j.rootLogger=${tests.logger.level}, out
|
||||||
|
|
||||||
log4j.logger.org.apache.http=INFO, out
|
log4j.logger.org.apache.http=INFO, out
|
||||||
log4j.additivity.org.apache.http=false
|
log4j.additivity.org.apache.http=false
|
||||||
|
|
Loading…
Reference in New Issue