github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/integration-cli/docker_cli_links_test.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"regexp"
     8  	"sort"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/Prakhar-Agarwal-byte/moby/integration-cli/cli"
    13  	"github.com/Prakhar-Agarwal-byte/moby/runconfig"
    14  	"gotest.tools/v3/assert"
    15  	is "gotest.tools/v3/assert/cmp"
    16  )
    17  
    18  type DockerCLILinksSuite struct {
    19  	ds *DockerSuite
    20  }
    21  
    22  func (s *DockerCLILinksSuite) TearDownTest(ctx context.Context, c *testing.T) {
    23  	s.ds.TearDownTest(ctx, c)
    24  }
    25  
    26  func (s *DockerCLILinksSuite) OnTimeout(c *testing.T) {
    27  	s.ds.OnTimeout(c)
    28  }
    29  
    30  func (s *DockerCLILinksSuite) TestLinksPingUnlinkedContainers(c *testing.T) {
    31  	testRequires(c, DaemonIsLinux)
    32  	_, exitCode, err := dockerCmdWithError("run", "--rm", "busybox", "sh", "-c", "ping -c 1 alias1 -W 1 && ping -c 1 alias2 -W 1")
    33  
    34  	// run ping failed with error
    35  	assert.Equal(c, exitCode, 1, fmt.Sprintf("error: %v", err))
    36  }
    37  
    38  // Test for appropriate error when calling --link with an invalid target container
    39  func (s *DockerCLILinksSuite) TestLinksInvalidContainerTarget(c *testing.T) {
    40  	testRequires(c, DaemonIsLinux)
    41  	out, _, err := dockerCmdWithError("run", "--link", "bogus:alias", "busybox", "true")
    42  
    43  	// an invalid container target should produce an error
    44  	assert.Check(c, is.ErrorContains(err, "could not get container for bogus"))
    45  	assert.Check(c, is.Contains(out, "could not get container"))
    46  }
    47  
    48  func (s *DockerCLILinksSuite) TestLinksPingLinkedContainers(c *testing.T) {
    49  	testRequires(c, DaemonIsLinux)
    50  	// Test with the three different ways of specifying the default network on Linux
    51  	testLinkPingOnNetwork(c, "")
    52  	testLinkPingOnNetwork(c, "default")
    53  	testLinkPingOnNetwork(c, "bridge")
    54  }
    55  
    56  func testLinkPingOnNetwork(c *testing.T, network string) {
    57  	var postArgs []string
    58  	if network != "" {
    59  		postArgs = append(postArgs, []string{"--net", network}...)
    60  	}
    61  	postArgs = append(postArgs, []string{"busybox", "top"}...)
    62  	runArgs1 := append([]string{"run", "-d", "--name", "container1", "--hostname", "fred"}, postArgs...)
    63  	runArgs2 := append([]string{"run", "-d", "--name", "container2", "--hostname", "wilma"}, postArgs...)
    64  
    65  	// Run the two named containers
    66  	cli.DockerCmd(c, runArgs1...)
    67  	cli.DockerCmd(c, runArgs2...)
    68  
    69  	postArgs = []string{}
    70  	if network != "" {
    71  		postArgs = append(postArgs, []string{"--net", network}...)
    72  	}
    73  	postArgs = append(postArgs, []string{"busybox", "sh", "-c"}...)
    74  
    75  	// Format a run for a container which links to the other two
    76  	runArgs := append([]string{"run", "--rm", "--link", "container1:alias1", "--link", "container2:alias2"}, postArgs...)
    77  	pingCmd := "ping -c 1 %s -W 1 && ping -c 1 %s -W 1"
    78  
    79  	// test ping by alias, ping by name, and ping by hostname
    80  	// 1. Ping by alias
    81  	cli.DockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "alias1", "alias2"))...)
    82  	// 2. Ping by container name
    83  	cli.DockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "container1", "container2"))...)
    84  	// 3. Ping by hostname
    85  	cli.DockerCmd(c, append(runArgs, fmt.Sprintf(pingCmd, "fred", "wilma"))...)
    86  
    87  	// Clean for next round
    88  	cli.DockerCmd(c, "rm", "-f", "container1")
    89  	cli.DockerCmd(c, "rm", "-f", "container2")
    90  }
    91  
    92  func (s *DockerCLILinksSuite) TestLinksPingLinkedContainersAfterRename(c *testing.T) {
    93  	testRequires(c, DaemonIsLinux)
    94  	idA := cli.DockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top").Stdout()
    95  	idB := cli.DockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top").Stdout()
    96  	cli.DockerCmd(c, "rename", "container1", "container_new")
    97  	cli.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")
    98  	cli.DockerCmd(c, "kill", strings.TrimSpace(idA))
    99  	cli.DockerCmd(c, "kill", strings.TrimSpace(idB))
   100  }
   101  
   102  func (s *DockerCLILinksSuite) TestLinksInspectLinksStarted(c *testing.T) {
   103  	testRequires(c, DaemonIsLinux)
   104  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   105  	cli.DockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
   106  	cli.DockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "top")
   107  	links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
   108  
   109  	var result []string
   110  	err := json.Unmarshal([]byte(links), &result)
   111  	assert.NilError(c, err)
   112  
   113  	expected := []string{
   114  		"/container1:/testinspectlink/alias1",
   115  		"/container2:/testinspectlink/alias2",
   116  	}
   117  	sort.Strings(result)
   118  	assert.DeepEqual(c, result, expected)
   119  }
   120  
   121  func (s *DockerCLILinksSuite) TestLinksInspectLinksStopped(c *testing.T) {
   122  	testRequires(c, DaemonIsLinux)
   123  
   124  	cli.DockerCmd(c, "run", "-d", "--name", "container1", "busybox", "top")
   125  	cli.DockerCmd(c, "run", "-d", "--name", "container2", "busybox", "top")
   126  	cli.DockerCmd(c, "run", "-d", "--name", "testinspectlink", "--link", "container1:alias1", "--link", "container2:alias2", "busybox", "true")
   127  	links := inspectFieldJSON(c, "testinspectlink", "HostConfig.Links")
   128  
   129  	var result []string
   130  	err := json.Unmarshal([]byte(links), &result)
   131  	assert.NilError(c, err)
   132  
   133  	expected := []string{
   134  		"/container1:/testinspectlink/alias1",
   135  		"/container2:/testinspectlink/alias2",
   136  	}
   137  	sort.Strings(result)
   138  	assert.DeepEqual(c, result, expected)
   139  }
   140  
   141  func (s *DockerCLILinksSuite) TestLinksNotStartedParentNotFail(c *testing.T) {
   142  	testRequires(c, DaemonIsLinux)
   143  	cli.DockerCmd(c, "create", "--name=first", "busybox", "top")
   144  	cli.DockerCmd(c, "create", "--name=second", "--link=first:first", "busybox", "top")
   145  	cli.DockerCmd(c, "start", "first")
   146  }
   147  
   148  func (s *DockerCLILinksSuite) TestLinksHostsFilesInject(c *testing.T) {
   149  	testRequires(c, DaemonIsLinux)
   150  	testRequires(c, testEnv.IsLocalDaemon)
   151  
   152  	idOne := cli.DockerCmd(c, "run", "-itd", "--name", "one", "busybox", "top").Stdout()
   153  	idOne = strings.TrimSpace(idOne)
   154  	idTwo := cli.DockerCmd(c, "run", "-itd", "--name", "two", "--link", "one:onetwo", "busybox", "top").Stdout()
   155  	idTwo = strings.TrimSpace(idTwo)
   156  	cli.WaitRun(c, idTwo)
   157  
   158  	readContainerFileWithExec(c, idOne, "/etc/hosts")
   159  	contentTwo := readContainerFileWithExec(c, idTwo, "/etc/hosts")
   160  	// Host is not present in updated hosts file
   161  	assert.Assert(c, is.Contains(string(contentTwo), "onetwo"))
   162  }
   163  
   164  func (s *DockerCLILinksSuite) TestLinksUpdateOnRestart(c *testing.T) {
   165  	testRequires(c, DaemonIsLinux)
   166  	testRequires(c, testEnv.IsLocalDaemon)
   167  	cli.DockerCmd(c, "run", "-d", "--name", "one", "busybox", "top")
   168  	id := cli.DockerCmd(c, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top").Stdout()
   169  	id = strings.TrimSpace(id)
   170  
   171  	realIP := inspectField(c, "one", "NetworkSettings.Networks.bridge.IPAddress")
   172  	content := readContainerFileWithExec(c, id, "/etc/hosts")
   173  
   174  	getIP := func(hosts []byte, hostname string) string {
   175  		re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname)))
   176  		matches := re.FindSubmatch(hosts)
   177  		assert.Assert(c, matches != nil, "Hostname %s have no matches in hosts", hostname)
   178  		return string(matches[1])
   179  	}
   180  	ip := getIP(content, "one")
   181  	assert.Check(c, is.Equal(ip, realIP))
   182  
   183  	ip = getIP(content, "onetwo")
   184  	assert.Check(c, is.Equal(ip, realIP))
   185  
   186  	cli.DockerCmd(c, "restart", "one")
   187  	realIP = inspectField(c, "one", "NetworkSettings.Networks.bridge.IPAddress")
   188  
   189  	content = readContainerFileWithExec(c, id, "/etc/hosts")
   190  	ip = getIP(content, "one")
   191  	assert.Check(c, is.Equal(ip, realIP))
   192  
   193  	ip = getIP(content, "onetwo")
   194  	assert.Check(c, is.Equal(ip, realIP))
   195  }
   196  
   197  func (s *DockerCLILinksSuite) TestLinksEnvs(c *testing.T) {
   198  	testRequires(c, DaemonIsLinux)
   199  	cli.DockerCmd(c, "run", "-d", "-e", "e1=", "-e", "e2=v2", "-e", "e3=v3=v3", "--name=first", "busybox", "top")
   200  	out := cli.DockerCmd(c, "run", "--name=second", "--link=first:first", "busybox", "env").Stdout()
   201  	assert.Assert(c, is.Contains(out, "FIRST_ENV_e1=\n"))
   202  	assert.Assert(c, is.Contains(out, "FIRST_ENV_e2=v2"))
   203  	assert.Assert(c, is.Contains(out, "FIRST_ENV_e3=v3=v3"))
   204  }
   205  
   206  func (s *DockerCLILinksSuite) TestLinkShortDefinition(c *testing.T) {
   207  	testRequires(c, DaemonIsLinux)
   208  	cid := cli.DockerCmd(c, "run", "-d", "--name", "shortlinkdef", "busybox", "top").Stdout()
   209  	cid = strings.TrimSpace(cid)
   210  	cli.WaitRun(c, cid)
   211  
   212  	cid2 := cli.DockerCmd(c, "run", "-d", "--name", "link2", "--link", "shortlinkdef", "busybox", "top").Stdout()
   213  	cid2 = strings.TrimSpace(cid2)
   214  	cli.WaitRun(c, cid2)
   215  
   216  	links := inspectFieldJSON(c, cid2, "HostConfig.Links")
   217  	assert.Equal(c, links, `["/shortlinkdef:/link2/shortlinkdef"]`)
   218  }
   219  
   220  func (s *DockerCLILinksSuite) TestLinksNetworkHostContainer(c *testing.T) {
   221  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   222  	cli.DockerCmd(c, "run", "-d", "--net", "host", "--name", "host_container", "busybox", "top")
   223  	out, _, err := dockerCmdWithError("run", "--name", "should_fail", "--link", "host_container:tester", "busybox", "true")
   224  
   225  	// Running container linking to a container with --net host should have failed
   226  	assert.Check(c, err != nil, "out: %s", out)
   227  	// Running container linking to a container with --net host should have failed
   228  	assert.Check(c, is.Contains(out, runconfig.ErrConflictHostNetworkAndLinks.Error()))
   229  }
   230  
   231  func (s *DockerCLILinksSuite) TestLinksEtcHostsRegularFile(c *testing.T) {
   232  	testRequires(c, DaemonIsLinux, NotUserNamespace)
   233  	out := cli.DockerCmd(c, "run", "--net=host", "busybox", "ls", "-la", "/etc/hosts").Stdout()
   234  	// /etc/hosts should be a regular file
   235  	assert.Assert(c, is.Regexp("^-.+\n$", out))
   236  }
   237  
   238  func (s *DockerCLILinksSuite) TestLinksMultipleWithSameName(c *testing.T) {
   239  	testRequires(c, DaemonIsLinux)
   240  	cli.DockerCmd(c, "run", "-d", "--name=upstream-a", "busybox", "top")
   241  	cli.DockerCmd(c, "run", "-d", "--name=upstream-b", "busybox", "top")
   242  	cli.DockerCmd(c, "run", "--link", "upstream-a:upstream", "--link", "upstream-b:upstream", "busybox", "sh", "-c", "ping -c 1 upstream")
   243  }