mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-03-24 17:09:48 +00:00
add ability to prompt for selected settings on startup
Some settings may be considered sensitive, such as passwords, and storing them in the configuration file on disk is not good from a security perspective. This change allows settings to have a special value, `${prompt::text}` or `${prompt::secret}`, to indicate that elasticsearch should prompt the user for the actual value on startup. This only works when started in the foreground. In cases where elasticsearch is started as a service or in the background, an exception will be thrown. Closes #10838
This commit is contained in:
parent
a4e0ecc172
commit
f6191d05de
@ -264,6 +264,29 @@ file which will resolve to an environment setting, for example:
|
||||
}
|
||||
--------------------------------------------------
|
||||
|
||||
Additionally, for settings that you do not wish to store in the configuration
|
||||
file, you can use the value `${prompt::text}` or `${prompt::secret}` and start
|
||||
Elasticsearch in the foreground. `${prompt::secret}` has echoing disabled so
|
||||
that the value entered will not be shown in your terminal; `${prompt::text}`
|
||||
will allow you to see the value as you type it in. For example:
|
||||
|
||||
[source,yaml]
|
||||
--------------------------------------------------
|
||||
node:
|
||||
name: ${prompt::text}
|
||||
--------------------------------------------------
|
||||
|
||||
On execution of the `elasticsearch` command, you will be prompted to enter
|
||||
the actual value like so:
|
||||
|
||||
[source,sh]
|
||||
--------------------------------------------------
|
||||
Enter value for [node.name]:
|
||||
--------------------------------------------------
|
||||
|
||||
NOTE: Elasticsearch will not start if `${prompt::text}` or `${prompt::secret}`
|
||||
is used in the settings and the process is run as a service or in the background.
|
||||
|
||||
The location of the configuration file can be set externally using a
|
||||
system property:
|
||||
|
||||
|
@ -25,6 +25,7 @@ import org.elasticsearch.ExceptionsHelper;
|
||||
import org.elasticsearch.Version;
|
||||
import org.elasticsearch.common.PidFile;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.inject.CreationException;
|
||||
import org.elasticsearch.common.inject.spi.Message;
|
||||
@ -163,8 +164,16 @@ public class Bootstrap {
|
||||
|
||||
// install SM after natives, shutdown hooks, etc.
|
||||
setupSecurity(settings, environment);
|
||||
|
||||
NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(settings).loadConfigSettings(false);
|
||||
|
||||
// We do not need to reload system properties here as we have already applied them in building the settings and
|
||||
// reloading could cause multiple prompts to the user for values if a system property was specified with a prompt
|
||||
// placeholder
|
||||
Settings nodeSettings = Settings.settingsBuilder()
|
||||
.put(settings)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.build();
|
||||
|
||||
NodeBuilder nodeBuilder = NodeBuilder.nodeBuilder().settings(nodeSettings).loadConfigSettings(false);
|
||||
node = nodeBuilder.build();
|
||||
}
|
||||
|
||||
@ -195,8 +204,9 @@ public class Bootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<Settings, Environment> initialSettings() {
|
||||
return InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true);
|
||||
private static Tuple<Settings, Environment> initialSettings(boolean foreground) {
|
||||
Terminal terminal = foreground ? Terminal.DEFAULT : null;
|
||||
return InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true, terminal);
|
||||
}
|
||||
|
||||
private void start() {
|
||||
@ -227,7 +237,7 @@ public class Bootstrap {
|
||||
Settings settings = null;
|
||||
Environment environment = null;
|
||||
try {
|
||||
Tuple<Settings, Environment> tuple = initialSettings();
|
||||
Tuple<Settings, Environment> tuple = initialSettings(foreground);
|
||||
settings = tuple.v1();
|
||||
environment = tuple.v2();
|
||||
|
||||
|
@ -93,7 +93,7 @@ public abstract class CliTool {
|
||||
Preconditions.checkArgument(config.cmds().size() != 0, "At least one command must be configured");
|
||||
this.config = config;
|
||||
this.terminal = terminal;
|
||||
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true);
|
||||
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true, terminal);
|
||||
settings = tuple.v1();
|
||||
env = tuple.v2();
|
||||
}
|
||||
|
@ -1211,7 +1211,7 @@ public final class Settings implements ToXContent {
|
||||
* 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(String... ignoredValues) {
|
||||
PropertyPlaceholder propertyPlaceholder = new PropertyPlaceholder("${", "}", false);
|
||||
PropertyPlaceholder.PlaceholderResolver placeholderResolver = new PropertyPlaceholder.PlaceholderResolver() {
|
||||
@Override
|
||||
@ -1241,7 +1241,19 @@ public final class Settings implements ToXContent {
|
||||
}
|
||||
};
|
||||
for (Map.Entry<String, String> entry : Maps.newHashMap(map).entrySet()) {
|
||||
String value = propertyPlaceholder.replacePlaceholders(entry.getValue(), placeholderResolver);
|
||||
String possiblePlaceholder = entry.getValue();
|
||||
boolean ignored = false;
|
||||
for (String ignoredValue : ignoredValues) {
|
||||
if (ignoredValue.equals(possiblePlaceholder)) {
|
||||
ignored = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ignored) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String value = propertyPlaceholder.replacePlaceholders(possiblePlaceholder, placeholderResolver);
|
||||
// if the values exists and has length, we should maintain it in the map
|
||||
// otherwise, the replace process resolved into removing it
|
||||
if (Strings.hasLength(value)) {
|
||||
|
@ -20,9 +20,11 @@
|
||||
package org.elasticsearch.node.internal;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.UnmodifiableIterator;
|
||||
import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.common.Names;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
@ -41,10 +43,38 @@ public class InternalSettingsPreparer {
|
||||
|
||||
static final List<String> ALLOWED_SUFFIXES = ImmutableList.of(".yml", ".yaml", ".json", ".properties");
|
||||
|
||||
public static final String SECRET_PROMPT_VALUE = "${prompt::secret}";
|
||||
public static final String TEXT_PROMPT_VALUE = "${prompt::text}";
|
||||
public static final String IGNORE_SYSTEM_PROPERTIES_SETTING = "config.ignore_system_properties";
|
||||
|
||||
/**
|
||||
* Prepares the settings by gathering all elasticsearch system properties, optionally loading the configuration settings,
|
||||
* and then replacing all property placeholders. This method will not work with settings that have <code>__prompt__</code>
|
||||
* as their value unless they have been resolved previously.
|
||||
* @param pSettings The initial settings to use
|
||||
* @param loadConfigSettings flag to indicate whether to load settings from the configuration directory/file
|
||||
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
||||
*/
|
||||
public static Tuple<Settings, Environment> prepareSettings(Settings pSettings, boolean loadConfigSettings) {
|
||||
return prepareSettings(pSettings, loadConfigSettings, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 the <code>__prompt__</code> value will result in a prompt for the setting to the user.
|
||||
* @param pSettings The initial settings to use
|
||||
* @param loadConfigSettings flag to indicate whether to load settings from the configuration directory/file
|
||||
* @param terminal the Terminal to use for input/output
|
||||
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
||||
*/
|
||||
public static Tuple<Settings, Environment> prepareSettings(Settings pSettings, boolean loadConfigSettings, Terminal terminal) {
|
||||
// ignore this prefixes when getting properties from es. and elasticsearch.
|
||||
String[] ignorePrefixes = new String[]{"es.default.", "elasticsearch.default."};
|
||||
boolean useSystemProperties = !pSettings.getAsBoolean("config.ignore_system_properties", false);
|
||||
// ignore the special prompt placeholders since they have the same format as property placeholders and will be resolved
|
||||
// as having a default value because of the ':' in the format
|
||||
String[] ignoredPlaceholders = new String[] { SECRET_PROMPT_VALUE, TEXT_PROMPT_VALUE };
|
||||
boolean useSystemProperties = !pSettings.getAsBoolean(IGNORE_SYSTEM_PROPERTIES_SETTING, false);
|
||||
// just create enough settings to build the environment
|
||||
Settings.Builder settingsBuilder = settingsBuilder().put(pSettings);
|
||||
if (useSystemProperties) {
|
||||
@ -53,7 +83,7 @@ public class InternalSettingsPreparer {
|
||||
.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes)
|
||||
.putProperties("es.", System.getProperties(), ignorePrefixes);
|
||||
}
|
||||
settingsBuilder.replacePropertyPlaceholders();
|
||||
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders);
|
||||
|
||||
Environment environment = new Environment(settingsBuilder.build());
|
||||
|
||||
@ -91,17 +121,17 @@ public class InternalSettingsPreparer {
|
||||
settingsBuilder.putProperties("elasticsearch.", System.getProperties(), ignorePrefixes)
|
||||
.putProperties("es.", System.getProperties(), ignorePrefixes);
|
||||
}
|
||||
settingsBuilder.replacePropertyPlaceholders();
|
||||
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders);
|
||||
|
||||
// allow to force set properties based on configuration of the settings provided
|
||||
for (Map.Entry<String, String> entry : pSettings.getAsMap().entrySet()) {
|
||||
String setting = entry.getKey();
|
||||
if (setting.startsWith("force.")) {
|
||||
settingsBuilder.remove(setting);
|
||||
settingsBuilder.put(setting.substring(".force".length()), entry.getValue());
|
||||
settingsBuilder.put(setting.substring("force.".length()), entry.getValue());
|
||||
}
|
||||
}
|
||||
settingsBuilder.replacePropertyPlaceholders();
|
||||
settingsBuilder.replacePropertyPlaceholders(ignoredPlaceholders);
|
||||
|
||||
// generate the name
|
||||
if (settingsBuilder.get("name") == null) {
|
||||
@ -123,7 +153,7 @@ public class InternalSettingsPreparer {
|
||||
settingsBuilder.put(ClusterName.SETTING, ClusterName.DEFAULT.value());
|
||||
}
|
||||
|
||||
Settings v1 = settingsBuilder.build();
|
||||
Settings v1 = replacePromptPlaceholders(settingsBuilder.build(), terminal);
|
||||
environment = new Environment(v1);
|
||||
|
||||
// put back the env settings
|
||||
@ -135,4 +165,45 @@ public class InternalSettingsPreparer {
|
||||
|
||||
return new Tuple<>(v1, environment);
|
||||
}
|
||||
|
||||
static Settings replacePromptPlaceholders(Settings settings, Terminal terminal) {
|
||||
UnmodifiableIterator<Map.Entry<String, String>> iter = settings.getAsMap().entrySet().iterator();
|
||||
Settings.Builder builder = Settings.builder();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<String, String> entry = iter.next();
|
||||
String value = entry.getValue();
|
||||
String key = entry.getKey();
|
||||
switch (value) {
|
||||
case SECRET_PROMPT_VALUE:
|
||||
String secretValue = promptForValue(key, terminal, true);
|
||||
if (Strings.hasLength(secretValue)) {
|
||||
builder.put(key, secretValue);
|
||||
}
|
||||
break;
|
||||
case TEXT_PROMPT_VALUE:
|
||||
String textValue = promptForValue(key, terminal, false);
|
||||
if (Strings.hasLength(textValue)) {
|
||||
builder.put(key, textValue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
builder.put(key, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static String promptForValue(String key, Terminal terminal, boolean secret) {
|
||||
if (terminal == null) {
|
||||
throw new UnsupportedOperationException("found property [" + key + "] with value [" + (secret ? SECRET_PROMPT_VALUE : TEXT_PROMPT_VALUE) +"]. prompting for property values is only supported when running elasticsearch in the foreground");
|
||||
}
|
||||
|
||||
if (secret) {
|
||||
return new String(terminal.readSecret("Enter value for [%s]: ", key));
|
||||
}
|
||||
return terminal.readText("Enter value for [%s]: ", key);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import com.google.common.collect.Iterators;
|
||||
import org.apache.lucene.util.IOUtils;
|
||||
import org.elasticsearch.*;
|
||||
import org.elasticsearch.common.SuppressForbidden;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.http.client.HttpDownloadHelper;
|
||||
import org.elasticsearch.common.io.FileSystemUtils;
|
||||
@ -338,7 +339,7 @@ public class PluginManager {
|
||||
private static final int EXIT_CODE_ERROR = 70;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Tuple<Settings, Environment> initialSettings = InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true);
|
||||
Tuple<Settings, Environment> initialSettings = InternalSettingsPreparer.prepareSettings(EMPTY_SETTINGS, true, Terminal.DEFAULT);
|
||||
|
||||
try {
|
||||
Files.createDirectories(initialSettings.v2().pluginsFile());
|
||||
|
@ -45,6 +45,7 @@ import org.elasticsearch.discovery.DiscoveryService;
|
||||
import org.elasticsearch.gateway.GatewayService;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.NodeBuilder;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.rest.RestStatus;
|
||||
|
||||
import java.util.EnumSet;
|
||||
@ -128,7 +129,7 @@ public class TribeService extends AbstractLifecycleComponent<TribeService> {
|
||||
sb.put("node.name", settings.get("name") + "/" + entry.getKey());
|
||||
sb.put("path.home", settings.get("path.home")); // pass through ES home dir
|
||||
sb.put(TRIBE_NAME, entry.getKey());
|
||||
sb.put("config.ignore_system_properties", true);
|
||||
sb.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true);
|
||||
if (sb.get("http.enabled") == null) {
|
||||
sb.put("http.enabled", false);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.elasticsearch.cluster.ClusterName;
|
||||
import org.elasticsearch.cluster.ClusterState;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.plugins.PluginsService;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
@ -61,7 +62,7 @@ public class TransportClientRetryTests extends ElasticsearchIntegrationTest {
|
||||
.put("node.mode", InternalTestCluster.nodeMode())
|
||||
.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false)
|
||||
.put(ClusterName.SETTING, internalCluster().getClusterName())
|
||||
.put("config.ignore_system_properties", true)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.put("path.home", createTempDir());
|
||||
|
||||
try (TransportClient transportClient = TransportClient.builder().settings(builder.build()).build()) {
|
||||
|
@ -25,6 +25,7 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest.ClusterScope;
|
||||
import org.elasticsearch.transport.TransportService;
|
||||
@ -59,7 +60,7 @@ public class TransportClientTests extends ElasticsearchIntegrationTest {
|
||||
.put("path.home", createTempDir())
|
||||
.put("node.name", "testNodeVersionIsUpdated")
|
||||
.put("http.enabled", false)
|
||||
.put("config.ignore_system_properties", true) // make sure we get what we set :)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true) // make sure we get what we set :)
|
||||
.build()).clusterName("foobar").build();
|
||||
node.start();
|
||||
try {
|
||||
|
@ -25,10 +25,12 @@ import org.elasticsearch.ElasticsearchException;
|
||||
import org.elasticsearch.common.Strings;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import static org.elasticsearch.common.cli.CliToolConfig.Builder.cmd;
|
||||
@ -271,6 +273,49 @@ public class CliToolTests extends CliToolTestCase {
|
||||
tool.parse("cmd", Strings.splitStringByCommaToArray("--help"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPromptForSetting() throws Exception {
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
final AtomicReference<String> promptedSecretValue = new AtomicReference<>(null);
|
||||
final AtomicReference<String> promptedTextValue = new AtomicReference<>(null);
|
||||
final Terminal terminal = new MockTerminal() {
|
||||
@Override
|
||||
public char[] readSecret(String text, Object... args) {
|
||||
counter.incrementAndGet();
|
||||
assertThat(args, arrayContaining((Object) "foo.password"));
|
||||
return "changeit".toCharArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readText(String text, Object... args) {
|
||||
counter.incrementAndGet();
|
||||
assertThat(args, arrayContaining((Object) "replace"));
|
||||
return "replaced";
|
||||
}
|
||||
};
|
||||
final NamedCommand cmd = new NamedCommand("noop", terminal) {
|
||||
@Override
|
||||
public CliTool.ExitStatus execute(Settings settings, Environment env) {
|
||||
promptedSecretValue.set(settings.get("foo.password"));
|
||||
promptedTextValue.set(settings.get("replace"));
|
||||
return CliTool.ExitStatus.OK;
|
||||
}
|
||||
};
|
||||
|
||||
System.setProperty("es.foo.password", InternalSettingsPreparer.SECRET_PROMPT_VALUE);
|
||||
System.setProperty("es.replace", InternalSettingsPreparer.TEXT_PROMPT_VALUE);
|
||||
try {
|
||||
new SingleCmdTool("tool", terminal, cmd).execute();
|
||||
} finally {
|
||||
System.clearProperty("es.foo.password");
|
||||
System.clearProperty("es.replace");
|
||||
}
|
||||
|
||||
assertThat(counter.intValue(), is(2));
|
||||
assertThat(promptedSecretValue.get(), is("changeit"));
|
||||
assertThat(promptedTextValue.get(), is("replaced"));
|
||||
}
|
||||
|
||||
private void assertStatus(int status, CliTool.ExitStatus expectedStatus) {
|
||||
assertThat(status, is(expectedStatus.status()));
|
||||
}
|
||||
|
@ -137,6 +137,17 @@ public class SettingsTests extends ElasticsearchTestCase {
|
||||
assertThat(settings.get("setting1"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplacePropertiesPlaceholderIgnores() {
|
||||
Settings settings = settingsBuilder()
|
||||
.put("setting1", "${foo.bar}")
|
||||
.put("setting2", "${foo.bar1}")
|
||||
.replacePropertyPlaceholders("${foo.bar}", "${foo.bar1}")
|
||||
.build();
|
||||
assertThat(settings.get("setting1"), is("${foo.bar}"));
|
||||
assertThat(settings.get("setting2"), is("${foo.bar1}"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnFlattenedSettings() {
|
||||
Settings settings = settingsBuilder()
|
||||
|
@ -27,6 +27,7 @@ import org.elasticsearch.common.util.concurrent.EsExecutors;
|
||||
import org.elasticsearch.index.engine.EngineConfig;
|
||||
import org.elasticsearch.index.shard.IndexShard;
|
||||
import org.elasticsearch.indices.IndicesService;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||
import org.junit.Test;
|
||||
|
||||
@ -143,7 +144,7 @@ public class IndexingMemoryControllerTests extends ElasticsearchIntegrationTest
|
||||
.put(IndexMetaData.SETTING_NUMBER_OF_REPLICAS, 0)
|
||||
.put(EsExecutors.PROCESSORS, 1) // limit the number of threads created
|
||||
.put("http.enabled", false)
|
||||
.put("config.ignore_system_properties", true) // make sure we get what we set :)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true) // make sure we get what we set :)
|
||||
.put("indices.memory.interval", "100ms")
|
||||
.put(settings)
|
||||
);
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package org.elasticsearch.node.internal;
|
||||
|
||||
import org.elasticsearch.common.cli.CliToolTestCase;
|
||||
import org.elasticsearch.common.cli.Terminal;
|
||||
import org.elasticsearch.common.collect.Tuple;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.env.Environment;
|
||||
@ -27,11 +29,16 @@ import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
||||
|
||||
@Before
|
||||
public void setupSystemProperties() {
|
||||
System.setProperty("es.node.zone", "foo");
|
||||
@ -53,7 +60,7 @@ public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
||||
assertThat(tuple.v1().get("node.zone"), equalTo("foo"));
|
||||
|
||||
settings = settingsBuilder()
|
||||
.put("config.ignore_system_properties", true)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.put("node.zone", "bar")
|
||||
.put("path.home", createTempDir().toString())
|
||||
.build();
|
||||
@ -74,4 +81,74 @@ public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
||||
assertThat(tuple.v1().get("json.config.exists"), equalTo("true"));
|
||||
assertThat(tuple.v1().get("properties.config.exists"), equalTo("true"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplacePromptPlaceholders() {
|
||||
final List<String> replacedSecretProperties = new ArrayList<>();
|
||||
final List<String> replacedTextProperties = new ArrayList<>();
|
||||
final Terminal terminal = new CliToolTestCase.MockTerminal() {
|
||||
@Override
|
||||
public char[] readSecret(String message, Object... args) {
|
||||
for (Object arg : args) {
|
||||
replacedSecretProperties.add((String) arg);
|
||||
}
|
||||
return "replaced".toCharArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readText(String message, Object... args) {
|
||||
for (Object arg : args) {
|
||||
replacedTextProperties.add((String) arg);
|
||||
}
|
||||
return "text";
|
||||
}
|
||||
};
|
||||
|
||||
Settings.Builder builder = settingsBuilder()
|
||||
.put("password.replace", InternalSettingsPreparer.SECRET_PROMPT_VALUE)
|
||||
.put("dont.replace", "prompt:secret")
|
||||
.put("dont.replace2", "_prompt:secret_")
|
||||
.put("dont.replace3", "_prompt:text__")
|
||||
.put("dont.replace4", "__prompt:text_")
|
||||
.put("dont.replace5", "prompt:secret__")
|
||||
.put("replace_me", InternalSettingsPreparer.TEXT_PROMPT_VALUE);
|
||||
Settings settings = builder.build();
|
||||
settings = InternalSettingsPreparer.replacePromptPlaceholders(settings, terminal);
|
||||
|
||||
assertThat(replacedSecretProperties.size(), is(1));
|
||||
assertThat(replacedTextProperties.size(), is(1));
|
||||
assertThat(settings.get("password.replace"), equalTo("replaced"));
|
||||
assertThat(settings.get("replace_me"), equalTo("text"));
|
||||
|
||||
// verify other values unchanged
|
||||
assertThat(settings.get("dont.replace"), equalTo("prompt:secret"));
|
||||
assertThat(settings.get("dont.replace2"), equalTo("_prompt:secret_"));
|
||||
assertThat(settings.get("dont.replace3"), equalTo("_prompt:text__"));
|
||||
assertThat(settings.get("dont.replace4"), equalTo("__prompt:text_"));
|
||||
assertThat(settings.get("dont.replace5"), equalTo("prompt:secret__"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceSecretPromptPlaceholderWithNullTerminal() {
|
||||
Settings.Builder builder = settingsBuilder()
|
||||
.put("replace_me1", InternalSettingsPreparer.SECRET_PROMPT_VALUE);
|
||||
try {
|
||||
InternalSettingsPreparer.replacePromptPlaceholders(builder.build(), null);
|
||||
fail("an exception should have been thrown since no terminal was provided!");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
assertThat(e.getMessage(), containsString("with value [" + InternalSettingsPreparer.SECRET_PROMPT_VALUE + "]"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTextPromptPlaceholderWithNullTerminal() {
|
||||
Settings.Builder builder = settingsBuilder()
|
||||
.put("replace_me1", InternalSettingsPreparer.TEXT_PROMPT_VALUE);
|
||||
try {
|
||||
InternalSettingsPreparer.replacePromptPlaceholders(builder.build(), null);
|
||||
fail("an exception should have been thrown since no terminal was provided!");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
assertThat(e.getMessage(), containsString("with value [" + InternalSettingsPreparer.TEXT_PROMPT_VALUE + "]"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ import org.elasticsearch.index.IndexService;
|
||||
import org.elasticsearch.indices.IndicesService;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.NodeBuilder;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.threadpool.ThreadPool;
|
||||
import org.junit.After;
|
||||
@ -127,7 +128,7 @@ public abstract class ElasticsearchSingleNodeTest extends ElasticsearchTestCase
|
||||
.put("script.indexed", "on")
|
||||
.put(EsExecutors.PROCESSORS, 1) // limit the number of threads created
|
||||
.put("http.enabled", false)
|
||||
.put("config.ignore_system_properties", true) // make sure we get what we set :)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true) // make sure we get what we set :)
|
||||
).build();
|
||||
build.start();
|
||||
assertThat(DiscoveryNode.localNode(build.settings()), is(true));
|
||||
|
@ -33,6 +33,7 @@ import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.discovery.DiscoveryModule;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.transport.TransportModule;
|
||||
|
||||
import java.io.Closeable;
|
||||
@ -53,7 +54,7 @@ import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||
final class ExternalNode implements Closeable {
|
||||
|
||||
public static final Settings REQUIRED_SETTINGS = Settings.builder()
|
||||
.put("config.ignore_system_properties", true)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.put(DiscoveryModule.DISCOVERY_TYPE_KEY, "zen")
|
||||
.put("node.mode", "network").build(); // we need network mode for this
|
||||
|
||||
@ -115,7 +116,7 @@ final class ExternalNode implements Closeable {
|
||||
case TransportModule.TRANSPORT_TYPE_KEY:
|
||||
case DiscoveryModule.DISCOVERY_TYPE_KEY:
|
||||
case TransportModule.TRANSPORT_SERVICE_TYPE_KEY:
|
||||
case "config.ignore_system_properties":
|
||||
case InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING:
|
||||
continue;
|
||||
default:
|
||||
externaNodeSettingsBuilder.put(entry.getKey(), entry.getValue());
|
||||
|
@ -33,6 +33,7 @@ import org.elasticsearch.common.logging.Loggers;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.InetSocketTransportAddress;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
@ -67,7 +68,7 @@ public final class ExternalTestCluster extends TestCluster {
|
||||
super(0);
|
||||
Settings clientSettings = Settings.settingsBuilder()
|
||||
.put("name", InternalTestCluster.TRANSPORT_CLIENT_PREFIX + EXTERNAL_CLUSTER_PREFIX + counter.getAndIncrement())
|
||||
.put("config.ignore_system_properties", true) // prevents any settings to be replaced by system properties.
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true) // prevents any settings to be replaced by system properties.
|
||||
.put("client.transport.ignore_cluster_name", true)
|
||||
.put("node.mode", "network").build(); // we require network here!
|
||||
|
||||
|
@ -88,6 +88,7 @@ import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService;
|
||||
import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
|
||||
import org.elasticsearch.indices.recovery.RecoverySettings;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.node.service.NodeService;
|
||||
import org.elasticsearch.plugins.PluginsService;
|
||||
import org.elasticsearch.search.SearchService;
|
||||
@ -279,7 +280,7 @@ public final class InternalTestCluster extends TestCluster {
|
||||
builder.put("path.repo", baseDir.resolve("repos"));
|
||||
builder.put("transport.tcp.port", BASE_PORT + "-" + (BASE_PORT+100));
|
||||
builder.put("http.port", BASE_PORT+101 + "-" + (BASE_PORT+200));
|
||||
builder.put("config.ignore_system_properties", true);
|
||||
builder.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true);
|
||||
builder.put("node.mode", NODE_MODE);
|
||||
builder.put("http.pipelining", enableHttpPipelining);
|
||||
builder.put("plugins." + PluginsService.LOAD_PLUGIN_FROM_CLASSPATH, false);
|
||||
@ -874,7 +875,7 @@ public final class InternalTestCluster extends TestCluster {
|
||||
.put("node.local", nodeSettings.get("node.local", ""))
|
||||
.put("logger.prefix", nodeSettings.get("logger.prefix", ""))
|
||||
.put("logger.level", nodeSettings.get("logger.level", "INFO"))
|
||||
.put("config.ignore_system_properties", true)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.put(settings);
|
||||
|
||||
TransportClient client = TransportClient.builder().settings(builder.build()).build();
|
||||
|
@ -25,6 +25,7 @@ import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.node.Node;
|
||||
import org.elasticsearch.node.NodeBuilder;
|
||||
import org.elasticsearch.node.internal.InternalSettingsPreparer;
|
||||
import org.elasticsearch.test.ElasticsearchTestCase;
|
||||
import org.elasticsearch.test.InternalTestCluster;
|
||||
import org.junit.AfterClass;
|
||||
@ -51,7 +52,7 @@ public class TribeUnitTests extends ElasticsearchTestCase {
|
||||
@BeforeClass
|
||||
public static void createTribes() {
|
||||
Settings baseSettings = Settings.builder()
|
||||
.put("config.ignore_system_properties", true)
|
||||
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
|
||||
.put("http.enabled", false)
|
||||
.put("node.mode", NODE_MODE)
|
||||
.put("path.home", createTempDir()).build();
|
||||
@ -86,7 +87,7 @@ public class TribeUnitTests extends ElasticsearchTestCase {
|
||||
@Test
|
||||
public void testThatTribeClientsIgnoreGlobalConfig() throws Exception {
|
||||
Path pathConf = getDataPath("elasticsearch.yml").getParent();
|
||||
Settings settings = Settings.builder().put("config.ignore_system_properties", true).put("path.conf", pathConf).build();
|
||||
Settings settings = Settings.builder().put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true).put("path.conf", pathConf).build();
|
||||
assertTribeNodeSuccesfullyCreated(settings);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user