6d974ec19d
This is done by calling waitRun() followed by the docker run, which ensures the container is loaded before calling docker exec to obtain the env variable set previously. Incorporated the change as suggeted by duglin. Signed-off-by: Anil Belur <askb23@gmail.com>
628 lines
18 KiB
Go
628 lines
18 KiB
Go
// +build !test_no_exec
|
|
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/docker/docker/pkg/integration/checker"
|
|
"github.com/go-check/check"
|
|
)
|
|
|
|
func (s *DockerSuite) TestExec(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
|
|
|
|
out, _ := dockerCmd(c, "exec", "testing", "cat", "/tmp/file")
|
|
out = strings.Trim(out, "\r\n")
|
|
if out != "test" {
|
|
c.Errorf("container exec should've printed test but printed %q", out)
|
|
}
|
|
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecInteractive(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
|
|
|
|
execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh")
|
|
stdin, err := execCmd.StdinPipe()
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
stdout, err := execCmd.StdoutPipe()
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
if err := execCmd.Start(); err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
if _, err := stdin.Write([]byte("cat /tmp/file\n")); err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
r := bufio.NewReader(stdout)
|
|
line, err := r.ReadString('\n')
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
line = strings.TrimSpace(line)
|
|
if line != "test" {
|
|
c.Fatalf("Output should be 'test', got '%q'", line)
|
|
}
|
|
if err := stdin.Close(); err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
errChan := make(chan error)
|
|
go func() {
|
|
errChan <- execCmd.Wait()
|
|
close(errChan)
|
|
}()
|
|
select {
|
|
case err := <-errChan:
|
|
c.Assert(err, check.IsNil)
|
|
case <-time.After(1 * time.Second):
|
|
c.Fatal("docker exec failed to exit on stdin close")
|
|
}
|
|
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
|
cleanedContainerID := strings.TrimSpace(out)
|
|
dockerCmd(c, "restart", cleanedContainerID)
|
|
|
|
out, _ = dockerCmd(c, "exec", cleanedContainerID, "echo", "hello")
|
|
outStr := strings.TrimSpace(out)
|
|
if outStr != "hello" {
|
|
c.Errorf("container should've printed hello, instead printed %q", outStr)
|
|
}
|
|
}
|
|
|
|
func (s *DockerDaemonSuite) TestExecAfterDaemonRestart(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
testRequires(c, SameHostDaemon)
|
|
|
|
if err := s.d.StartWithBusybox(); err != nil {
|
|
c.Fatalf("Could not start daemon with busybox: %v", err)
|
|
}
|
|
|
|
if out, err := s.d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
|
|
c.Fatalf("Could not run top: err=%v\n%s", err, out)
|
|
}
|
|
|
|
if err := s.d.Restart(); err != nil {
|
|
c.Fatalf("Could not restart daemon: %v", err)
|
|
}
|
|
|
|
if out, err := s.d.Cmd("start", "top"); err != nil {
|
|
c.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out)
|
|
}
|
|
|
|
out, err := s.d.Cmd("exec", "top", "echo", "hello")
|
|
if err != nil {
|
|
c.Fatalf("Could not exec on container top: err=%v\n%s", err, out)
|
|
}
|
|
|
|
outStr := strings.TrimSpace(string(out))
|
|
if outStr != "hello" {
|
|
c.Errorf("container should've printed hello, instead printed %q", outStr)
|
|
}
|
|
}
|
|
|
|
// Regression test for #9155, #9044
|
|
func (s *DockerSuite) TestExecEnv(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-e", "LALA=value1", "-e", "LALA=value2",
|
|
"-d", "--name", "testing", "busybox", "top")
|
|
c.Assert(waitRun("testing"), check.IsNil)
|
|
|
|
out, _ := dockerCmd(c, "exec", "testing", "env")
|
|
if strings.Contains(out, "LALA=value1") ||
|
|
!strings.Contains(out, "LALA=value2") ||
|
|
!strings.Contains(out, "HOME=/root") {
|
|
c.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root")
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecExitStatus(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "top", "busybox", "top")
|
|
|
|
// Test normal (non-detached) case first
|
|
cmd := exec.Command(dockerBinary, "exec", "top", "sh", "-c", "exit 23")
|
|
ec, _ := runCommand(cmd)
|
|
if ec != 23 {
|
|
c.Fatalf("Should have had an ExitCode of 23, not: %d", ec)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
defer unpauseAllContainers()
|
|
|
|
out, _ := dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
|
|
ContainerID := strings.TrimSpace(out)
|
|
|
|
dockerCmd(c, "pause", "testing")
|
|
out, _, err := dockerCmdWithError("exec", "-i", "-t", ContainerID, "echo", "hello")
|
|
if err == nil {
|
|
c.Fatal("container should fail to exec new command if it is paused")
|
|
}
|
|
|
|
expected := ContainerID + " is paused, unpause the container before exec"
|
|
if !strings.Contains(out, expected) {
|
|
c.Fatal("container should not exec new command if it is paused")
|
|
}
|
|
}
|
|
|
|
// regression test for #9476
|
|
func (s *DockerSuite) TestExecTtyCloseStdin(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox")
|
|
|
|
cmd := exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat")
|
|
stdinRw, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
stdinRw.Write([]byte("test"))
|
|
stdinRw.Close()
|
|
|
|
if out, _, err := runCommandWithOutput(cmd); err != nil {
|
|
c.Fatal(out, err)
|
|
}
|
|
|
|
out, _ := dockerCmd(c, "top", "exec_tty_stdin")
|
|
outArr := strings.Split(out, "\n")
|
|
if len(outArr) > 3 || strings.Contains(out, "nsenter-exec") {
|
|
c.Fatalf("exec process left running\n\t %s", out)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecTtyWithoutStdin(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
out, _ := dockerCmd(c, "run", "-d", "-ti", "busybox")
|
|
id := strings.TrimSpace(out)
|
|
c.Assert(waitRun(id), check.IsNil)
|
|
|
|
errChan := make(chan error)
|
|
go func() {
|
|
defer close(errChan)
|
|
|
|
cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
|
|
if _, err := cmd.StdinPipe(); err != nil {
|
|
errChan <- err
|
|
return
|
|
}
|
|
|
|
expected := "cannot enable tty mode"
|
|
if out, _, err := runCommandWithOutput(cmd); err == nil {
|
|
errChan <- fmt.Errorf("exec should have failed")
|
|
return
|
|
} else if !strings.Contains(out, expected) {
|
|
errChan <- fmt.Errorf("exec failed with error %q: expected %q", out, expected)
|
|
return
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case err := <-errChan:
|
|
c.Assert(err, check.IsNil)
|
|
case <-time.After(3 * time.Second):
|
|
c.Fatal("exec is running but should have failed")
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecParseError(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "top", "busybox", "top")
|
|
|
|
// Test normal (non-detached) case first
|
|
cmd := exec.Command(dockerBinary, "exec", "top")
|
|
if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 {
|
|
c.Fatalf("Should have thrown error & point to help: %s", stderr)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecStopNotHanging(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
|
|
|
|
if err := exec.Command(dockerBinary, "exec", "testing", "top").Start(); err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
type dstop struct {
|
|
out []byte
|
|
err error
|
|
}
|
|
|
|
ch := make(chan dstop)
|
|
go func() {
|
|
out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput()
|
|
ch <- dstop{out, err}
|
|
close(ch)
|
|
}()
|
|
select {
|
|
case <-time.After(3 * time.Second):
|
|
c.Fatal("Container stop timed out")
|
|
case s := <-ch:
|
|
c.Assert(s.err, check.IsNil)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecCgroup(c *check.C) {
|
|
testRequires(c, NotUserNamespace)
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
|
|
|
|
out, _ := dockerCmd(c, "exec", "testing", "cat", "/proc/1/cgroup")
|
|
containerCgroups := sort.StringSlice(strings.Split(out, "\n"))
|
|
|
|
var wg sync.WaitGroup
|
|
var mu sync.Mutex
|
|
execCgroups := []sort.StringSlice{}
|
|
errChan := make(chan error)
|
|
// exec a few times concurrently to get consistent failure
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
out, _, err := dockerCmdWithError("exec", "testing", "cat", "/proc/self/cgroup")
|
|
if err != nil {
|
|
errChan <- err
|
|
return
|
|
}
|
|
cg := sort.StringSlice(strings.Split(out, "\n"))
|
|
|
|
mu.Lock()
|
|
execCgroups = append(execCgroups, cg)
|
|
mu.Unlock()
|
|
wg.Done()
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
close(errChan)
|
|
|
|
for err := range errChan {
|
|
c.Assert(err, check.IsNil)
|
|
}
|
|
|
|
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)
|
|
}
|
|
c.Fatal("cgroups mismatched")
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestInspectExecID(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
|
id := strings.TrimSuffix(out, "\n")
|
|
|
|
out, err := inspectField(id, "ExecIDs")
|
|
if err != nil {
|
|
c.Fatalf("failed to inspect container: %s, %v", out, err)
|
|
}
|
|
if out != "[]" {
|
|
c.Fatalf("ExecIDs should be empty, got: %s", out)
|
|
}
|
|
|
|
// Start an exec, have it block waiting so we can do some checking
|
|
cmd := exec.Command(dockerBinary, "exec", id, "sh", "-c",
|
|
"while ! test -e /tmp/execid1; do sleep 1; done")
|
|
|
|
if err = cmd.Start(); err != nil {
|
|
c.Fatalf("failed to start the exec cmd: %q", err)
|
|
}
|
|
|
|
// Give the exec 10 chances/seconds to start then give up and stop the test
|
|
tries := 10
|
|
for i := 0; i < tries; i++ {
|
|
// Since its still running we should see exec as part of the container
|
|
out, err = inspectField(id, "ExecIDs")
|
|
if err != nil {
|
|
c.Fatalf("failed to inspect container: %s, %v", out, err)
|
|
}
|
|
|
|
out = strings.TrimSuffix(out, "\n")
|
|
if out != "[]" && out != "<no value>" {
|
|
break
|
|
}
|
|
if i+1 == tries {
|
|
c.Fatalf("ExecIDs should not be empty, got: %s", out)
|
|
}
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
// Save execID for later
|
|
execID, err := inspectFilter(id, "index .ExecIDs 0")
|
|
if err != nil {
|
|
c.Fatalf("failed to get the exec id: %v", err)
|
|
}
|
|
|
|
// End the exec by creating the missing file
|
|
err = exec.Command(dockerBinary, "exec", id,
|
|
"sh", "-c", "touch /tmp/execid1").Run()
|
|
|
|
if err != nil {
|
|
c.Fatalf("failed to run the 2nd exec cmd: %q", err)
|
|
}
|
|
|
|
// Wait for 1st exec to complete
|
|
cmd.Wait()
|
|
|
|
// All execs for the container should be gone now
|
|
out, err = inspectField(id, "ExecIDs")
|
|
if err != nil {
|
|
c.Fatalf("failed to inspect container: %s, %v", out, err)
|
|
}
|
|
|
|
out = strings.TrimSuffix(out, "\n")
|
|
if out != "[]" && out != "<no value>" {
|
|
c.Fatalf("ExecIDs should be empty, got: %s", out)
|
|
}
|
|
|
|
// But we should still be able to query the execID
|
|
sc, body, err := sockRequest("GET", "/exec/"+execID+"/json", nil)
|
|
if sc != http.StatusOK {
|
|
c.Fatalf("received status != 200 OK: %d\n%s", sc, body)
|
|
}
|
|
|
|
// Now delete the container and then an 'inspect' on the exec should
|
|
// result in a 404 (not 'container not running')
|
|
out, ec := dockerCmd(c, "rm", "-f", id)
|
|
if ec != 0 {
|
|
c.Fatalf("error removing container: %s", out)
|
|
}
|
|
sc, body, err = sockRequest("GET", "/exec/"+execID+"/json", nil)
|
|
if sc != http.StatusNotFound {
|
|
c.Fatalf("received status != 404: %d\n%s", sc, body)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
var out string
|
|
out, _ = dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
|
|
idA := strings.TrimSpace(out)
|
|
if idA == "" {
|
|
c.Fatal(out, "id should not be nil")
|
|
}
|
|
out, _ = dockerCmd(c, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top")
|
|
idB := strings.TrimSpace(out)
|
|
if idB == "" {
|
|
c.Fatal(out, "id should not be nil")
|
|
}
|
|
|
|
dockerCmd(c, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
|
|
dockerCmd(c, "rename", "container1", "container_new")
|
|
dockerCmd(c, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
|
|
}
|
|
|
|
func (s *DockerSuite) TestRunExecDir(c *check.C) {
|
|
testRequires(c, SameHostDaemon)
|
|
|
|
out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
|
|
id := strings.TrimSpace(out)
|
|
execDir := filepath.Join(execDriverPath, id)
|
|
stateFile := filepath.Join(execDir, "state.json")
|
|
|
|
{
|
|
fi, err := os.Stat(execDir)
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
if !fi.IsDir() {
|
|
c.Fatalf("%q must be a directory", execDir)
|
|
}
|
|
fi, err = os.Stat(stateFile)
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
}
|
|
|
|
dockerCmd(c, "stop", id)
|
|
{
|
|
_, err := os.Stat(execDir)
|
|
if err == nil {
|
|
c.Fatal(err)
|
|
}
|
|
if err == nil {
|
|
c.Fatalf("Exec directory %q exists for removed container!", execDir)
|
|
}
|
|
if !os.IsNotExist(err) {
|
|
c.Fatalf("Error should be about non-existing, got %s", err)
|
|
}
|
|
}
|
|
dockerCmd(c, "start", id)
|
|
{
|
|
fi, err := os.Stat(execDir)
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
if !fi.IsDir() {
|
|
c.Fatalf("%q must be a directory", execDir)
|
|
}
|
|
fi, err = os.Stat(stateFile)
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
}
|
|
dockerCmd(c, "rm", "-f", id)
|
|
{
|
|
_, err := os.Stat(execDir)
|
|
if err == nil {
|
|
c.Fatal(err)
|
|
}
|
|
if err == nil {
|
|
c.Fatalf("Exec directory %q is exists for removed container!", execDir)
|
|
}
|
|
if !os.IsNotExist(err) {
|
|
c.Fatalf("Error should be about non-existing, got %s", err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestRunMutableNetworkFiles(c *check.C) {
|
|
testRequires(c, SameHostDaemon)
|
|
|
|
for _, fn := range []string{"resolv.conf", "hosts"} {
|
|
deleteAllContainers()
|
|
|
|
content, err := runCommandAndReadContainerFile(fn, exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn)))
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
if strings.TrimSpace(string(content)) != "success" {
|
|
c.Fatal("Content was not what was modified in the container", string(content))
|
|
}
|
|
|
|
out, _ := dockerCmd(c, "run", "-d", "--name", "c2", "busybox", "top")
|
|
contID := strings.TrimSpace(out)
|
|
netFilePath := containerStorageFile(contID, fn)
|
|
|
|
f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644)
|
|
if err != nil {
|
|
c.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.Seek(0, 0); err != nil {
|
|
f.Close()
|
|
c.Fatal(err)
|
|
}
|
|
|
|
if err := f.Truncate(0); err != nil {
|
|
f.Close()
|
|
c.Fatal(err)
|
|
}
|
|
|
|
if _, err := f.Write([]byte("success2\n")); err != nil {
|
|
f.Close()
|
|
c.Fatal(err)
|
|
}
|
|
f.Close()
|
|
|
|
res, _ := dockerCmd(c, "exec", contID, "cat", "/etc/"+fn)
|
|
if res != "success2\n" {
|
|
c.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecWithUser(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
dockerCmd(c, "run", "-d", "--name", "parent", "busybox", "top")
|
|
|
|
out, _ := dockerCmd(c, "exec", "-u", "1", "parent", "id")
|
|
if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
|
|
c.Fatalf("exec with user by id expected daemon user got %s", out)
|
|
}
|
|
|
|
out, _ = dockerCmd(c, "exec", "-u", "root", "parent", "id")
|
|
if !strings.Contains(out, "uid=0(root) gid=0(root)") {
|
|
c.Fatalf("exec with user by root expected root user got %s", out)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecWithPrivileged(c *check.C) {
|
|
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
|
// Start main loop which attempts mknod repeatedly
|
|
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`)
|
|
|
|
// Check exec mknod doesn't work
|
|
cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdb b 8 16")
|
|
out, _, err := runCommandWithOutput(cmd)
|
|
if err == nil || !strings.Contains(out, "Operation not permitted") {
|
|
c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should fail")
|
|
}
|
|
|
|
// Check exec mknod does work with --privileged
|
|
cmd = exec.Command(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`)
|
|
out, _, err = runCommandWithOutput(cmd)
|
|
if err != nil {
|
|
c.Fatal(err, out)
|
|
}
|
|
|
|
if actual := strings.TrimSpace(out); actual != "ok" {
|
|
c.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out)
|
|
}
|
|
|
|
// Check subsequent unprivileged exec cannot mknod
|
|
cmd = exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sdc b 8 32")
|
|
out, _, err = runCommandWithOutput(cmd)
|
|
if err == nil || !strings.Contains(out, "Operation not permitted") {
|
|
c.Fatalf("repeating exec mknod in --cap-drop=ALL container after --privileged without --privileged should fail")
|
|
}
|
|
|
|
// Confirm at no point was mknod allowed
|
|
logCmd := exec.Command(dockerBinary, "logs", "parent")
|
|
if out, _, err := runCommandWithOutput(logCmd); err != nil || strings.Contains(out, "Success") {
|
|
c.Fatal(out, err)
|
|
}
|
|
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecWithImageUser(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
name := "testbuilduser"
|
|
_, err := buildImage(name,
|
|
`FROM busybox
|
|
RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
|
|
USER dockerio`,
|
|
true)
|
|
if err != nil {
|
|
c.Fatalf("Could not build image %s: %v", name, err)
|
|
}
|
|
|
|
dockerCmd(c, "run", "-d", "--name", "dockerioexec", name, "top")
|
|
|
|
out, _ := dockerCmd(c, "exec", "dockerioexec", "whoami")
|
|
if !strings.Contains(out, "dockerio") {
|
|
c.Fatalf("exec with user by id expected dockerio user got %s", out)
|
|
}
|
|
}
|
|
|
|
func (s *DockerSuite) TestExecOnReadonlyContainer(c *check.C) {
|
|
// --read-only + userns has remount issues
|
|
testRequires(c, DaemonIsLinux, NotUserNamespace)
|
|
dockerCmd(c, "run", "-d", "--read-only", "--name", "parent", "busybox", "top")
|
|
if _, status := dockerCmd(c, "exec", "parent", "true"); status != 0 {
|
|
c.Fatalf("exec into a read-only container failed with exit status %d", status)
|
|
}
|
|
}
|
|
|
|
// #15750
|
|
func (s *DockerSuite) TestExecStartFails(c *check.C) {
|
|
testRequires(c, DaemonIsLinux)
|
|
name := "exec-15750"
|
|
dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
|
|
c.Assert(waitRun(name), check.IsNil)
|
|
|
|
out, _, err := dockerCmdWithError("exec", name, "no-such-cmd")
|
|
c.Assert(err, check.NotNil, check.Commentf(out))
|
|
c.Assert(out, checker.Contains, "executable file not found")
|
|
}
|