do not prompt for node name twice
We allow setting the node's name a few different ways: the `name` system property, the setting `name`, and the setting `node.name`. There is an order of preference to these settings that gets applied, which can copy values from the system property or `node.name` setting to the `name` setting. When setting only `node.name` to one of the prompt placeholders, the user would be prompted twice as the value of `node.name` is copied to `name` prior to prompting for input. Additionally, the value entered by the user for `node.name` would not be used and only the value entered for `name` would be used. This fix changes the behavior to only prompt once when `node.name is set` and `name` is not set. This is accomplished by waiting until all values have been prompted and replaced, then the logic for determining the node's name is executed. Closes #11564
This commit is contained in:
parent
2213a5aa81
commit
ae1ed34355
|
@ -50,8 +50,8 @@ public class InternalSettingsPreparer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepares the settings by gathering all elasticsearch system properties, optionally loading the configuration settings,
|
* 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>
|
* and then replacing all property placeholders. This method will not work with settings that have <code>${prompt.text}</code>
|
||||||
* as their value unless they have been resolved previously.
|
* or <code>${prompt.secret}</code> as their value unless they have been resolved previously.
|
||||||
* @param pSettings The initial settings to use
|
* @param pSettings The initial settings to use
|
||||||
* @param loadConfigSettings flag to indicate whether to load settings from the configuration directory/file
|
* @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}
|
* @return the {@link Settings} and {@link Environment} as a {@link Tuple}
|
||||||
|
@ -63,7 +63,8 @@ public class InternalSettingsPreparer {
|
||||||
/**
|
/**
|
||||||
* Prepares the settings by gathering all elasticsearch system properties, optionally loading the configuration settings,
|
* 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,
|
* 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.
|
* 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 pSettings The initial settings to use
|
* @param pSettings The initial settings to use
|
||||||
* @param loadConfigSettings flag to indicate whether to load settings from the configuration directory/file
|
* @param loadConfigSettings flag to indicate whether to load settings from the configuration directory/file
|
||||||
* @param terminal the Terminal to use for input/output
|
* @param terminal the Terminal to use for input/output
|
||||||
|
@ -131,16 +132,9 @@ public class InternalSettingsPreparer {
|
||||||
}
|
}
|
||||||
settingsBuilder.replacePropertyPlaceholders();
|
settingsBuilder.replacePropertyPlaceholders();
|
||||||
|
|
||||||
// generate the name
|
// check if name is set in settings, if not look for system property and set it
|
||||||
if (settingsBuilder.get("name") == null) {
|
if (settingsBuilder.get("name") == null) {
|
||||||
String name = System.getProperty("name");
|
String name = System.getProperty("name");
|
||||||
if (name == null || name.isEmpty()) {
|
|
||||||
name = settingsBuilder.get("node.name");
|
|
||||||
if (name == null || name.isEmpty()) {
|
|
||||||
name = Names.randomNodeName(environment.resolveConfig("names.txt"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
settingsBuilder.put("name", name);
|
settingsBuilder.put("name", name);
|
||||||
}
|
}
|
||||||
|
@ -155,17 +149,33 @@ public class InternalSettingsPreparer {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
Settings.setSettingsRequireUnits(Booleans.parseBoolean(v, true));
|
Settings.setSettingsRequireUnits(Booleans.parseBoolean(v, true));
|
||||||
}
|
}
|
||||||
Settings v1 = replacePromptPlaceholders(settingsBuilder.build(), terminal);
|
|
||||||
environment = new Environment(v1);
|
Settings settings = replacePromptPlaceholders(settingsBuilder.build(), terminal);
|
||||||
|
// all settings placeholders have been resolved. resolve the value for the name setting by checking for name,
|
||||||
|
// then looking for node.name, and finally generate one if needed
|
||||||
|
if (settings.get("name") == null) {
|
||||||
|
final String name = settings.get("node.name");
|
||||||
|
if (name == null || name.isEmpty()) {
|
||||||
|
settings = settingsBuilder().put(settings)
|
||||||
|
.put("name", Names.randomNodeName(environment.resolveConfig("names.txt")))
|
||||||
|
.build();
|
||||||
|
} else {
|
||||||
|
settings = settingsBuilder().put(settings)
|
||||||
|
.put("name", name)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
environment = new Environment(settings);
|
||||||
|
|
||||||
// put back the env settings
|
// put back the env settings
|
||||||
settingsBuilder = settingsBuilder().put(v1);
|
settingsBuilder = settingsBuilder().put(settings);
|
||||||
// we put back the path.logs so we can use it in the logging configuration file
|
// we put back the path.logs so we can use it in the logging configuration file
|
||||||
settingsBuilder.put("path.logs", cleanPath(environment.logsFile().toAbsolutePath().toString()));
|
settingsBuilder.put("path.logs", cleanPath(environment.logsFile().toAbsolutePath().toString()));
|
||||||
|
|
||||||
v1 = settingsBuilder.build();
|
settings = settingsBuilder.build();
|
||||||
|
|
||||||
return new Tuple<>(v1, environment);
|
return new Tuple<>(settings, environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Settings replacePromptPlaceholders(Settings settings, Terminal terminal) {
|
static Settings replacePromptPlaceholders(Settings settings, Terminal terminal) {
|
||||||
|
|
|
@ -31,22 +31,23 @@ import org.junit.Test;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
|
|
||||||
public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setupSystemProperties() {
|
public void setupSystemProperties() {
|
||||||
System.setProperty("es.node.zone", "foo");
|
System.setProperty("es.node.zone", "foo");
|
||||||
|
System.setProperty("name", "sys-prop-name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanupSystemProperties() {
|
public void cleanupSystemProperties() {
|
||||||
System.clearProperty("es.node.zone");
|
System.clearProperty("es.node.zone");
|
||||||
|
System.clearProperty("name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -151,4 +152,72 @@ public class InternalSettingsPreparerTests extends ElasticsearchTestCase {
|
||||||
assertThat(e.getMessage(), containsString("with value [" + InternalSettingsPreparer.TEXT_PROMPT_VALUE + "]"));
|
assertThat(e.getMessage(), containsString("with value [" + InternalSettingsPreparer.TEXT_PROMPT_VALUE + "]"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameSettingsPreference() {
|
||||||
|
// Test system property overrides node.name
|
||||||
|
Settings settings = settingsBuilder()
|
||||||
|
.put("node.name", "node-name")
|
||||||
|
.put("path.home", createTempDir().toString())
|
||||||
|
.build();
|
||||||
|
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(settings, true);
|
||||||
|
assertThat(tuple.v1().get("name"), equalTo("sys-prop-name"));
|
||||||
|
|
||||||
|
// test name in settings overrides sys prop and node.name
|
||||||
|
settings = settingsBuilder()
|
||||||
|
.put("name", "name-in-settings")
|
||||||
|
.put("node.name", "node-name")
|
||||||
|
.put("path.home", createTempDir().toString())
|
||||||
|
.build();
|
||||||
|
tuple = InternalSettingsPreparer.prepareSettings(settings, true);
|
||||||
|
assertThat(tuple.v1().get("name"), equalTo("name-in-settings"));
|
||||||
|
|
||||||
|
// test only node.name in settings
|
||||||
|
System.clearProperty("name");
|
||||||
|
settings = settingsBuilder()
|
||||||
|
.put("node.name", "node-name")
|
||||||
|
.put("path.home", createTempDir().toString())
|
||||||
|
.build();
|
||||||
|
tuple = InternalSettingsPreparer.prepareSettings(settings, true);
|
||||||
|
assertThat(tuple.v1().get("name"), equalTo("node-name"));
|
||||||
|
|
||||||
|
// test no name at all results in name being set
|
||||||
|
settings = settingsBuilder()
|
||||||
|
.put("path.home", createTempDir().toString())
|
||||||
|
.build();
|
||||||
|
tuple = InternalSettingsPreparer.prepareSettings(settings, true);
|
||||||
|
assertThat(tuple.v1().get("name"), not("name-in-settings"));
|
||||||
|
assertThat(tuple.v1().get("name"), not("sys-prop-name"));
|
||||||
|
assertThat(tuple.v1().get("name"), not("node-name"));
|
||||||
|
assertThat(tuple.v1().get("name"), notNullValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPromptForNodeNameOnlyPromptsOnce() {
|
||||||
|
final AtomicInteger counter = new AtomicInteger();
|
||||||
|
final Terminal terminal = new CliToolTestCase.MockTerminal() {
|
||||||
|
@Override
|
||||||
|
public char[] readSecret(String message, Object... args) {
|
||||||
|
fail("readSecret should never be called by this test");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String readText(String message, Object... args) {
|
||||||
|
int count = counter.getAndIncrement();
|
||||||
|
return "prompted name " + count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
System.clearProperty("name");
|
||||||
|
Settings settings = Settings.builder()
|
||||||
|
.put("path.home", createTempDir())
|
||||||
|
.put("node.name", InternalSettingsPreparer.TEXT_PROMPT_VALUE)
|
||||||
|
.build();
|
||||||
|
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(settings, false, terminal);
|
||||||
|
settings = tuple.v1();
|
||||||
|
assertThat(counter.intValue(), is(1));
|
||||||
|
assertThat(settings.get("name"), is("prompted name 0"));
|
||||||
|
assertThat(settings.get("node.name"), is("prompted name 0"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue