github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/integration-cli/docker_cli_links_test.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"reflect"
     9  	"regexp"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/docker/docker/pkg/iptables"
    14  	"github.com/go-check/check"
    15  )
    16  
    17  func (s *DockerSuite) TestLinksEtcHostsRegularFile(c *check.C) {
    18  	runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts")
    19  	out, _, _, err := runCommandWithStdoutStderr(runCmd)
    20  	if err != nil {
    21  		c.Fatal(out, err)
    22  	}
    23  
    24  	if !strings.HasPrefix(out, "-") {
    25  		c.Errorf("/etc/hosts should be a regular file")
    26  	}
    27  }
    28  
    29  func (s *DockerSuite) TestLinksEtcHostsContentMatch(c *check.C) {
    30  	testRequires(c, SameHostDaemon)
    31  
    32  	runCmd := exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hosts")
    33  	out, _, _, err := runCommandWithStdoutStderr(runCmd)
    34  	if err != nil {
    35  		c.Fatal(out, err)
    36  	}
    37  
    38  	hosts, err := ioutil.ReadFile("/etc/hosts")
    39  	if os.IsNotExist(err) {
    40  		c.Skip("/etc/hosts does not exist, skip this test")
    41  	}
    42  
    43  	if out != string(hosts) {
    44  		c.Errorf("container")
    45  	}
    46  
    47  }
    48  
    49  func (s *DockerSuite) TestLinksPingUnlinkedContainers(c *check.C) {
    50  	runCmd := exec.Command(dockerBinary, "run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
    51  	exitCode, err := runCommand(runCmd)
    52  
    53  	if exitCode == 0 {
    54  		c.Fatal("run ping did not fail")
    55  	} else if exitCode != 1 {
    56  		c.Fatalf("run ping failed with errors: %v", err)
    57  	}
    58  
    59  }
    60  
    61  // Test for appropriate error when calling --link with an invalid target container
    62  func (s *DockerSuite) TestLinksInvalidContainerTarget(c *check.C) {
    63  
    64  	runCmd := exec.Command(dockerBinary, "run", "--link", "bogus:alias", "busybox", "true")
    65  	out, _, err := runCommandWithOutput(runCmd)
    66  
    67  	if err == nil {
    68  		c.Fatal("an invalid container target should produce an error")
    69  	}
    70  	if !strings.Contains(out, "Could not get container") {
    71  		c.Fatalf("error output expected 'Could not get container', but got %q instead; err: %v", out, err)
    72  	}
    73  
    74  }
    75  
    76  func (s *DockerSuite) TestLinksPingLinkedContainers(c *check.C) {
    77  
    78  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "container1", "--hostname", "fred", "busybox", "top")
    79  	if _, err := runCommand(runCmd); err != nil {
    80  		c.Fatal(err)
    81  	}
    82  	runCmd = exec.Command(dockerBinary, "run", "-d", "--name", "container2", "--hostname", "wilma", "busybox", "top")
    83  	if _, err := runCommand(runCmd); err != nil {
    84  		c.Fatal(err)
    85  	}
    86  
    87  	runArgs := []string{"run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "sh", "-c"}
    88  	pingCmd := "ping -c 1 %s -W 1 && ping -c 1 %s -W 1"
    89  
    90  	// test ping by alias, ping by name, and ping by hostname
    91  	// 1. Ping by alias
    92  	dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
    93  	// 2. Ping by container name
    94  	dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
    95  	// 3. Ping by hostname
    96  	dockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
    97  
    98  }
    99  
   100  func (s *DockerSuite) TestLinksPingLinkedContainersAfterRename(c *check.C) {
   101  
   102  	out, _ := dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   103  	idA := strings.TrimSpace(out)
   104  	out, _ = dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
   105  	idB := strings.TrimSpace(out)
   106  	dockerCmd(c, "rename", "container1", "container_new")
   107  	dockerCmd(c, "run", "--rm", "--link", "container_new:alias1", "--link", "container2:alias2", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
   108  	dockerCmd(c, "kill", idA)
   109  	dockerCmd(c, "kill", idB)
   110  
   111  }
   112  
   113  func (s *DockerSuite) TestLinksIpTablesRulesWhenLinkAndUnlink(c *check.C) {
   114  	testRequires(c, SameHostDaemon)
   115  
   116  	dockerCmd(c, "run", "-d", "--name", "child", "--publish", "8080:80", "busybox", "top")
   117  	dockerCmd(c, "run", "-d", "--name", "parent", "--link", "child:http", "busybox", "top")
   118  
   119  	childIP := findContainerIP(c, "child")
   120  	parentIP := findContainerIP(c, "parent")
   121  
   122  	sourceRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", childIP, "--sport", "80", "-d", parentIP, "-j", "ACCEPT"}
   123  	destinationRule := []string{"-i", "docker0", "-o", "docker0", "-p", "tcp", "-s", parentIP, "--dport", "80", "-d", childIP, "-j", "ACCEPT"}
   124  	if !iptables.Exists("filter", "DOCKER", sourceRule...) || !iptables.Exists("filter", "DOCKER", destinationRule...) {
   125  		c.Fatal("Iptables rules not found")
   126  	}
   127  
   128  	dockerCmd(c, "rm", "--link", "parent/http")
   129  	if iptables.Exists("filter", "DOCKER", sourceRule...) || iptables.Exists("filter", "DOCKER", destinationRule...) {
   130  		c.Fatal("Iptables rules should be removed when unlink")
   131  	}
   132  
   133  	dockerCmd(c, "kill", "child")
   134  	dockerCmd(c, "kill", "parent")
   135  
   136  }
   137  
   138  func (s *DockerSuite) TestLinksInspectLinksStarted(c *check.C) {
   139  	var (
   140  		expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
   141  		result   []string
   142  	)
   143  	dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   144  	dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
   145  	dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
   146  	links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
   147  	if err != nil {
   148  		c.Fatal(err)
   149  	}
   150  
   151  	err = unmarshalJSON([]byte(links), &result)
   152  	if err != nil {
   153  		c.Fatal(err)
   154  	}
   155  
   156  	output := convertSliceOfStringsToMap(result)
   157  
   158  	equal := reflect.DeepEqual(output, expected)
   159  
   160  	if !equal {
   161  		c.Fatalf("Links %s, expected %s", result, expected)
   162  	}
   163  }
   164  
   165  func (s *DockerSuite) TestLinksInspectLinksStopped(c *check.C) {
   166  	var (
   167  		expected = map[string]struct{}{"/container1:/testinspectlink/alias1": {}, "/container2:/testinspectlink/alias2": {}}
   168  		result   []string
   169  	)
   170  	dockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   171  	dockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
   172  	dockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
   173  	links, err := inspectFieldJSON("testinspectlink", "HostConfig.Links")
   174  	if err != nil {
   175  		c.Fatal(err)
   176  	}
   177  
   178  	err = unmarshalJSON([]byte(links), &result)
   179  	if err != nil {
   180  		c.Fatal(err)
   181  	}
   182  
   183  	output := convertSliceOfStringsToMap(result)
   184  
   185  	equal := reflect.DeepEqual(output, expected)
   186  
   187  	if !equal {
   188  		c.Fatalf("Links %s, but expected %s", result, expected)
   189  	}
   190  
   191  }
   192  
   193  func (s *DockerSuite) TestLinksNotStartedParentNotFail(c *check.C) {
   194  	runCmd := exec.Command(dockerBinary, "create", "--name=first", "busybox", "top")
   195  	out, _, _, err := runCommandWithStdoutStderr(runCmd)
   196  	if err != nil {
   197  		c.Fatal(out, err)
   198  	}
   199  	runCmd = exec.Command(dockerBinary, "create", "--name=second", "--link=first:first", "busybox", "top")
   200  	out, _, _, err = runCommandWithStdoutStderr(runCmd)
   201  	if err != nil {
   202  		c.Fatal(out, err)
   203  	}
   204  	runCmd = exec.Command(dockerBinary, "start", "first")
   205  	out, _, _, err = runCommandWithStdoutStderr(runCmd)
   206  	if err != nil {
   207  		c.Fatal(out, err)
   208  	}
   209  }
   210  
   211  func (s *DockerSuite) TestLinksHostsFilesInject(c *check.C) {
   212  	testRequires(c, SameHostDaemon, ExecSupport)
   213  
   214  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "one", "busybox", "top"))
   215  	if err != nil {
   216  		c.Fatal(err, out)
   217  	}
   218  
   219  	idOne := strings.TrimSpace(out)
   220  
   221  	out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "--name", "two", "--link", "one:onetwo", "busybox", "top"))
   222  	if err != nil {
   223  		c.Fatal(err, out)
   224  	}
   225  
   226  	idTwo := strings.TrimSpace(out)
   227  
   228  	time.Sleep(1 * time.Second)
   229  
   230  	contentOne, err := readContainerFileWithExec(idOne, "/etc/hosts")
   231  	if err != nil {
   232  		c.Fatal(err, string(contentOne))
   233  	}
   234  
   235  	contentTwo, err := readContainerFileWithExec(idTwo, "/etc/hosts")
   236  	if err != nil {
   237  		c.Fatal(err, string(contentTwo))
   238  	}
   239  
   240  	if !strings.Contains(string(contentTwo), "onetwo") {
   241  		c.Fatal("Host is not present in updated hosts file", string(contentTwo))
   242  	}
   243  
   244  }
   245  
   246  func (s *DockerSuite) TestLinksNetworkHostContainer(c *check.C) {
   247  
   248  	out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-d", "--net", "host", "--name", "host_container", "busybox", "top"))
   249  	if err != nil {
   250  		c.Fatal(err, out)
   251  	}
   252  
   253  	out, _, err = runCommandWithOutput(exec.Command(dockerBinary, "run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true"))
   254  	if err == nil || !strings.Contains(out, "--net=host can't be used with links. This would result in undefined behavior") {
   255  		c.Fatalf("Running container linking to a container with --net host should have failed: %s", out)
   256  	}
   257  
   258  }
   259  
   260  func (s *DockerSuite) TestLinksUpdateOnRestart(c *check.C) {
   261  	testRequires(c, SameHostDaemon, ExecSupport)
   262  
   263  	if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "one", "busybox", "top").CombinedOutput(); err != nil {
   264  		c.Fatal(err, string(out))
   265  	}
   266  	out, err := exec.Command(dockerBinary, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top").CombinedOutput()
   267  	if err != nil {
   268  		c.Fatal(err, string(out))
   269  	}
   270  	id := strings.TrimSpace(string(out))
   271  
   272  	realIP, err := inspectField("one", "NetworkSettings.IPAddress")
   273  	if err != nil {
   274  		c.Fatal(err)
   275  	}
   276  	content, err := readContainerFileWithExec(id, "/etc/hosts")
   277  	if err != nil {
   278  		c.Fatal(err, string(content))
   279  	}
   280  	getIP := func(hosts []byte, hostname string) string {
   281  		re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname)))
   282  		matches := re.FindSubmatch(hosts)
   283  		if matches == nil {
   284  			c.Fatalf("Hostname %s have no matches in hosts", hostname)
   285  		}
   286  		return string(matches[1])
   287  	}
   288  	if ip := getIP(content, "one"); ip != realIP {
   289  		c.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
   290  	}
   291  	if ip := getIP(content, "onetwo"); ip != realIP {
   292  		c.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
   293  	}
   294  	if out, err := exec.Command(dockerBinary, "restart", "one").CombinedOutput(); err != nil {
   295  		c.Fatal(err, string(out))
   296  	}
   297  	realIP, err = inspectField("one", "NetworkSettings.IPAddress")
   298  	if err != nil {
   299  		c.Fatal(err)
   300  	}
   301  	content, err = readContainerFileWithExec(id, "/etc/hosts")
   302  	if err != nil {
   303  		c.Fatal(err, string(content))
   304  	}
   305  	if ip := getIP(content, "one"); ip != realIP {
   306  		c.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip)
   307  	}
   308  	if ip := getIP(content, "onetwo"); ip != realIP {
   309  		c.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip)
   310  	}
   311  }
   312  
   313  func (s *DockerSuite) TestLinksEnvs(c *check.C) {
   314  	runCmd := exec.Command(dockerBinary, "run", "-d", "-e", "e1=", "-e", "e2=v2", "-e", "e3=v3=v3", "--name=first", "busybox", "top")
   315  	out, _, _, err := runCommandWithStdoutStderr(runCmd)
   316  	if err != nil {
   317  		c.Fatalf("Run of first failed: %s\n%s", out, err)
   318  	}
   319  
   320  	runCmd = exec.Command(dockerBinary, "run", "--name=second", "--link=first:first", "busybox", "env")
   321  
   322  	out, stde, rc, err := runCommandWithStdoutStderr(runCmd)
   323  	if err != nil || rc != 0 {
   324  		c.Fatalf("run of 2nd failed: rc: %d, out: %s\n err: %s", rc, out, stde)
   325  	}
   326  
   327  	if !strings.Contains(out, "FIRST_ENV_e1=\n") ||
   328  		!strings.Contains(out, "FIRST_ENV_e2=v2") ||
   329  		!strings.Contains(out, "FIRST_ENV_e3=v3=v3") {
   330  		c.Fatalf("Incorrect output: %s", out)
   331  	}
   332  }
   333  
   334  func (s *DockerSuite) TestLinkShortDefinition(c *check.C) {
   335  	runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "shortlinkdef", "busybox", "top")
   336  	out, _, err := runCommandWithOutput(runCmd)
   337  	c.Assert(err, check.IsNil)
   338  
   339  	cid := strings.TrimSpace(out)
   340  	c.Assert(waitRun(cid), check.IsNil)
   341  
   342  	runCmd = exec.Command(dockerBinary, "run", "-d", "--name", "link2", "--link", "shortlinkdef", "busybox", "top")
   343  	out, _, err = runCommandWithOutput(runCmd)
   344  	c.Assert(err, check.IsNil)
   345  
   346  	cid2 := strings.TrimSpace(out)
   347  	c.Assert(waitRun(cid2), check.IsNil)
   348  
   349  	links, err := inspectFieldJSON(cid2, "HostConfig.Links")
   350  	c.Assert(err, check.IsNil)
   351  	c.Assert(links, check.Equals, "[\"/shortlinkdef:/link2/shortlinkdef\"]")
   352  }