Skip to content

Commit 42dc870

Browse files
authored
Ensure logs dir exists before using as working dir (#126566)
With the change to using the logs dir as the working dir of the Elasticsearch process we need to ensure the logs dir exists within the CLI instead of later during startup. relates #124966
1 parent 7e62862 commit 42dc870

File tree

3 files changed

+46
-25
lines changed

3 files changed

+46
-25
lines changed

Diff for: distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerCli.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,7 @@ protected ServerProcess startServer(Terminal terminal, ProcessInfo processInfo,
271271
.withProcessInfo(processInfo)
272272
.withServerArgs(args)
273273
.withTempDir(tempDir)
274-
.withJvmOptions(jvmOptions)
275-
.withWorkingDir(args.logsDir());
274+
.withJvmOptions(jvmOptions);
276275
return serverProcessBuilder.start();
277276
}
278277

Diff for: distribution/tools/server-cli/src/main/java/org/elasticsearch/server/cli/ServerProcessBuilder.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package org.elasticsearch.server.cli;
1111

1212
import org.elasticsearch.bootstrap.ServerArgs;
13+
import org.elasticsearch.cli.ExitCodes;
1314
import org.elasticsearch.cli.ProcessInfo;
1415
import org.elasticsearch.cli.Terminal;
1516
import org.elasticsearch.cli.UserException;
@@ -21,6 +22,8 @@
2122
import java.io.IOException;
2223
import java.io.OutputStream;
2324
import java.io.UncheckedIOException;
25+
import java.nio.file.FileAlreadyExistsException;
26+
import java.nio.file.Files;
2427
import java.nio.file.Path;
2528
import java.util.HashMap;
2629
import java.util.List;
@@ -44,7 +47,6 @@ public class ServerProcessBuilder {
4447
private ServerArgs serverArgs;
4548
private ProcessInfo processInfo;
4649
private List<String> jvmOptions;
47-
private Path workingDir;
4850
private Terminal terminal;
4951

5052
// this allows mocking the process building by tests
@@ -84,11 +86,6 @@ public ServerProcessBuilder withJvmOptions(List<String> jvmOptions) {
8486
return this;
8587
}
8688

87-
public ServerProcessBuilder withWorkingDir(Path workingDir) {
88-
this.workingDir = workingDir;
89-
return this;
90-
}
91-
9289
/**
9390
* Specifies the {@link Terminal} to use for reading input and writing output from/to the cli console
9491
*/
@@ -141,6 +138,17 @@ public ServerProcess start() throws UserException {
141138
return start(ProcessBuilder::start);
142139
}
143140

141+
private void ensureWorkingDirExists() throws UserException {
142+
Path workingDir = serverArgs.logsDir();
143+
try {
144+
Files.createDirectories(workingDir);
145+
} catch (FileAlreadyExistsException e) {
146+
throw new UserException(ExitCodes.CONFIG, "Logs dir [" + workingDir + "] exists but is not a directory", e);
147+
} catch (IOException e) {
148+
throw new UserException(ExitCodes.CONFIG, "Unable to create logs dir [" + workingDir + "]", e);
149+
}
150+
}
151+
144152
private static void checkRequiredArgument(Object argument, String argumentName) {
145153
if (argument == null) {
146154
throw new IllegalStateException(
@@ -157,12 +165,14 @@ ServerProcess start(ProcessStarter processStarter) throws UserException {
157165
checkRequiredArgument(jvmOptions, "jvmOptions");
158166
checkRequiredArgument(terminal, "terminal");
159167

168+
ensureWorkingDirExists();
169+
160170
Process jvmProcess = null;
161171
ErrorPumpThread errorPump;
162172

163173
boolean success = false;
164174
try {
165-
jvmProcess = createProcess(getCommand(), getJvmArgs(), jvmOptions, getEnvironment(), workingDir, processStarter);
175+
jvmProcess = createProcess(getCommand(), getJvmArgs(), jvmOptions, getEnvironment(), serverArgs.logsDir(), processStarter);
166176
errorPump = new ErrorPumpThread(terminal, jvmProcess.getErrorStream());
167177
errorPump.start();
168178
sendArgs(serverArgs, jvmProcess.getOutputStream());

Diff for: distribution/tools/server-cli/src/test/java/org/elasticsearch/server/cli/ServerProcessTests.java

+28-16
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public class ServerProcessTests extends ESTestCase {
6565
protected final Map<String, String> sysprops = new HashMap<>();
6666
protected final Map<String, String> envVars = new HashMap<>();
6767
Path esHomeDir;
68-
Path workingDir;
68+
Path logsDir;
6969
Settings.Builder nodeSettings;
7070
ProcessValidator processValidator;
7171
MainMethod mainCallback;
@@ -94,8 +94,8 @@ public void resetEnv() {
9494
sysprops.put("os.name", "Linux");
9595
sysprops.put("java.home", "javahome");
9696
sysprops.put("es.path.home", esHomeDir.toString());
97+
logsDir = esHomeDir.resolve("logs");
9798
envVars.clear();
98-
workingDir = createTempDir();
9999
nodeSettings = Settings.builder();
100100
processValidator = null;
101101
mainCallback = null;
@@ -207,15 +207,7 @@ ProcessInfo createProcessInfo() {
207207
}
208208

209209
ServerArgs createServerArgs(boolean daemonize, boolean quiet) {
210-
return new ServerArgs(
211-
daemonize,
212-
quiet,
213-
null,
214-
secrets,
215-
nodeSettings.build(),
216-
esHomeDir.resolve("config"),
217-
esHomeDir.resolve("logs")
218-
);
210+
return new ServerArgs(daemonize, quiet, null, secrets, nodeSettings.build(), esHomeDir.resolve("config"), logsDir);
219211
}
220212

221213
ServerProcess startProcess(boolean daemonize, boolean quiet) throws Exception {
@@ -231,8 +223,7 @@ ServerProcess startProcess(boolean daemonize, boolean quiet) throws Exception {
231223
.withProcessInfo(pinfo)
232224
.withServerArgs(createServerArgs(daemonize, quiet))
233225
.withJvmOptions(List.of())
234-
.withTempDir(ServerProcessUtils.setupTempDir(pinfo))
235-
.withWorkingDir(workingDir);
226+
.withTempDir(ServerProcessUtils.setupTempDir(pinfo));
236227
return serverProcessBuilder.start(starter);
237228
}
238229

@@ -241,7 +232,7 @@ public void testProcessBuilder() throws Exception {
241232
assertThat(pb.redirectInput(), equalTo(ProcessBuilder.Redirect.PIPE));
242233
assertThat(pb.redirectOutput(), equalTo(ProcessBuilder.Redirect.INHERIT));
243234
assertThat(pb.redirectError(), equalTo(ProcessBuilder.Redirect.PIPE));
244-
assertThat(String.valueOf(pb.directory()), equalTo(workingDir.toString())); // leave default, which is working directory
235+
assertThat(String.valueOf(pb.directory()), equalTo(esHomeDir.resolve("logs").toString()));
245236
};
246237
mainCallback = (args, stdin, stderr, exitCode) -> {
247238
try (PrintStream err = new PrintStream(stderr, true, StandardCharsets.UTF_8)) {
@@ -315,8 +306,7 @@ public void testCommandLineSysprops() throws Exception {
315306
.withProcessInfo(createProcessInfo())
316307
.withServerArgs(createServerArgs(false, false))
317308
.withJvmOptions(List.of("-Dfoo1=bar", "-Dfoo2=baz"))
318-
.withTempDir(Path.of("."))
319-
.withWorkingDir(workingDir);
309+
.withTempDir(Path.of("."));
320310
serverProcessBuilder.start(starter).waitFor();
321311
}
322312

@@ -433,4 +423,26 @@ public void testProcessDies() throws Exception {
433423
int exitCode = server.waitFor();
434424
assertThat(exitCode, equalTo(-9));
435425
}
426+
427+
public void testLogsDirIsFile() throws Exception {
428+
Files.createFile(logsDir);
429+
var e = expectThrows(UserException.class, this::runForeground);
430+
assertThat(e.getMessage(), containsString("exists but is not a directory"));
431+
}
432+
433+
public void testLogsDirCreateParents() throws Exception {
434+
Path testDir = createTempDir();
435+
logsDir = testDir.resolve("subdir/logs");
436+
processValidator = pb -> assertThat(String.valueOf(pb.directory()), equalTo(logsDir.toString()));
437+
runForeground();
438+
}
439+
440+
public void testLogsCreateFailure() throws Exception {
441+
Path testDir = createTempDir();
442+
Path parentFile = testDir.resolve("exists");
443+
Files.createFile(parentFile);
444+
logsDir = parentFile.resolve("logs");
445+
var e = expectThrows(UserException.class, this::runForeground);
446+
assertThat(e.getMessage(), containsString("Unable to create logs dir"));
447+
}
436448
}

0 commit comments

Comments
 (0)