Skip to content

Commit 836e171

Browse files
committed
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.
1 parent 1fb836a commit 836e171

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

distribution/docker/src/docker/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ RUN ${package_manager} update --setopt=tsflags=nodocs -y && \\
134134
135135
<% } else if (docker_base == "default") { %>
136136
137-
RUN <%= retry.loop(
137+
# Change default shell to bash, then install required packages with retries.
138+
RUN yes no | dpkg-reconfigure dash && \\
139+
<%= retry.loop(
138140
package_manager,
139141
"export DEBIAN_FRONTEND=noninteractive && \n" +
140142
" ${package_manager} update && \n" +

docs/changelog/81828.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 81828
2+
summary: Change default shell to bash in default Docker image
3+
area: Packaging
4+
type: bug
5+
issues: []

qa/os/src/test/java/org/elasticsearch/packaging/test/DockerTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.elasticsearch.packaging.util.Shell;
1919
import org.elasticsearch.packaging.util.Shell.Result;
2020
import org.elasticsearch.packaging.util.docker.DockerRun;
21+
import org.elasticsearch.packaging.util.docker.DockerShell;
2122
import org.elasticsearch.packaging.util.docker.MockServer;
2223
import org.junit.After;
2324
import org.junit.Before;
@@ -993,6 +994,19 @@ public void test160CheckImageHealthcheckDefinition() throws Exception {
993994
}
994995
}
995996

997+
/**
998+
* Ensure that the default shell in the image is {@code bash}, since some alternatives e.g. {@code dash}
999+
* are stricter about environment variable names.
1000+
*/
1001+
public void test170DefaultShellIsBash() {
1002+
final Result result = DockerShell.executeCommand("/bin/sh", "-c", "echo $SHELL");
1003+
if (result.isSuccess()) {
1004+
assertThat(result.stdout, equalTo("/bin/bash"));
1005+
} else {
1006+
throw new RuntimeException("Command failed: " + result.stderr);
1007+
}
1008+
}
1009+
9961010
/**
9971011
* Check that the UBI images has the correct license information in the correct place.
9981012
*/

qa/os/src/test/java/org/elasticsearch/packaging/util/docker/DockerShell.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@
88

99
package org.elasticsearch.packaging.util.docker;
1010

11+
import org.elasticsearch.common.util.ArrayUtils;
1112
import org.elasticsearch.packaging.util.Shell;
1213

14+
import java.io.ByteArrayOutputStream;
15+
import java.io.IOException;
16+
import java.io.InputStream;
17+
import java.nio.charset.StandardCharsets;
1318
import java.util.ArrayList;
1419
import java.util.List;
1520

@@ -64,4 +69,43 @@ public Result run(String script) {
6469
throw e;
6570
}
6671
}
72+
73+
/**
74+
* Execute a command inside the Docker container, but without invoking a local shell. The caller
75+
* is entirely responsible for correctly escaping command arguments, or for invoking a shell
76+
* inside the container if required.
77+
* @param args the command and arguments to execute inside the container
78+
* @return the result of executing the command
79+
*/
80+
public static Shell.Result executeCommand(String... args) {
81+
assert Docker.containerId != null;
82+
83+
final String[] prefix = new String[] { "docker", "exec", "--tty", Docker.containerId };
84+
final String[] command = ArrayUtils.concat(prefix, args);
85+
final ProcessBuilder pb = new ProcessBuilder(command);
86+
87+
final Process p;
88+
final int exitCode;
89+
final String stdout;
90+
final String stderr;
91+
try {
92+
p = pb.start();
93+
exitCode = p.waitFor();
94+
stdout = readFully(p.getInputStream()).trim();
95+
stderr = readFully(p.getErrorStream()).trim();
96+
} catch (Exception e) {
97+
throw new RuntimeException(e);
98+
}
99+
100+
return new Shell.Result(exitCode, stdout, stderr);
101+
}
102+
103+
private static String readFully(InputStream inputStream) throws IOException {
104+
ByteArrayOutputStream result = new ByteArrayOutputStream();
105+
byte[] buffer = new byte[1024];
106+
for (int length; (length = inputStream.read(buffer)) != -1;) {
107+
result.write(buffer, 0, length);
108+
}
109+
return result.toString(StandardCharsets.UTF_8.name());
110+
}
67111
}

0 commit comments

Comments
 (0)