Skip to content

Commit 5bf92ca

Browse files
authored
Enforce that java.io.tmpdir exists on startup (#28217)
If the default java.io.tmpdir is used then the startup script creates it, but if a custom java.io.tmpdir is used then the user must ensure it exists before running Elasticsearch. If they forget then it can cause errors that are hard to understand, so this change adds an explicit check early in the bootstrap and reports a clear error if java.io.tmpdir is not an accessible directory.
1 parent 3e0e644 commit 5bf92ca

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

server/src/main/java/org/elasticsearch/bootstrap/Elasticsearch.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,13 @@ protected void execute(Terminal terminal, OptionSet options, Environment env) th
108108
final Path pidFile = pidfileOption.value(options);
109109
final boolean quiet = options.has(quietOption);
110110

111+
// a misconfigured java.io.tmpdir can cause hard-to-diagnose problems later, so reject it immediately
112+
try {
113+
env.validateTmpFile();
114+
} catch (IOException e) {
115+
throw new UserException(ExitCodes.CONFIG, e.getMessage());
116+
}
117+
111118
try {
112119
init(daemonize, pidFile, quiet, env);
113120
} catch (NodeValidationException e) {

server/src/main/java/org/elasticsearch/env/Environment.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.common.settings.Setting.Property;
2828
import org.elasticsearch.common.settings.Settings;
2929

30+
import java.io.FileNotFoundException;
3031
import java.io.IOException;
3132
import java.net.MalformedURLException;
3233
import java.net.URISyntaxException;
@@ -87,9 +88,14 @@ public class Environment {
8788
private final Path pidFile;
8889

8990
/** Path to the temporary file directory used by the JDK */
90-
private final Path tmpFile = PathUtils.get(System.getProperty("java.io.tmpdir"));
91+
private final Path tmpFile;
9192

9293
public Environment(final Settings settings, final Path configPath) {
94+
this(settings, configPath, PathUtils.get(System.getProperty("java.io.tmpdir")));
95+
}
96+
97+
// Should only be called directly by this class's unit tests
98+
Environment(final Settings settings, final Path configPath, final Path tmpPath) {
9399
final Path homeFile;
94100
if (PATH_HOME_SETTING.exists(settings)) {
95101
homeFile = PathUtils.get(PATH_HOME_SETTING.get(settings)).normalize();
@@ -103,6 +109,8 @@ public Environment(final Settings settings, final Path configPath) {
103109
configFile = homeFile.resolve("config");
104110
}
105111

112+
tmpFile = Objects.requireNonNull(tmpPath);
113+
106114
pluginsFile = homeFile.resolve("plugins");
107115

108116
List<String> dataPaths = PATH_DATA_SETTING.get(settings);
@@ -302,6 +310,16 @@ public Path tmpFile() {
302310
return tmpFile;
303311
}
304312

313+
/** Ensure the configured temp directory is a valid directory */
314+
public void validateTmpFile() throws IOException {
315+
if (Files.exists(tmpFile) == false) {
316+
throw new FileNotFoundException("Temporary file directory [" + tmpFile + "] does not exist or is not accessible");
317+
}
318+
if (Files.isDirectory(tmpFile) == false) {
319+
throw new IOException("Configured temporary file directory [" + tmpFile + "] is not a directory");
320+
}
321+
}
322+
305323
public static FileStore getFileStore(final Path path) throws IOException {
306324
return new ESFileStore(Files.getFileStore(path));
307325
}

server/src/test/java/org/elasticsearch/env/EnvironmentTests.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
import org.elasticsearch.common.settings.Settings;
2222
import org.elasticsearch.test.ESTestCase;
2323

24+
import java.io.FileNotFoundException;
2425
import java.io.IOException;
2526
import java.net.URL;
2627
import java.nio.file.Path;
2728

2829
import static org.hamcrest.CoreMatchers.endsWith;
2930
import static org.hamcrest.CoreMatchers.notNullValue;
3031
import static org.hamcrest.CoreMatchers.nullValue;
32+
import static org.hamcrest.CoreMatchers.startsWith;
3133
import static org.hamcrest.Matchers.arrayWithSize;
3234
import static org.hamcrest.Matchers.containsString;
3335
import static org.hamcrest.Matchers.equalTo;
@@ -37,11 +39,11 @@
3739
* Simple unit-tests for Environment.java
3840
*/
3941
public class EnvironmentTests extends ESTestCase {
40-
public Environment newEnvironment() throws IOException {
42+
public Environment newEnvironment() {
4143
return newEnvironment(Settings.EMPTY);
4244
}
4345

44-
public Environment newEnvironment(Settings settings) throws IOException {
46+
public Environment newEnvironment(Settings settings) {
4547
Settings build = Settings.builder()
4648
.put(settings)
4749
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir().toAbsolutePath())
@@ -146,4 +148,23 @@ public void testNodeDoesNotRequireLocalStorageButHasPathData() {
146148
assertThat(e, hasToString(containsString("node does not require local storage yet path.data is set to [" + pathData + "]")));
147149
}
148150

151+
public void testNonExistentTempPathValidation() {
152+
Settings build = Settings.builder()
153+
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
154+
.build();
155+
Environment environment = new Environment(build, null, createTempDir().resolve("this_does_not_exist"));
156+
FileNotFoundException e = expectThrows(FileNotFoundException.class, environment::validateTmpFile);
157+
assertThat(e.getMessage(), startsWith("Temporary file directory ["));
158+
assertThat(e.getMessage(), endsWith("this_does_not_exist] does not exist or is not accessible"));
159+
}
160+
161+
public void testTempPathValidationWhenRegularFile() throws IOException {
162+
Settings build = Settings.builder()
163+
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
164+
.build();
165+
Environment environment = new Environment(build, null, createTempFile("something", ".test"));
166+
IOException e = expectThrows(IOException.class, environment::validateTmpFile);
167+
assertThat(e.getMessage(), startsWith("Configured temporary file directory ["));
168+
assertThat(e.getMessage(), endsWith(".test] is not a directory"));
169+
}
149170
}

0 commit comments

Comments
 (0)