11package org .testcontainers .containers ;
22
33import com .github .dockerjava .api .DockerClient ;
4+ import com .github .dockerjava .api .command .ExecCreateCmd ;
45import com .github .dockerjava .api .command .ExecCreateCmdResponse ;
56import com .github .dockerjava .api .command .InspectContainerResponse ;
67import com .github .dockerjava .api .exception .DockerException ;
@@ -45,7 +46,7 @@ public Container.ExecResult execInContainer(
4546 String ... command
4647 ) throws UnsupportedOperationException , IOException , InterruptedException {
4748 DockerClient dockerClient = DockerClientFactory .instance ().client ();
48- return execInContainer (dockerClient , containerInfo , outputCharset , command );
49+ return execInContainerWithUser (dockerClient , containerInfo , outputCharset , null , command );
4950 }
5051
5152 /**
@@ -55,34 +56,77 @@ public Container.ExecResult execInContainer(
5556 * @param dockerClient the {@link DockerClient}
5657 * @param containerInfo the container info
5758 * @param command the command to execute
58- * @see #execInContainer (DockerClient, InspectContainerResponse, Charset , String...)
59+ * @see #execInContainerWithUser (DockerClient, InspectContainerResponse, String , String...)
5960 */
6061 public Container .ExecResult execInContainer (
6162 DockerClient dockerClient ,
6263 InspectContainerResponse containerInfo ,
6364 String ... command
6465 ) throws UnsupportedOperationException , IOException , InterruptedException {
65- return execInContainer (dockerClient , containerInfo , StandardCharsets .UTF_8 , command );
66+ return execInContainerWithUser (dockerClient , containerInfo , StandardCharsets .UTF_8 , null , command );
6667 }
6768
6869 /**
69- * Run a command inside a running container, as though using "docker exec".
70+ * Run a command inside a running container, as though using "docker exec", and interpreting
71+ * the output as UTF8.
72+ * <p></p>
73+ * @param dockerClient the {@link DockerClient}
74+ * @param containerInfo the container info
75+ * @param outputCharset the character set used to interpret the output.
76+ * @param command the command to execute
77+ * @see #execInContainerWithUser(DockerClient, InspectContainerResponse, Charset, String, String...)
78+ */
79+ public Container .ExecResult execInContainer (
80+ DockerClient dockerClient ,
81+ InspectContainerResponse containerInfo ,
82+ Charset outputCharset ,
83+ String ... command
84+ ) throws UnsupportedOperationException , IOException , InterruptedException {
85+ return execInContainerWithUser (dockerClient , containerInfo , outputCharset , null , command );
86+ }
87+
88+ /**
89+ * Run a command inside a running container as a given user, as using "docker exec -u user" and
90+ * interpreting the output as UTF8.
7091 * <p>
7192 * This functionality is not available on a docker daemon running the older "lxc" execution driver. At
7293 * the time of writing, CircleCI was using this driver.
7394 * @param dockerClient the {@link DockerClient}
7495 * @param containerInfo the container info
96+ * @param user the user to run the command with, optional
97+ * @param command the command to execute
98+ * @see #execInContainerWithUser(DockerClient, InspectContainerResponse, Charset, String,
99+ * String...)
100+ */
101+ public Container .ExecResult execInContainerWithUser (
102+ DockerClient dockerClient ,
103+ InspectContainerResponse containerInfo ,
104+ String user ,
105+ String ... command
106+ ) throws UnsupportedOperationException , IOException , InterruptedException {
107+ return execInContainerWithUser (dockerClient , containerInfo , StandardCharsets .UTF_8 , user , command );
108+ }
109+
110+ /**
111+ * Run a command inside a running container as a given user, as using "docker exec -u user".
112+ * <p>
113+ * This functionality is not available on a docker daemon running the older "lxc" execution
114+ * driver. At the time of writing, CircleCI was using this driver.
115+ * @param dockerClient the {@link DockerClient}
116+ * @param containerInfo the container info
75117 * @param outputCharset the character set used to interpret the output.
118+ * @param user the user to run the command with, optional
76119 * @param command the parts of the command to run
77120 * @return the result of execution
78121 * @throws IOException if there's an issue communicating with Docker
79122 * @throws InterruptedException if the thread waiting for the response is interrupted
80123 * @throws UnsupportedOperationException if the docker daemon you're connecting to doesn't support "exec".
81124 */
82- public Container .ExecResult execInContainer (
125+ public Container .ExecResult execInContainerWithUser (
83126 DockerClient dockerClient ,
84127 InspectContainerResponse containerInfo ,
85128 Charset outputCharset ,
129+ String user ,
86130 String ... command
87131 ) throws UnsupportedOperationException , IOException , InterruptedException {
88132 if (!TestEnvironment .dockerExecutionDriverSupportsExec ()) {
@@ -100,12 +144,17 @@ public Container.ExecResult execInContainer(
100144 String containerName = containerInfo .getName ();
101145
102146 log .debug ("{}: Running \" exec\" command: {}" , containerName , String .join (" " , command ));
103- final ExecCreateCmdResponse execCreateCmdResponse = dockerClient
147+ final ExecCreateCmd execCreateCmd = dockerClient
104148 .execCreateCmd (containerId )
105149 .withAttachStdout (true )
106150 .withAttachStderr (true )
107- .withCmd (command )
108- .exec ();
151+ .withCmd (command );
152+ if (user != null && !user .isEmpty ()) {
153+ log .debug ("{}: Running \" exec\" command with user: {}" , containerName , user );
154+ execCreateCmd .withUser (user );
155+ }
156+
157+ final ExecCreateCmdResponse execCreateCmdResponse = execCreateCmd .exec ();
109158
110159 final ToStringConsumer stdoutConsumer = new ToStringConsumer ();
111160 final ToStringConsumer stderrConsumer = new ToStringConsumer ();
@@ -116,7 +165,7 @@ public Container.ExecResult execInContainer(
116165
117166 dockerClient .execStartCmd (execCreateCmdResponse .getId ()).exec (callback ).awaitCompletion ();
118167 }
119- Integer exitCode = dockerClient .inspectExecCmd (execCreateCmdResponse .getId ()).exec ().getExitCode ();
168+ int exitCode = dockerClient .inspectExecCmd (execCreateCmdResponse .getId ()).exec ().getExitCodeLong (). intValue ();
120169
121170 final Container .ExecResult result = new Container .ExecResult (
122171 exitCode ,
0 commit comments