diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveTests.java b/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveTests.java index 0f3a150ad12ef..c6998ffe99fc7 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveTests.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/test/ArchiveTests.java @@ -138,7 +138,7 @@ public void test50StartAndStop() throws Exception { rm(installation.config("elasticsearch.keystore")); try { - Archives.runElasticsearch(installation, sh); + startElasticsearch(); } catch (Exception e ){ if (Files.exists(installation.home.resolve("elasticsearch.pid"))) { String pid = FileUtils.slurp(installation.home.resolve("elasticsearch.pid")).trim(); @@ -155,7 +155,7 @@ public void test50StartAndStop() throws Exception { assertTrue("gc logs exist", Files.exists(installation.logs.resolve(gcLogName))); ServerUtils.runElasticsearchTests(); - Archives.stopElasticsearch(installation); + stopElasticsearch(); } public void test51JavaHomeOverride() throws Exception { @@ -168,9 +168,9 @@ public void test51JavaHomeOverride() throws Exception { sh.getEnv().put("JAVA_HOME", systemJavaHome1); }); - Archives.runElasticsearch(installation, sh); + startElasticsearch(); ServerUtils.runElasticsearchTests(); - Archives.stopElasticsearch(installation); + stopElasticsearch(); String systemJavaHome1 = sh.getEnv().get("JAVA_HOME"); assertThat(FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz"), @@ -192,9 +192,9 @@ public void test52BundledJdkRemoved() throws Exception { sh.getEnv().put("JAVA_HOME", systemJavaHome1); }); - Archives.runElasticsearch(installation, sh); + startElasticsearch(); ServerUtils.runElasticsearchTests(); - Archives.stopElasticsearch(installation); + stopElasticsearch(); String systemJavaHome1 = sh.getEnv().get("JAVA_HOME"); assertThat(FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz"), @@ -215,9 +215,9 @@ public void test53JavaHomeWithSpecialCharacters() throws Exception { sh.getEnv().put("JAVA_HOME", "C:\\Program Files (x86)\\java"); //verify ES can start, stop and run plugin list - Archives.runElasticsearch(installation, sh); + startElasticsearch(); - Archives.stopElasticsearch(installation); + stopElasticsearch(); String pluginListCommand = installation.bin + "/elasticsearch-plugin list"; Result result = sh.run(pluginListCommand); @@ -241,9 +241,9 @@ public void test53JavaHomeWithSpecialCharacters() throws Exception { sh.getEnv().put("JAVA_HOME", testJavaHome); //verify ES can start, stop and run plugin list - Archives.runElasticsearch(installation, sh); + startElasticsearch(); - Archives.stopElasticsearch(installation); + stopElasticsearch(); String pluginListCommand = installation.bin + "/elasticsearch-plugin list"; Result result = sh.run(pluginListCommand); @@ -288,13 +288,12 @@ public void test70CustomPathConfAndJvmOptions() throws Exception { "-Dlog4j2.disable.jmx=true\n"; append(tempConf.resolve("jvm.options"), jvmOptions); - final Shell sh = newShell(); sh.chown(tempConf); sh.getEnv().put("ES_PATH_CONF", tempConf.toString()); sh.getEnv().put("ES_JAVA_OPTS", "-XX:-UseCompressedOops"); - Archives.runElasticsearch(installation, sh); + startElasticsearch(); final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes")); assertThat(nodesResponse, containsString("\"heap_init_in_bytes\":536870912")); @@ -322,17 +321,16 @@ public void test80RelativePathConf() throws Exception { append(tempConf.resolve("elasticsearch.yml"), "node.name: relative"); - final Shell sh = newShell(); sh.chown(temp); sh.setWorkingDirectory(temp); sh.getEnv().put("ES_PATH_CONF", "config"); - Archives.runElasticsearch(installation, sh); + startElasticsearch(); final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes")); assertThat(nodesResponse, containsString("\"name\":\"relative\"")); - Archives.stopElasticsearch(installation); + stopElasticsearch(); } finally { rm(tempConf); @@ -397,7 +395,7 @@ public void test93ElasticsearchNodeCustomDataPathAndNotEsHomeWorkDir() throws Ex sh.setWorkingDirectory(getTempDir()); - Archives.runElasticsearch(installation, sh); + startElasticsearch(); Archives.stopElasticsearch(installation); Result result = sh.run("echo y | " + installation.executables().elasticsearchNode + " unsafe-bootstrap"); diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/test/PackageTests.java b/qa/os/src/test/java/org/elasticsearch/packaging/test/PackageTests.java index 4aa9e0d0e0ae3..f7c7673c4ad84 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/test/PackageTests.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/test/PackageTests.java @@ -50,9 +50,6 @@ import static org.elasticsearch.packaging.util.Packages.installPackage; import static org.elasticsearch.packaging.util.Packages.remove; import static org.elasticsearch.packaging.util.Packages.restartElasticsearch; -import static org.elasticsearch.packaging.util.Packages.startElasticsearch; -import static org.elasticsearch.packaging.util.Packages.startElasticsearchIgnoringFailure; -import static org.elasticsearch.packaging.util.Packages.stopElasticsearch; import static org.elasticsearch.packaging.util.Packages.verifyPackageInstallation; import static org.elasticsearch.packaging.util.Platforms.getOsRelease; import static org.elasticsearch.packaging.util.Platforms.isSystemd; @@ -101,9 +98,9 @@ private void assertRunsWithJavaHome() throws Exception { try { Files.write(installation.envFile, ("JAVA_HOME=" + systemJavaHome + "\n").getBytes(StandardCharsets.UTF_8), StandardOpenOption.APPEND); - startElasticsearch(sh, installation); + startElasticsearch(); runElasticsearchTests(); - stopElasticsearch(sh); + stopElasticsearch(); } finally { Files.write(installation.envFile, originalEnvFile); } @@ -129,9 +126,9 @@ public void test33RunsIfJavaNotOnPath() throws Exception { } try { - startElasticsearch(sh, installation); + startElasticsearch(); runElasticsearchTests(); - stopElasticsearch(sh); + stopElasticsearch(); } finally { if (Files.exists(Paths.get(backupPath))) { sh.run("sudo mv " + backupPath + " /usr/bin/java"); @@ -153,7 +150,7 @@ public void test42BundledJdkRemoved() throws Exception { public void test40StartServer() throws Exception { String start = sh.runIgnoreExitCode("date ").stdout.trim(); - startElasticsearch(sh, installation); + startElasticsearch(); String journalEntries = sh.runIgnoreExitCode("journalctl _SYSTEMD_UNIT=elasticsearch.service " + "--since \"" + start + "\" --output cat | grep -v \"future versions of Elasticsearch will require Java 11\" | wc -l") @@ -219,7 +216,7 @@ public void test50Remove() throws Exception { } public void test60Reinstall() throws Exception { - installation = installPackage(distribution()); + install(); assertInstalled(distribution()); verifyPackageInstallation(installation, distribution(), sh); @@ -229,13 +226,13 @@ public void test60Reinstall() throws Exception { public void test70RestartServer() throws Exception { try { - installation = installPackage(distribution()); + install(); assertInstalled(distribution()); - startElasticsearch(sh, installation); + startElasticsearch(); restartElasticsearch(sh, installation); runElasticsearchTests(); - stopElasticsearch(sh); + stopElasticsearch(); } finally { cleanup(); } @@ -244,22 +241,22 @@ public void test70RestartServer() throws Exception { public void test72TestRuntimeDirectory() throws Exception { try { - installation = installPackage(distribution()); + install(); FileUtils.rm(installation.pidDir); - startElasticsearch(sh, installation); + startElasticsearch(); assertPathsExist(installation.pidDir); - stopElasticsearch(sh); + stopElasticsearch(); } finally { cleanup(); } } public void test73gcLogsExist() throws Exception { - installation = installPackage(distribution()); - startElasticsearch(sh, installation); + install(); + startElasticsearch(); // it can be gc.log or gc.log.0.current assertThat(installation.logs, fileWithGlobExist("gc.log*")); - stopElasticsearch(sh); + stopElasticsearch(); } // TEST CASES FOR SYSTEMD ONLY @@ -278,26 +275,26 @@ public void test80DeletePID_DIRandRestart() throws Exception { sh.run("systemd-tmpfiles --create"); - startElasticsearch(sh, installation); + startElasticsearch(); final Path pidFile = installation.pidDir.resolve("elasticsearch.pid"); assertTrue(Files.exists(pidFile)); - stopElasticsearch(sh); + stopElasticsearch(); } public void test81CustomPathConfAndJvmOptions() throws Exception { withCustomConfig(tempConf -> { append(installation.envFile, "ES_JAVA_OPTS=-XX:-UseCompressedOops"); - startElasticsearch(sh, installation); + startElasticsearch(); final String nodesResponse = makeRequest(Request.Get("http://localhost:9200/_nodes")); assertThat(nodesResponse, containsString("\"heap_init_in_bytes\":536870912")); assertThat(nodesResponse, containsString("\"using_compressed_ordinary_object_pointers\":\"false\"")); - stopElasticsearch(sh); + stopElasticsearch(); }); } @@ -307,7 +304,7 @@ public void test82SystemdMask() throws Exception { sh.run("systemctl mask systemd-sysctl.service"); - installation = installPackage(distribution()); + install(); sh.run("systemctl unmask systemd-sysctl.service"); } finally { @@ -319,9 +316,9 @@ public void test83serviceFileSetsLimits() throws Exception { // Limits are changed on systemd platforms only assumeTrue(isSystemd()); - installation = installPackage(distribution()); + install(); - startElasticsearch(sh, installation); + startElasticsearch(); final Path pidFile = installation.pidDir.resolve("elasticsearch.pid"); assertTrue(Files.exists(pidFile)); @@ -338,7 +335,7 @@ public void test83serviceFileSetsLimits() throws Exception { String maxAddressSpace = sh.run("cat /proc/%s/limits | grep \"Max address space\" | awk '{ print $4 }'", pid).stdout.trim(); assertThat(maxAddressSpace, equalTo("unlimited")); - stopElasticsearch(sh); + stopElasticsearch(); } public void test90DoNotCloseStderrWhenQuiet() throws Exception { @@ -348,7 +345,7 @@ public void test90DoNotCloseStderrWhenQuiet() throws Exception { // Make sure we don't pick up the journal entries for previous ES instances. clearJournal(sh); - startElasticsearchIgnoringFailure(sh); + runElasticsearchStartCommand(); final Result logs = sh.run("journalctl -u elasticsearch.service"); @@ -366,7 +363,7 @@ private void withCustomConfig(CustomConfigConsumer pathConsumer) throws Exceptio assertPathsExist(installation.envFile); - stopElasticsearch(sh); + stopElasticsearch(); // The custom config directory is not under /tmp or /var/tmp because // systemd's private temp directory functionally means different diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java b/qa/os/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java index cb95408b2a5bf..f797d8d49684a 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/test/PackagingTestCase.java @@ -48,6 +48,8 @@ import java.nio.file.Paths; import static org.elasticsearch.packaging.util.Cleanup.cleanEverything; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; @@ -139,6 +141,9 @@ protected static void install() throws Exception { case DOCKER: installation = Docker.runContainer(distribution); Docker.verifyContainerInstallation(installation, distribution); + break; + default: + throw new IllegalStateException("Unknown Elasticsearch packaging type."); } } @@ -147,19 +152,7 @@ protected static void install() throws Exception { */ protected void assertWhileRunning(Platforms.PlatformAction assertions) throws Exception { try { - switch (distribution.packaging) { - case TAR: - case ZIP: - Archives.runElasticsearch(installation, sh); - break; - case DEB: - case RPM: - Packages.startElasticsearch(sh, installation); - break; - case DOCKER: - // nothing, "installing" docker image is running it - } - + awaitElasticsearchStartup(runElasticsearchStartCommand()); } catch (Exception e ){ if (Files.exists(installation.home.resolve("elasticsearch.pid"))) { String pid = FileUtils.slurp(installation.home.resolve("elasticsearch.pid")).trim(); @@ -180,7 +173,46 @@ protected void assertWhileRunning(Platforms.PlatformAction assertions) throws Ex FileUtils.slurpAllLogs(installation.logs, "elasticsearch.log", "*.log.gz")); throw e; } + stopElasticsearch(); + } + + protected static Shell newShell() throws Exception { + Shell sh = new Shell(); + if (distribution().hasJdk == false) { + Platforms.onLinux(() -> { + sh.getEnv().put("JAVA_HOME", systemJavaHome); + }); + Platforms.onWindows(() -> { + sh.getEnv().put("JAVA_HOME", systemJavaHome); + }); + } + return sh; + } + /** + * Run the command to start Elasticsearch, but don't wait or test for success. + * This method is useful for testing failure conditions in startup. To await success, + * use {@link #startElasticsearch()}. + * @return Shell results of the startup command. + * @throws Exception when command fails immediately. + */ + public Shell.Result runElasticsearchStartCommand() throws Exception { + switch (distribution.packaging) { + case TAR: + case ZIP: + return Archives.runElasticsearchStartCommand(installation, sh); + case DEB: + case RPM: + return Packages.runElasticsearchStartCommand(sh); + case DOCKER: + // nothing, "installing" docker image is running it + return Shell.NO_OP; + default: + throw new IllegalStateException("Unknown Elasticsearch packaging type."); + } + } + + public void stopElasticsearch() throws Exception { switch (distribution.packaging) { case TAR: case ZIP: @@ -191,20 +223,74 @@ protected void assertWhileRunning(Platforms.PlatformAction assertions) throws Ex Packages.stopElasticsearch(sh); break; case DOCKER: - // nothing, removing container is handled externally + // nothing, "installing" docker image is running it + break; + default: + throw new IllegalStateException("Unknown Elasticsearch packaging type."); } } - protected static Shell newShell() throws Exception { - Shell sh = new Shell(); - if (distribution().hasJdk == false) { - Platforms.onLinux(() -> { - sh.getEnv().put("JAVA_HOME", systemJavaHome); - }); - Platforms.onWindows(() -> { - sh.getEnv().put("JAVA_HOME", systemJavaHome); - }); + public void awaitElasticsearchStartup(Shell.Result result) throws Exception { + assertThat("Startup command should succeed", result.exitCode, equalTo(0)); + switch (distribution.packaging) { + case TAR: + case ZIP: + Archives.assertElasticsearchStarted(installation); + break; + case DEB: + case RPM: + Packages.assertElasticsearchStarted(sh, installation); + break; + case DOCKER: + Docker.waitForElasticsearchToStart(); + break; + default: + throw new IllegalStateException("Unknown Elasticsearch packaging type."); + } + } + + /** + * Start Elasticsearch and wait until it's up and running. If you just want to run + * the start command, use {@link #runElasticsearchStartCommand()}. + * @throws Exception if Elasticsearch can't start + */ + public void startElasticsearch() throws Exception { + awaitElasticsearchStartup(runElasticsearchStartCommand()); + } + + public void assertElasticsearchFailure(Shell.Result result, String expectedMessage) { + + if (Files.exists(installation.logs.resolve("elasticsearch.log"))) { + + // If log file exists, then we have bootstrapped our logging and the + // error should be in the logs + assertTrue("log file exists", Files.exists(installation.logs.resolve("elasticsearch.log"))); + String logfile = FileUtils.slurp(installation.logs.resolve("elasticsearch.log")); + assertThat(logfile, containsString(expectedMessage)); + + } else if (distribution().isPackage() && Platforms.isSystemd()) { + + // For systemd, retrieve the error from journalctl + assertThat(result.stderr, containsString("Job for elasticsearch.service failed")); + Shell.Result error = sh.run("journalctl --boot --unit elasticsearch.service"); + assertThat(error.stdout, containsString(expectedMessage)); + + } else if (Platforms.WINDOWS == true) { + + // In Windows, we have written our stdout and stderr to files in order to run + // in the background + String wrapperPid = result.stdout.trim(); + sh.runIgnoreExitCode("Wait-Process -Timeout " + Archives.ES_STARTUP_SLEEP_TIME_SECONDS + " -Id " + wrapperPid); + sh.runIgnoreExitCode("Get-EventSubscriber | " + + "where {($_.EventName -eq 'OutputDataReceived' -Or $_.EventName -eq 'ErrorDataReceived' |" + + "Unregister-EventSubscriber -Force"); + assertThat(FileUtils.slurp(Archives.getPowershellErrorPath(installation)), containsString(expectedMessage)); + + } else { + + // Otherwise, error should be on shell stderr + assertThat(result.stderr, containsString(expectedMessage)); + } - return sh; } } diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/util/Archives.java b/qa/os/src/test/java/org/elasticsearch/packaging/util/Archives.java index fa5e6bea592ef..c13a45d98a07d 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/util/Archives.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/util/Archives.java @@ -43,7 +43,7 @@ import static org.elasticsearch.packaging.util.FileUtils.slurp; import static org.elasticsearch.packaging.util.Platforms.isDPKG; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.collection.IsEmptyCollection.empty; import static org.hamcrest.core.Is.is; @@ -63,6 +63,10 @@ public class Archives { ? System.getenv("username") : "elasticsearch"; + /** This is an arbitrarily chosen value that gives Elasticsearch time to log Bootstrap + * errors to the console if they occur before the logging framework is initialized. */ + public static final String ES_STARTUP_SLEEP_TIME_SECONDS = "10"; + public static Installation installArchive(Distribution distribution) throws Exception { return installArchive(distribution, getDefaultArchiveInstallPath(), getCurrentVersion()); } @@ -243,89 +247,109 @@ private static void verifyDefaultInstallation(Installation es, Distribution dist ).forEach(configFile -> assertThat(es.config(configFile), file(File, owner, owner, p660))); } - public static void runElasticsearch(Installation installation, Shell sh) throws Exception { + public static Shell.Result runElasticsearchStartCommand(Installation installation, Shell sh) { final Path pidFile = installation.home.resolve("elasticsearch.pid"); assertFalse("Pid file doesn't exist when starting Elasticsearch", Files.exists(pidFile)); final Installation.Executables bin = installation.executables(); - Platforms.onLinux(() -> { + if (Platforms.WINDOWS == false) { // If jayatana is installed then we try to use it. Elasticsearch should ignore it even when we try. // If it doesn't ignore it then Elasticsearch will fail to start because of security errors. // This line is attempting to emulate the on login behavior of /usr/share/upstart/sessions/jayatana.conf if (Files.exists(Paths.get("/usr/share/java/jayatanaag.jar"))) { sh.getEnv().put("JAVA_TOOL_OPTIONS", "-javaagent:/usr/share/java/jayatanaag.jar"); } - sh.run("sudo -E -u " + ARCHIVE_OWNER + " " + - bin.elasticsearch + " -d -p " + installation.home.resolve("elasticsearch.pid")); - }); - Platforms.onWindows(() -> { - // this starts the server in the background. the -d flag is unsupported on windows - if (System.getenv("username").equals("vagrant")) { - // these tests run as Administrator in vagrant. - // we don't want to run the server as Administrator, so we provide the current user's - // username and password to the process which has the effect of starting it not as Administrator. - sh.run( - "$password = ConvertTo-SecureString 'vagrant' -AsPlainText -Force; " + - "$processInfo = New-Object System.Diagnostics.ProcessStartInfo; " + - "$processInfo.FileName = '" + bin.elasticsearch + "'; " + - "$processInfo.Arguments = '-p " + installation.home.resolve("elasticsearch.pid") + "'; " + - "$processInfo.Username = 'vagrant'; " + - "$processInfo.Password = $password; " + - "$processInfo.RedirectStandardOutput = $true; " + - "$processInfo.RedirectStandardError = $true; " + - sh.env.entrySet().stream() - .map(entry -> "$processInfo.Environment.Add('" + entry.getKey() + "', '" + entry.getValue() + "'); ") - .collect(joining()) + - "$processInfo.UseShellExecute = $false; " + - "$process = New-Object System.Diagnostics.Process; " + - "$process.StartInfo = $processInfo; " + - "$process.Start() | Out-Null; " + - "$process.Id;" - ); - } else { - sh.run( - "$processInfo = New-Object System.Diagnostics.ProcessStartInfo; " + - "$processInfo.FileName = '" + bin.elasticsearch + "'; " + - "$processInfo.Arguments = '-p " + installation.home.resolve("elasticsearch.pid") + "'; " + - "$processInfo.RedirectStandardOutput = $true; " + - "$processInfo.RedirectStandardError = $true; " + - sh.env.entrySet().stream() - .map(entry -> "$processInfo.Environment.Add('" + entry.getKey() + "', '" + entry.getValue() + "'); ") - .collect(joining()) + - "$processInfo.UseShellExecute = $false; " + - "$process = New-Object System.Diagnostics.Process; " + - "$process.StartInfo = $processInfo; " + - "$process.Start() | Out-Null; " + - "$process.Id;" - ); - } - }); + // We need to give Elasticsearch enough time to print failures to stderr before exiting + sh.getEnv().put("ES_STARTUP_SLEEP_TIME", ES_STARTUP_SLEEP_TIME_SECONDS); + return sh.runIgnoreExitCode("sudo -E -u " + ARCHIVE_OWNER + " " + bin.elasticsearch + " -d -p " + pidFile); + } + final Path stdout = getPowershellOutputPath(installation); + final Path stderr = getPowershellErrorPath(installation); + + String powerShellProcessUserSetup; + if (System.getenv("username").equals("vagrant")) { + // the tests will run as Administrator in vagrant. + // we don't want to run the server as Administrator, so we provide the current user's + // username and password to the process which has the effect of starting it not as Administrator. + powerShellProcessUserSetup = + "$password = ConvertTo-SecureString 'vagrant' -AsPlainText -Force; " + + "$processInfo.Username = 'vagrant'; " + + "$processInfo.Password = $password; "; + } else { + powerShellProcessUserSetup = ""; + } + + // this starts the server in the background. the -d flag is unsupported on windows + return sh.run( + "$processInfo = New-Object System.Diagnostics.ProcessStartInfo; " + + "$processInfo.FileName = '" + bin.elasticsearch + "'; " + + "$processInfo.Arguments = '-p " + installation.home.resolve("elasticsearch.pid") + "'; " + + powerShellProcessUserSetup + + "$processInfo.RedirectStandardOutput = $true; " + + "$processInfo.RedirectStandardError = $true; " + + "$processInfo.RedirectStandardInput = $true; " + + sh.env.entrySet().stream() + .map(entry -> "$processInfo.Environment.Add('" + entry.getKey() + "', '" + entry.getValue() + "'); ") + .collect(joining()) + + "$processInfo.UseShellExecute = $false; " + + "$process = New-Object System.Diagnostics.Process; " + + "$process.StartInfo = $processInfo; " + + + // set up some asynchronous output handlers + "$outScript = { $EventArgs.Data | Out-File -Encoding UTF8 -Append '" + stdout + "' }; " + + "$errScript = { $EventArgs.Data | Out-File -Encoding UTF8 -Append '" + stderr + "' }; " + + "$stdOutEvent = Register-ObjectEvent -InputObject $process " + + "-Action $outScript -EventName 'OutputDataReceived'; " + + "$stdErrEvent = Register-ObjectEvent -InputObject $process " + + "-Action $errScript -EventName 'ErrorDataReceived'; " + + + "$process.Start() | Out-Null; " + + "$process.BeginOutputReadLine(); " + + "$process.BeginErrorReadLine(); " + + "Wait-Process -Timeout " + ES_STARTUP_SLEEP_TIME_SECONDS + " -Id $process.Id; " + + "$process.Id;" + ); + } + public static void assertElasticsearchStarted(Installation installation) throws Exception { + final Path pidFile = installation.home.resolve("elasticsearch.pid"); ServerUtils.waitForElasticsearch(installation); assertTrue("Starting Elasticsearch produced a pid file at " + pidFile, Files.exists(pidFile)); String pid = slurp(pidFile).trim(); - assertThat(pid, not(isEmptyOrNullString())); - - Platforms.onLinux(() -> sh.run("ps " + pid)); - Platforms.onWindows(() -> sh.run("Get-Process -Id " + pid)); + assertThat(pid, is(not(emptyOrNullString()))); } public static void stopElasticsearch(Installation installation) throws Exception { Path pidFile = installation.home.resolve("elasticsearch.pid"); - assertTrue(Files.exists(pidFile)); + assertTrue("pid file should exist", Files.exists(pidFile)); String pid = slurp(pidFile).trim(); - assertThat(pid, not(isEmptyOrNullString())); + assertThat(pid, is(not(emptyOrNullString()))); final Shell sh = new Shell(); Platforms.onLinux(() -> sh.run("kill -SIGTERM " + pid + "; tail --pid=" + pid + " -f /dev/null")); - Platforms.onWindows(() -> sh.run("Get-Process -Id " + pid + " | Stop-Process -Force; Wait-Process -Id " + pid)); + Platforms.onWindows(() -> { + sh.run("Get-Process -Id " + pid + " | Stop-Process -Force; Wait-Process -Id " + pid); + + // Clear the asynchronous event handlers + sh.runIgnoreExitCode("Get-EventSubscriber | " + + "where {($_.EventName -eq 'OutputDataReceived' -Or $_.EventName -eq 'ErrorDataReceived' |" + + "Unregister-EventSubscriber -Force"); + }); if (Files.exists(pidFile)) { Files.delete(pidFile); } } + public static Path getPowershellErrorPath(Installation installation) { + return installation.logs.resolve("output.err"); + } + + private static Path getPowershellOutputPath(Installation installation) { + return installation.logs.resolve("output.out"); + } + } diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java b/qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java index e44e3f7eb78db..2f41fbc46da47 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java @@ -166,7 +166,7 @@ private static void executeDockerRun(Distribution distribution, Map * Waits for the Elasticsearch process to start executing in the container. * This is called every time a container is started. */ - private static void waitForElasticsearchToStart() { + public static void waitForElasticsearchToStart() { boolean isElasticsearchRunning = false; int attempt = 0; diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/util/Packages.java b/qa/os/src/test/java/org/elasticsearch/packaging/util/Packages.java index 020ee7df4894c..cd64ecec53f87 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/util/Packages.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/util/Packages.java @@ -268,32 +268,17 @@ private static void verifyDefaultInstallation(Installation es) { ).forEach(configFile -> assertThat(es.config(configFile), file(File, "root", "elasticsearch", p660))); } - public static void startElasticsearch(Shell sh, Installation installation) throws IOException { + /** + * Starts Elasticsearch, without checking that startup is successful. + */ + public static Shell.Result runElasticsearchStartCommand(Shell sh) throws IOException { if (isSystemd()) { sh.run("systemctl daemon-reload"); sh.run("systemctl enable elasticsearch.service"); sh.run("systemctl is-enabled elasticsearch.service"); - sh.run("systemctl start elasticsearch.service"); - } else { - sh.run("service elasticsearch start"); - } - - assertElasticsearchStarted(sh, installation); - } - - /** - * Starts Elasticsearch, without checking that startup is successful. To also check - * that Elasticsearch has started, call {@link #startElasticsearch(Shell, Installation)}. - */ - public static void startElasticsearchIgnoringFailure(Shell sh) { - if (isSystemd()) { - sh.runIgnoreExitCode("systemctl daemon-reload"); - sh.runIgnoreExitCode("systemctl enable elasticsearch.service"); - sh.runIgnoreExitCode("systemctl is-enabled elasticsearch.service"); - sh.runIgnoreExitCode("systemctl start elasticsearch.service"); - } else { - sh.runIgnoreExitCode("service elasticsearch start"); + return sh.runIgnoreExitCode("systemctl start elasticsearch.service"); } + return sh.runIgnoreExitCode("service elasticsearch start"); } /** @@ -307,7 +292,7 @@ public static void clearJournal(Shell sh) { } } - private static void assertElasticsearchStarted(Shell sh, Installation installation) throws IOException { + public static void assertElasticsearchStarted(Shell sh, Installation installation) throws IOException { waitForElasticsearch(installation); if (isSystemd()) { @@ -332,7 +317,6 @@ public static void restartElasticsearch(Shell sh, Installation installation) thr } else { sh.run("service elasticsearch restart"); } - - waitForElasticsearch(installation); + assertElasticsearchStarted(sh, installation); } } diff --git a/qa/os/src/test/java/org/elasticsearch/packaging/util/Shell.java b/qa/os/src/test/java/org/elasticsearch/packaging/util/Shell.java index 55488522797c1..bbcbcd1b1d498 100644 --- a/qa/os/src/test/java/org/elasticsearch/packaging/util/Shell.java +++ b/qa/os/src/test/java/org/elasticsearch/packaging/util/Shell.java @@ -43,6 +43,7 @@ public class Shell { public static final int TAIL_WHEN_TOO_MUCH_OUTPUT = 1000; + public static final Result NO_OP = new Shell.Result(0, "",""); protected final Logger logger = LogManager.getLogger(getClass()); final Map env = new HashMap<>();