Browse Source

Dump container logs on shell command failure (#52316)

The Docker tests framework captures container logs when Elasticsearch
fails to start. However, it doesn't do this if a later shell command
fails. Amend the DockerShell wrapper to capture the container logs if
a command fails when it should succeed.
Rory Hunter 5 years ago
parent
commit
5d74c1f16e

+ 30 - 0
qa/os/src/test/java/org/elasticsearch/packaging/util/Docker.java

@@ -291,6 +291,36 @@ public class Docker {
 
             return super.getScriptCommand("docker exec --user elasticsearch:root --tty " + containerId + " " + script);
         }
+
+        /**
+         * Overrides {@link Shell#run(String)} to attempt to collect Docker container
+         * logs when a command fails to execute successfully.
+         * @param script the command to run
+         * @return the command's output
+         */
+        @Override
+        public Result run(String script) {
+            try {
+                return super.run(script);
+            } catch (ShellException e) {
+                try {
+                    final Shell.Result dockerLogs = getContainerLogs();
+                    logger.error(
+                        "Command [{}] failed.\n\nContainer stdout: [{}]\n\nContainer stderr: [{}]",
+                        script,
+                        dockerLogs.stdout,
+                        dockerLogs.stderr
+                    );
+                } catch (ShellException shellException) {
+                    logger.error(
+                        "Command [{}] failed.\n\nTried to dump container logs but that failed too: [{}]",
+                        script,
+                        shellException.getMessage()
+                    );
+                }
+                throw e;
+            }
+        }
     }
 
     /**

+ 14 - 1
qa/os/src/test/java/org/elasticsearch/packaging/util/Shell.java

@@ -132,7 +132,7 @@ public class Shell {
         logger.warn("Running command with env: " + env);
         Result result = runScriptIgnoreExitCode(command);
         if (result.isSuccess() == false) {
-            throw new RuntimeException("Command was not successful: [" + String.join(" ", command) + "]\n   result: " + result.toString());
+            throw new ShellException("Command was not successful: [" + String.join(" ", command) + "]\n   result: " + result.toString());
         }
         return result;
     }
@@ -266,4 +266,17 @@ public class Shell {
         }
     }
 
+    /**
+     * An exception to model failures to run a shell command. This exists so that calling code can differentiate between
+     * shell / command errors, and other runtime errors.
+     */
+    public static class ShellException extends RuntimeException {
+        public ShellException(String message) {
+            super(message);
+        }
+
+        public ShellException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
 }