github.com/guilhermebr/docker@v1.4.2-0.20150428121140-67da055cebca/integration-cli/docker_cli_exec_test.go (about)

     1  // +build !test_no_exec
     2  
     3  package main
     4  
     5  import (
     6  	"bufio"
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"reflect"
    12  	"sort"
    13  	"strings"
    14  	"sync"
    15  	"time"
    16  
    17  	"github.com/go-check/check"
    18  )
    19  
    20  func (s *DockerSuite) TestExec(c *check.C) {
    21  
    22  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
    23  	if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
    24  		c.Fatal(out, err)
    25  	}
    26  
    27  	execCmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/tmp/file")
    28  	out, _, err := runCommandWithOutput(execCmd)
    29  	if err != nil {
    30  		c.Fatal(out, err)
    31  	}
    32  
    33  	out = strings.Trim(out, "\r\n")
    34  
    35  	if expected := "test"; out != expected {
    36  		c.Errorf("container exec should've printed %q but printed %q", expected, out)
    37  	}
    38  
    39  }
    40  
    41  func (s *DockerSuite) TestExecInteractive(c *check.C) {
    42  
    43  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && top")
    44  	if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
    45  		c.Fatal(out, err)
    46  	}
    47  
    48  	execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh")
    49  	stdin, err := execCmd.StdinPipe()
    50  	if err != nil {
    51  		c.Fatal(err)
    52  	}
    53  	stdout, err := execCmd.StdoutPipe()
    54  	if err != nil {
    55  		c.Fatal(err)
    56  	}
    57  
    58  	if err := execCmd.Start(); err != nil {
    59  		c.Fatal(err)
    60  	}
    61  	if _, err := stdin.Write([]byte("cat /tmp/file\n")); err != nil {
    62  		c.Fatal(err)
    63  	}
    64  
    65  	r := bufio.NewReader(stdout)
    66  	line, err := r.ReadString('\n')
    67  	if err != nil {
    68  		c.Fatal(err)
    69  	}
    70  	line = strings.TrimSpace(line)
    71  	if line != "test" {
    72  		c.Fatalf("Output should be 'test', got '%q'", line)
    73  	}
    74  	if err := stdin.Close(); err != nil {
    75  		c.Fatal(err)
    76  	}
    77  	finish := make(chan struct{})
    78  	go func() {
    79  		if err := execCmd.Wait(); err != nil {
    80  			c.Fatal(err)
    81  		}
    82  		close(finish)
    83  	}()
    84  	select {
    85  	case <-finish:
    86  	case <-time.After(1 * time.Second):
    87  		c.Fatal("docker exec failed to exit on stdin close")
    88  	}
    89  
    90  }
    91  
    92  func (s *DockerSuite) TestExecAfterContainerRestart(c *check.C) {
    93  
    94  	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
    95  	out, _, err := runCommandWithOutput(runCmd)
    96  	if err != nil {
    97  		c.Fatal(out, err)
    98  	}
    99  
   100  	cleanedContainerID := strings.TrimSpace(out)
   101  
   102  	runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID)
   103  	if out, _, err = runCommandWithOutput(runCmd); err != nil {
   104  		c.Fatal(out, err)
   105  	}
   106  
   107  	runCmd = exec.Command(dockerBinary, "exec", cleanedContainerID, "echo", "hello")
   108  	out, _, err = runCommandWithOutput(runCmd)
   109  	if err != nil {
   110  		c.Fatal(out, err)
   111  	}
   112  
   113  	outStr := strings.TrimSpace(out)
   114  	if outStr != "hello" {
   115  		c.Errorf("container should've printed hello, instead printed %q", outStr)
   116  	}
   117  
   118  }
   119  
   120  func (s *DockerSuite) TestExecAfterDaemonRestart(c *check.C) {
   121  	testRequires(c, SameHostDaemon)
   122  
   123  	d := NewDaemon(c)
   124  	if err := d.StartWithBusybox(); err != nil {
   125  		c.Fatalf("Could not start daemon with busybox: %v", err)
   126  	}
   127  	defer d.Stop()
   128  
   129  	if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
   130  		c.Fatalf("Could not run top: err=%v\n%s", err, out)
   131  	}
   132  
   133  	if err := d.Restart(); err != nil {
   134  		c.Fatalf("Could not restart daemon: %v", err)
   135  	}
   136  
   137  	if out, err := d.Cmd("start", "top"); err != nil {
   138  		c.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out)
   139  	}
   140  
   141  	out, err := d.Cmd("exec", "top", "echo", "hello")
   142  	if err != nil {
   143  		c.Fatalf("Could not exec on container top: err=%v\n%s", err, out)
   144  	}
   145  
   146  	outStr := strings.TrimSpace(string(out))
   147  	if outStr != "hello" {
   148  		c.Errorf("container should've printed hello, instead printed %q", outStr)
   149  	}
   150  
   151  }
   152  
   153  // Regression test for #9155, #9044
   154  func (s *DockerSuite) TestExecEnv(c *check.C) {
   155  
   156  	runCmd := exec.Command(dockerBinary, "run",
   157  		"-e", "LALA=value1",
   158  		"-e", "LALA=value2",
   159  		"-d", "--name", "testing", "busybox", "top")
   160  	if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
   161  		c.Fatal(out, err)
   162  	}
   163  
   164  	execCmd := exec.Command(dockerBinary, "exec", "testing", "env")
   165  	out, _, err := runCommandWithOutput(execCmd)
   166  	if err != nil {
   167  		c.Fatal(out, err)
   168  	}
   169  
   170  	if strings.Contains(out, "LALA=value1") ||
   171  		!strings.Contains(out, "LALA=value2") ||
   172  		!strings.Contains(out, "HOME=/root") {
   173  		c.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root")
   174  	}
   175  
   176  }
   177  
   178  func (s *DockerSuite) TestExecExitStatus(c *check.C) {
   179  
   180  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top")
   181  	if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil {
   182  		c.Fatal(out, err)
   183  	}
   184  
   185  	// Test normal (non-detached) case first
   186  	cmd := exec.Command(dockerBinary, "exec", "top", "sh", "-c", "exit 23")
   187  	ec, _ := runCommand(cmd)
   188  
   189  	if ec != 23 {
   190  		c.Fatalf("Should have had an ExitCode of 23, not: %d", ec)
   191  	}
   192  
   193  }
   194  
   195  func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
   196  	defer unpauseAllContainers()
   197  
   198  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top")
   199  	out, _, err := runCommandWithOutput(runCmd)
   200  	if err != nil {
   201  		c.Fatal(out, err)
   202  	}
   203  
   204  	ContainerID := strings.TrimSpace(out)
   205  
   206  	pausedCmd := exec.Command(dockerBinary, "pause", "testing")
   207  	out, _, _, err = runCommandWithStdoutStderr(pausedCmd)
   208  	if err != nil {
   209  		c.Fatal(out, err)
   210  	}
   211  
   212  	execCmd := exec.Command(dockerBinary, "exec", "-i", "-t", ContainerID, "echo", "hello")
   213  	out, _, err = runCommandWithOutput(execCmd)
   214  	if err == nil {
   215  		c.Fatal("container should fail to exec new command if it is paused")
   216  	}
   217  
   218  	expected := ContainerID + " is paused, unpause the container before exec"
   219  	if !strings.Contains(out, expected) {
   220  		c.Fatal("container should not exec new command if it is paused")
   221  	}
   222  
   223  }
   224  
   225  // regression test for #9476
   226  func (s *DockerSuite) TestExecTtyCloseStdin(c *check.C) {
   227  
   228  	cmd := exec.Command(dockerBinary, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox")
   229  	if out, _, err := runCommandWithOutput(cmd); err != nil {
   230  		c.Fatal(out, err)
   231  	}
   232  
   233  	cmd = exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat")
   234  	stdinRw, err := cmd.StdinPipe()
   235  	if err != nil {
   236  		c.Fatal(err)
   237  	}
   238  
   239  	stdinRw.Write([]byte("test"))
   240  	stdinRw.Close()
   241  
   242  	if out, _, err := runCommandWithOutput(cmd); err != nil {
   243  		c.Fatal(out, err)
   244  	}
   245  
   246  	cmd = exec.Command(dockerBinary, "top", "exec_tty_stdin")
   247  	out, _, err := runCommandWithOutput(cmd)
   248  	if err != nil {
   249  		c.Fatal(out, err)
   250  	}
   251  
   252  	outArr := strings.Split(out, "\n")
   253  	if len(outArr) > 3 || strings.Contains(out, "nsenter-exec") {
   254  		// This is the really bad part
   255  		if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "exec_tty_stdin")); err != nil {
   256  			c.Fatal(out, err)
   257  		}
   258  
   259  		c.Fatalf("exec process left running\n\t %s", out)
   260  	}
   261  
   262  }
   263  
   264  func (s *DockerSuite) TestExecTtyWithoutStdin(c *check.C) {
   265  
   266  	cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox")
   267  	out, _, err := runCommandWithOutput(cmd)
   268  	if err != nil {
   269  		c.Fatalf("failed to start container: %v (%v)", out, err)
   270  	}
   271  
   272  	id := strings.TrimSpace(out)
   273  	if err := waitRun(id); err != nil {
   274  		c.Fatal(err)
   275  	}
   276  
   277  	defer func() {
   278  		cmd := exec.Command(dockerBinary, "kill", id)
   279  		if out, _, err := runCommandWithOutput(cmd); err != nil {
   280  			c.Fatalf("failed to kill container: %v (%v)", out, err)
   281  		}
   282  	}()
   283  
   284  	done := make(chan struct{})
   285  	go func() {
   286  		defer close(done)
   287  
   288  		cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
   289  		if _, err := cmd.StdinPipe(); err != nil {
   290  			c.Fatal(err)
   291  		}
   292  
   293  		expected := "cannot enable tty mode"
   294  		if out, _, err := runCommandWithOutput(cmd); err == nil {
   295  			c.Fatal("exec should have failed")
   296  		} else if !strings.Contains(out, expected) {
   297  			c.Fatalf("exec failed with error %q: expected %q", out, expected)
   298  		}
   299  	}()
   300  
   301  	select {
   302  	case <-done:
   303  	case <-time.After(3 * time.Second):
   304  		c.Fatal("exec is running but should have failed")
   305  	}
   306  
   307  }
   308  
   309  func (s *DockerSuite) TestExecParseError(c *check.C) {
   310  
   311  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top")
   312  	if out, _, err := runCommandWithOutput(runCmd); err != nil {
   313  		c.Fatal(out, err)
   314  	}
   315  
   316  	// Test normal (non-detached) case first
   317  	cmd := exec.Command(dockerBinary, "exec", "top")
   318  	if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 {
   319  		c.Fatalf("Should have thrown error & point to help: %s", stderr)
   320  	}
   321  }
   322  
   323  func (s *DockerSuite) TestExecStopNotHanging(c *check.C) {
   324  	if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top").CombinedOutput(); err != nil {
   325  		c.Fatal(out, err)
   326  	}
   327  
   328  	if err := exec.Command(dockerBinary, "exec", "testing", "top").Start(); err != nil {
   329  		c.Fatal(err)
   330  	}
   331  
   332  	wait := make(chan struct{})
   333  	go func() {
   334  		if out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput(); err != nil {
   335  			c.Fatal(out, err)
   336  		}
   337  		close(wait)
   338  	}()
   339  	select {
   340  	case <-time.After(3 * time.Second):
   341  		c.Fatal("Container stop timed out")
   342  	case <-wait:
   343  	}
   344  }
   345  
   346  func (s *DockerSuite) TestExecCgroup(c *check.C) {
   347  	var cmd *exec.Cmd
   348  
   349  	cmd = exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top")
   350  	_, err := runCommand(cmd)
   351  	if err != nil {
   352  		c.Fatal(err)
   353  	}
   354  
   355  	cmd = exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/1/cgroup")
   356  	out, _, err := runCommandWithOutput(cmd)
   357  	if err != nil {
   358  		c.Fatal(out, err)
   359  	}
   360  	containerCgroups := sort.StringSlice(strings.Split(string(out), "\n"))
   361  
   362  	var wg sync.WaitGroup
   363  	var mu sync.Mutex
   364  	execCgroups := []sort.StringSlice{}
   365  	// exec a few times concurrently to get consistent failure
   366  	for i := 0; i < 5; i++ {
   367  		wg.Add(1)
   368  		go func() {
   369  			cmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/self/cgroup")
   370  			out, _, err := runCommandWithOutput(cmd)
   371  			if err != nil {
   372  				c.Fatal(out, err)
   373  			}
   374  			cg := sort.StringSlice(strings.Split(string(out), "\n"))
   375  
   376  			mu.Lock()
   377  			execCgroups = append(execCgroups, cg)
   378  			mu.Unlock()
   379  			wg.Done()
   380  		}()
   381  	}
   382  	wg.Wait()
   383  
   384  	for _, cg := range execCgroups {
   385  		if !reflect.DeepEqual(cg, containerCgroups) {
   386  			fmt.Println("exec cgroups:")
   387  			for _, name := range cg {
   388  				fmt.Printf(" %s\n", name)
   389  			}
   390  
   391  			fmt.Println("container cgroups:")
   392  			for _, name := range containerCgroups {
   393  				fmt.Printf(" %s\n", name)
   394  			}
   395  			c.Fatal("cgroups mismatched")
   396  		}
   397  	}
   398  
   399  }
   400  
   401  func (s *DockerSuite) TestInspectExecID(c *check.C) {
   402  
   403  	out, exitCode, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "busybox", "top"))
   404  	if exitCode != 0 || err != nil {
   405  		c.Fatalf("failed to run container: %s, %v", out, err)
   406  	}
   407  	id := strings.TrimSuffix(out, "\n")
   408  
   409  	out, err = inspectField(id, "ExecIDs")
   410  	if err != nil {
   411  		c.Fatalf("failed to inspect container: %s, %v", out, err)
   412  	}
   413  	if out != "[]" {
   414  		c.Fatalf("ExecIDs should be empty, got: %s", out)
   415  	}
   416  
   417  	exitCode, err = runCommand(exec.Command(dockerBinary, "exec", "-d", id, "ls", "/"))
   418  	if exitCode != 0 || err != nil {
   419  		c.Fatalf("failed to exec in container: %s, %v", out, err)
   420  	}
   421  
   422  	out, err = inspectField(id, "ExecIDs")
   423  	if err != nil {
   424  		c.Fatalf("failed to inspect container: %s, %v", out, err)
   425  	}
   426  
   427  	out = strings.TrimSuffix(out, "\n")
   428  	if out == "[]" || out == "<no value>" {
   429  		c.Fatalf("ExecIDs should not be empty, got: %s", out)
   430  	}
   431  
   432  }
   433  
   434  func (s *DockerSuite) TestLinksPingLinkedContainersOnRename(c *check.C) {
   435  
   436  	var out string
   437  	out, _ = dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   438  	idA := strings.TrimSpace(out)
   439  	if idA == "" {
   440  		c.Fatal(out, "id should not be nil")
   441  	}
   442  	out, _ = dockerCmd(c, "run", "-d", "--link", "container1:alias1", "--name", "container2", "busybox", "top")
   443  	idB := strings.TrimSpace(out)
   444  	if idB == "" {
   445  		c.Fatal(out, "id should not be nil")
   446  	}
   447  
   448  	execCmd := exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
   449  	out, _, err := runCommandWithOutput(execCmd)
   450  	if err != nil {
   451  		c.Fatal(out, err)
   452  	}
   453  
   454  	dockerCmd(c, "rename", "container1", "container_new")
   455  
   456  	execCmd = exec.Command(dockerBinary, "exec", "container2", "ping", "-c", "1", "alias1", "-W", "1")
   457  	out, _, err = runCommandWithOutput(execCmd)
   458  	if err != nil {
   459  		c.Fatal(out, err)
   460  	}
   461  
   462  }
   463  
   464  func (s *DockerSuite) TestRunExecDir(c *check.C) {
   465  	testRequires(c, SameHostDaemon)
   466  	cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top")
   467  	out, _, err := runCommandWithOutput(cmd)
   468  	if err != nil {
   469  		c.Fatal(err, out)
   470  	}
   471  	id := strings.TrimSpace(out)
   472  	execDir := filepath.Join(execDriverPath, id)
   473  	stateFile := filepath.Join(execDir, "state.json")
   474  
   475  	{
   476  		fi, err := os.Stat(execDir)
   477  		if err != nil {
   478  			c.Fatal(err)
   479  		}
   480  		if !fi.IsDir() {
   481  			c.Fatalf("%q must be a directory", execDir)
   482  		}
   483  		fi, err = os.Stat(stateFile)
   484  		if err != nil {
   485  			c.Fatal(err)
   486  		}
   487  	}
   488  
   489  	stopCmd := exec.Command(dockerBinary, "stop", id)
   490  	out, _, err = runCommandWithOutput(stopCmd)
   491  	if err != nil {
   492  		c.Fatal(err, out)
   493  	}
   494  	{
   495  		_, err := os.Stat(execDir)
   496  		if err == nil {
   497  			c.Fatal(err)
   498  		}
   499  		if err == nil {
   500  			c.Fatalf("Exec directory %q exists for removed container!", execDir)
   501  		}
   502  		if !os.IsNotExist(err) {
   503  			c.Fatalf("Error should be about non-existing, got %s", err)
   504  		}
   505  	}
   506  	startCmd := exec.Command(dockerBinary, "start", id)
   507  	out, _, err = runCommandWithOutput(startCmd)
   508  	if err != nil {
   509  		c.Fatal(err, out)
   510  	}
   511  	{
   512  		fi, err := os.Stat(execDir)
   513  		if err != nil {
   514  			c.Fatal(err)
   515  		}
   516  		if !fi.IsDir() {
   517  			c.Fatalf("%q must be a directory", execDir)
   518  		}
   519  		fi, err = os.Stat(stateFile)
   520  		if err != nil {
   521  			c.Fatal(err)
   522  		}
   523  	}
   524  	rmCmd := exec.Command(dockerBinary, "rm", "-f", id)
   525  	out, _, err = runCommandWithOutput(rmCmd)
   526  	if err != nil {
   527  		c.Fatal(err, out)
   528  	}
   529  	{
   530  		_, err := os.Stat(execDir)
   531  		if err == nil {
   532  			c.Fatal(err)
   533  		}
   534  		if err == nil {
   535  			c.Fatalf("Exec directory %q is exists for removed container!", execDir)
   536  		}
   537  		if !os.IsNotExist(err) {
   538  			c.Fatalf("Error should be about non-existing, got %s", err)
   539  		}
   540  	}
   541  
   542  }
   543  
   544  func (s *DockerSuite) TestRunMutableNetworkFiles(c *check.C) {
   545  	testRequires(c, SameHostDaemon)
   546  
   547  	for _, fn := range []string{"resolv.conf", "hosts"} {
   548  		deleteAllContainers()
   549  
   550  		content, err := runCommandAndReadContainerFile(fn, exec.Command(dockerBinary, "run", "-d", "--name", "c1", "busybox", "sh", "-c", fmt.Sprintf("echo success >/etc/%s && top", fn)))
   551  		if err != nil {
   552  			c.Fatal(err)
   553  		}
   554  
   555  		if strings.TrimSpace(string(content)) != "success" {
   556  			c.Fatal("Content was not what was modified in the container", string(content))
   557  		}
   558  
   559  		out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--name", "c2", "busybox", "top"))
   560  		if err != nil {
   561  			c.Fatal(err)
   562  		}
   563  
   564  		contID := strings.TrimSpace(out)
   565  
   566  		netFilePath := containerStorageFile(contID, fn)
   567  
   568  		f, err := os.OpenFile(netFilePath, os.O_WRONLY|os.O_SYNC|os.O_APPEND, 0644)
   569  		if err != nil {
   570  			c.Fatal(err)
   571  		}
   572  
   573  		if _, err := f.Seek(0, 0); err != nil {
   574  			f.Close()
   575  			c.Fatal(err)
   576  		}
   577  
   578  		if err := f.Truncate(0); err != nil {
   579  			f.Close()
   580  			c.Fatal(err)
   581  		}
   582  
   583  		if _, err := f.Write([]byte("success2\n")); err != nil {
   584  			f.Close()
   585  			c.Fatal(err)
   586  		}
   587  		f.Close()
   588  
   589  		res, err := exec.Command(dockerBinary, "exec", contID, "cat", "/etc/"+fn).CombinedOutput()
   590  		if err != nil {
   591  			c.Fatalf("Output: %s, error: %s", res, err)
   592  		}
   593  		if string(res) != "success2\n" {
   594  			c.Fatalf("Expected content of %s: %q, got: %q", fn, "success2\n", res)
   595  		}
   596  	}
   597  }
   598  
   599  func (s *DockerSuite) TestExecWithUser(c *check.C) {
   600  
   601  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "busybox", "top")
   602  	if out, _, err := runCommandWithOutput(runCmd); err != nil {
   603  		c.Fatal(out, err)
   604  	}
   605  
   606  	cmd := exec.Command(dockerBinary, "exec", "-u", "1", "parent", "id")
   607  	out, _, err := runCommandWithOutput(cmd)
   608  	if err != nil {
   609  		c.Fatal(err, out)
   610  	}
   611  	if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") {
   612  		c.Fatalf("exec with user by id expected daemon user got %s", out)
   613  	}
   614  
   615  	cmd = exec.Command(dockerBinary, "exec", "-u", "root", "parent", "id")
   616  	out, _, err = runCommandWithOutput(cmd)
   617  	if err != nil {
   618  		c.Fatal(err, out)
   619  	}
   620  	if !strings.Contains(out, "uid=0(root) gid=0(root)") {
   621  		c.Fatalf("exec with user by root expected root user got %s", out)
   622  	}
   623  
   624  }
   625  
   626  func (s *DockerSuite) TestExecWithPrivileged(c *check.C) {
   627  
   628  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "parent", "--cap-drop=ALL", "busybox", "top")
   629  	if out, _, err := runCommandWithOutput(runCmd); err != nil {
   630  		c.Fatal(out, err)
   631  	}
   632  
   633  	cmd := exec.Command(dockerBinary, "exec", "parent", "sh", "-c", "mknod /tmp/sda b 8 0")
   634  	out, _, err := runCommandWithOutput(cmd)
   635  	if err == nil || !strings.Contains(out, "Operation not permitted") {
   636  		c.Fatalf("exec mknod in --cap-drop=ALL container without --privileged should failed")
   637  	}
   638  
   639  	cmd = exec.Command(dockerBinary, "exec", "--privileged", "parent", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok")
   640  	out, _, err = runCommandWithOutput(cmd)
   641  	if err != nil {
   642  		c.Fatal(err, out)
   643  	}
   644  
   645  	if actual := strings.TrimSpace(out); actual != "ok" {
   646  		c.Fatalf("exec mknod in --cap-drop=ALL container with --privileged failed: %v, output: %q", err, out)
   647  	}
   648  
   649  }