github.com/feiyang21687/docker@v1.5.0/integration-cli/docker_cli_daemon_test.go (about)

     1  // +build daemon
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"os/exec"
    11  	"path/filepath"
    12  	"strings"
    13  	"testing"
    14  
    15  	"github.com/docker/libtrust"
    16  )
    17  
    18  func TestDaemonRestartWithRunningContainersPorts(t *testing.T) {
    19  	d := NewDaemon(t)
    20  	if err := d.StartWithBusybox(); err != nil {
    21  		t.Fatalf("Could not start daemon with busybox: %v", err)
    22  	}
    23  	defer d.Stop()
    24  
    25  	if out, err := d.Cmd("run", "-d", "--name", "top1", "-p", "1234:80", "--restart", "always", "busybox:latest", "top"); err != nil {
    26  		t.Fatalf("Could not run top1: err=%v\n%s", err, out)
    27  	}
    28  	// --restart=no by default
    29  	if out, err := d.Cmd("run", "-d", "--name", "top2", "-p", "80", "busybox:latest", "top"); err != nil {
    30  		t.Fatalf("Could not run top2: err=%v\n%s", err, out)
    31  	}
    32  
    33  	testRun := func(m map[string]bool, prefix string) {
    34  		var format string
    35  		for c, shouldRun := range m {
    36  			out, err := d.Cmd("ps")
    37  			if err != nil {
    38  				t.Fatalf("Could not run ps: err=%v\n%q", err, out)
    39  			}
    40  			if shouldRun {
    41  				format = "%scontainer %q is not running"
    42  			} else {
    43  				format = "%scontainer %q is running"
    44  			}
    45  			if shouldRun != strings.Contains(out, c) {
    46  				t.Fatalf(format, prefix, c)
    47  			}
    48  		}
    49  	}
    50  
    51  	testRun(map[string]bool{"top1": true, "top2": true}, "")
    52  
    53  	if err := d.Restart(); err != nil {
    54  		t.Fatalf("Could not restart daemon: %v", err)
    55  	}
    56  
    57  	testRun(map[string]bool{"top1": true, "top2": false}, "After daemon restart: ")
    58  
    59  	logDone("daemon - running containers on daemon restart")
    60  }
    61  
    62  func TestDaemonRestartWithVolumesRefs(t *testing.T) {
    63  	d := NewDaemon(t)
    64  	if err := d.StartWithBusybox(); err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	defer d.Stop()
    68  
    69  	if out, err := d.Cmd("run", "-d", "--name", "volrestarttest1", "-v", "/foo", "busybox"); err != nil {
    70  		t.Fatal(err, out)
    71  	}
    72  	if err := d.Restart(); err != nil {
    73  		t.Fatal(err)
    74  	}
    75  	if _, err := d.Cmd("run", "-d", "--volumes-from", "volrestarttest1", "--name", "volrestarttest2", "busybox", "top"); err != nil {
    76  		t.Fatal(err)
    77  	}
    78  	if out, err := d.Cmd("rm", "-fv", "volrestarttest2"); err != nil {
    79  		t.Fatal(err, out)
    80  	}
    81  	v, err := d.Cmd("inspect", "--format", "{{ json .Volumes }}", "volrestarttest1")
    82  	if err != nil {
    83  		t.Fatal(err)
    84  	}
    85  	volumes := make(map[string]string)
    86  	json.Unmarshal([]byte(v), &volumes)
    87  	if _, err := os.Stat(volumes["/foo"]); err != nil {
    88  		t.Fatalf("Expected volume to exist: %s - %s", volumes["/foo"], err)
    89  	}
    90  
    91  	logDone("daemon - volume refs are restored")
    92  }
    93  
    94  func TestDaemonStartIptablesFalse(t *testing.T) {
    95  	d := NewDaemon(t)
    96  	if err := d.Start("--iptables=false"); err != nil {
    97  		t.Fatalf("we should have been able to start the daemon with passing iptables=false: %v", err)
    98  	}
    99  	d.Stop()
   100  
   101  	logDone("daemon - started daemon with iptables=false")
   102  }
   103  
   104  // Issue #8444: If docker0 bridge is modified (intentionally or unintentionally) and
   105  // no longer has an IP associated, we should gracefully handle that case and associate
   106  // an IP with it rather than fail daemon start
   107  func TestDaemonStartBridgeWithoutIPAssociation(t *testing.T) {
   108  	d := NewDaemon(t)
   109  	// rather than depending on brctl commands to verify docker0 is created and up
   110  	// let's start the daemon and stop it, and then make a modification to run the
   111  	// actual test
   112  	if err := d.Start(); err != nil {
   113  		t.Fatalf("Could not start daemon: %v", err)
   114  	}
   115  	if err := d.Stop(); err != nil {
   116  		t.Fatalf("Could not stop daemon: %v", err)
   117  	}
   118  
   119  	// now we will remove the ip from docker0 and then try starting the daemon
   120  	ipCmd := exec.Command("ip", "addr", "flush", "dev", "docker0")
   121  	stdout, stderr, _, err := runCommandWithStdoutStderr(ipCmd)
   122  	if err != nil {
   123  		t.Fatalf("failed to remove docker0 IP association: %v, stdout: %q, stderr: %q", err, stdout, stderr)
   124  	}
   125  
   126  	if err := d.Start(); err != nil {
   127  		warning := "**WARNING: Docker bridge network in bad state--delete docker0 bridge interface to fix"
   128  		t.Fatalf("Could not start daemon when docker0 has no IP address: %v\n%s", err, warning)
   129  	}
   130  
   131  	// cleanup - stop the daemon if test passed
   132  	if err := d.Stop(); err != nil {
   133  		t.Fatalf("Could not stop daemon: %v", err)
   134  	}
   135  
   136  	logDone("daemon - successful daemon start when bridge has no IP association")
   137  }
   138  
   139  func TestDaemonIptablesClean(t *testing.T) {
   140  	d := NewDaemon(t)
   141  	if err := d.StartWithBusybox(); err != nil {
   142  		t.Fatalf("Could not start daemon with busybox: %v", err)
   143  	}
   144  	defer d.Stop()
   145  
   146  	if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil {
   147  		t.Fatalf("Could not run top: %s, %v", out, err)
   148  	}
   149  
   150  	// get output from iptables with container running
   151  	ipTablesSearchString := "tcp dpt:80"
   152  	ipTablesCmd := exec.Command("iptables", "-nvL")
   153  	out, _, err := runCommandWithOutput(ipTablesCmd)
   154  	if err != nil {
   155  		t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
   156  	}
   157  
   158  	if !strings.Contains(out, ipTablesSearchString) {
   159  		t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
   160  	}
   161  
   162  	if err := d.Stop(); err != nil {
   163  		t.Fatalf("Could not stop daemon: %v", err)
   164  	}
   165  
   166  	// get output from iptables after restart
   167  	ipTablesCmd = exec.Command("iptables", "-nvL")
   168  	out, _, err = runCommandWithOutput(ipTablesCmd)
   169  	if err != nil {
   170  		t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
   171  	}
   172  
   173  	if strings.Contains(out, ipTablesSearchString) {
   174  		t.Fatalf("iptables output should not have contained %q, but was %q", ipTablesSearchString, out)
   175  	}
   176  
   177  	deleteAllContainers()
   178  
   179  	logDone("daemon - run,iptables - iptables rules cleaned after daemon restart")
   180  }
   181  
   182  func TestDaemonIptablesCreate(t *testing.T) {
   183  	d := NewDaemon(t)
   184  	if err := d.StartWithBusybox(); err != nil {
   185  		t.Fatalf("Could not start daemon with busybox: %v", err)
   186  	}
   187  	defer d.Stop()
   188  
   189  	if out, err := d.Cmd("run", "-d", "--name", "top", "--restart=always", "-p", "80", "busybox:latest", "top"); err != nil {
   190  		t.Fatalf("Could not run top: %s, %v", out, err)
   191  	}
   192  
   193  	// get output from iptables with container running
   194  	ipTablesSearchString := "tcp dpt:80"
   195  	ipTablesCmd := exec.Command("iptables", "-nvL")
   196  	out, _, err := runCommandWithOutput(ipTablesCmd)
   197  	if err != nil {
   198  		t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
   199  	}
   200  
   201  	if !strings.Contains(out, ipTablesSearchString) {
   202  		t.Fatalf("iptables output should have contained %q, but was %q", ipTablesSearchString, out)
   203  	}
   204  
   205  	if err := d.Restart(); err != nil {
   206  		t.Fatalf("Could not restart daemon: %v", err)
   207  	}
   208  
   209  	// make sure the container is not running
   210  	runningOut, err := d.Cmd("inspect", "--format='{{.State.Running}}'", "top")
   211  	if err != nil {
   212  		t.Fatalf("Could not inspect on container: %s, %v", out, err)
   213  	}
   214  	if strings.TrimSpace(runningOut) != "true" {
   215  		t.Fatalf("Container should have been restarted after daemon restart. Status running should have been true but was: %q", strings.TrimSpace(runningOut))
   216  	}
   217  
   218  	// get output from iptables after restart
   219  	ipTablesCmd = exec.Command("iptables", "-nvL")
   220  	out, _, err = runCommandWithOutput(ipTablesCmd)
   221  	if err != nil {
   222  		t.Fatalf("Could not run iptables -nvL: %s, %v", out, err)
   223  	}
   224  
   225  	if !strings.Contains(out, ipTablesSearchString) {
   226  		t.Fatalf("iptables output after restart should have contained %q, but was %q", ipTablesSearchString, out)
   227  	}
   228  
   229  	deleteAllContainers()
   230  
   231  	logDone("daemon - run,iptables - iptables rules for always restarted container created after daemon restart")
   232  }
   233  
   234  func TestDaemonLoggingLevel(t *testing.T) {
   235  	d := NewDaemon(t)
   236  
   237  	if err := d.Start("--log-level=bogus"); err == nil {
   238  		t.Fatal("Daemon should not have been able to start")
   239  	}
   240  
   241  	d = NewDaemon(t)
   242  	if err := d.Start("--log-level=debug"); err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	d.Stop()
   246  	content, _ := ioutil.ReadFile(d.logFile.Name())
   247  	if !strings.Contains(string(content), `level="debug"`) {
   248  		t.Fatalf(`Missing level="debug" in log file:\n%s`, string(content))
   249  	}
   250  
   251  	d = NewDaemon(t)
   252  	if err := d.Start("--log-level=fatal"); err != nil {
   253  		t.Fatal(err)
   254  	}
   255  	d.Stop()
   256  	content, _ = ioutil.ReadFile(d.logFile.Name())
   257  	if strings.Contains(string(content), `level="debug"`) {
   258  		t.Fatalf(`Should not have level="debug" in log file:\n%s`, string(content))
   259  	}
   260  
   261  	d = NewDaemon(t)
   262  	if err := d.Start("-D"); err != nil {
   263  		t.Fatal(err)
   264  	}
   265  	d.Stop()
   266  	content, _ = ioutil.ReadFile(d.logFile.Name())
   267  	if !strings.Contains(string(content), `level="debug"`) {
   268  		t.Fatalf(`Missing level="debug" in log file using -D:\n%s`, string(content))
   269  	}
   270  
   271  	d = NewDaemon(t)
   272  	if err := d.Start("--debug"); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	d.Stop()
   276  	content, _ = ioutil.ReadFile(d.logFile.Name())
   277  	if !strings.Contains(string(content), `level="debug"`) {
   278  		t.Fatalf(`Missing level="debug" in log file using --debug:\n%s`, string(content))
   279  	}
   280  
   281  	d = NewDaemon(t)
   282  	if err := d.Start("--debug", "--log-level=fatal"); err != nil {
   283  		t.Fatal(err)
   284  	}
   285  	d.Stop()
   286  	content, _ = ioutil.ReadFile(d.logFile.Name())
   287  	if !strings.Contains(string(content), `level="debug"`) {
   288  		t.Fatalf(`Missing level="debug" in log file when using both --debug and --log-level=fatal:\n%s`, string(content))
   289  	}
   290  
   291  	logDone("daemon - Logging Level")
   292  }
   293  
   294  func TestDaemonAllocatesListeningPort(t *testing.T) {
   295  	listeningPorts := [][]string{
   296  		{"0.0.0.0", "0.0.0.0", "5678"},
   297  		{"127.0.0.1", "127.0.0.1", "1234"},
   298  		{"localhost", "127.0.0.1", "1235"},
   299  	}
   300  
   301  	cmdArgs := []string{}
   302  	for _, hostDirective := range listeningPorts {
   303  		cmdArgs = append(cmdArgs, "--host", fmt.Sprintf("tcp://%s:%s", hostDirective[0], hostDirective[2]))
   304  	}
   305  
   306  	d := NewDaemon(t)
   307  	if err := d.StartWithBusybox(cmdArgs...); err != nil {
   308  		t.Fatalf("Could not start daemon with busybox: %v", err)
   309  	}
   310  	defer d.Stop()
   311  
   312  	for _, hostDirective := range listeningPorts {
   313  		output, err := d.Cmd("run", "-p", fmt.Sprintf("%s:%s:80", hostDirective[1], hostDirective[2]), "busybox", "true")
   314  		if err == nil {
   315  			t.Fatalf("Container should not start, expected port already allocated error: %q", output)
   316  		} else if !strings.Contains(output, "port is already allocated") {
   317  			t.Fatalf("Expected port is already allocated error: %q", output)
   318  		}
   319  	}
   320  
   321  	logDone("daemon - daemon listening port is allocated")
   322  }
   323  
   324  // #9629
   325  func TestDaemonVolumesBindsRefs(t *testing.T) {
   326  	d := NewDaemon(t)
   327  
   328  	if err := d.StartWithBusybox(); err != nil {
   329  		t.Fatal(err)
   330  	}
   331  
   332  	tmp, err := ioutil.TempDir(os.TempDir(), "")
   333  	if err != nil {
   334  		t.Fatal(err)
   335  	}
   336  	defer os.RemoveAll(tmp)
   337  
   338  	if err := ioutil.WriteFile(tmp+"/test", []byte("testing"), 0655); err != nil {
   339  		t.Fatal(err)
   340  	}
   341  
   342  	if out, err := d.Cmd("create", "-v", tmp+":/foo", "--name=voltest", "busybox"); err != nil {
   343  		t.Fatal(err, out)
   344  	}
   345  
   346  	if err := d.Restart(); err != nil {
   347  		t.Fatal(err)
   348  	}
   349  
   350  	if out, err := d.Cmd("run", "--volumes-from=voltest", "--name=consumer", "busybox", "/bin/sh", "-c", "[ -f /foo/test ]"); err != nil {
   351  		t.Fatal(err, out)
   352  	}
   353  
   354  	logDone("daemon - bind refs in data-containers survive daemon restart")
   355  }
   356  
   357  func TestDaemonKeyGeneration(t *testing.T) {
   358  	// TODO: skip or update for Windows daemon
   359  	os.Remove("/etc/docker/key.json")
   360  	d := NewDaemon(t)
   361  	if err := d.Start(); err != nil {
   362  		t.Fatalf("Could not start daemon: %v", err)
   363  	}
   364  	d.Stop()
   365  
   366  	k, err := libtrust.LoadKeyFile("/etc/docker/key.json")
   367  	if err != nil {
   368  		t.Fatalf("Error opening key file")
   369  	}
   370  	kid := k.KeyID()
   371  	// Test Key ID is a valid fingerprint (e.g. QQXN:JY5W:TBXI:MK3X:GX6P:PD5D:F56N:NHCS:LVRZ:JA46:R24J:XEFF)
   372  	if len(kid) != 59 {
   373  		t.Fatalf("Bad key ID: %s", kid)
   374  	}
   375  
   376  	logDone("daemon - key generation")
   377  }
   378  
   379  func TestDaemonKeyMigration(t *testing.T) {
   380  	// TODO: skip or update for Windows daemon
   381  	os.Remove("/etc/docker/key.json")
   382  	k1, err := libtrust.GenerateECP256PrivateKey()
   383  	if err != nil {
   384  		t.Fatalf("Error generating private key: %s", err)
   385  	}
   386  	if err := os.MkdirAll(filepath.Join(os.Getenv("HOME"), ".docker"), 0755); err != nil {
   387  		t.Fatalf("Error creating .docker directory: %s", err)
   388  	}
   389  	if err := libtrust.SaveKey(filepath.Join(os.Getenv("HOME"), ".docker", "key.json"), k1); err != nil {
   390  		t.Fatalf("Error saving private key: %s", err)
   391  	}
   392  
   393  	d := NewDaemon(t)
   394  	if err := d.Start(); err != nil {
   395  		t.Fatalf("Could not start daemon: %v", err)
   396  	}
   397  	d.Stop()
   398  
   399  	k2, err := libtrust.LoadKeyFile("/etc/docker/key.json")
   400  	if err != nil {
   401  		t.Fatalf("Error opening key file")
   402  	}
   403  	if k1.KeyID() != k2.KeyID() {
   404  		t.Fatalf("Key not migrated")
   405  	}
   406  
   407  	logDone("daemon - key migration")
   408  }
   409  
   410  // Simulate an older daemon (pre 1.3) coming up with volumes specified in containers
   411  //	without corrosponding volume json
   412  func TestDaemonUpgradeWithVolumes(t *testing.T) {
   413  	d := NewDaemon(t)
   414  
   415  	graphDir := filepath.Join(os.TempDir(), "docker-test")
   416  	defer os.RemoveAll(graphDir)
   417  	if err := d.StartWithBusybox("-g", graphDir); err != nil {
   418  		t.Fatal(err)
   419  	}
   420  
   421  	tmpDir := filepath.Join(os.TempDir(), "test")
   422  	defer os.RemoveAll(tmpDir)
   423  
   424  	if out, err := d.Cmd("create", "-v", tmpDir+":/foo", "--name=test", "busybox"); err != nil {
   425  		t.Fatal(err, out)
   426  	}
   427  
   428  	if err := d.Stop(); err != nil {
   429  		t.Fatal(err)
   430  	}
   431  
   432  	// Remove this since we're expecting the daemon to re-create it too
   433  	if err := os.RemoveAll(tmpDir); err != nil {
   434  		t.Fatal(err)
   435  	}
   436  
   437  	configDir := filepath.Join(graphDir, "volumes")
   438  
   439  	if err := os.RemoveAll(configDir); err != nil {
   440  		t.Fatal(err)
   441  	}
   442  
   443  	if err := d.Start("-g", graphDir); err != nil {
   444  		t.Fatal(err)
   445  	}
   446  
   447  	if _, err := os.Stat(tmpDir); os.IsNotExist(err) {
   448  		t.Fatalf("expected volume path %s to exist but it does not", tmpDir)
   449  	}
   450  
   451  	dir, err := ioutil.ReadDir(configDir)
   452  	if err != nil {
   453  		t.Fatal(err)
   454  	}
   455  	if len(dir) == 0 {
   456  		t.Fatalf("expected volumes config dir to contain data for new volume")
   457  	}
   458  
   459  	// Now with just removing the volume config and not the volume data
   460  	if err := d.Stop(); err != nil {
   461  		t.Fatal(err)
   462  	}
   463  
   464  	if err := os.RemoveAll(configDir); err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	if err := d.Start("-g", graphDir); err != nil {
   469  		t.Fatal(err)
   470  	}
   471  
   472  	dir, err = ioutil.ReadDir(configDir)
   473  	if err != nil {
   474  		t.Fatal(err)
   475  	}
   476  
   477  	if len(dir) == 0 {
   478  		t.Fatalf("expected volumes config dir to contain data for new volume")
   479  	}
   480  
   481  	logDone("daemon - volumes from old(pre 1.3) daemon work")
   482  }