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