Browse Source

Change default shell to bash in default Docker image (#81828)

As a result of changing the base Docker to Ubuntu in #80820, the default shell
i.e. `/bin/sh` changed to `dash`, rather than `bash`, which could impact anyone
invoking `/bin/sh` and expecting it to still propagate environment variables with
periods in their names.

Reconfigure the default shell back to `bash` so that this type of situation works
again.
Rory Hunter 3 years ago
parent
commit
4544196c74

+ 3 - 1
distribution/docker/src/docker/Dockerfile

@@ -191,7 +191,9 @@ RUN ${package_manager} update --setopt=tsflags=nodocs -y && \\
 
 <% } else if (docker_base == "default" || docker_base == "cloud") { %>
 
-RUN <%= retry.loop(
+# Change default shell to bash, then install required packages with retries.
+RUN yes no | dpkg-reconfigure dash && \\
+    <%= retry.loop(
     package_manager,
       "export DEBIAN_FRONTEND=noninteractive && \n" +
       "      ${package_manager} update && \n" +

+ 5 - 0
docs/changelog/81828.yaml

@@ -0,0 +1,5 @@
+pr: 81828
+summary: Change default shell to bash in default Docker image
+area: Packaging
+type: bug
+issues: []

+ 14 - 0
qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java

@@ -20,6 +20,7 @@ import org.elasticsearch.packaging.util.ServerUtils;
 import org.elasticsearch.packaging.util.Shell;
 import org.elasticsearch.packaging.util.Shell.Result;
 import org.elasticsearch.packaging.util.docker.DockerRun;
+import org.elasticsearch.packaging.util.docker.DockerShell;
 import org.elasticsearch.packaging.util.docker.MockServer;
 import org.hamcrest.Matcher;
 import org.junit.After;
@@ -1161,6 +1162,19 @@ public class DockerTests extends PackagingTestCase {
         }
     }
 
+    /**
+     * Ensure that the default shell in the image is {@code bash}, since some alternatives e.g. {@code dash}
+     * are stricter about environment variable names.
+     */
+    public void test170DefaultShellIsBash() {
+        final Result result = DockerShell.executeCommand("/bin/sh", "-c", "echo $SHELL");
+        if (result.isSuccess()) {
+            assertThat(result.stdout, equalTo("/bin/bash"));
+        } else {
+            throw new RuntimeException("Command failed: " + result.stderr);
+        }
+    }
+
     /**
      * Check that the UBI images has the correct license information in the correct place.
      */

+ 32 - 0
qa/os/src/test/java/org/elasticsearch/packaging/util/docker/DockerShell.java

@@ -8,8 +8,10 @@
 
 package org.elasticsearch.packaging.util.docker;
 
+import org.elasticsearch.common.util.ArrayUtils;
 import org.elasticsearch.packaging.util.Shell;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -64,4 +66,34 @@ public class DockerShell extends Shell {
             throw e;
         }
     }
+
+    /**
+     * Execute a command inside the Docker container, but without invoking a local shell. The caller
+     * is entirely responsible for correctly escaping command arguments, or for invoking a shell
+     * inside the container if required.
+     * @param args the command and arguments to execute inside the container
+     * @return the result of executing the command
+     */
+    public static Shell.Result executeCommand(String... args) {
+        assert Docker.containerId != null;
+
+        final String[] prefix = new String[] { "docker", "exec", "--tty", Docker.containerId };
+        final String[] command = ArrayUtils.concat(prefix, args);
+        final ProcessBuilder pb = new ProcessBuilder(command);
+
+        final Process p;
+        final int exitCode;
+        final String stdout;
+        final String stderr;
+        try {
+            p = pb.start();
+            exitCode = p.waitFor();
+            stdout = new String(p.getInputStream().readAllBytes(), StandardCharsets.UTF_8).trim();
+            stderr = new String(p.getErrorStream().readAllBytes(), StandardCharsets.UTF_8).trim();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+
+        return new Shell.Result(exitCode, stdout, stderr);
+    }
 }