2014-09-18 21:36:34 +00:00
package main
import (
"bufio"
2018-04-19 22:30:59 +00:00
"context"
2015-01-15 18:37:30 +00:00
"fmt"
2014-11-05 23:12:24 +00:00
"os"
2014-09-18 21:36:34 +00:00
"os/exec"
2015-01-15 18:37:30 +00:00
"reflect"
2016-05-25 17:19:17 +00:00
"runtime"
2015-01-15 18:37:30 +00:00
"sort"
2014-09-18 21:36:34 +00:00
"strings"
2015-01-15 18:37:30 +00:00
"sync"
2019-09-09 21:06:12 +00:00
"testing"
2014-09-18 21:36:34 +00:00
"time"
2015-04-18 16:46:47 +00:00
2017-05-24 03:56:26 +00:00
"github.com/docker/docker/client"
2017-04-11 19:18:30 +00:00
"github.com/docker/docker/integration-cli/cli"
2017-03-23 17:35:22 +00:00
"github.com/docker/docker/integration-cli/cli/build"
2023-07-14 18:02:38 +00:00
"github.com/docker/docker/testutil"
2020-02-07 13:39:24 +00:00
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/icmd"
2014-09-18 21:36:34 +00:00
)
2022-06-16 21:32:10 +00:00
type DockerCLIExecSuite struct {
ds * DockerSuite
}
2023-07-14 18:02:38 +00:00
func ( s * DockerCLIExecSuite ) TearDownTest ( ctx context . Context , c * testing . T ) {
s . ds . TearDownTest ( ctx , c )
2022-06-16 21:32:10 +00:00
}
func ( s * DockerCLIExecSuite ) OnTimeout ( c * testing . T ) {
s . ds . OnTimeout ( c )
}
func ( s * DockerCLIExecSuite ) TestExec ( c * testing . T ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "run" , "-d" , "--name" , "testing" , "busybox" , "sh" , "-c" , "echo test > /tmp/file && top" ) . Stdout ( )
cli . WaitRun ( c , strings . TrimSpace ( out ) )
2015-02-20 06:56:02 +00:00
2023-07-27 11:32:46 +00:00
out = cli . DockerCmd ( c , "exec" , "testing" , "cat" , "/tmp/file" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , strings . Trim ( out , "\r\n" ) , "test" )
2014-09-18 21:36:34 +00:00
}
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecInteractive ( c * testing . T ) {
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "testing" , "busybox" , "sh" , "-c" , "echo test > /tmp/file && top" )
2014-09-18 21:36:34 +00:00
execCmd := exec . Command ( dockerBinary , "exec" , "-i" , "testing" , "sh" )
stdin , err := execCmd . StdinPipe ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-09-18 21:36:34 +00:00
stdout , err := execCmd . StdoutPipe ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-09-18 21:36:34 +00:00
2015-10-21 23:58:19 +00:00
err = execCmd . Start ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2015-10-21 23:58:19 +00:00
_ , err = stdin . Write ( [ ] byte ( "cat /tmp/file\n" ) )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-09-18 21:36:34 +00:00
r := bufio . NewReader ( stdout )
line , err := r . ReadString ( '\n' )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-09-18 21:36:34 +00:00
line = strings . TrimSpace ( line )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , line , "test" )
2015-10-21 23:58:19 +00:00
err = stdin . Close ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2020-02-25 22:13:25 +00:00
errChan := make ( chan error , 1 )
2014-09-18 21:36:34 +00:00
go func ( ) {
2015-04-27 17:29:48 +00:00
errChan <- execCmd . Wait ( )
close ( errChan )
2014-09-18 21:36:34 +00:00
} ( )
select {
2015-04-27 17:29:48 +00:00
case err := <- errChan :
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-09-18 21:36:34 +00:00
case <- time . After ( 1 * time . Second ) :
2015-04-18 16:46:47 +00:00
c . Fatal ( "docker exec failed to exit on stdin close" )
2014-09-18 21:36:34 +00:00
}
}
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecAfterContainerRestart ( c * testing . T ) {
2023-07-27 11:32:46 +00:00
cID := runSleepingContainer ( c )
cli . WaitRun ( c , cID )
cli . DockerCmd ( c , "restart" , cID )
cli . WaitRun ( c , cID )
2014-09-18 21:36:34 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , cID , "echo" , "hello" ) . Combined ( )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , strings . TrimSpace ( out ) , "hello" )
2014-09-18 21:36:34 +00:00
}
2019-09-09 21:05:55 +00:00
func ( s * DockerDaemonSuite ) TestExecAfterDaemonRestart ( c * testing . T ) {
2023-07-14 18:02:38 +00:00
ctx := testutil . GetContext ( c )
2019-07-19 08:53:42 +00:00
// TODO Windows CI: DockerDaemonSuite doesn't run on Windows, and requires a little work to get this ported.
2023-07-14 18:02:38 +00:00
s . d . StartWithBusybox ( ctx , c )
2014-09-18 21:36:34 +00:00
2015-10-21 23:58:19 +00:00
out , err := s . d . Cmd ( "run" , "-d" , "--name" , "top" , "-p" , "80" , "busybox:latest" , "top" )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , "Could not run top: %s" , out )
2014-09-18 21:36:34 +00:00
2016-12-09 22:20:14 +00:00
s . d . Restart ( c )
2014-09-18 21:36:34 +00:00
2015-10-21 23:58:19 +00:00
out , err = s . d . Cmd ( "start" , "top" )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , "Could not start top after daemon restart: %s" , out )
2014-09-18 21:36:34 +00:00
2015-10-21 23:58:19 +00:00
out , err = s . d . Cmd ( "exec" , "top" , "echo" , "hello" )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , "Could not exec on container top: %s" , out )
assert . Equal ( c , strings . TrimSpace ( out ) , "hello" )
2014-09-18 21:36:34 +00:00
}
2014-11-14 17:37:04 +00:00
2015-03-13 09:12:02 +00:00
// Regression test for #9155, #9044
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecEnv ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// TODO Windows CI: This one is interesting and may just end up being a feature
// difference between Windows and Linux. On Windows, the environment is passed
// into the process that is launched, not into the machine environment. Hence
// a subsequent exec will not have LALA set/
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2016-01-29 02:22:24 +00:00
runSleepingContainer ( c , "-e" , "LALA=value1" , "-e" , "LALA=value2" , "-d" , "--name" , "testing" )
2023-07-27 11:32:46 +00:00
cli . WaitRun ( c , "testing" )
2014-11-14 17:37:04 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "testing" , "env" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Check ( c , ! strings . Contains ( out , "LALA=value1" ) )
assert . Check ( c , strings . Contains ( out , "LALA=value2" ) )
assert . Check ( c , strings . Contains ( out , "HOME=/root" ) )
2014-11-14 17:37:04 +00:00
}
2014-11-17 23:50:09 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecSetEnv ( c * testing . T ) {
2016-07-13 17:24:41 +00:00
testRequires ( c , DaemonIsLinux )
runSleepingContainer ( c , "-e" , "HOME=/root" , "-d" , "--name" , "testing" )
2023-07-27 11:32:46 +00:00
cli . WaitRun ( c , "testing" )
2016-07-13 17:24:41 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "-e" , "HOME=/another" , "-e" , "ABC=xyz" , "testing" , "env" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Check ( c , ! strings . Contains ( out , "HOME=/root" ) )
assert . Check ( c , strings . Contains ( out , "HOME=/another" ) )
assert . Check ( c , strings . Contains ( out , "ABC=xyz" ) )
2016-07-13 17:24:41 +00:00
}
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecExitStatus ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
runSleepingContainer ( c , "-d" , "--name" , "top" )
2014-11-17 23:50:09 +00:00
2016-08-04 16:57:34 +00:00
result := icmd . RunCommand ( dockerBinary , "exec" , "top" , "sh" , "-c" , "exit 23" )
2017-08-23 21:01:29 +00:00
result . Assert ( c , icmd . Expected { ExitCode : 23 , Error : "exit status 23" } )
2014-11-17 23:50:09 +00:00
}
2014-11-27 16:08:39 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecPausedContainer ( c * testing . T ) {
2016-09-09 00:31:04 +00:00
testRequires ( c , IsPausable )
2014-11-27 16:08:39 +00:00
2023-07-27 11:32:46 +00:00
ContainerID := runSleepingContainer ( c , "-d" , "--name" , "testing" )
2014-11-27 16:08:39 +00:00
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "pause" , "testing" )
2017-05-10 15:14:11 +00:00
out , _ , err := dockerCmdWithError ( "exec" , ContainerID , "echo" , "hello" )
2019-04-04 13:23:19 +00:00
assert . ErrorContains ( c , err , "" , "container should fail to exec new command if it is paused" )
2014-11-27 16:08:39 +00:00
expected := ContainerID + " is paused, unpause the container before exec"
2019-04-04 13:23:19 +00:00
assert . Assert ( c , is . Contains ( out , expected ) , "container should not exec new command if it is paused" )
2014-11-27 16:08:39 +00:00
}
2014-12-04 01:27:39 +00:00
// regression test for #9476
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecTTYCloseStdin ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// TODO Windows CI: This requires some work to port to Windows.
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "-it" , "--name" , "exec_tty_stdin" , "busybox" )
2014-12-04 01:27:39 +00:00
2015-07-20 06:55:40 +00:00
cmd := exec . Command ( dockerBinary , "exec" , "-i" , "exec_tty_stdin" , "cat" )
2014-12-04 01:27:39 +00:00
stdinRw , err := cmd . StdinPipe ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-12-04 01:27:39 +00:00
stdinRw . Write ( [ ] byte ( "test" ) )
stdinRw . Close ( )
2015-10-21 23:58:19 +00:00
out , _ , err := runCommandWithOutput ( cmd )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , out )
2014-12-04 01:27:39 +00:00
2023-07-27 11:32:46 +00:00
out = cli . DockerCmd ( c , "top" , "exec_tty_stdin" ) . Combined ( )
2014-12-04 01:27:39 +00:00
outArr := strings . Split ( out , "\n" )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , len ( outArr ) <= 3 , "exec process left running" )
assert . Assert ( c , ! strings . Contains ( out , "nsenter-exec" ) )
2014-12-04 01:27:39 +00:00
}
2014-12-06 00:50:56 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecTTYWithoutStdin ( c * testing . T ) {
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "run" , "-d" , "-ti" , "busybox" ) . Stdout ( )
2014-12-06 00:50:56 +00:00
id := strings . TrimSpace ( out )
2023-07-27 11:32:46 +00:00
cli . WaitRun ( c , id )
2014-12-06 00:50:56 +00:00
2020-02-25 22:13:25 +00:00
errChan := make ( chan error , 1 )
2014-12-06 00:50:56 +00:00
go func ( ) {
2015-04-27 17:29:48 +00:00
defer close ( errChan )
2014-12-06 00:50:56 +00:00
cmd := exec . Command ( dockerBinary , "exec" , "-ti" , id , "true" )
if _ , err := cmd . StdinPipe ( ) ; err != nil {
2015-04-27 17:29:48 +00:00
errChan <- err
return
2014-12-06 00:50:56 +00:00
}
2016-05-25 17:19:17 +00:00
expected := "the input device is not a TTY"
if runtime . GOOS == "windows" {
expected += ". If you are using mintty, try prefixing the command with 'winpty'"
}
2014-12-06 00:50:56 +00:00
if out , _ , err := runCommandWithOutput ( cmd ) ; err == nil {
2015-04-27 17:29:48 +00:00
errChan <- fmt . Errorf ( "exec should have failed" )
return
2014-12-06 00:50:56 +00:00
} else if ! strings . Contains ( out , expected ) {
2015-04-27 17:29:48 +00:00
errChan <- fmt . Errorf ( "exec failed with error %q: expected %q" , out , expected )
return
2014-12-06 00:50:56 +00:00
}
} ( )
select {
2015-04-27 17:29:48 +00:00
case err := <- errChan :
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2014-12-06 00:50:56 +00:00
case <- time . After ( 3 * time . Second ) :
2015-04-18 16:46:47 +00:00
c . Fatal ( "exec is running but should have failed" )
2014-12-06 00:50:56 +00:00
}
}
2014-12-23 19:16:23 +00:00
2016-12-13 20:21:51 +00:00
// FIXME(vdemeester) this should be a unit tests on cli/command/container package
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecParseError ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// TODO Windows CI: Requires some extra work. Consider copying the
// runSleepingContainer helper to have an exec version.
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "top" , "busybox" , "top" )
2014-12-23 19:16:23 +00:00
// Test normal (non-detached) case first
2016-12-13 20:21:51 +00:00
icmd . RunCommand ( dockerBinary , "exec" , "top" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Error : "exit status 1" ,
Err : "See 'docker exec --help'" ,
} )
2014-12-23 19:16:23 +00:00
}
2014-12-27 01:19:23 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecStopNotHanging ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// TODO Windows CI: Requires some extra work. Consider copying the
// runSleepingContainer helper to have an exec version.
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "testing" , "busybox" , "top" )
2014-12-27 01:19:23 +00:00
2017-09-07 17:11:25 +00:00
result := icmd . StartCmd ( icmd . Command ( dockerBinary , "exec" , "testing" , "top" ) )
result . Assert ( c , icmd . Success )
go icmd . WaitOnCmd ( 0 , result )
2014-12-27 01:19:23 +00:00
2015-04-27 17:29:48 +00:00
type dstop struct {
2017-09-07 17:11:25 +00:00
out string
2015-04-27 17:29:48 +00:00
err error
}
2020-02-25 22:13:25 +00:00
ch := make ( chan dstop , 1 )
2014-12-27 01:19:23 +00:00
go func ( ) {
2017-09-07 17:11:25 +00:00
result := icmd . RunCommand ( dockerBinary , "stop" , "testing" )
ch <- dstop { result . Combined ( ) , result . Error }
2015-04-27 17:29:48 +00:00
close ( ch )
2014-12-27 01:19:23 +00:00
} ( )
select {
case <- time . After ( 3 * time . Second ) :
2015-04-18 16:46:47 +00:00
c . Fatal ( "Container stop timed out" )
2015-04-27 17:29:48 +00:00
case s := <- ch :
2019-04-04 13:23:19 +00:00
assert . NilError ( c , s . err )
2014-12-27 01:19:23 +00:00
}
}
2015-01-15 18:37:30 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecCgroup ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Not applicable on Windows - using Linux specific functionality
2015-09-18 17:41:12 +00:00
testRequires ( c , NotUserNamespace )
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "testing" , "busybox" , "top" )
2015-01-15 18:37:30 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "testing" , "cat" , "/proc/1/cgroup" ) . Stdout ( )
2015-07-20 06:55:40 +00:00
containerCgroups := sort . StringSlice ( strings . Split ( out , "\n" ) )
2015-01-15 18:37:30 +00:00
var wg sync . WaitGroup
2015-04-18 16:46:47 +00:00
var mu sync . Mutex
2018-05-19 11:38:54 +00:00
var execCgroups [ ] sort . StringSlice
2020-02-25 22:13:25 +00:00
errChan := make ( chan error , 5 )
2015-01-15 18:37:30 +00:00
// exec a few times concurrently to get consistent failure
for i := 0 ; i < 5 ; i ++ {
wg . Add ( 1 )
go func ( ) {
2020-02-25 22:13:25 +00:00
defer wg . Done ( )
2015-07-27 18:13:25 +00:00
out , _ , err := dockerCmdWithError ( "exec" , "testing" , "cat" , "/proc/self/cgroup" )
2015-01-15 18:37:30 +00:00
if err != nil {
2015-04-27 17:29:48 +00:00
errChan <- err
return
2015-01-15 18:37:30 +00:00
}
2015-07-20 06:55:40 +00:00
cg := sort . StringSlice ( strings . Split ( out , "\n" ) )
2015-01-15 18:37:30 +00:00
2015-04-18 16:46:47 +00:00
mu . Lock ( )
2015-01-15 18:37:30 +00:00
execCgroups = append ( execCgroups , cg )
2015-04-18 16:46:47 +00:00
mu . Unlock ( )
2015-01-15 18:37:30 +00:00
} ( )
}
wg . Wait ( )
2015-04-27 17:29:48 +00:00
close ( errChan )
for err := range errChan {
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2015-04-27 17:29:48 +00:00
}
2015-01-15 18:37:30 +00:00
for _ , cg := range execCgroups {
if ! reflect . DeepEqual ( cg , containerCgroups ) {
fmt . Println ( "exec cgroups:" )
for _ , name := range cg {
fmt . Printf ( " %s\n" , name )
}
fmt . Println ( "container cgroups:" )
for _ , name := range containerCgroups {
fmt . Printf ( " %s\n" , name )
}
2015-04-18 16:46:47 +00:00
c . Fatal ( "cgroups mismatched" )
2015-01-15 18:37:30 +00:00
}
}
}
2014-12-30 22:05:00 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecInspectID ( c * testing . T ) {
2023-07-27 11:32:46 +00:00
id := runSleepingContainer ( c , "-d" )
2014-12-30 22:05:00 +00:00
2023-07-27 11:32:46 +00:00
out := inspectField ( c , id , "ExecIDs" )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , out , "[]" , "ExecIDs should be empty, got: %s" , out )
2014-12-30 22:05:00 +00:00
2015-08-04 11:08:30 +00:00
// Start an exec, have it block waiting so we can do some checking
cmd := exec . Command ( dockerBinary , "exec" , id , "sh" , "-c" ,
2016-01-29 02:22:24 +00:00
"while ! test -e /execid1; do sleep 1; done" )
2015-07-10 03:57:03 +00:00
2016-01-28 14:19:25 +00:00
err := cmd . Start ( )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , "failed to start the exec cmd" )
2015-07-10 03:57:03 +00:00
// Give the exec 10 chances/seconds to start then give up and stop the test
tries := 10
for i := 0 ; i < tries ; i ++ {
2015-07-18 00:30:24 +00:00
// Since its still running we should see exec as part of the container
2016-03-08 17:51:39 +00:00
out = strings . TrimSpace ( inspectField ( c , id , "ExecIDs" ) )
2015-07-18 00:30:24 +00:00
2015-07-10 03:57:03 +00:00
if out != "[]" && out != "<no value>" {
break
}
2019-04-04 13:23:19 +00:00
assert . Check ( c , i + 1 != tries , "ExecIDs still empty after 10 second" )
2015-07-10 03:57:03 +00:00
time . Sleep ( 1 * time . Second )
}
// Save execID for later
execID , err := inspectFilter ( id , "index .ExecIDs 0" )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err , "failed to get the exec id" )
2014-12-30 22:05:00 +00:00
2015-08-04 11:08:30 +00:00
// End the exec by creating the missing file
2019-04-04 13:23:19 +00:00
err = exec . Command ( dockerBinary , "exec" , id , "sh" , "-c" , "touch /execid1" ) . Run ( )
assert . NilError ( c , err , "failed to run the 2nd exec cmd" )
2015-08-04 11:08:30 +00:00
// Wait for 1st exec to complete
2015-07-10 03:57:03 +00:00
cmd . Wait ( )
2016-03-08 17:51:39 +00:00
// Give the exec 10 chances/seconds to stop then give up and stop the test
for i := 0 ; i < tries ; i ++ {
// Since its still running we should see exec as part of the container
out = strings . TrimSpace ( inspectField ( c , id , "ExecIDs" ) )
2014-12-30 22:05:00 +00:00
2016-03-08 17:51:39 +00:00
if out == "[]" {
break
}
2019-04-04 13:23:19 +00:00
assert . Check ( c , i + 1 != tries , "ExecIDs still empty after 10 second" )
2016-03-08 17:51:39 +00:00
time . Sleep ( 1 * time . Second )
}
2015-07-10 03:57:03 +00:00
// But we should still be able to query the execID
2023-04-03 11:00:29 +00:00
apiClient , err := client . NewClientWithOpts ( client . FromEnv )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2023-04-03 11:00:29 +00:00
defer apiClient . Close ( )
2017-01-28 19:08:30 +00:00
2023-07-14 18:02:38 +00:00
_ , err = apiClient . ContainerExecInspect ( testutil . GetContext ( c ) , execID )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2015-07-10 02:39:57 +00:00
// Now delete the container and then an 'inspect' on the exec should
// result in a 404 (not 'container not running')
2023-07-27 11:32:46 +00:00
res := cli . DockerCmd ( c , "rm" , "-f" , id )
assert . Equal ( c , res . ExitCode , 0 , "error removing container: %s" , res . Combined ( ) )
2017-05-24 03:56:26 +00:00
2023-07-14 18:02:38 +00:00
_ , err = apiClient . ContainerExecInspect ( testutil . GetContext ( c ) , execID )
2019-04-04 13:23:19 +00:00
assert . ErrorContains ( c , err , "No such exec instance" )
2014-12-30 22:05:00 +00:00
}
2015-01-19 20:11:19 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestLinksPingLinkedContainersOnRename ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Problematic on Windows as Windows does not support links
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "run" , "-d" , "--name" , "container1" , "busybox" , "top" ) . Stdout ( )
2015-04-06 13:21:18 +00:00
idA := strings . TrimSpace ( out )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , idA != "" , "%s, id should not be nil" , out )
2023-07-27 11:32:46 +00:00
out = cli . DockerCmd ( c , "run" , "-d" , "--link" , "container1:alias1" , "--name" , "container2" , "busybox" , "top" ) . Stdout ( )
2015-04-06 13:21:18 +00:00
idB := strings . TrimSpace ( out )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , idB != "" , "%s, id should not be nil" , out )
2015-01-19 20:11:19 +00:00
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "exec" , "container2" , "ping" , "-c" , "1" , "alias1" , "-W" , "1" )
cli . DockerCmd ( c , "rename" , "container1" , "container_new" )
cli . DockerCmd ( c , "exec" , "container2" , "ping" , "-c" , "1" , "alias1" , "-W" , "1" )
2015-01-19 20:11:19 +00:00
}
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestRunMutableNetworkFiles ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Not applicable on Windows to Windows CI.
2018-12-24 12:25:53 +00:00
testRequires ( c , testEnv . IsLocalDaemon , DaemonIsLinux )
2015-01-27 01:17:08 +00:00
for _ , fn := range [ ] string { "resolv.conf" , "hosts" } {
2017-04-11 17:42:54 +00:00
containers := cli . DockerCmd ( c , "ps" , "-q" , "-a" ) . Combined ( )
if containers != "" {
cli . DockerCmd ( c , append ( [ ] string { "rm" , "-fv" } , strings . Split ( strings . TrimSpace ( containers ) , "\n" ) ... ) ... )
}
2015-01-27 01:17:08 +00:00
2017-01-16 15:39:12 +00:00
content := runCommandAndReadContainerFile ( c , fn , dockerBinary , "run" , "-d" , "--name" , "c1" , "busybox" , "sh" , "-c" , fmt . Sprintf ( "echo success >/etc/%s && top" , fn ) )
2015-01-27 01:17:08 +00:00
2019-04-04 13:23:19 +00:00
assert . Equal ( c , strings . TrimSpace ( string ( content ) ) , "success" , "Content was not what was modified in the container" , string ( content ) )
2015-01-27 01:17:08 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "run" , "-d" , "--name" , "c2" , "busybox" , "top" ) . Stdout ( )
2015-01-27 01:17:08 +00:00
contID := strings . TrimSpace ( out )
netFilePath := containerStorageFile ( contID , fn )
2022-01-20 12:43:42 +00:00
f , err := os . OpenFile ( netFilePath , os . O_WRONLY | os . O_SYNC | os . O_APPEND , 0 o644 )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
2015-01-27 01:17:08 +00:00
if _ , err := f . Seek ( 0 , 0 ) ; err != nil {
f . Close ( )
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-27 01:17:08 +00:00
}
if err := f . Truncate ( 0 ) ; err != nil {
f . Close ( )
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-27 01:17:08 +00:00
}
if _ , err := f . Write ( [ ] byte ( "success2\n" ) ) ; err != nil {
f . Close ( )
2015-04-18 16:46:47 +00:00
c . Fatal ( err )
2015-01-27 01:17:08 +00:00
}
f . Close ( )
2023-07-27 11:32:46 +00:00
res := cli . DockerCmd ( c , "exec" , contID , "cat" , "/etc/" + fn ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , res , "success2\n" )
2015-01-27 01:17:08 +00:00
}
}
2015-04-11 03:04:24 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecWithUser ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// TODO Windows CI: This may be fixable in the future once Windows
// supports users
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "parent" , "busybox" , "top" )
2015-04-11 03:04:24 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "-u" , "1" , "parent" , "id" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , strings . Contains ( out , "uid=1(daemon) gid=1(daemon)" ) )
2015-04-11 03:04:24 +00:00
2023-07-27 11:32:46 +00:00
out = cli . DockerCmd ( c , "exec" , "-u" , "root" , "parent" , "id" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , strings . Contains ( out , "uid=0(root) gid=0(root)" ) , "exec with user by id expected daemon user got %s" , out )
2015-04-11 03:04:24 +00:00
}
2015-06-26 22:06:37 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecWithPrivileged ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Not applicable on Windows
2015-09-18 17:41:12 +00:00
testRequires ( c , DaemonIsLinux , NotUserNamespace )
2015-06-22 03:06:07 +00:00
// Start main loop which attempts mknod repeatedly
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "parent" , "--cap-drop=ALL" , "busybox" , "sh" , "-c" , ` while (true); do if [ -e /exec_priv ]; then cat /exec_priv && mknod /tmp/sda b 8 0 && echo "Success"; else echo "Privileged exec has not run yet"; fi; usleep 10000; done ` )
2015-06-19 06:01:50 +00:00
2015-06-22 03:06:07 +00:00
// Check exec mknod doesn't work
2017-01-16 15:39:12 +00:00
icmd . RunCommand ( dockerBinary , "exec" , "parent" , "sh" , "-c" , "mknod /tmp/sdb b 8 16" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "Operation not permitted" ,
} )
2015-06-19 06:01:50 +00:00
2015-06-22 03:06:07 +00:00
// Check exec mknod does work with --privileged
2017-01-16 15:39:12 +00:00
result := icmd . RunCommand ( dockerBinary , "exec" , "--privileged" , "parent" , "sh" , "-c" , ` echo "Running exec --privileged" > /exec_priv && mknod /tmp/sdb b 8 16 && usleep 50000 && echo "Finished exec --privileged" > /exec_priv && echo ok ` )
result . Assert ( c , icmd . Success )
2015-06-19 06:01:50 +00:00
2017-01-16 15:39:12 +00:00
actual := strings . TrimSpace ( result . Combined ( ) )
2019-04-04 13:23:19 +00:00
assert . Equal ( c , actual , "ok" , "exec mknod in --cap-drop=ALL container with --privileged failed, output: %q" , result . Combined ( ) )
2015-06-19 06:01:50 +00:00
2015-06-22 03:06:07 +00:00
// Check subsequent unprivileged exec cannot mknod
2017-01-16 15:39:12 +00:00
icmd . RunCommand ( dockerBinary , "exec" , "parent" , "sh" , "-c" , "mknod /tmp/sdc b 8 32" ) . Assert ( c , icmd . Expected {
ExitCode : 1 ,
Err : "Operation not permitted" ,
} )
2015-06-22 03:06:07 +00:00
// Confirm at no point was mknod allowed
2017-01-16 15:39:12 +00:00
result = icmd . RunCommand ( dockerBinary , "logs" , "parent" )
result . Assert ( c , icmd . Success )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , ! strings . Contains ( result . Combined ( ) , "Success" ) )
2015-06-19 06:01:50 +00:00
}
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecWithImageUser ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Not applicable on Windows
2015-08-28 17:36:42 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
const name = "testbuilduser"
2017-03-23 17:35:22 +00:00
buildImageSuccessfully ( c , name , build . WithDockerfile ( ` FROM busybox
2015-06-26 22:06:37 +00:00
RUN echo ' dockerio : x : 1001 : 1001 : : / bin : / bin / false ' >> / etc / passwd
2017-01-16 10:30:14 +00:00
USER dockerio ` ) )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--name" , "dockerioexec" , name , "top" )
2015-06-26 22:06:37 +00:00
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "dockerioexec" , "whoami" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , strings . Contains ( out , "dockerio" ) , "exec with user by id expected dockerio user got %s" , out )
2015-06-26 22:06:37 +00:00
}
2015-07-30 17:26:45 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecOnReadonlyContainer ( c * testing . T ) {
2016-01-29 02:22:24 +00:00
// Windows does not support read-only
2015-09-18 17:41:12 +00:00
// --read-only + userns has remount issues
testRequires ( c , DaemonIsLinux , NotUserNamespace )
2023-07-27 11:32:46 +00:00
cli . DockerCmd ( c , "run" , "-d" , "--read-only" , "--name" , "parent" , "busybox" , "top" )
cli . DockerCmd ( c , "exec" , "parent" , "true" )
2015-07-30 17:26:45 +00:00
}
2015-08-21 12:39:26 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecUlimits ( c * testing . T ) {
2016-03-24 02:54:32 +00:00
testRequires ( c , DaemonIsLinux )
2023-07-27 11:32:46 +00:00
const name = "testexeculimits"
2017-03-23 11:31:28 +00:00
runSleepingContainer ( c , "-d" , "--ulimit" , "nofile=511:511" , "--name" , name )
2023-07-27 11:32:46 +00:00
cli . WaitRun ( c , name )
2016-03-24 02:54:32 +00:00
2017-03-23 11:31:28 +00:00
out , _ , err := dockerCmdWithError ( "exec" , name , "sh" , "-c" , "ulimit -n" )
2019-04-04 13:23:19 +00:00
assert . NilError ( c , err )
assert . Equal ( c , strings . TrimSpace ( out ) , "511" )
2016-03-24 02:54:32 +00:00
}
2015-08-21 12:39:26 +00:00
// #15750
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecStartFails ( c * testing . T ) {
2023-07-27 11:32:46 +00:00
const name = "exec-15750"
2016-01-29 02:22:24 +00:00
runSleepingContainer ( c , "-d" , "--name" , name )
2023-07-27 11:32:46 +00:00
cli . WaitRun ( c , name )
2015-08-21 12:39:26 +00:00
2015-09-29 02:09:04 +00:00
out , _ , err := dockerCmdWithError ( "exec" , name , "no-such-cmd" )
2019-04-04 13:23:19 +00:00
assert . ErrorContains ( c , err , "" , out )
2023-03-13 12:57:34 +00:00
expectedMsg := "executable file not found"
if DaemonIsWindows ( ) {
expectedMsg = "The system cannot find the file specified"
}
assert . Assert ( c , is . Contains ( out , expectedMsg ) )
2015-08-21 12:39:26 +00:00
}
2016-09-28 20:34:47 +00:00
// Fix regression in https://github.com/docker/docker/pull/26461#issuecomment-250287297
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecWindowsPathNotWiped ( c * testing . T ) {
2016-09-28 20:34:47 +00:00
testRequires ( c , DaemonIsWindows )
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "run" , "-d" , "--name" , "testing" , minimalBaseImage ( ) , "powershell" , "start-sleep" , "60" ) . Stdout ( )
cli . WaitRun ( c , strings . TrimSpace ( out ) )
2016-09-28 20:34:47 +00:00
2023-07-27 11:32:46 +00:00
out = cli . DockerCmd ( c , "exec" , "testing" , "powershell" , "write-host" , "$env:PATH" ) . Stdout ( )
2016-09-28 20:34:47 +00:00
out = strings . ToLower ( strings . Trim ( out , "\r\n" ) )
2019-04-04 13:23:19 +00:00
assert . Assert ( c , strings . Contains ( out , ` windowspowershell\v1.0 ` ) )
2016-09-28 20:34:47 +00:00
}
2016-09-28 22:21:33 +00:00
2022-06-16 21:32:10 +00:00
func ( s * DockerCLIExecSuite ) TestExecEnvLinksHost ( c * testing . T ) {
2016-09-28 22:21:33 +00:00
testRequires ( c , DaemonIsLinux )
runSleepingContainer ( c , "-d" , "--name" , "foo" )
runSleepingContainer ( c , "-d" , "--link" , "foo:db" , "--hostname" , "myhost" , "--name" , "bar" )
2023-07-27 11:32:46 +00:00
out := cli . DockerCmd ( c , "exec" , "bar" , "env" ) . Stdout ( )
2019-04-04 13:23:19 +00:00
assert . Check ( c , is . Contains ( out , "HOSTNAME=myhost" ) )
assert . Check ( c , is . Contains ( out , "DB_NAME=/bar/db" ) )
2016-09-28 22:21:33 +00:00
}