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