github.com/moby/docker@v26.1.3+incompatible/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/docker/docker/integration-cli/cli" 13 "github.com/docker/docker/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 }